 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
75.0% |
72 / 96 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
97.9% |
94 / 96 |
| |
|
Line Coverage: |
99.4% |
174 / 175 |
| |
 |
|
 |
1 : //===--- Lookup.h - Classes for name lookup ---------------------*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // This file defines the LookupResult class, which is integral to
11 : // Sema's name-lookup subsystem.
12 : //
13 : //===----------------------------------------------------------------------===//
14 :
15 : #ifndef LLVM_CLANG_SEMA_LOOKUP_H
16 : #define LLVM_CLANG_SEMA_LOOKUP_H
17 :
18 : #include "Sema.h"
19 :
20 : namespace clang {
21 :
22 : /// @brief Represents the results of name lookup.
23 : ///
24 : /// An instance of the LookupResult class captures the results of a
25 : /// single name lookup, which can return no result (nothing found),
26 : /// a single declaration, a set of overloaded functions, or an
27 : /// ambiguity. Use the getKind() method to determine which of these
28 : /// results occurred for a given lookup.
29 : class LookupResult {
30 : public:
31 : enum LookupResultKind {
32 : /// @brief No entity found met the criteria.
33 : NotFound = 0,
34 :
35 : /// @brief No entity found met the criteria within the current
36 : /// instantiation,, but there were dependent base classes of the
37 : /// current instantiation that could not be searched.
38 : NotFoundInCurrentInstantiation,
39 :
40 : /// @brief Name lookup found a single declaration that met the
41 : /// criteria. getFoundDecl() will return this declaration.
42 : Found,
43 :
44 : /// @brief Name lookup found a set of overloaded functions that
45 : /// met the criteria.
46 : FoundOverloaded,
47 :
48 : /// @brief Name lookup found an unresolvable value declaration
49 : /// and cannot yet complete. This only happens in C++ dependent
50 : /// contexts with dependent using declarations.
51 : FoundUnresolvedValue,
52 :
53 : /// @brief Name lookup results in an ambiguity; use
54 : /// getAmbiguityKind to figure out what kind of ambiguity
55 : /// we have.
56 : Ambiguous
57 : };
58 :
59 : enum AmbiguityKind {
60 : /// Name lookup results in an ambiguity because multiple
61 : /// entities that meet the lookup criteria were found in
62 : /// subobjects of different types. For example:
63 : /// @code
64 : /// struct A { void f(int); }
65 : /// struct B { void f(double); }
66 : /// struct C : A, B { };
67 : /// void test(C c) {
68 : /// c.f(0); // error: A::f and B::f come from subobjects of different
69 : /// // types. overload resolution is not performed.
70 : /// }
71 : /// @endcode
72 : AmbiguousBaseSubobjectTypes,
73 :
74 : /// Name lookup results in an ambiguity because multiple
75 : /// nonstatic entities that meet the lookup criteria were found
76 : /// in different subobjects of the same type. For example:
77 : /// @code
78 : /// struct A { int x; };
79 : /// struct B : A { };
80 : /// struct C : A { };
81 : /// struct D : B, C { };
82 : /// int test(D d) {
83 : /// return d.x; // error: 'x' is found in two A subobjects (of B and C)
84 : /// }
85 : /// @endcode
86 : AmbiguousBaseSubobjects,
87 :
88 : /// Name lookup results in an ambiguity because multiple definitions
89 : /// of entity that meet the lookup criteria were found in different
90 : /// declaration contexts.
91 : /// @code
92 : /// namespace A {
93 : /// int i;
94 : /// namespace B { int i; }
95 : /// int test() {
96 : /// using namespace B;
97 : /// return i; // error 'i' is found in namespace A and A::B
98 : /// }
99 : /// }
100 : /// @endcode
101 : AmbiguousReference,
102 :
103 : /// Name lookup results in an ambiguity because an entity with a
104 : /// tag name was hidden by an entity with an ordinary name from
105 : /// a different context.
106 : /// @code
107 : /// namespace A { struct Foo {}; }
108 : /// namespace B { void Foo(); }
109 : /// namespace C {
110 : /// using namespace A;
111 : /// using namespace B;
112 : /// }
113 : /// void test() {
114 : /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a
115 : /// // different namespace
116 : /// }
117 : /// @endcode
118 : AmbiguousTagHiding
119 : };
120 :
121 : /// A little identifier for flagging temporary lookup results.
122 : enum TemporaryToken {
123 : Temporary
124 : };
125 :
126 : typedef UnresolvedSetImpl::iterator iterator;
127 : typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS);
128 :
129 : LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc,
130 : Sema::LookupNameKind LookupKind,
131 140418: Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration)
132 : : ResultKind(NotFound),
133 : Paths(0),
134 : NamingClass(0),
135 : SemaRef(SemaRef),
136 : Name(Name),
137 : NameLoc(NameLoc),
138 : LookupKind(LookupKind),
139 : IsAcceptableFn(0),
140 : IDNS(0),
141 : Redecl(Redecl != Sema::NotForRedeclaration),
142 : HideTags(true),
143 140418: Diagnose(Redecl == Sema::NotForRedeclaration)
144 : {
145 140418: configure();
146 140418: }
147 :
148 : /// Creates a temporary lookup result, initializing its core data
149 : /// using the information from another result. Diagnostics are always
150 : /// disabled.
151 61: LookupResult(TemporaryToken _, const LookupResult &Other)
152 : : ResultKind(NotFound),
153 : Paths(0),
154 : NamingClass(0),
155 : SemaRef(Other.SemaRef),
156 : Name(Other.Name),
157 : NameLoc(Other.NameLoc),
158 : LookupKind(Other.LookupKind),
159 : IsAcceptableFn(Other.IsAcceptableFn),
160 : IDNS(Other.IDNS),
161 : Redecl(Other.Redecl),
162 : HideTags(Other.HideTags),
163 61: Diagnose(false)
164 61: {}
165 :
166 140479: ~LookupResult() {
78385: branch 0 taken
62094: branch 1 taken
167 140479: if (Diagnose) diagnose();
30: branch 0 taken
140449: branch 1 taken
168 140479: if (Paths) deletePaths(Paths);
169 140479: }
170 :
171 : /// Gets the name to look up.
172 332992: DeclarationName getLookupName() const {
173 332992: return Name;
174 : }
175 :
176 : /// \brief Sets the name to look up.
177 61: void setLookupName(DeclarationName Name) {
178 61: this->Name = Name;
179 61: }
180 :
181 : /// Gets the kind of lookup to perform.
182 136952: Sema::LookupNameKind getLookupKind() const {
183 136952: return LookupKind;
184 : }
185 :
186 : /// True if this lookup is just looking for an existing declaration.
187 194765: bool isForRedeclaration() const {
188 194765: return Redecl;
189 : }
190 :
191 : /// Sets whether tag declarations should be hidden by non-tag
192 : /// declarations during resolution. The default is true.
193 239: void setHideTags(bool Hide) {
194 239: HideTags = Hide;
195 239: }
196 :
197 121162: bool isAmbiguous() const {
198 121162: return getResultKind() == Ambiguous;
199 : }
200 :
201 : /// Determines if this names a single result which is not an
202 : /// unresolved value using decl. If so, it is safe to call
203 : /// getFoundDecl().
204 86245: bool isSingleResult() const {
205 86245: return getResultKind() == Found;
206 : }
207 :
208 : /// Determines if the results are overloaded.
209 3499: bool isOverloadedResult() const {
210 3499: return getResultKind() == FoundOverloaded;
211 : }
212 :
213 3076: bool isUnresolvableResult() const {
214 3076: return getResultKind() == FoundUnresolvedValue;
215 : }
216 :
217 514755: LookupResultKind getResultKind() const {
218 514755: sanity();
219 514755: return ResultKind;
220 : }
221 :
222 52: AmbiguityKind getAmbiguityKind() const {
0: branch 1 not taken
52: branch 2 taken
223 52: assert(isAmbiguous());
224 52: return Ambiguity;
225 : }
226 :
227 : const UnresolvedSetImpl &asUnresolvedSet() const {
228 : return Decls;
229 : }
230 :
231 220897: iterator begin() const { return iterator(Decls.begin()); }
232 59093: iterator end() const { return iterator(Decls.end()); }
233 :
234 : /// \brief Return true if no decls were found
235 189592: bool empty() const { return Decls.empty(); }
236 :
237 : /// \brief Return the base paths structure that's associated with
238 : /// these results, or null if none is.
239 21: CXXBasePaths *getBasePaths() const {
240 21: return Paths;
241 : }
242 :
243 : /// \brief Tests whether the given declaration is acceptable.
244 52717: bool isAcceptableDecl(NamedDecl *D) const {
0: branch 0 not taken
52717: branch 1 taken
245 52717: assert(IsAcceptableFn);
246 52717: return IsAcceptableFn(D, IDNS);
247 : }
248 :
249 : /// \brief Returns the identifier namespace mask for this lookup.
250 78743: unsigned getIdentifierNamespace() const {
251 78743: return IDNS;
252 : }
253 :
254 : /// \brief Returns whether these results arose from performing a
255 : /// lookup into a class.
256 78352: bool isClassLookup() const {
257 78352: return NamingClass != 0;
258 : }
259 :
260 : /// \brief Returns the 'naming class' for this lookup, i.e. the
261 : /// class which was looked into to find these results.
262 : ///
263 : /// C++0x [class.access.base]p5:
264 : /// The access to a member is affected by the class in which the
265 : /// member is named. This naming class is the class in which the
266 : /// member name was looked up and found. [Note: this class can be
267 : /// explicit, e.g., when a qualified-id is used, or implicit,
268 : /// e.g., when a class member access operator (5.2.5) is used
269 : /// (including cases where an implicit "this->" is added). If both
270 : /// a class member access operator and a qualified-id are used to
271 : /// name the member (as in p->T::m), the class naming the member
272 : /// is the class named by the nested-name-specifier of the
273 : /// qualified-id (that is, T). -- end note ]
274 : ///
275 : /// This is set by the lookup routines when they find results in a class.
276 1820: CXXRecordDecl *getNamingClass() const {
277 1820: return NamingClass;
278 : }
279 :
280 : /// \brief Sets the 'naming class' for this lookup.
281 4255: void setNamingClass(CXXRecordDecl *Record) {
282 4255: NamingClass = Record;
283 4255: }
284 :
285 : /// \brief Add a declaration to these results with its natural access.
286 : /// Does not test the acceptance criteria.
287 94739: void addDecl(NamedDecl *D) {
288 94739: addDecl(D, D->getAccess());
289 94739: }
290 :
291 : /// \brief Add a declaration to these results with the given access.
292 : /// Does not test the acceptance criteria.
293 95184: void addDecl(NamedDecl *D, AccessSpecifier AS) {
294 95184: Decls.addDecl(D, AS);
295 95184: ResultKind = Found;
296 95184: }
297 :
298 : /// \brief Add all the declarations from another set of lookup
299 : /// results.
300 32: void addAllDecls(const LookupResult &Other) {
301 32: Decls.append(Other.Decls.begin(), Other.Decls.end());
302 32: ResultKind = Found;
303 32: }
304 :
305 : /// \brief Determine whether no result was found because we could not
306 : /// search into dependent base classes of the current instantiation.
307 8: bool wasNotFoundInCurrentInstantiation() const {
308 8: return ResultKind == NotFoundInCurrentInstantiation;
309 : }
310 :
311 : /// \brief Note that while no result was found in the current instantiation,
312 : /// there were dependent base classes that could not be searched.
313 7: void setNotFoundInCurrentInstantiation() {
7: branch 0 taken
0: branch 1 not taken
0: branch 3 not taken
7: branch 4 taken
314 7: assert(ResultKind == NotFound && Decls.empty());
315 7: ResultKind = NotFoundInCurrentInstantiation;
316 7: }
317 :
318 : /// \brief Resolves the result kind of the lookup, possibly hiding
319 : /// decls.
320 : ///
321 : /// This should be called in any environment where lookup might
322 : /// generate multiple lookup results.
323 : void resolveKind();
324 :
325 : /// \brief Re-resolves the result kind of the lookup after a set of
326 : /// removals has been performed.
327 882: void resolveKindAfterFilter() {
761: branch 1 taken
121: branch 2 taken
328 882: if (Decls.empty()) {
761: branch 0 taken
0: branch 1 not taken
329 761: if (ResultKind != NotFoundInCurrentInstantiation)
330 761: ResultKind = NotFound;
331 : } else {
332 121: ResultKind = Found;
333 121: resolveKind();
334 : }
335 882: }
336 :
337 : template <class DeclClass>
338 94306: DeclClass *getAsSingle() const {
25068: branch 1 taken
34226: branch 2 taken
28: branch 4 taken
101: branch 5 taken
56: branch 7 taken
770: branch 8 taken
0: branch 10 not taken
4: branch 11 taken
0: branch 13 not taken
27002: branch 14 taken
0: branch 16 not taken
0: branch 17 not taken
706: branch 19 taken
6345: branch 20 taken
339 94306: if (getResultKind() != Found) return 0;
340 68448: return dyn_cast<DeclClass>(getFoundDecl());
341 : }
342 :
343 : /// \brief Fetch the unique decl found by this lookup. Asserts
344 : /// that one was found.
345 : ///
346 : /// This is intended for users who have examined the result kind
347 : /// and are certain that there is only one result.
348 140661: NamedDecl *getFoundDecl() const {
349 : assert(getResultKind() == Found
140661: branch 1 taken
0: branch 2 not taken
350 140661: && "getFoundDecl called on non-unique result");
351 140661: return (*begin())->getUnderlyingDecl();
352 : }
353 :
354 : /// Fetches a representative decl. Useful for lazy diagnostics.
355 24: NamedDecl *getRepresentativeDecl() const {
24: branch 1 taken
0: branch 2 not taken
356 24: assert(!Decls.empty() && "cannot get representative of empty set");
357 24: return *begin();
358 : }
359 :
360 : /// \brief Asks if the result is a single tag decl.
361 30697: bool isSingleTagDecl() const {
1790: branch 1 taken
28907: branch 2 taken
130: branch 5 taken
1660: branch 6 taken
362 30697: return getResultKind() == Found && isa<TagDecl>(getFoundDecl());
363 : }
364 :
365 : /// \brief Make these results show that the name was found in
366 : /// base classes of different types.
367 : ///
368 : /// The given paths object is copied and invalidated.
369 : void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P);
370 :
371 : /// \brief Make these results show that the name was found in
372 : /// distinct base classes of the same type.
373 : ///
374 : /// The given paths object is copied and invalidated.
375 : void setAmbiguousBaseSubobjects(CXXBasePaths &P);
376 :
377 : /// \brief Make these results show that the name was found in
378 : /// different contexts and a tag decl was hidden by an ordinary
379 : /// decl in a different context.
380 2: void setAmbiguousQualifiedTagHiding() {
381 2: setAmbiguous(AmbiguousTagHiding);
382 2: }
383 :
384 : /// \brief Clears out any current state.
385 15522: void clear() {
386 15522: ResultKind = NotFound;
387 15522: Decls.clear();
0: branch 0 not taken
15522: branch 1 taken
388 15522: if (Paths) deletePaths(Paths);
389 15522: Paths = NULL;
390 15522: }
391 :
392 : /// \brief Clears out any current state and re-initializes for a
393 : /// different kind of lookup.
394 14434: void clear(Sema::LookupNameKind Kind) {
395 14434: clear();
396 14434: LookupKind = Kind;
397 14434: configure();
398 14434: }
399 :
400 : void print(llvm::raw_ostream &);
401 :
402 : /// Suppress the diagnostics that would normally fire because of this
403 : /// lookup. This happens during (e.g.) redeclaration lookups.
404 16009: void suppressDiagnostics() {
405 16009: Diagnose = false;
406 16009: }
407 :
408 : /// Sets a 'context' source range.
409 743: void setContextRange(SourceRange SR) {
410 743: NameContextRange = SR;
411 743: }
412 :
413 : /// Gets the source range of the context of this name; for C++
414 : /// qualified lookups, this is the source range of the scope
415 : /// specifier.
416 33: SourceRange getContextRange() const {
417 33: return NameContextRange;
418 : }
419 :
420 : /// Gets the location of the identifier. This isn't always defined:
421 : /// sometimes we're doing lookups on synthesized names.
422 38394: SourceLocation getNameLoc() const {
423 38394: return NameLoc;
424 : }
425 :
426 : /// \brief Get the Sema object that this lookup result is searching
427 : /// with.
428 85: Sema &getSema() const { return SemaRef; }
429 :
430 : /// A class for iterating through a result set and possibly
431 : /// filtering out results. The results returned are possibly
432 : /// sugared.
433 : class Filter {
434 : LookupResult &Results;
435 : LookupResult::iterator I;
436 : bool Changed;
437 : #ifndef NDEBUG
438 : bool CalledDone;
439 : #endif
440 :
441 : friend class LookupResult;
442 33654: Filter(LookupResult &Results)
443 : : Results(Results), I(Results.begin()), Changed(false)
444 : #ifndef NDEBUG
445 33654: , CalledDone(false)
446 : #endif
447 33654: {}
448 :
449 : public:
450 : #ifndef NDEBUG
451 33654: ~Filter() {
452 : assert(CalledDone &&
0: branch 0 not taken
33654: branch 1 taken
453 33654: "LookupResult::Filter destroyed without done() call");
454 33654: }
455 : #endif
456 :
457 40120: bool hasNext() const {
458 40120: return I != Results.end();
459 : }
460 :
461 6466: NamedDecl *next() {
6466: branch 2 taken
0: branch 3 not taken
462 6466: assert(I != Results.end() && "next() called on empty filter");
463 6466: return *I++;
464 : }
465 :
466 : /// Erase the last element returned from this iterator.
467 818: void erase() {
468 818: Results.Decls.erase(--I);
469 818: Changed = true;
470 818: }
471 :
472 : /// Replaces the current entry with the given one, preserving the
473 : /// access bits.
474 107: void replace(NamedDecl *D) {
475 107: Results.Decls.replace(I-1, D);
476 107: Changed = true;
477 107: }
478 :
479 : /// Replaces the current entry with the given one.
480 : void replace(NamedDecl *D, AccessSpecifier AS) {
481 : Results.Decls.replace(I-1, D, AS);
482 : Changed = true;
483 : }
484 :
485 33654: void done() {
486 : #ifndef NDEBUG
0: branch 0 not taken
33654: branch 1 taken
487 33654: assert(!CalledDone && "done() called twice");
488 33654: CalledDone = true;
489 : #endif
490 :
882: branch 0 taken
32772: branch 1 taken
491 33654: if (Changed)
492 882: Results.resolveKindAfterFilter();
493 33654: }
494 : };
495 :
496 : /// Create a filter for this result set.
497 33654: Filter makeFilter() {
498 33654: return Filter(*this);
499 : }
500 :
501 : private:
502 78385: void diagnose() {
33: branch 1 taken
78352: branch 2 taken
503 78385: if (isAmbiguous())
504 33: SemaRef.DiagnoseAmbiguousLookup(*this);
2563: branch 1 taken
75789: branch 2 taken
143: branch 4 taken
2420: branch 5 taken
143: branch 6 taken
78209: branch 7 taken
505 78352: else if (isClassLookup() && SemaRef.getLangOptions().AccessControl)
506 143: SemaRef.CheckAccess(*this);
507 78385: }
508 :
509 73: void setAmbiguous(AmbiguityKind AK) {
510 73: ResultKind = Ambiguous;
511 73: Ambiguity = AK;
512 73: }
513 :
514 : void addDeclsFromBasePaths(const CXXBasePaths &P);
515 : void configure();
516 :
517 : // Sanity checks.
518 514755: void sanity() const {
125023: branch 0 taken
389732: branch 1 taken
0: branch 3 not taken
125023: branch 4 taken
519 514755: assert(ResultKind != NotFound || Decls.size() == 0);
383176: branch 0 taken
131579: branch 1 taken
0: branch 3 not taken
383176: branch 4 taken
520 514755: assert(ResultKind != Found || Decls.size() == 1);
521 : assert(ResultKind != FoundOverloaded || Decls.size() > 1 ||
522 : (Decls.size() == 1 &&
6322: branch 0 taken
508433: branch 1 taken
2197: branch 3 taken
4125: branch 4 taken
2197: branch 6 taken
0: branch 7 not taken
0: branch 12 not taken
2197: branch 13 taken
523 514755: isa<FunctionTemplateDecl>((*begin())->getUnderlyingDecl())));
60: branch 0 taken
514695: branch 1 taken
0: branch 3 not taken
60: branch 4 taken
524 514755: assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved());
525 : assert(ResultKind != Ambiguous || Decls.size() > 1 ||
163: branch 0 taken
514592: branch 1 taken
20: branch 3 taken
143: branch 4 taken
20: branch 6 taken
0: branch 7 not taken
0: branch 8 not taken
20: branch 9 taken
526 514755: (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects));
527 : assert((Paths != NULL) == (ResultKind == Ambiguous &&
528 : (Ambiguity == AmbiguousBaseSubobjectTypes ||
163: branch 0 taken
514592: branch 1 taken
90: branch 2 taken
73: branch 3 taken
32: branch 4 taken
58: branch 5 taken
0: branch 6 not taken
514755: branch 7 taken
529 514755: Ambiguity == AmbiguousBaseSubobjects)));
530 514755: }
531 :
532 60: bool sanityCheckUnresolved() const {
69: branch 4 taken
0: branch 5 not taken
533 69: for (iterator I = begin(), E = end(); I != E; ++I)
60: branch 2 taken
9: branch 3 taken
534 69: if (isa<UnresolvedUsingValueDecl>(*I))
535 60: return true;
536 0: return false;
537 : }
538 :
539 : static void deletePaths(CXXBasePaths *);
540 :
541 : // Results.
542 : LookupResultKind ResultKind;
543 : AmbiguityKind Ambiguity; // ill-defined unless ambiguous
544 : UnresolvedSet<8> Decls;
545 : CXXBasePaths *Paths;
546 : CXXRecordDecl *NamingClass;
547 :
548 : // Parameters.
549 : Sema &SemaRef;
550 : DeclarationName Name;
551 : SourceLocation NameLoc;
552 : SourceRange NameContextRange;
553 : Sema::LookupNameKind LookupKind;
554 : ResultFilter IsAcceptableFn; // set by configure()
555 : unsigned IDNS; // set by configure()
556 :
557 : bool Redecl;
558 :
559 : /// \brief True if tag declarations should be hidden if non-tags
560 : /// are present
561 : bool HideTags;
562 :
563 : bool Diagnose;
564 : };
565 :
566 : /// \brief Consumes visible declarations found when searching for
567 : /// all visible names within a given scope or context.
568 : ///
569 : /// This abstract class is meant to be subclassed by clients of \c
570 : /// Sema::LookupVisibleDecls(), each of which should override the \c
571 : /// FoundDecl() function to process declarations as they are found.
572 223: class VisibleDeclConsumer {
573 : public:
574 : /// \brief Destroys the visible declaration consumer.
575 : virtual ~VisibleDeclConsumer();
576 :
577 : /// \brief Invoked each time \p Sema::LookupVisibleDecls() finds a
578 : /// declaration visible from the current scope or context.
579 : ///
580 : /// \param ND the declaration found.
581 : ///
582 : /// \param Hiding a declaration that hides the declaration \p ND,
583 : /// or NULL if no such declaration exists.
584 : ///
585 : /// \param InBaseClass whether this declaration was found in base
586 : /// class of the context we searched.
587 : virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding,
588 : bool InBaseClass) = 0;
589 : };
590 :
591 : /// \brief A class for storing results from argument-dependent lookup.
592 3266: class ADLResult {
593 : private:
594 : /// A map from canonical decls to the 'most recent' decl.
595 : llvm::DenseMap<NamedDecl*, NamedDecl*> Decls;
596 :
597 : public:
598 : /// Adds a new ADL candidate to this map.
599 : void insert(NamedDecl *D);
600 :
601 : /// Removes any data associated with a given decl.
602 2043: void erase(NamedDecl *D) {
603 2043: Decls.erase(cast<NamedDecl>(D->getCanonicalDecl()));
604 2043: }
605 :
606 : class iterator {
607 : typedef llvm::DenseMap<NamedDecl*,NamedDecl*>::iterator inner_iterator;
608 : inner_iterator iter;
609 :
610 : friend class ADLResult;
611 3266: iterator(const inner_iterator &iter) : iter(iter) {}
612 : public:
613 : iterator() {}
614 :
615 69: iterator &operator++() { ++iter; return *this; }
616 : iterator operator++(int) { return iterator(iter++); }
617 :
618 73: NamedDecl *operator*() const { return iter->second; }
619 :
620 : bool operator==(const iterator &other) const { return iter == other.iter; }
621 1702: bool operator!=(const iterator &other) const { return iter != other.iter; }
622 : };
623 :
624 1633: iterator begin() { return iterator(Decls.begin()); }
625 1633: iterator end() { return iterator(Decls.end()); }
626 : };
627 :
628 : }
629 :
630 : #endif
Generated: 2010-02-10 01:31 by zcov