diff options
author | dim <dim@FreeBSD.org> | 2011-02-20 13:06:31 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-02-20 13:06:31 +0000 |
commit | 39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df (patch) | |
tree | a9243275843fbeaa590afc07ee888e006b8d54ea /lib/Sema/SemaLookup.cpp | |
parent | 69b4eca4a4255ba43baa5c1d9bbdec3ec17f479e (diff) | |
download | FreeBSD-src-39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df.zip FreeBSD-src-39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df.tar.gz |
Vendor import of clang trunk r126079:
http://llvm.org/svn/llvm-project/cfe/trunk@126079
Diffstat (limited to 'lib/Sema/SemaLookup.cpp')
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 1007 |
1 files changed, 622 insertions, 385 deletions
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 306e95a..0fd0e08 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -31,7 +31,9 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/ErrorHandling.h" +#include <limits> #include <list> #include <set> #include <vector> @@ -89,7 +91,7 @@ namespace { UnqualUsingDirectiveSet() {} void visitScopeChain(Scope *S, Scope *InnermostFileScope) { - // C++ [namespace.udir]p1: + // C++ [namespace.udir]p1: // During unqualified name lookup, the names appear as if they // were declared in the nearest enclosing namespace which contains // both the using-directive and the nominated namespace. @@ -104,7 +106,7 @@ namespace { } else { Scope::udir_iterator I = S->using_directives_begin(), End = S->using_directives_end(); - + for (; I != End; ++I) visit(*I, InnermostFileDC); } @@ -175,7 +177,7 @@ namespace { while (!Common->Encloses(EffectiveDC)) Common = Common->getParent(); Common = Common->getPrimaryContext(); - + list.push_back(UnqualUsingEntry(UD->getNominatedNamespace(), Common)); } @@ -183,11 +185,8 @@ namespace { std::sort(list.begin(), list.end(), UnqualUsingEntry::Comparator()); } - typedef ListTy::iterator iterator; typedef ListTy::const_iterator const_iterator; - - iterator begin() { return list.begin(); } - iterator end() { return list.end(); } + const_iterator begin() const { return list.begin(); } const_iterator end() const { return list.end(); } @@ -211,7 +210,8 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_Ordinary; if (CPlusPlus) { IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace; - if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend; + if (Redeclaration) + IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend; } break; @@ -237,7 +237,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_Tag; } break; - + case Sema::LookupLabel: + IDNS = Decl::IDNS_Label; + break; + case Sema::LookupMemberName: IDNS = Decl::IDNS_Member; if (CPlusPlus) @@ -260,9 +263,9 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; - + case Sema::LookupAnyName: - IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol | Decl::IDNS_Type; break; @@ -271,8 +274,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, } void LookupResult::configure() { - IDNS = getIDNS(LookupKind, - SemaRef.getLangOptions().CPlusPlus, + IDNS = getIDNS(LookupKind, SemaRef.getLangOptions().CPlusPlus, isForRedeclaration()); // If we're looking for one of the allocation or deallocation @@ -293,7 +295,6 @@ void LookupResult::configure() { } } -#ifndef NDEBUG void LookupResult::sanity() const { assert(ResultKind != NotFound || Decls.size() == 0); assert(ResultKind != Found || Decls.size() == 1); @@ -302,12 +303,12 @@ void LookupResult::sanity() const { isa<FunctionTemplateDecl>((*begin())->getUnderlyingDecl()))); assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); assert(ResultKind != Ambiguous || Decls.size() > 1 || - (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects)); + (Decls.size() == 1 && (Ambiguity == AmbiguousBaseSubobjects || + Ambiguity == AmbiguousBaseSubobjectTypes))); assert((Paths != NULL) == (ResultKind == Ambiguous && (Ambiguity == AmbiguousBaseSubobjectTypes || Ambiguity == AmbiguousBaseSubobjects))); } -#endif // Necessary because CXXBasePaths is not complete in Sema.h void LookupResult::deletePaths(CXXBasePaths *Paths) { @@ -317,7 +318,7 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) { /// Resolves the result kind of this lookup. void LookupResult::resolveKind() { unsigned N = Decls.size(); - + // Fast case: no possible ambiguity. if (N == 0) { assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation); @@ -340,13 +341,13 @@ void LookupResult::resolveKind() { llvm::SmallPtrSet<NamedDecl*, 16> Unique; llvm::SmallPtrSet<QualType, 16> UniqueTypes; - + bool Ambiguous = false; bool HasTag = false, HasFunction = false, HasNonFunction = false; bool HasFunctionTemplate = false, HasUnresolved = false; unsigned UniqueTagIndex = 0; - + unsigned I = 0; while (I < N) { NamedDecl *D = Decls[I]->getUnderlyingDecl(); @@ -367,14 +368,14 @@ void LookupResult::resolveKind() { } } } - + if (!Unique.insert(D)) { // If it's not unique, pull something off the back (and // continue at this index). Decls[I] = Decls[--N]; continue; - } - + } + // Otherwise, do some decl type analysis and then continue. if (isa<UnresolvedUsingValueDecl>(D)) { @@ -407,8 +408,13 @@ void LookupResult::resolveKind() { // But it's still an error if there are distinct tag types found, // even if they're not visible. (ref?) if (HideTags && HasTag && !Ambiguous && - (HasFunction || HasNonFunction || HasUnresolved)) - Decls[UniqueTagIndex] = Decls[--N]; + (HasFunction || HasNonFunction || HasUnresolved)) { + if (Decls[UniqueTagIndex]->getDeclContext()->getRedeclContext()->Equals( + Decls[UniqueTagIndex? 0 : N-1]->getDeclContext()->getRedeclContext())) + Decls[UniqueTagIndex] = Decls[--N]; + else + Ambiguous = true; + } Decls.set_size(N); @@ -453,7 +459,7 @@ void LookupResult::print(llvm::raw_ostream &Out) { Out << Decls.size() << " result(s)"; if (isAmbiguous()) Out << ", ambiguous"; if (Paths) Out << ", base paths present"; - + for (iterator I = begin(), E = end(); I != E; ++I) { Out << "\n"; (*I)->print(Out, 2); @@ -480,12 +486,21 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return false; - NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, - S.TUScope, R.isForRedeclaration(), - R.getNameLoc()); - if (D) + if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II, + BuiltinID, S.TUScope, + R.isForRedeclaration(), + R.getNameLoc())) { R.addDecl(D); - return (D != NULL); + return true; + } + + if (R.isForRedeclaration()) { + // If we're redeclaring this function anyway, forget that + // this was a builtin at all. + S.Context.BuiltinInfo.ForgetBuiltin(BuiltinID, S.Context.Idents); + } + + return false; } } } @@ -500,16 +515,16 @@ static bool CanDeclareSpecialMemberFunction(ASTContext &Context, // Don't do it if the class is invalid. if (Class->isInvalidDecl()) return false; - + // We need to have a definition for the class. if (!Class->getDefinition() || Class->isDependentContext()) return false; - + // We can't be in the middle of defining the class. if (const RecordType *RecordTy = Context.getTypeDeclType(Class)->getAs<RecordType>()) return !RecordTy->isBeingDefined(); - + return false; } @@ -520,46 +535,46 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { // If the default constructor has not yet been declared, do so now. if (!Class->hasDeclaredDefaultConstructor()) DeclareImplicitDefaultConstructor(Class); - + // If the copy constructor has not yet been declared, do so now. if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); - + // If the copy assignment operator has not yet been declared, do so now. if (!Class->hasDeclaredCopyAssignment()) DeclareImplicitCopyAssignment(Class); // If the destructor has not yet been declared, do so now. if (!Class->hasDeclaredDestructor()) - DeclareImplicitDestructor(Class); + DeclareImplicitDestructor(Class); } -/// \brief Determine whether this is the name of an implicitly-declared +/// \brief Determine whether this is the name of an implicitly-declared /// special member function. static bool isImplicitlyDeclaredMemberFunctionName(DeclarationName Name) { switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: return true; - + case DeclarationName::CXXOperatorName: return Name.getCXXOverloadedOperator() == OO_Equal; - + default: - break; + break; } - + return false; } /// \brief If there are any implicit member functions with the given name /// that need to be declared in the given declaration context, do so. -static void DeclareImplicitMemberFunctionsWithName(Sema &S, +static void DeclareImplicitMemberFunctionsWithName(Sema &S, DeclarationName Name, const DeclContext *DC) { if (!DC) return; - + switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) @@ -572,26 +587,26 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S, S.DeclareImplicitCopyConstructor(const_cast<CXXRecordDecl *>(Record)); } break; - + case DeclarationName::CXXDestructorName: if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) if (Record->getDefinition() && !Record->hasDeclaredDestructor() && CanDeclareSpecialMemberFunction(S.Context, Record)) S.DeclareImplicitDestructor(const_cast<CXXRecordDecl *>(Record)); break; - + case DeclarationName::CXXOperatorName: if (Name.getCXXOverloadedOperator() != OO_Equal) break; - + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) if (Record->getDefinition() && !Record->hasDeclaredCopyAssignment() && CanDeclareSpecialMemberFunction(S.Context, Record)) S.DeclareImplicitCopyAssignment(const_cast<CXXRecordDecl *>(Record)); break; - + default: - break; + break; } } @@ -603,7 +618,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // Lazily declare C++ special member functions. if (S.getLangOptions().CPlusPlus) DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC); - + // Perform lookup into this declaration context. DeclContext::lookup_const_iterator I, E; for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) { @@ -624,7 +639,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { return Found; // C++ [temp.mem]p6: - // A specialization of a conversion function template is not found by + // A specialization of a conversion function template is not found by // name lookup. Instead, any conversion function templates visible in the // context of the use are considered. [...] const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); @@ -632,50 +647,51 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { return Found; const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); - for (UnresolvedSetImpl::iterator U = Unresolved->begin(), + for (UnresolvedSetImpl::iterator U = Unresolved->begin(), UEnd = Unresolved->end(); U != UEnd; ++U) { FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U); if (!ConvTemplate) continue; - + // When we're performing lookup for the purposes of redeclaration, just - // add the conversion function template. When we deduce template - // arguments for specializations, we'll end up unifying the return + // add the conversion function template. When we deduce template + // arguments for specializations, we'll end up unifying the return // type of the new declaration with the type of the function template. if (R.isForRedeclaration()) { R.addDecl(ConvTemplate); Found = true; continue; } - + // C++ [temp.mem]p6: - // [...] For each such operator, if argument deduction succeeds - // (14.9.2.3), the resulting specialization is used as if found by + // [...] For each such operator, if argument deduction succeeds + // (14.9.2.3), the resulting specialization is used as if found by // name lookup. // // When referencing a conversion function for any purpose other than // a redeclaration (such that we'll be building an expression with the - // result), perform template argument deduction and place the + // result), perform template argument deduction and place the // specialization into the result set. We do this to avoid forcing all // callers to perform special deduction for conversion functions. TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc()); FunctionDecl *Specialization = 0; - - const FunctionProtoType *ConvProto + + const FunctionProtoType *ConvProto = ConvTemplate->getTemplatedDecl()->getType()->getAs<FunctionProtoType>(); assert(ConvProto && "Nonsensical conversion function template type"); // Compute the type of the function that we would expect the conversion // function to have, if it were to match the name given. // FIXME: Calling convention! - FunctionType::ExtInfo ConvProtoInfo = ConvProto->getExtInfo(); + FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo(); + EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_Default); + EPI.HasExceptionSpec = false; + EPI.HasAnyExceptionSpec = false; + EPI.NumExceptions = 0; QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), - 0, 0, ConvProto->isVariadic(), - ConvProto->getTypeQuals(), - false, false, 0, 0, - ConvProtoInfo.withCallingConv(CC_Default)); - + 0, 0, EPI); + // Perform template argument deduction against the type that we would // expect the function to have. if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType, @@ -691,7 +707,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // Performs C++ unqualified lookup into the given file context. static bool -CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, +CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, DeclContext *NS, UnqualUsingDirectiveSet &UDirs) { assert(NS && NS->isFileContext() && "CppNamespaceLookup() requires namespace!"); @@ -729,7 +745,7 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) { static std::pair<DeclContext *, bool> findOuterContext(Scope *S) { DeclContext *DC = static_cast<DeclContext *>(S->getEntity()); DeclContext *Lexical = 0; - for (Scope *OuterS = S->getParent(); OuterS; + for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent()) { if (OuterS->getEntity()) { Lexical = static_cast<DeclContext *>(OuterS->getEntity()); @@ -745,12 +761,12 @@ static std::pair<DeclContext *, bool> findOuterContext(Scope *S) { // // Example: // - // namespace N { - // class C { }; + // namespace N { + // class C { }; // // template<class T> class B { // void f(T); - // }; + // }; // } // // template<class C> void N::B<C>::f(C) { @@ -759,24 +775,24 @@ static std::pair<DeclContext *, bool> findOuterContext(Scope *S) { // // In this example, the lexical context we return is the // TranslationUnit, while the semantic context is the namespace N. - if (!Lexical || !DC || !S->getParent() || + if (!Lexical || !DC || !S->getParent() || !S->getParent()->isTemplateParamScope()) return std::make_pair(Lexical, false); - // Find the outermost template parameter scope. + // Find the outermost template parameter scope. // For the example, this is the scope for the template parameters of // template<class C>. Scope *OutermostTemplateScope = S->getParent(); while (OutermostTemplateScope->getParent() && OutermostTemplateScope->getParent()->isTemplateParamScope()) OutermostTemplateScope = OutermostTemplateScope->getParent(); - + // Find the namespace context in which the original scope occurs. In // the example, this is namespace N. DeclContext *Semantic = DC; while (!Semantic->isFileContext()) Semantic = Semantic->getParent(); - + // Find the declaration context just outside of the template // parameter scope. This is the context in which the template is // being lexically declaration (a namespace context). In the @@ -800,7 +816,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (DeclContext *DC = static_cast<DeclContext *>(PreS->getEntity())) DeclareImplicitMemberFunctionsWithName(*this, Name, DC); } - + // Implicitly declare member functions with the name we're looking for, if in // fact we are in a scope where it matters. @@ -883,7 +899,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (ObjCInterfaceDecl *Class = Method->getClassInterface()) { ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable( - Name.getAsIdentifierInfo(), + Name.getAsIdentifierInfo(), ClassDeclared)) { if (R.isAcceptableDecl(Ivar)) { R.addDecl(Ivar); @@ -913,6 +929,10 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // FIXME: This really, really shouldn't be happening. if (!S) return false; + // If we are looking for members, no need to look into global/namespace scope. + if (R.getLookupKind() == LookupMemberName) + return false; + // Collect UsingDirectiveDecls in all scopes, and recursively all // nominated namespaces by those using-directives. // @@ -958,7 +978,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { Ctx = OutsideOfTemplateParamDC; OutsideOfTemplateParamDC = 0; } - + if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; @@ -972,24 +992,24 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // non-transparent context. if (Ctx->isTransparentContext()) continue; - + // If we have a context, and it's not a context stashed in the // template parameter scope for an out-of-line definition, also // look into that context. if (!(Found && S && S->isTemplateParamScope())) { assert(Ctx->isFileContext() && "We should have been looking only at file context here already."); - + // Look into context considering using-directives. if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) Found = true; } - + if (Found) { R.resolveKind(); return true; } - + if (R.isForRedeclaration() && !Ctx->isTransparentContext()) return false; } @@ -1042,7 +1062,6 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { if (!getLangOptions().CPlusPlus) { // Unqualified name lookup in C/Objective-C is purely lexical, so // search in the declarations attached to the name. - if (NameKind == Sema::LookupRedeclarationWithLinkage) { // Find the nearest non-transparent declaration scope. while (!(S->getFlags() & Scope::DeclScope) || @@ -1228,16 +1247,48 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, } /// \brief Callback that looks for any member of a class with the given name. -static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, +static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); - + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); Path.Decls = BaseRecord->lookup(N); return Path.Decls.first != Path.Decls.second; } +/// \brief Determine whether the given set of member declarations contains only +/// static members, nested types, and enumerators. +template<typename InputIterator> +static bool HasOnlyStaticMembers(InputIterator First, InputIterator Last) { + Decl *D = (*First)->getUnderlyingDecl(); + if (isa<VarDecl>(D) || isa<TypeDecl>(D) || isa<EnumConstantDecl>(D)) + return true; + + if (isa<CXXMethodDecl>(D)) { + // Determine whether all of the methods are static. + bool AllMethodsAreStatic = true; + for(; First != Last; ++First) { + D = (*First)->getUnderlyingDecl(); + + if (!isa<CXXMethodDecl>(D)) { + assert(isa<TagDecl>(D) && "Non-function must be a tag decl"); + break; + } + + if (!cast<CXXMethodDecl>(D)->isStatic()) { + AllMethodsAreStatic = false; + break; + } + } + + if (AllMethodsAreStatic) + return true; + } + + return false; +} + /// \brief Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find @@ -1256,7 +1307,7 @@ static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, /// search. If the lookup criteria permits, name lookup may also search /// in the parent contexts or (for C++ classes) base classes. /// -/// \param InUnqualifiedLookup true if this is qualified name lookup that +/// \param InUnqualifiedLookup true if this is qualified name lookup that /// occurs as part of unqualified name lookup. /// /// \returns true if lookup succeeded, false if it failed. @@ -1307,7 +1358,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // If we're performing qualified name lookup into a dependent class, // then we are actually looking into a current instantiation. If we have any - // dependent base classes, then we either have to delay lookup until + // dependent base classes, then we either have to delay lookup until // template instantiation time (at which point all bases will be available) // or we have to fail. if (!InUnqualifiedLookup && LookupRec->isDependentContext() && @@ -1315,7 +1366,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, R.setNotFoundInCurrentInstantiation(); return false; } - + // Perform lookup into our base classes. CXXBasePaths Paths; Paths.setOrigin(LookupRec); @@ -1328,7 +1379,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, case LookupRedeclarationWithLinkage: BaseCallback = &CXXRecordDecl::FindOrdinaryMember; break; - + case LookupTagName: BaseCallback = &CXXRecordDecl::FindTagMember; break; @@ -1336,21 +1387,22 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, case LookupAnyName: BaseCallback = &LookupAnyMember; break; - + case LookupUsingDeclName: // This lookup is for redeclarations only. - + case LookupOperatorName: case LookupNamespaceName: case LookupObjCProtocolName: + case LookupLabel: // These lookups will never find a member in a C++ class (or base class). return false; - + case LookupNestedNameSpecifierName: BaseCallback = &CXXRecordDecl::FindNestedNameSpecifierMember; break; } - + if (!LookupRec->lookupInBases(BaseCallback, R.getLookupName().getAsOpaquePtr(), Paths)) return false; @@ -1363,10 +1415,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // and includes members from distinct sub-objects, there is an // ambiguity and the program is ill-formed. Otherwise that set is // the result of the lookup. - // FIXME: support using declarations! QualType SubobjectType; int SubobjectNumber = 0; AccessSpecifier SubobjectAccess = AS_none; + for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); @@ -1374,51 +1426,54 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Pick the best (i.e. most permissive i.e. numerically lowest) access // across all paths. SubobjectAccess = std::min(SubobjectAccess, Path->Access); - + // Determine whether we're looking at a distinct sub-object or not. if (SubobjectType.isNull()) { // This is the first subobject we've looked at. Record its type. SubobjectType = Context.getCanonicalType(PathElement.Base->getType()); SubobjectNumber = PathElement.SubobjectNumber; - } else if (SubobjectType + continue; + } + + if (SubobjectType != Context.getCanonicalType(PathElement.Base->getType())) { // We found members of the given name in two subobjects of - // different types. This lookup is ambiguous. + // different types. If the declaration sets aren't the same, this + // this lookup is ambiguous. + if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) { + CXXBasePaths::paths_iterator FirstPath = Paths.begin(); + DeclContext::lookup_iterator FirstD = FirstPath->Decls.first; + DeclContext::lookup_iterator CurrentD = Path->Decls.first; + + while (FirstD != FirstPath->Decls.second && + CurrentD != Path->Decls.second) { + if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() != + (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl()) + break; + + ++FirstD; + ++CurrentD; + } + + if (FirstD == FirstPath->Decls.second && + CurrentD == Path->Decls.second) + continue; + } + R.setAmbiguousBaseSubobjectTypes(Paths); return true; - } else if (SubobjectNumber != PathElement.SubobjectNumber) { + } + + if (SubobjectNumber != PathElement.SubobjectNumber) { // We have a different subobject of the same type. // C++ [class.member.lookup]p5: // A static member, a nested type or an enumerator defined in // a base class T can unambiguously be found even if an object // has more than one base class subobject of type T. - Decl *FirstDecl = *Path->Decls.first; - if (isa<VarDecl>(FirstDecl) || - isa<TypeDecl>(FirstDecl) || - isa<EnumConstantDecl>(FirstDecl)) + if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) continue; - if (isa<CXXMethodDecl>(FirstDecl)) { - // Determine whether all of the methods are static. - bool AllMethodsAreStatic = true; - for (DeclContext::lookup_iterator Func = Path->Decls.first; - Func != Path->Decls.second; ++Func) { - if (!isa<CXXMethodDecl>(*Func)) { - assert(isa<TagDecl>(*Func) && "Non-function must be a tag decl"); - break; - } - - if (!cast<CXXMethodDecl>(*Func)->isStatic()) { - AllMethodsAreStatic = false; - break; - } - } - - if (AllMethodsAreStatic) - continue; - } - // We have found a nonstatic member name in multiple, distinct // subobjects. Name lookup is ambiguous. R.setAmbiguousBaseSubobjects(Paths); @@ -1453,13 +1508,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, /// /// @param SS An optional C++ scope-specifier, e.g., "::N::M". /// -/// @param Name The name of the entity that name lookup will -/// search for. -/// -/// @param Loc If provided, the source location where we're performing -/// name lookup. At present, this is only used to produce diagnostics when -/// C library functions (like "malloc") are implicitly declared. -/// /// @param EnteringContext Indicates whether we are going to enter the /// context of the scope-specifier SS (if present). /// @@ -1525,21 +1573,21 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects) << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths) << LookupRange; - + DeclContext::lookup_iterator Found = Paths->front().Decls.first; while (isa<CXXMethodDecl>(*Found) && cast<CXXMethodDecl>(*Found)->isStatic()) ++Found; - + Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); - + return true; } case LookupResult::AmbiguousBaseSubobjectTypes: { Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types) << Name << LookupRange; - + CXXBasePaths *Paths = Result.getBasePaths(); std::set<Decl *> DeclsPrinted; for (CXXBasePaths::paths_iterator Path = Paths->begin(), @@ -1582,7 +1630,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { case LookupResult::AmbiguousReference: { Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange; - + LookupResult::iterator DI = Result.begin(), DE = Result.end(); for (; DI != DE; ++DI) Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI; @@ -1648,11 +1696,12 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, addAssociatedClassesAndNamespaces(Result, Arg.getAsType()); break; - case TemplateArgument::Template: { + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { // [...] the namespaces in which any template template arguments are // defined; and the classes in which any member templates used as // template template arguments are defined. - TemplateName Template = Arg.getAsTemplate(); + TemplateName Template = Arg.getAsTemplateOrTemplatePattern(); if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(Template.getAsTemplateDecl())) { DeclContext *Ctx = ClassTemplate->getDeclContext(); @@ -1663,7 +1712,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, } break; } - + case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Expression: @@ -1713,7 +1762,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // -- If T is a template-id, its associated namespaces and classes are // the namespace in which the template is defined; for member - // templates, the member template’s class; the namespaces and classes + // templates, the member template's class; the namespaces and classes // associated with the types of the template arguments provided for // template type parameters (excluding template template parameters); the // namespaces in which any template template arguments are defined; and @@ -1840,7 +1889,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // -- If T is an enumeration type, its associated namespace is // the namespace in which it is defined. If it is class - // member, its associated class is the member’s class; else + // member, its associated class is the member's class; else // it has no associated class. case Type::Enum: { EnumDecl *Enum = cast<EnumType>(T)->getDecl(); @@ -2032,7 +2081,7 @@ NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, } /// \brief Find the protocol with the given name, if any. -ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, +ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc) { Decl *D = LookupSingleName(TUScope, II, IdLoc, LookupObjCProtocolName); @@ -2089,7 +2138,7 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { if (!Class->hasDeclaredCopyConstructor()) DeclareImplicitCopyConstructor(Class); } - + CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class)); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(T); return Class->lookup(Name); @@ -2097,7 +2146,7 @@ DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) { /// \brief Look for the destructor of the given class. /// -/// During semantic analysis, this routine should be used in lieu of +/// During semantic analysis, this routine should be used in lieu of /// CXXRecordDecl::getDestructor(). /// /// \returns The destructor for this class. @@ -2233,7 +2282,7 @@ public: /// of declarations. class ShadowMapEntry { typedef llvm::SmallVector<NamedDecl *, 4> DeclVector; - + /// \brief Contains either the solitary NamedDecl * or a vector /// of declarations. llvm::PointerUnion<NamedDecl *, DeclVector*> DeclOrVector; @@ -2245,7 +2294,7 @@ public: void Destroy(); // Iteration. - typedef NamedDecl **iterator; + typedef NamedDecl * const *iterator; iterator begin(); iterator end(); }; @@ -2315,7 +2364,7 @@ void VisibleDeclsRecord::ShadowMapEntry::Add(NamedDecl *ND) { DeclOrVector = ND; return; } - + if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) { // 1 -> 2 elements: create the vector of results and push in the // existing declaration. @@ -2335,18 +2384,18 @@ void VisibleDeclsRecord::ShadowMapEntry::Destroy() { } } -VisibleDeclsRecord::ShadowMapEntry::iterator +VisibleDeclsRecord::ShadowMapEntry::iterator VisibleDeclsRecord::ShadowMapEntry::begin() { if (DeclOrVector.isNull()) return 0; - if (DeclOrVector.dyn_cast<NamedDecl *>()) - return &reinterpret_cast<NamedDecl*&>(DeclOrVector); + if (DeclOrVector.is<NamedDecl *>()) + return DeclOrVector.getAddrOf<NamedDecl *>(); return DeclOrVector.get<DeclVector *>()->begin(); } -VisibleDeclsRecord::ShadowMapEntry::iterator +VisibleDeclsRecord::ShadowMapEntry::iterator VisibleDeclsRecord::ShadowMapEntry::end() { if (DeclOrVector.isNull()) return 0; @@ -2360,7 +2409,7 @@ VisibleDeclsRecord::ShadowMapEntry::end() { NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { // Look through using declarations. ND = ND->getUnderlyingDecl(); - + unsigned IDNS = ND->getIdentifierNamespace(); std::list<ShadowMap>::reverse_iterator SM = ShadowMaps.rbegin(); for (std::list<ShadowMap>::reverse_iterator SMEnd = ShadowMaps.rend(); @@ -2369,12 +2418,12 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { if (Pos == SM->end()) continue; - for (ShadowMapEntry::iterator I = Pos->second.begin(), + for (ShadowMapEntry::iterator I = Pos->second.begin(), IEnd = Pos->second.end(); I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. if ((*I)->hasTagIdentifierNamespace() && - (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | + (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; @@ -2391,7 +2440,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { ND->isFunctionOrFunctionTemplate() && SM == ShadowMaps.rbegin()) continue; - + // We've found a declaration that hides this one. return *I; } @@ -2411,22 +2460,44 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Make sure we don't visit the same context twice. if (Visited.visitedContext(Ctx->getPrimaryContext())) return; - + if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) Result.getSema().ForceDeclarationOfImplicitMembers(Class); // Enumerate all of the results in this context. - for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; + for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; CurCtx = CurCtx->getNextContext()) { - for (DeclContext::decl_iterator D = CurCtx->decls_begin(), + for (DeclContext::decl_iterator D = CurCtx->decls_begin(), DEnd = CurCtx->decls_end(); D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) + if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) { if (Result.isAcceptableDecl(ND)) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), InBaseClass); Visited.add(ND); } - + } else if (ObjCForwardProtocolDecl *ForwardProto + = dyn_cast<ObjCForwardProtocolDecl>(*D)) { + for (ObjCForwardProtocolDecl::protocol_iterator + P = ForwardProto->protocol_begin(), + PEnd = ForwardProto->protocol_end(); + P != PEnd; + ++P) { + if (Result.isAcceptableDecl(*P)) { + Consumer.FoundDecl(*P, Visited.checkHidden(*P), InBaseClass); + Visited.add(*P); + } + } + } else if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) { + for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end(); + I != IEnd; ++I) { + ObjCInterfaceDecl *IFace = I->getInterface(); + if (Result.isAcceptableDecl(IFace)) { + Consumer.FoundDecl(IFace, Visited.checkHidden(IFace), InBaseClass); + Visited.add(IFace); + } + } + } + // Visit transparent contexts and inline namespaces inside this context. if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) { if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) @@ -2441,7 +2512,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, ShadowContextRAII Shadow(Visited); DeclContext::udir_iterator I, E; for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) { - LookupVisibleDecls((*I)->getNominatedNamespace(), Result, + LookupVisibleDecls((*I)->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } } @@ -2455,16 +2526,16 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, BEnd = Record->bases_end(); B != BEnd; ++B) { QualType BaseType = B->getType(); - + // Don't look into dependent bases, because name lookup can't look // there anyway. if (BaseType->isDependentType()) continue; - + const RecordType *Record = BaseType->getAs<RecordType>(); if (!Record) continue; - + // FIXME: It would be nice to be able to determine whether referencing // a particular member would be ambiguous. For example, given // @@ -2483,21 +2554,21 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // or // // c->A::member - + // Find results in this base class (and its bases). ShadowContextRAII Shadow(Visited); LookupVisibleDecls(Record->getDecl(), Result, QualifiedNameLookup, true, Consumer, Visited); } } - + // Traverse the contexts of Objective-C classes. if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) { // Traverse categories. for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category; Category = Category->getNextClassCategory()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Category, Result, QualifiedNameLookup, false, + LookupVisibleDecls(Category, Result, QualifiedNameLookup, false, Consumer, Visited); } @@ -2506,7 +2577,7 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, I = IFace->all_referenced_protocol_begin(), E = IFace->all_referenced_protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } @@ -2516,35 +2587,35 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, true, Consumer, Visited); } - + // If there is an implementation, traverse it. We do this to find // synthesized ivars. if (IFace->getImplementation()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(IFace->getImplementation(), Result, + LookupVisibleDecls(IFace->getImplementation(), Result, QualifiedNameLookup, true, Consumer, Visited); } } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) { for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(), E = Protocol->protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) { for (ObjCCategoryDecl::protocol_iterator I = Category->protocol_begin(), E = Category->protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } - + // If there is an implementation, traverse it. if (Category->getImplementation()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(Category->getImplementation(), Result, + LookupVisibleDecls(Category->getImplementation(), Result, QualifiedNameLookup, true, Consumer, Visited); - } + } } } @@ -2555,8 +2626,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, if (!S) return; - if (!S->getEntity() || - (!S->getParent() && + if (!S->getEntity() || + (!S->getParent() && !Visited.alreadyVisitedContext((DeclContext *)S->getEntity())) || ((DeclContext *)S->getEntity())->isFunctionOrMethod()) { // Walk through the declarations in this Scope. @@ -2569,7 +2640,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, } } } - + // FIXME: C++ [temp.local]p8 DeclContext *Entity = 0; if (S->getEntity()) { @@ -2578,7 +2649,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // where we hit the context stored in the next outer scope. Entity = (DeclContext *)S->getEntity(); DeclContext *OuterCtx = findOuterContext(S).first; // FIXME - + for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) { @@ -2586,9 +2657,27 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // For instance methods, look for ivars in the method's interface. LookupResult IvarResult(Result.getSema(), Result.getLookupName(), Result.getNameLoc(), Sema::LookupMemberName); - if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) - LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, + if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) { + LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); + + // Look for properties from which we can synthesize ivars, if + // permitted. + if (Result.getSema().getLangOptions().ObjCNonFragileABI2 && + IFace->getImplementation() && + Result.getLookupKind() == Sema::LookupOrdinaryName) { + for (ObjCInterfaceDecl::prop_iterator + P = IFace->prop_begin(), + PEnd = IFace->prop_end(); + P != PEnd; ++P) { + if (Result.getSema().canSynthesizeProvisionalIvar(*P) && + !IFace->lookupInstanceVariable((*P)->getIdentifier())) { + Consumer.FoundDecl(*P, Visited.checkHidden(*P), false); + Visited.add(*P); + } + } + } + } } // We've already performed all of the name lookup that we need @@ -2599,8 +2688,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, if (Ctx->isFunctionOrMethod()) continue; - - LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, + + LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } } else if (!S->getParent()) { @@ -2610,14 +2699,14 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // FIXME: We would like the translation unit's Scope object to point to the // translation unit, so we don't need this special "if" branch. However, // doing so would force the normal C++ name-lookup code to look into the - // translation unit decl when the IdentifierInfo chains would suffice. + // translation unit decl when the IdentifierInfo chains would suffice. // Once we fix that problem (which is part of a more general "don't look // in DeclContexts unless we have to" optimization), we can eliminate this. Entity = Result.getSema().Context.getTranslationUnitDecl(); - LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, + LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); - } - + } + if (Entity) { // Lookup visible declarations in any namespaces found by using // directives. @@ -2625,7 +2714,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity); for (; UI != UEnd; ++UI) LookupVisibleDecls(const_cast<DeclContext *>(UI->getNominatedNamespace()), - Result, /*QualifiedNameLookup=*/false, + Result, /*QualifiedNameLookup=*/false, /*InBaseClass=*/false, Consumer, Visited); } @@ -2667,13 +2756,41 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, if (!IncludeGlobalScope) Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); - ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, + ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, /*InBaseClass=*/false, Consumer, Visited); } -//---------------------------------------------------------------------------- +/// LookupOrCreateLabel - Do a name lookup of a label with the specified name. +/// If isLocalLabel is true, then this is a definition of an __label__ label +/// name, otherwise it is a normal label definition or use. +LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, + bool isLocalLabel) { + // Do a lookup to see if we have a label with this name already. + NamedDecl *Res = 0; + + // Local label definitions always shadow existing labels. + if (!isLocalLabel) + Res = LookupSingleName(CurScope, II, Loc, LookupLabel, NotForRedeclaration); + + // If we found a label, check to see if it is in the same context as us. When + // in a Block, we don't want to reuse a label in an enclosing function. + if (Res && Res->getDeclContext() != CurContext) + Res = 0; + + if (Res == 0) { + // If not forward referenced or defined already, create the backing decl. + Res = LabelDecl::Create(Context, CurContext, Loc, II); + Scope *S = isLocalLabel ? CurScope : CurScope->getFnParent(); + assert(S && "Not in a function?"); + PushOnScopeChains(Res, S, true); + } + + return cast<LabelDecl>(Res); +} + +//===----------------------------------------------------------------------===// // Typo correction -//---------------------------------------------------------------------------- +//===----------------------------------------------------------------------===// namespace { class TypoCorrectionConsumer : public VisibleDeclConsumer { @@ -2682,46 +2799,44 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { /// \brief The results found that have the smallest edit distance /// found (so far) with the typo name. - llvm::SmallVector<NamedDecl *, 4> BestResults; + /// + /// The boolean value indicates whether there is a keyword with this name. + llvm::StringMap<bool, llvm::BumpPtrAllocator> BestResults; - /// \brief The keywords that have the smallest edit distance. - llvm::SmallVector<IdentifierInfo *, 4> BestKeywords; - /// \brief The best edit distance found so far. unsigned BestEditDistance; - + public: explicit TypoCorrectionConsumer(IdentifierInfo *Typo) - : Typo(Typo->getName()) { } + : Typo(Typo->getName()), + BestEditDistance((std::numeric_limits<unsigned>::max)()) { } virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); + void FoundName(llvm::StringRef Name); void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword); - typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator; - iterator begin() const { return BestResults.begin(); } - iterator end() const { return BestResults.end(); } - void clear_decls() { BestResults.clear(); } - - bool empty() const { return BestResults.empty() && BestKeywords.empty(); } - - typedef llvm::SmallVector<IdentifierInfo *, 4>::const_iterator - keyword_iterator; - keyword_iterator keyword_begin() const { return BestKeywords.begin(); } - keyword_iterator keyword_end() const { return BestKeywords.end(); } - bool keyword_empty() const { return BestKeywords.empty(); } - unsigned keyword_size() const { return BestKeywords.size(); } - - unsigned getBestEditDistance() const { return BestEditDistance; } + typedef llvm::StringMap<bool, llvm::BumpPtrAllocator>::iterator iterator; + iterator begin() { return BestResults.begin(); } + iterator end() { return BestResults.end(); } + void erase(iterator I) { BestResults.erase(I); } + unsigned size() const { return BestResults.size(); } + bool empty() const { return BestResults.empty(); } + + bool &operator[](llvm::StringRef Name) { + return BestResults[Name]; + } + + unsigned getBestEditDistance() const { return BestEditDistance; } }; } -void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, +void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass) { // Don't consider hidden names for typo correction. if (Hiding) return; - + // Only consider entities with identifiers for names, ignoring // special names (constructors, overloaded operators, selectors, // etc.). @@ -2729,48 +2844,114 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, if (!Name) return; + FoundName(Name->getName()); +} + +void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) { + using namespace std; + + // Use a simple length-based heuristic to determine the minimum possible + // edit distance. If the minimum isn't good enough, bail out early. + unsigned MinED = abs((int)Name.size() - (int)Typo.size()); + if (MinED > BestEditDistance || (MinED && Typo.size() / MinED < 3)) + return; + + // Compute an upper bound on the allowable edit distance, so that the + // edit-distance algorithm can short-circuit. + unsigned UpperBound = min(unsigned((Typo.size() + 2) / 3), BestEditDistance); + // Compute the edit distance between the typo and the name of this // entity. If this edit distance is not worse than the best edit // distance we've seen so far, add it to the list of results. - unsigned ED = Typo.edit_distance(Name->getName()); - if (!BestResults.empty() || !BestKeywords.empty()) { - if (ED < BestEditDistance) { - // This result is better than any we've seen before; clear out - // the previous results. - BestResults.clear(); - BestKeywords.clear(); - BestEditDistance = ED; - } else if (ED > BestEditDistance) { - // This result is worse than the best results we've seen so far; - // ignore it. - return; - } - } else + unsigned ED = Typo.edit_distance(Name, true, UpperBound); + if (ED == 0) + return; + + if (ED < BestEditDistance) { + // This result is better than any we've seen before; clear out + // the previous results. + BestResults.clear(); BestEditDistance = ED; + } else if (ED > BestEditDistance) { + // This result is worse than the best results we've seen so far; + // ignore it. + return; + } - BestResults.push_back(ND); + // Add this name to the list of results. By not assigning a value, we + // keep the current value if we've seen this name before (either as a + // keyword or as a declaration), or get the default value (not a keyword) + // if we haven't seen it before. + (void)BestResults[Name]; } -void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, +void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, llvm::StringRef Keyword) { // Compute the edit distance between the typo and this keyword. // If this edit distance is not worse than the best edit // distance we've seen so far, add it to the list of results. unsigned ED = Typo.edit_distance(Keyword); - if (!BestResults.empty() || !BestKeywords.empty()) { - if (ED < BestEditDistance) { - BestResults.clear(); - BestKeywords.clear(); - BestEditDistance = ED; - } else if (ED > BestEditDistance) { - // This result is worse than the best results we've seen so far; - // ignore it. - return; - } - } else + if (ED < BestEditDistance) { + BestResults.clear(); BestEditDistance = ED; - - BestKeywords.push_back(&Context.Idents.get(Keyword)); + } else if (ED > BestEditDistance) { + // This result is worse than the best results we've seen so far; + // ignore it. + return; + } + + BestResults[Keyword] = true; +} + +/// \brief Perform name lookup for a possible result for typo correction. +static void LookupPotentialTypoResult(Sema &SemaRef, + LookupResult &Res, + IdentifierInfo *Name, + Scope *S, CXXScopeSpec *SS, + DeclContext *MemberContext, + bool EnteringContext, + Sema::CorrectTypoContext CTC) { + Res.suppressDiagnostics(); + Res.clear(); + Res.setLookupName(Name); + if (MemberContext) { + if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(MemberContext)) { + if (CTC == Sema::CTC_ObjCIvarLookup) { + if (ObjCIvarDecl *Ivar = Class->lookupInstanceVariable(Name)) { + Res.addDecl(Ivar); + Res.resolveKind(); + return; + } + } + + if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration(Name)) { + Res.addDecl(Prop); + Res.resolveKind(); + return; + } + } + + SemaRef.LookupQualifiedName(Res, MemberContext); + return; + } + + SemaRef.LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, + EnteringContext); + + // Fake ivar lookup; this should really be part of + // LookupParsedName. + if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl()) { + if (Method->isInstanceMethod() && Method->getClassInterface() && + (Res.empty() || + (Res.isSingleResult() && + Res.getFoundDecl()->isDefinedOutsideFunctionOrMethod()))) { + if (ObjCIvarDecl *IV + = Method->getClassInterface()->lookupInstanceVariable(Name)) { + Res.addDecl(IV); + Res.resolveKind(); + } + } + } } /// \brief Try to "correct" a typo in the source code by finding @@ -2790,7 +2971,7 @@ void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, /// \param MemberContext if non-NULL, the context in which to look for /// a member access expression. /// -/// \param EnteringContext whether we're entering the context described by +/// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// /// \param CTC The context in which typo correction occurs, which impacts the @@ -2804,21 +2985,13 @@ void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, /// may contain the results of name lookup for the correct name or it may be /// empty. DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, - DeclContext *MemberContext, + DeclContext *MemberContext, bool EnteringContext, CorrectTypoContext CTC, const ObjCObjectPointerType *OPT) { if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking) return DeclarationName(); - // Provide a stop gap for files that are just seriously broken. Trying - // to correct all typos can turn into a HUGE performance penalty, causing - // some files to take minutes to get rejected by the parser. - // FIXME: Is this the right solution? - if (TyposCorrected == 20) - return DeclarationName(); - ++TyposCorrected; - // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); if (!Typo) @@ -2833,17 +3006,18 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, // instantiation. if (!ActiveTemplateInstantiations.empty()) return DeclarationName(); - + TypoCorrectionConsumer Consumer(Typo); - + // Perform name lookup to find visible, similarly-named entities. + bool IsUnqualifiedLookup = false; if (MemberContext) { LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer); // Look in qualified interfaces. if (OPT) { - for (ObjCObjectPointerType::qual_iterator - I = OPT->qual_begin(), E = OPT->qual_end(); + for (ObjCObjectPointerType::qual_iterator + I = OPT->qual_begin(), E = OPT->qual_end(); I != E; ++I) LookupVisibleDecls(*I, Res.getLookupKind(), Consumer); } @@ -2851,10 +3025,54 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, DeclContext *DC = computeDeclContext(*SS, EnteringContext); if (!DC) return DeclarationName(); - + + // Provide a stop gap for files that are just seriously broken. Trying + // to correct all typos can turn into a HUGE performance penalty, causing + // some files to take minutes to get rejected by the parser. + if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) + return DeclarationName(); + ++TyposCorrected; + LookupVisibleDecls(DC, Res.getLookupKind(), Consumer); } else { - LookupVisibleDecls(S, Res.getLookupKind(), Consumer); + IsUnqualifiedLookup = true; + UnqualifiedTyposCorrectedMap::iterator Cached + = UnqualifiedTyposCorrected.find(Typo); + if (Cached == UnqualifiedTyposCorrected.end()) { + // Provide a stop gap for files that are just seriously broken. Trying + // to correct all typos can turn into a HUGE performance penalty, causing + // some files to take minutes to get rejected by the parser. + if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20) + return DeclarationName(); + + // For unqualified lookup, look through all of the names that we have + // seen in this translation unit. + for (IdentifierTable::iterator I = Context.Idents.begin(), + IEnd = Context.Idents.end(); + I != IEnd; ++I) + Consumer.FoundName(I->getKey()); + + // Walk through identifiers in external identifier sources. + if (IdentifierInfoLookup *External + = Context.Idents.getExternalIdentifierLookup()) { + llvm::OwningPtr<IdentifierIterator> Iter(External->getIdentifiers()); + do { + llvm::StringRef Name = Iter->Next(); + if (Name.empty()) + break; + + Consumer.FoundName(Name); + } while (true); + } + } else { + // Use the cached value, unless it's a keyword. In the keyword case, we'll + // end up adding the keyword below. + if (Cached->second.first.empty()) + return DeclarationName(); + + if (!Cached->second.second) + Consumer.FoundName(Cached->second.first); + } } // Add context-dependent keywords. @@ -2868,39 +3086,46 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, WantExpressionKeywords = true; WantCXXNamedCasts = true; WantRemainingKeywords = true; - + if (ObjCMethodDecl *Method = getCurMethodDecl()) if (Method->getClassInterface() && Method->getClassInterface()->getSuperClass()) Consumer.addKeywordResult(Context, "super"); - + break; - + case CTC_NoKeywords: break; - + case CTC_Type: WantTypeSpecifiers = true; break; - + case CTC_ObjCMessageReceiver: Consumer.addKeywordResult(Context, "super"); // Fall through to handle message receivers like expressions. - + case CTC_Expression: if (getLangOptions().CPlusPlus) WantTypeSpecifiers = true; WantExpressionKeywords = true; // Fall through to get C++ named casts. - + case CTC_CXXCasts: WantCXXNamedCasts = true; break; - + + case CTC_ObjCPropertyLookup: + // FIXME: Add "isa"? + break; + case CTC_MemberLookup: if (getLangOptions().CPlusPlus) Consumer.addKeywordResult(Context, "template"); break; + + case CTC_ObjCIvarLookup: + break; } if (WantTypeSpecifiers) { @@ -2912,67 +3137,67 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, // storage-specifiers as well "extern", "inline", "static", "typedef" }; - + const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]); for (unsigned I = 0; I != NumCTypeSpecs; ++I) Consumer.addKeywordResult(Context, CTypeSpecs[I]); - + if (getLangOptions().C99) Consumer.addKeywordResult(Context, "restrict"); if (getLangOptions().Bool || getLangOptions().CPlusPlus) Consumer.addKeywordResult(Context, "bool"); - + if (getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "class"); Consumer.addKeywordResult(Context, "typename"); Consumer.addKeywordResult(Context, "wchar_t"); - + if (getLangOptions().CPlusPlus0x) { Consumer.addKeywordResult(Context, "char16_t"); Consumer.addKeywordResult(Context, "char32_t"); Consumer.addKeywordResult(Context, "constexpr"); Consumer.addKeywordResult(Context, "decltype"); Consumer.addKeywordResult(Context, "thread_local"); - } + } } - + if (getLangOptions().GNUMode) Consumer.addKeywordResult(Context, "typeof"); } - + if (WantCXXNamedCasts && getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "const_cast"); Consumer.addKeywordResult(Context, "dynamic_cast"); Consumer.addKeywordResult(Context, "reinterpret_cast"); Consumer.addKeywordResult(Context, "static_cast"); } - + if (WantExpressionKeywords) { Consumer.addKeywordResult(Context, "sizeof"); if (getLangOptions().Bool || getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "false"); Consumer.addKeywordResult(Context, "true"); } - + if (getLangOptions().CPlusPlus) { - const char *CXXExprs[] = { - "delete", "new", "operator", "throw", "typeid" + const char *CXXExprs[] = { + "delete", "new", "operator", "throw", "typeid" }; const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]); for (unsigned I = 0; I != NumCXXExprs; ++I) Consumer.addKeywordResult(Context, CXXExprs[I]); - + if (isa<CXXMethodDecl>(CurContext) && cast<CXXMethodDecl>(CurContext)->isInstance()) Consumer.addKeywordResult(Context, "this"); - + if (getLangOptions().CPlusPlus0x) { Consumer.addKeywordResult(Context, "alignof"); Consumer.addKeywordResult(Context, "nullptr"); } } } - + if (WantRemainingKeywords) { if (getCurFunctionOrMethodDecl() || getCurBlock()) { // Statements. @@ -2981,18 +3206,18 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]); for (unsigned I = 0; I != NumCStmts; ++I) Consumer.addKeywordResult(Context, CStmts[I]); - + if (getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "catch"); Consumer.addKeywordResult(Context, "try"); } - + if (S && S->getBreakParent()) Consumer.addKeywordResult(Context, "break"); - + if (S && S->getContinueParent()) Consumer.addKeywordResult(Context, "continue"); - + if (!getCurFunction()->SwitchStack.empty()) { Consumer.addKeywordResult(Context, "case"); Consumer.addKeywordResult(Context, "default"); @@ -3013,7 +3238,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, Consumer.addKeywordResult(Context, "virtual"); } } - + if (getLangOptions().CPlusPlus) { Consumer.addKeywordResult(Context, "using"); @@ -3021,122 +3246,134 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, Consumer.addKeywordResult(Context, "static_assert"); } } - + // If we haven't found anything, we're done. - if (Consumer.empty()) + if (Consumer.empty()) { + // If this was an unqualified lookup, note that no correction was found. + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; + return DeclarationName(); + } - // Only allow a single, closest name in the result set (it's okay to - // have overloads of that name, though). - DeclarationName BestName; - NamedDecl *BestIvarOrPropertyDecl = 0; - bool FoundIvarOrPropertyDecl = false; - - // Check all of the declaration results to find the best name so far. - for (TypoCorrectionConsumer::iterator I = Consumer.begin(), + // Make sure that the user typed at least 3 characters for each correction + // made. Otherwise, we don't even both looking at the results. + + // We also suppress exact matches; those should be handled by a + // different mechanism (e.g., one that introduces qualification in + // C++). + unsigned ED = Consumer.getBestEditDistance(); + if (ED > 0 && Typo->getName().size() / ED < 3) { + // If this was an unqualified lookup, note that no correction was found. + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; + + return DeclarationName(); + } + + // Weed out any names that could not be found by name lookup. + bool LastLookupWasAccepted = false; + for (TypoCorrectionConsumer::iterator I = Consumer.begin(), IEnd = Consumer.end(); - I != IEnd; ++I) { - if (!BestName) - BestName = (*I)->getDeclName(); - else if (BestName != (*I)->getDeclName()) - return DeclarationName(); + I != IEnd; /* Increment in loop. */) { + // Keywords are always found. + if (I->second) { + ++I; + continue; + } + + // Perform name lookup on this name. + IdentifierInfo *Name = &Context.Idents.get(I->getKey()); + LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext, + EnteringContext, CTC); - // \brief Keep track of either an Objective-C ivar or a property, but not - // both. - if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I)) { - if (FoundIvarOrPropertyDecl) - BestIvarOrPropertyDecl = 0; - else { - BestIvarOrPropertyDecl = *I; - FoundIvarOrPropertyDecl = true; + switch (Res.getResultKind()) { + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::Ambiguous: + // We didn't find this name in our scope, or didn't like what we found; + // ignore it. + Res.suppressDiagnostics(); + { + TypoCorrectionConsumer::iterator Next = I; + ++Next; + Consumer.erase(I); + I = Next; } + LastLookupWasAccepted = false; + break; + + case LookupResult::Found: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + ++I; + LastLookupWasAccepted = true; + break; + } + + if (Res.isAmbiguous()) { + // We don't deal with ambiguities. + Res.suppressDiagnostics(); + Res.clear(); + return DeclarationName(); } } - // Now check all of the keyword results to find the best name. - switch (Consumer.keyword_size()) { - case 0: - // No keywords matched. - break; - - case 1: - // If we already have a name - if (!BestName) { - // We did not have anything previously, - BestName = *Consumer.keyword_begin(); - } else if (BestName.getAsIdentifierInfo() == *Consumer.keyword_begin()) { - // We have a declaration with the same name as a context-sensitive - // keyword. The keyword takes precedence. - BestIvarOrPropertyDecl = 0; - FoundIvarOrPropertyDecl = false; - Consumer.clear_decls(); - } else if (CTC == CTC_ObjCMessageReceiver && - (*Consumer.keyword_begin())->isStr("super")) { - // In an Objective-C message send, give the "super" keyword a slight - // edge over entities not in function or method scope. - for (TypoCorrectionConsumer::iterator I = Consumer.begin(), - IEnd = Consumer.end(); - I != IEnd; ++I) { - if ((*I)->getDeclName() == BestName) { - if ((*I)->getDeclContext()->isFunctionOrMethod()) - return DeclarationName(); - } - } - - // Everything found was outside a function or method; the 'super' - // keyword takes precedence. - BestIvarOrPropertyDecl = 0; - FoundIvarOrPropertyDecl = false; - Consumer.clear_decls(); - BestName = *Consumer.keyword_begin(); - } else { - // Name collision; we will not correct typos. + // If only a single name remains, return that result. + if (Consumer.size() == 1) { + IdentifierInfo *Name = &Context.Idents.get(Consumer.begin()->getKey()); + if (Consumer.begin()->second) { + Res.suppressDiagnostics(); + Res.clear(); + + // Don't correct to a keyword that's the same as the typo; the keyword + // wasn't actually in scope. + if (ED == 0) { + Res.setLookupName(Typo); return DeclarationName(); } - break; - - default: - // Name collision; we will not correct typos. - return DeclarationName(); - } - - // BestName is the closest viable name to what the user - // typed. However, to make sure that we don't pick something that's - // way off, make sure that the user typed at least 3 characters for - // each correction. - unsigned ED = Consumer.getBestEditDistance(); - if (ED == 0 || !BestName.getAsIdentifierInfo() || - (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3) - return DeclarationName(); - // Perform name lookup again with the name we chose, and declare - // success if we found something that was not ambiguous. - Res.clear(); - Res.setLookupName(BestName); - - // If we found an ivar or property, add that result; no further - // lookup is required. - if (BestIvarOrPropertyDecl) - Res.addDecl(BestIvarOrPropertyDecl); - // If we're looking into the context of a member, perform qualified - // name lookup on the best name. - else if (!Consumer.keyword_empty()) { - // The best match was a keyword. Return it. - return BestName; - } else if (MemberContext) - LookupQualifiedName(Res, MemberContext); - // Perform lookup as if we had just parsed the best name. - else - LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, - EnteringContext); + } else if (!LastLookupWasAccepted) { + // Perform name lookup on this name. + LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext, + EnteringContext, CTC); + } - if (Res.isAmbiguous()) { + // Record the correction for unqualified lookup. + if (IsUnqualifiedLookup) + UnqualifiedTyposCorrected[Typo] + = std::make_pair(Name->getName(), Consumer.begin()->second); + + return &Context.Idents.get(Consumer.begin()->getKey()); + } + else if (Consumer.size() > 1 && CTC == CTC_ObjCMessageReceiver + && Consumer["super"]) { + // Prefix 'super' when we're completing in a message-receiver + // context. Res.suppressDiagnostics(); - return DeclarationName(); + Res.clear(); + + // Don't correct to a keyword that's the same as the typo; the keyword + // wasn't actually in scope. + if (ED == 0) { + Res.setLookupName(Typo); + return DeclarationName(); + } + + // Record the correction for unqualified lookup. + if (IsUnqualifiedLookup) + UnqualifiedTyposCorrected[Typo] + = std::make_pair("super", Consumer.begin()->second); + + return &Context.Idents.get("super"); } - if (Res.getResultKind() != LookupResult::NotFound) - return BestName; - + Res.suppressDiagnostics(); + Res.setLookupName(Typo); + Res.clear(); + // Record the correction for unqualified lookup. + if (IsUnqualifiedLookup) + (void)UnqualifiedTyposCorrected[Typo]; + return DeclarationName(); } |