//===--- Lookup.h - Classes for name lookup ---------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the LookupResult class, which is integral to // Sema's name-lookup subsystem. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SEMA_LOOKUP_H #define LLVM_CLANG_SEMA_LOOKUP_H #include "clang/AST/DeclCXX.h" #include "clang/Sema/Sema.h" namespace clang { /// @brief Represents the results of name lookup. /// /// An instance of the LookupResult class captures the results of a /// single name lookup, which can return no result (nothing found), /// a single declaration, a set of overloaded functions, or an /// ambiguity. Use the getKind() method to determine which of these /// results occurred for a given lookup. class LookupResult { public: enum LookupResultKind { /// @brief No entity found met the criteria. NotFound = 0, /// @brief No entity found met the criteria within the current /// instantiation,, but there were dependent base classes of the /// current instantiation that could not be searched. NotFoundInCurrentInstantiation, /// @brief Name lookup found a single declaration that met the /// criteria. getFoundDecl() will return this declaration. Found, /// @brief Name lookup found a set of overloaded functions that /// met the criteria. FoundOverloaded, /// @brief Name lookup found an unresolvable value declaration /// and cannot yet complete. This only happens in C++ dependent /// contexts with dependent using declarations. FoundUnresolvedValue, /// @brief Name lookup results in an ambiguity; use /// getAmbiguityKind to figure out what kind of ambiguity /// we have. Ambiguous }; enum AmbiguityKind { /// Name lookup results in an ambiguity because multiple /// entities that meet the lookup criteria were found in /// subobjects of different types. For example: /// @code /// struct A { void f(int); } /// struct B { void f(double); } /// struct C : A, B { }; /// void test(C c) { /// c.f(0); // error: A::f and B::f come from subobjects of different /// // types. overload resolution is not performed. /// } /// @endcode AmbiguousBaseSubobjectTypes, /// Name lookup results in an ambiguity because multiple /// nonstatic entities that meet the lookup criteria were found /// in different subobjects of the same type. For example: /// @code /// struct A { int x; }; /// struct B : A { }; /// struct C : A { }; /// struct D : B, C { }; /// int test(D d) { /// return d.x; // error: 'x' is found in two A subobjects (of B and C) /// } /// @endcode AmbiguousBaseSubobjects, /// Name lookup results in an ambiguity because multiple definitions /// of entity that meet the lookup criteria were found in different /// declaration contexts. /// @code /// namespace A { /// int i; /// namespace B { int i; } /// int test() { /// using namespace B; /// return i; // error 'i' is found in namespace A and A::B /// } /// } /// @endcode AmbiguousReference, /// Name lookup results in an ambiguity because an entity with a /// tag name was hidden by an entity with an ordinary name from /// a different context. /// @code /// namespace A { struct Foo {}; } /// namespace B { void Foo(); } /// namespace C { /// using namespace A; /// using namespace B; /// } /// void test() { /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a /// // different namespace /// } /// @endcode AmbiguousTagHiding }; /// A little identifier for flagging temporary lookup results. enum TemporaryToken { Temporary }; typedef UnresolvedSetImpl::iterator iterator; LookupResult(Sema &SemaRef, const DeclarationNameInfo &NameInfo, Sema::LookupNameKind LookupKind, Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) : ResultKind(NotFound), Paths(0), NamingClass(0), SemaRef(SemaRef), NameInfo(NameInfo), LookupKind(LookupKind), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), HideTags(true), Diagnose(Redecl == Sema::NotForRedeclaration), AllowHidden(Redecl == Sema::ForRedeclaration), Shadowed(false) { configure(); } // TODO: consider whether this constructor should be restricted to take // as input a const IndentifierInfo* (instead of Name), // forcing other cases towards the constructor taking a DNInfo. LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, Sema::LookupNameKind LookupKind, Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) : ResultKind(NotFound), Paths(0), NamingClass(0), SemaRef(SemaRef), NameInfo(Name, NameLoc), LookupKind(LookupKind), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), HideTags(true), Diagnose(Redecl == Sema::NotForRedeclaration), AllowHidden(Redecl == Sema::ForRedeclaration), Shadowed(false) { configure(); } /// Creates a temporary lookup result, initializing its core data /// using the information from another result. Diagnostics are always /// disabled. LookupResult(TemporaryToken _, const LookupResult &Other) : ResultKind(NotFound), Paths(0), NamingClass(0), SemaRef(Other.SemaRef), NameInfo(Other.NameInfo), LookupKind(Other.LookupKind), IDNS(Other.IDNS), Redecl(Other.Redecl), HideTags(Other.HideTags), Diagnose(false), AllowHidden(Other.AllowHidden), Shadowed(false) {} ~LookupResult() { if (Diagnose) diagnose(); if (Paths) deletePaths(Paths); } /// Gets the name info to look up. const DeclarationNameInfo &getLookupNameInfo() const { return NameInfo; } /// \brief Sets the name info to look up. void setLookupNameInfo(const DeclarationNameInfo &NameInfo) { this->NameInfo = NameInfo; } /// Gets the name to look up. DeclarationName getLookupName() const { return NameInfo.getName(); } /// \brief Sets the name to look up. void setLookupName(DeclarationName Name) { NameInfo.setName(Name); } /// Gets the kind of lookup to perform. Sema::LookupNameKind getLookupKind() const { return LookupKind; } /// True if this lookup is just looking for an existing declaration. bool isForRedeclaration() const { return Redecl; } /// \brief Specify whether hidden declarations are visible, e.g., /// for recovery reasons. void setAllowHidden(bool AH) { AllowHidden = AH; } /// \brief Determine whether this lookup is permitted to see hidden /// declarations, such as those in modules that have not yet been imported. bool isHiddenDeclarationVisible() const { return AllowHidden || LookupKind == Sema::LookupTagName; } /// Sets whether tag declarations should be hidden by non-tag /// declarations during resolution. The default is true. void setHideTags(bool Hide) { HideTags = Hide; } bool isAmbiguous() const { return getResultKind() == Ambiguous; } /// Determines if this names a single result which is not an /// unresolved value using decl. If so, it is safe to call /// getFoundDecl(). bool isSingleResult() const { return getResultKind() == Found; } /// Determines if the results are overloaded. bool isOverloadedResult() const { return getResultKind() == FoundOverloaded; } bool isUnresolvableResult() const { return getResultKind() == FoundUnresolvedValue; } LookupResultKind getResultKind() const { sanity(); return ResultKind; } AmbiguityKind getAmbiguityKind() const { assert(isAmbiguous()); return Ambiguity; } const UnresolvedSetImpl &asUnresolvedSet() const { return Decls; } iterator begin() const { return iterator(Decls.begin()); } iterator end() const { return iterator(Decls.end()); } /// \brief Return true if no decls were found bool empty() const { return Decls.empty(); } /// \brief Return the base paths structure that's associated with /// these results, or null if none is. CXXBasePaths *getBasePaths() const { return Paths; } /// \brief Determine whether the given declaration is visible to the /// program. static bool isVisible(Sema &SemaRef, NamedDecl *D) { // If this declaration is not hidden, it's visible. if (!D->isHidden()) return true; if (SemaRef.ActiveTemplateInstantiations.empty()) return false; // During template instantiation, we can refer to hidden declarations, if // they were visible in any module along the path of instantiation. return isVisibleSlow(SemaRef, D); } /// \brief Retrieve the accepted (re)declaration of the given declaration, /// if there is one. NamedDecl *getAcceptableDecl(NamedDecl *D) const { if (!D->isInIdentifierNamespace(IDNS)) return 0; if (isHiddenDeclarationVisible() || isVisible(SemaRef, D)) return D; return getAcceptableDeclSlow(D); } private: static bool isVisibleSlow(Sema &SemaRef, NamedDecl *D); NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const; public: /// \brief Returns the identifier namespace mask for this lookup. unsigned getIdentifierNamespace() const { return IDNS; } /// \brief Returns whether these results arose from performing a /// lookup into a class. bool isClassLookup() const { return NamingClass != 0; } /// \brief Returns the 'naming class' for this lookup, i.e. the /// class which was looked into to find these results. /// /// C++0x [class.access.base]p5: /// The access to a member is affected by the class in which the /// member is named. This naming class is the class in which the /// member name was looked up and found. [Note: this class can be /// explicit, e.g., when a qualified-id is used, or implicit, /// e.g., when a class member access operator (5.2.5) is used /// (including cases where an implicit "this->" is added). If both /// a class member access operator and a qualified-id are used to /// name the member (as in p->T::m), the class naming the member /// is the class named by the nested-name-specifier of the /// qualified-id (that is, T). -- end note ] /// /// This is set by the lookup routines when they find results in a class. CXXRecordDecl *getNamingClass() const { return NamingClass; } /// \brief Sets the 'naming class' for this lookup. void setNamingClass(CXXRecordDecl *Record) { NamingClass = Record; } /// \brief Returns the base object type associated with this lookup; /// important for [class.protected]. Most lookups do not have an /// associated base object. QualType getBaseObjectType() const { return BaseObjectType; } /// \brief Sets the base object type for this lookup. void setBaseObjectType(QualType T) { BaseObjectType = T; } /// \brief Add a declaration to these results with its natural access. /// Does not test the acceptance criteria. void addDecl(NamedDecl *D) { addDecl(D, D->getAccess()); } /// \brief Add a declaration to these results with the given access. /// Does not test the acceptance criteria. void addDecl(NamedDecl *D, AccessSpecifier AS) { Decls.addDecl(D, AS); ResultKind = Found; } /// \brief Add all the declarations from another set of lookup /// results. void addAllDecls(const LookupResult &Other) { Decls.append(Other.Decls.begin(), Other.Decls.end()); ResultKind = Found; } /// \brief Determine whether no result was found because we could not /// search into dependent base classes of the current instantiation. bool wasNotFoundInCurrentInstantiation() const { return ResultKind == NotFoundInCurrentInstantiation; } /// \brief Note that while no result was found in the current instantiation, /// there were dependent base classes that could not be searched. void setNotFoundInCurrentInstantiation() { assert(ResultKind == NotFound && Decls.empty()); ResultKind = NotFoundInCurrentInstantiation; } /// \brief Determine whether the lookup result was shadowed by some other /// declaration that lookup ignored. bool isShadowed() const { return Shadowed; } /// \brief Note that we found and ignored a declaration while performing /// lookup. void setShadowed() { Shadowed = true; } /// \brief Resolves the result kind of the lookup, possibly hiding /// decls. /// /// This should be called in any environment where lookup might /// generate multiple lookup results. void resolveKind(); /// \brief Re-resolves the result kind of the lookup after a set of /// removals has been performed. void resolveKindAfterFilter() { if (Decls.empty()) { if (ResultKind != NotFoundInCurrentInstantiation) ResultKind = NotFound; if (Paths) { deletePaths(Paths); Paths = 0; } } else { AmbiguityKind SavedAK = Ambiguity; ResultKind = Found; resolveKind(); // If we didn't make the lookup unambiguous, restore the old // ambiguity kind. if (ResultKind == Ambiguous) { Ambiguity = SavedAK; } else if (Paths) { deletePaths(Paths); Paths = 0; } } } template DeclClass *getAsSingle() const { if (getResultKind() != Found) return 0; return dyn_cast(getFoundDecl()); } /// \brief Fetch the unique decl found by this lookup. Asserts /// that one was found. /// /// This is intended for users who have examined the result kind /// and are certain that there is only one result. NamedDecl *getFoundDecl() const { assert(getResultKind() == Found && "getFoundDecl called on non-unique result"); return (*begin())->getUnderlyingDecl(); } /// Fetches a representative decl. Useful for lazy diagnostics. NamedDecl *getRepresentativeDecl() const { assert(!Decls.empty() && "cannot get representative of empty set"); return *begin(); } /// \brief Asks if the result is a single tag decl. bool isSingleTagDecl() const { return getResultKind() == Found && isa(getFoundDecl()); } /// \brief Make these results show that the name was found in /// base classes of different types. /// /// The given paths object is copied and invalidated. void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P); /// \brief Make these results show that the name was found in /// distinct base classes of the same type. /// /// The given paths object is copied and invalidated. void setAmbiguousBaseSubobjects(CXXBasePaths &P); /// \brief Make these results show that the name was found in /// different contexts and a tag decl was hidden by an ordinary /// decl in a different context. void setAmbiguousQualifiedTagHiding() { setAmbiguous(AmbiguousTagHiding); } /// \brief Clears out any current state. void clear() { ResultKind = NotFound; Decls.clear(); if (Paths) deletePaths(Paths); Paths = NULL; NamingClass = 0; Shadowed = false; } /// \brief Clears out any current state and re-initializes for a /// different kind of lookup. void clear(Sema::LookupNameKind Kind) { clear(); LookupKind = Kind; configure(); } /// \brief Change this lookup's redeclaration kind. void setRedeclarationKind(Sema::RedeclarationKind RK) { Redecl = RK; AllowHidden = (RK == Sema::ForRedeclaration); configure(); } void print(raw_ostream &); /// Suppress the diagnostics that would normally fire because of this /// lookup. This happens during (e.g.) redeclaration lookups. void suppressDiagnostics() { Diagnose = false; } /// Determines whether this lookup is suppressing diagnostics. bool isSuppressingDiagnostics() const { return !Diagnose; } /// Sets a 'context' source range. void setContextRange(SourceRange SR) { NameContextRange = SR; } /// Gets the source range of the context of this name; for C++ /// qualified lookups, this is the source range of the scope /// specifier. SourceRange getContextRange() const { return NameContextRange; } /// Gets the location of the identifier. This isn't always defined: /// sometimes we're doing lookups on synthesized names. SourceLocation getNameLoc() const { return NameInfo.getLoc(); } /// \brief Get the Sema object that this lookup result is searching /// with. Sema &getSema() const { return SemaRef; } /// A class for iterating through a result set and possibly /// filtering out results. The results returned are possibly /// sugared. class Filter { LookupResult &Results; LookupResult::iterator I; bool Changed; bool CalledDone; friend class LookupResult; Filter(LookupResult &Results) : Results(Results), I(Results.begin()), Changed(false), CalledDone(false) {} public: ~Filter() { assert(CalledDone && "LookupResult::Filter destroyed without done() call"); } bool hasNext() const { return I != Results.end(); } NamedDecl *next() { assert(I != Results.end() && "next() called on empty filter"); return *I++; } /// Restart the iteration. void restart() { I = Results.begin(); } /// Erase the last element returned from this iterator. void erase() { Results.Decls.erase(--I); Changed = true; } /// Replaces the current entry with the given one, preserving the /// access bits. void replace(NamedDecl *D) { Results.Decls.replace(I-1, D); Changed = true; } /// Replaces the current entry with the given one. void replace(NamedDecl *D, AccessSpecifier AS) { Results.Decls.replace(I-1, D, AS); Changed = true; } void done() { assert(!CalledDone && "done() called twice"); CalledDone = true; if (Changed) Results.resolveKindAfterFilter(); } }; /// Create a filter for this result set. Filter makeFilter() { return Filter(*this); } void setFindLocalExtern(bool FindLocalExtern) { if (FindLocalExtern) IDNS |= Decl::IDNS_LocalExtern; else IDNS &= ~Decl::IDNS_LocalExtern; } private: void diagnose() { if (isAmbiguous()) SemaRef.DiagnoseAmbiguousLookup(*this); else if (isClassLookup() && SemaRef.getLangOpts().AccessControl) SemaRef.CheckLookupAccess(*this); } void setAmbiguous(AmbiguityKind AK) { ResultKind = Ambiguous; Ambiguity = AK; } void addDeclsFromBasePaths(const CXXBasePaths &P); void configure(); // Sanity checks. void sanityImpl() const; void sanity() const { #ifndef NDEBUG sanityImpl(); #endif } bool sanityCheckUnresolved() const { for (iterator I = begin(), E = end(); I != E; ++I) if (isa((*I)->getUnderlyingDecl())) return true; return false; } static void deletePaths(CXXBasePaths *); // Results. LookupResultKind ResultKind; AmbiguityKind Ambiguity; // ill-defined unless ambiguous UnresolvedSet<8> Decls; CXXBasePaths *Paths; CXXRecordDecl *NamingClass; QualType BaseObjectType; // Parameters. Sema &SemaRef; DeclarationNameInfo NameInfo; SourceRange NameContextRange; Sema::LookupNameKind LookupKind; unsigned IDNS; // set by configure() bool Redecl; /// \brief True if tag declarations should be hidden if non-tags /// are present bool HideTags; bool Diagnose; /// \brief True if we should allow hidden declarations to be 'visible'. bool AllowHidden; /// \brief True if the found declarations were shadowed by some other /// declaration that we skipped. This only happens when \c LookupKind /// is \c LookupRedeclarationWithLinkage. bool Shadowed; }; /// \brief Consumes visible declarations found when searching for /// all visible names within a given scope or context. /// /// This abstract class is meant to be subclassed by clients of \c /// Sema::LookupVisibleDecls(), each of which should override the \c /// FoundDecl() function to process declarations as they are found. class VisibleDeclConsumer { public: /// \brief Destroys the visible declaration consumer. virtual ~VisibleDeclConsumer(); /// \brief Determine whether hidden declarations (from unimported /// modules) should be given to this consumer. By default, they /// are not included. virtual bool includeHiddenDecls() const; /// \brief Invoked each time \p Sema::LookupVisibleDecls() finds a /// declaration visible from the current scope or context. /// /// \param ND the declaration found. /// /// \param Hiding a declaration that hides the declaration \p ND, /// or NULL if no such declaration exists. /// /// \param Ctx the original context from which the lookup started. /// /// \param InBaseClass whether this declaration was found in base /// class of the context we searched. virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, bool InBaseClass) = 0; }; /// \brief A class for storing results from argument-dependent lookup. class ADLResult { private: /// A map from canonical decls to the 'most recent' decl. llvm::DenseMap Decls; public: /// Adds a new ADL candidate to this map. void insert(NamedDecl *D); /// Removes any data associated with a given decl. void erase(NamedDecl *D) { Decls.erase(cast(D->getCanonicalDecl())); } class iterator : public std::iterator { typedef llvm::DenseMap::iterator inner_iterator; inner_iterator iter; friend class ADLResult; iterator(const inner_iterator &iter) : iter(iter) {} public: iterator() {} iterator &operator++() { ++iter; return *this; } iterator operator++(int) { return iterator(iter++); } value_type operator*() const { return iter->second; } bool operator==(const iterator &other) const { return iter == other.iter; } bool operator!=(const iterator &other) const { return iter != other.iter; } }; iterator begin() { return iterator(Decls.begin()); } iterator end() { return iterator(Decls.end()); } }; } #endif