diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp | 1352 |
1 files changed, 634 insertions, 718 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp index 919c6ad..fe2c816 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp @@ -23,6 +23,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/LangOptions.h" +#include "clang/Lex/ModuleLoader.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Overload.h" @@ -113,10 +114,8 @@ namespace { if (Ctx && Ctx->isFileContext()) { visit(Ctx, Ctx); } else if (!Ctx || Ctx->isFunctionOrMethod()) { - Scope::udir_iterator I = S->using_directives_begin(), - End = S->using_directives_end(); - for (; I != End; ++I) - visit(*I, InnermostFileDC); + for (auto *I : S->using_directives()) + visit(I, InnermostFileDC); } } } @@ -153,9 +152,7 @@ namespace { void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) { SmallVector<DeclContext*,4> queue; while (true) { - DeclContext::udir_iterator I, End; - for (llvm::tie(I, End) = DC->getUsingDirectives(); I != End; ++I) { - UsingDirectiveDecl *UD = *I; + for (auto UD : DC->using_directives()) { DeclContext *NS = UD->getNominatedNamespace(); if (visited.insert(NS)) { addUsingDirective(UD, EffectiveDC); @@ -248,10 +245,11 @@ 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) @@ -267,8 +265,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, break; case Sema::LookupUsingDeclName: - IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag - | Decl::IDNS_Member | Decl::IDNS_Using; + assert(Redeclaration && "should only be used for redecl lookup"); + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | + Decl::IDNS_Using | Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend | + Decl::IDNS_LocalExtern; break; case Sema::LookupObjCProtocolName: @@ -288,36 +288,33 @@ void LookupResult::configure() { IDNS = getIDNS(LookupKind, SemaRef.getLangOpts().CPlusPlus, isForRedeclaration()); - if (!isForRedeclaration()) { - // If we're looking for one of the allocation or deallocation - // operators, make sure that the implicitly-declared new and delete - // operators can be found. - switch (NameInfo.getName().getCXXOverloadedOperator()) { - case OO_New: - case OO_Delete: - case OO_Array_New: - case OO_Array_Delete: - SemaRef.DeclareGlobalNewDelete(); - break; + // If we're looking for one of the allocation or deallocation + // operators, make sure that the implicitly-declared new and delete + // operators can be found. + switch (NameInfo.getName().getCXXOverloadedOperator()) { + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + SemaRef.DeclareGlobalNewDelete(); + break; - default: - break; - } + default: + break; + } - // Compiler builtins are always visible, regardless of where they end - // up being declared. - if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) { - if (unsigned BuiltinID = Id->getBuiltinID()) { - if (!SemaRef.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) - AllowHidden = true; - } + // Compiler builtins are always visible, regardless of where they end + // up being declared. + if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) { + if (unsigned BuiltinID = Id->getBuiltinID()) { + if (!SemaRef.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) + AllowHidden = true; } } } -void LookupResult::sanityImpl() const { - // Note that this function is never called by NDEBUG builds. See - // LookupResult::sanity(). +bool LookupResult::sanity() const { + // This function is never called by NDEBUG builds. assert(ResultKind != NotFound || Decls.size() == 0); assert(ResultKind != Found || Decls.size() == 1); assert(ResultKind != FoundOverloaded || Decls.size() > 1 || @@ -327,9 +324,10 @@ void LookupResult::sanityImpl() const { assert(ResultKind != Ambiguous || Decls.size() > 1 || (Decls.size() == 1 && (Ambiguity == AmbiguousBaseSubobjects || Ambiguity == AmbiguousBaseSubobjectTypes))); - assert((Paths != NULL) == (ResultKind == Ambiguous && - (Ambiguity == AmbiguousBaseSubobjectTypes || - Ambiguity == AmbiguousBaseSubobjects))); + assert((Paths != nullptr) == (ResultKind == Ambiguous && + (Ambiguity == AmbiguousBaseSubobjectTypes || + Ambiguity == AmbiguousBaseSubobjects))); + return true; } // Necessary because CXXBasePaths is not complete in Sema.h @@ -544,14 +542,6 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { R.addDecl(D); 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; } } } @@ -734,7 +724,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // specialization into the result set. We do this to avoid forcing all // callers to perform special deduction for conversion functions. TemplateDeductionInfo Info(R.getNameLoc()); - FunctionDecl *Specialization = 0; + FunctionDecl *Specialization = nullptr; const FunctionProtoType *ConvProto = ConvTemplate->getTemplatedDecl()->getType()->getAs<FunctionProtoType>(); @@ -753,7 +743,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // Perform template argument deduction against the type that we would // expect the function to have. - if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType, + if (R.getSema().DeduceTemplateArguments(ConvTemplate, nullptr, ExpectedType, Specialization, Info) == Sema::TDK_Success) { R.addDecl(Specialization); @@ -777,7 +767,7 @@ CppNamespaceLookup(Sema &S, LookupResult &R, ASTContext &Context, // Perform direct name lookup into the namespaces nominated by the // using directives whose common ancestor is this namespace. UnqualUsingDirectiveSet::const_iterator UI, UEnd; - llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(NS); + std::tie(UI, UEnd) = UDirs.getNamespacesFor(NS); for (; UI != UEnd; ++UI) if (LookupDirect(S, R, UI->getNominatedNamespace())) @@ -803,7 +793,7 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) { // it leaves the current template parameter scope. static std::pair<DeclContext *, bool> findOuterContext(Scope *S) { DeclContext *DC = S->getEntity(); - DeclContext *Lexical = 0; + DeclContext *Lexical = nullptr; for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent()) { if (OuterS->getEntity()) { @@ -926,7 +916,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { UnqualUsingDirectiveSet UDirs; bool VisitedUsingDirectives = false; bool LeftStartingScope = false; - DeclContext *OutsideOfTemplateParamDC = 0; + DeclContext *OutsideOfTemplateParamDC = nullptr; // When performing a scope lookup, we want to find local extern decls. FindLocalExternScope FindLocals(R); @@ -983,13 +973,13 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // findOuterContext(). This implements the name lookup behavior // of C++ [temp.local]p8. Ctx = OutsideOfTemplateParamDC; - OutsideOfTemplateParamDC = 0; + OutsideOfTemplateParamDC = nullptr; } if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; - llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); + std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); if (SearchAfterTemplateScope) OutsideOfTemplateParamDC = OuterCtx; @@ -1126,13 +1116,13 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // findOuterContext(). This implements the name lookup behavior // of C++ [temp.local]p8. Ctx = OutsideOfTemplateParamDC; - OutsideOfTemplateParamDC = 0; + OutsideOfTemplateParamDC = nullptr; } if (Ctx) { DeclContext *OuterCtx; bool SearchAfterTemplateScope; - llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); + std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); if (SearchAfterTemplateScope) OutsideOfTemplateParamDC = OuterCtx; @@ -1224,7 +1214,7 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() { I != N; ++I) { Module *M = getDefiningModule(ActiveTemplateInstantiations[I].Entity); if (M && !LookupModulesCache.insert(M).second) - M = 0; + M = nullptr; ActiveTemplateInstantiationLookupModules.push_back(M); } return LookupModulesCache; @@ -1278,15 +1268,14 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case"); - for (Decl::redecl_iterator RD = D->redecls_begin(), RDEnd = D->redecls_end(); - RD != RDEnd; ++RD) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(*RD)) { + for (auto RD : D->redecls()) { + if (auto ND = dyn_cast<NamedDecl>(RD)) { if (LookupResult::isVisible(SemaRef, ND)) return ND; } } - return 0; + return nullptr; } NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { @@ -1381,10 +1370,10 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { // then we'll need to perform our checks based on the matching // DeclContexts rather than matching scopes. if (S && isNamespaceOrTranslationUnitScope(S)) - S = 0; + S = nullptr; // Compute the DeclContext, if we need it. - DeclContext *DC = 0; + DeclContext *DC = nullptr; if (!S) DC = (*I)->getDeclContext()->getRedeclContext(); @@ -1462,10 +1451,8 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, DeclContext *StartDC) { assert(StartDC->isFileContext() && "start context is not a file context"); - DeclContext::udir_iterator I = StartDC->using_directives_begin(); - DeclContext::udir_iterator E = StartDC->using_directives_end(); - - if (I == E) return false; + DeclContext::udir_range UsingDirectives = StartDC->using_directives(); + if (UsingDirectives.begin() == UsingDirectives.end()) return false; // We have at least added all these contexts to the queue. llvm::SmallPtrSet<DeclContext*, 8> Visited; @@ -1477,8 +1464,8 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, // We have already looked into the initial namespace; seed the queue // with its using-children. - for (; I != E; ++I) { - NamespaceDecl *ND = (*I)->getNominatedNamespace()->getOriginalNamespace(); + for (auto *I : UsingDirectives) { + NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace(); if (Visited.insert(ND)) Queue.push_back(ND); } @@ -1525,8 +1512,8 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, continue; } - for (llvm::tie(I,E) = ND->getUsingDirectives(); I != E; ++I) { - NamespaceDecl *Nom = (*I)->getNominatedNamespace(); + for (auto I : ND->using_directives()) { + NamespaceDecl *Nom = I->getNominatedNamespace(); if (Visited.insert(Nom)) Queue.push_back(Nom); } @@ -1667,7 +1654,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, Paths.setOrigin(LookupRec); // Look for this member in our base classes - CXXRecordDecl::BaseMatchesCallback *BaseCallback = 0; + CXXRecordDecl::BaseMatchesCallback *BaseCallback = nullptr; switch (R.getLookupKind()) { case LookupObjCImplicitSelfParam: case LookupOrdinaryName: @@ -1736,7 +1723,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, != Context.getCanonicalType(PathElement.Base->getType())) { // We found members of the given name in two subobjects of // different types. If the declaration sets aren't the same, this - // this lookup is ambiguous. + // lookup is ambiguous. if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end())) { CXXBasePaths::paths_iterator FirstPath = Paths.begin(); DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin(); @@ -1780,9 +1767,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Lookup in a base class succeeded; return these results. - DeclContext::lookup_result DR = Paths.front().Decls; - for (DeclContext::lookup_iterator I = DR.begin(), E = DR.end(); I != E; ++I) { - NamedDecl *D = *I; + for (auto *D : Paths.front().Decls) { AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess, D->getAccess()); R.addDecl(D, AS); @@ -1890,16 +1875,15 @@ void Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { llvm::SmallPtrSet<NamedDecl*,8> TagDecls; - LookupResult::iterator DI, DE = Result.end(); - for (DI = Result.begin(); DI != DE; ++DI) - if (TagDecl *TD = dyn_cast<TagDecl>(*DI)) { + for (auto *D : Result) + if (TagDecl *TD = dyn_cast<TagDecl>(D)) { TagDecls.insert(TD); Diag(TD->getLocation(), diag::note_hidden_tag); } - for (DI = Result.begin(); DI != DE; ++DI) - if (!isa<TagDecl>(*DI)) - Diag((*DI)->getLocation(), diag::note_hiding_object); + for (auto *D : Result) + if (!isa<TagDecl>(D)) + Diag(D->getLocation(), diag::note_hiding_object); // For recovery purposes, go ahead and implement the hiding. LookupResult::Filter F = Result.makeFilter(); @@ -1914,9 +1898,8 @@ void 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; + for (auto *D : Result) + Diag(D->getLocation(), diag::note_ambiguous_candidate) << D; break; } } @@ -2003,10 +1986,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, break; case TemplateArgument::Pack: - for (TemplateArgument::pack_iterator P = Arg.pack_begin(), - PEnd = Arg.pack_end(); - P != PEnd; ++P) - addAssociatedClassesAndNamespaces(Result, *P); + for (const auto &P : Arg.pack_elements()) + addAssociatedClassesAndNamespaces(Result, P); break; } } @@ -2039,6 +2020,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // Add the class itself. If we've already seen this class, we don't // need to visit base classes. + // + // FIXME: That's not correct, we may have added this class only because it + // was the enclosing class of another class, and in that case we won't have + // added its base classes yet. if (!Result.Classes.insert(Class)) return; @@ -2065,12 +2050,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, } // Only recurse into base classes for complete types. - if (!Class->hasDefinition()) { - QualType type = Result.S.Context.getTypeDeclType(Class); - if (Result.S.RequireCompleteType(Result.InstantiationLoc, type, - /*no diagnostic*/ 0)) - return; - } + if (!Class->hasDefinition()) + return; // Add direct and indirect base classes along with their associated // namespaces. @@ -2081,10 +2062,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, Class = Bases.pop_back_val(); // Visit the base classes. - for (CXXRecordDecl::base_class_iterator Base = Class->bases_begin(), - BaseEnd = Class->bases_end(); - Base != BaseEnd; ++Base) { - const RecordType *BaseType = Base->getType()->getAs<RecordType>(); + for (const auto &Base : Class->bases()) { + const RecordType *BaseType = Base.getType()->getAs<RecordType>(); // In dependent contexts, we do ADL twice, and the first time around, // the base type might be a dependent TemplateSpecializationType, or a // TemplateTypeParmType. If that happens, simply ignore it. @@ -2164,6 +2143,8 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // classes. Its associated namespaces are the namespaces in // which its associated classes are defined. case Type::Record: { + Result.S.RequireCompleteType(Result.InstantiationLoc, QualType(T, 0), + /*no diagnostic*/ 0); CXXRecordDecl *Class = cast<CXXRecordDecl>(cast<RecordType>(T)->getDecl()); addAssociatedClassesAndNamespaces(Result, Class); @@ -2192,15 +2173,13 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // types and those associated with the return type. case Type::FunctionProto: { const FunctionProtoType *Proto = cast<FunctionProtoType>(T); - for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), - ArgEnd = Proto->arg_type_end(); - Arg != ArgEnd; ++Arg) - Queue.push_back(Arg->getTypePtr()); + for (const auto &Arg : Proto->param_types()) + Queue.push_back(Arg.getTypePtr()); // fallthrough } case Type::FunctionNoProto: { const FunctionType *FnType = cast<FunctionType>(T); - T = FnType->getResultType().getTypePtr(); + T = FnType->getReturnType().getTypePtr(); continue; } @@ -2315,14 +2294,9 @@ void Sema::FindAssociatedClassesAndNamespaces( UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Arg); if (!ULE) continue; - for (UnresolvedSetIterator I = ULE->decls_begin(), E = ULE->decls_end(); - I != E; ++I) { + for (const auto *D : ULE->decls()) { // Look through any using declarations to find the underlying function. - NamedDecl *Fn = (*I)->getUnderlyingDecl(); - - FunctionDecl *FDecl = dyn_cast<FunctionDecl>(Fn); - if (!FDecl) - FDecl = cast<FunctionTemplateDecl>(Fn)->getTemplatedDecl(); + const FunctionDecl *FDecl = D->getUnderlyingDecl()->getAsFunction(); // Add the classes and namespaces associated with the parameter // types and return type of this function. @@ -2331,43 +2305,6 @@ void Sema::FindAssociatedClassesAndNamespaces( } } -/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is -/// an acceptable non-member overloaded operator for a call whose -/// arguments have types T1 (and, if non-empty, T2). This routine -/// implements the check in C++ [over.match.oper]p3b2 concerning -/// enumeration types. -static bool -IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn, - QualType T1, QualType T2, - ASTContext &Context) { - if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType())) - return true; - - if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType())) - return true; - - const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>(); - if (Proto->getNumArgs() < 1) - return false; - - if (T1->isEnumeralType()) { - QualType ArgType = Proto->getArgType(0).getNonReferenceType(); - if (Context.hasSameUnqualifiedType(T1, ArgType)) - return true; - } - - if (Proto->getNumArgs() < 2) - return false; - - if (!T2.isNull() && T2->isEnumeralType()) { - QualType ArgType = Proto->getArgType(1).getNonReferenceType(); - if (Context.hasSameUnqualifiedType(T2, ArgType)) - return true; - } - - return false; -} - NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, SourceLocation Loc, LookupNameKind NameKind, @@ -2394,37 +2331,13 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, // unqualified lookup of operator@ in the context of the // expression according to the usual rules for name lookup in // unqualified function calls (3.4.2) except that all member - // functions are ignored. However, if no operand has a class - // type, only those non-member functions in the lookup set - // that have a first parameter of type T1 or "reference to - // (possibly cv-qualified) T1", when T1 is an enumeration - // type, or (if there is a right operand) a second parameter - // of type T2 or "reference to (possibly cv-qualified) T2", - // when T2 is an enumeration type, are candidate functions. + // functions are ignored. DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); LookupResult Operators(*this, OpName, SourceLocation(), LookupOperatorName); LookupName(Operators, S); assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous"); - - if (Operators.empty()) - return; - - for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end(); - Op != OpEnd; ++Op) { - NamedDecl *Found = (*Op)->getUnderlyingDecl(); - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Found)) { - if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context)) - Functions.addDecl(*Op, Op.getAccess()); // FIXME: canonical FD - } else if (FunctionTemplateDecl *FunTmpl - = dyn_cast<FunctionTemplateDecl>(Found)) { - // FIXME: friend operators? - // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate, - // later? - if (!FunTmpl->getDeclContext()->isRecord()) - Functions.addDecl(*Op, Op.getAccess()); - } - } + Functions.append(Operators.begin(), Operators.end()); } Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, @@ -2481,7 +2394,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, // if necessary and make sure that implicit functions are declared. CanQualType CanTy = Context.getCanonicalType(Context.getTagDeclType(RD)); DeclarationName Name; - Expr *Arg = 0; + Expr *Arg = nullptr; unsigned NumArgs; QualType ArgType = CanTy; @@ -2545,7 +2458,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, // Now we perform lookup on the name we computed earlier and do overload // resolution. Lookup is only performed directly into the class since there // will always be a (possibly implicit) declaration to shadow any others. - OverloadCandidateSet OCS((SourceLocation())); + OverloadCandidateSet OCS(RD->getLocation(), OverloadCandidateSet::CSK_Normal); DeclContext::lookup_result R = RD->lookup(Name); assert(!R.empty() && "lookup for a constructor or assignment operator was empty"); @@ -2554,11 +2467,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, // from an external source and invalidate lookup_result. SmallVector<NamedDecl *, 8> Candidates(R.begin(), R.end()); - for (SmallVectorImpl<NamedDecl *>::iterator I = Candidates.begin(), - E = Candidates.end(); - I != E; ++I) { - NamedDecl *Cand = *I; - + for (auto *Cand : Candidates) { if (Cand->isInvalidDecl()) continue; @@ -2585,12 +2494,12 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, dyn_cast<FunctionTemplateDecl>(Cand)) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), - RD, 0, ThisTy, Classification, + RD, nullptr, ThisTy, Classification, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); else AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), - 0, llvm::makeArrayRef(&Arg, NumArgs), + nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); } else { assert(isa<UsingDecl>(Cand) && "illegal Kind of operator = Decl"); @@ -2610,12 +2519,12 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, break; case OR_Ambiguous: - Result->setMethod(0); + Result->setMethod(nullptr); Result->setKind(SpecialMemberOverloadResult::Ambiguous); break; case OR_No_Viable_Function: - Result->setMethod(0); + Result->setMethod(nullptr); Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); break; } @@ -2812,14 +2721,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, // operator template, but not both. if (FoundRaw && FoundTemplate) { Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName(); - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - Decl *D = *I; - if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D)) - D = USD->getTargetDecl(); - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) - D = FunTmpl->getTemplatedDecl(); - NoteOverloadCandidate(cast<FunctionDecl>(D)); - } + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + NoteOverloadCandidate((*I)->getUnderlyingDecl()->getAsFunction()); return LOLR_Error; } @@ -2845,20 +2748,14 @@ void ADLResult::insert(NamedDecl *New) { // If we haven't yet seen a decl for this key, or the last decl // was exactly this one, we're done. - if (Old == 0 || Old == New) { + if (Old == nullptr || Old == New) { Old = New; return; } // Otherwise, decide which is a more recent redeclaration. - FunctionDecl *OldFD, *NewFD; - if (isa<FunctionTemplateDecl>(New)) { - OldFD = cast<FunctionTemplateDecl>(Old)->getTemplatedDecl(); - NewFD = cast<FunctionTemplateDecl>(New)->getTemplatedDecl(); - } else { - OldFD = cast<FunctionDecl>(Old); - NewFD = cast<FunctionDecl>(New); - } + FunctionDecl *OldFD = Old->getAsFunction(); + FunctionDecl *NewFD = New->getAsFunction(); FunctionDecl *Cursor = NewFD; while (true) { @@ -2877,9 +2774,8 @@ void ADLResult::insert(NamedDecl *New) { Old = New; } -void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, - SourceLocation Loc, ArrayRef<Expr *> Args, - ADLResult &Result) { +void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, + ArrayRef<Expr *> Args, ADLResult &Result) { // Find all of the associated namespaces and classes based on the // arguments we have. AssociatedNamespaceSet AssociatedNamespaces; @@ -2888,13 +2784,6 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, AssociatedNamespaces, AssociatedClasses); - QualType T1, T2; - if (Operator) { - T1 = Args[0]->getType(); - if (Args.size() >= 2) - T2 = Args[1]->getType(); - } - // C++ [basic.lookup.argdep]p3: // Let X be the lookup set produced by unqualified lookup (3.4.1) // and let Y be the lookup set produced by argument dependent @@ -2906,9 +2795,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, // // Here, we compute Y and add its members to the overloaded // candidate set. - for (AssociatedNamespaceSet::iterator NS = AssociatedNamespaces.begin(), - NSEnd = AssociatedNamespaces.end(); - NS != NSEnd; ++NS) { + for (auto *NS : AssociatedNamespaces) { // When considering an associated namespace, the lookup is the // same as the lookup performed when the associated namespace is // used as a qualifier (3.4.3.2) except that: @@ -2920,10 +2807,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, // associated classes are visible within their respective // namespaces even if they are not visible during an ordinary // lookup (11.4). - DeclContext::lookup_result R = (*NS)->lookup(Name); - for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; - ++I) { - NamedDecl *D = *I; + DeclContext::lookup_result R = NS->lookup(Name); + for (auto *D : R) { // If the only declaration here is an ordinary friend, consider // it only if it was declared in an associated classes. if ((D->getIdentifierNamespace() & Decl::IDNS_Ordinary) == 0) { @@ -2947,12 +2832,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); - if (isa<FunctionDecl>(D)) { - if (Operator && - !IsAcceptableNonMemberOperatorCandidate(cast<FunctionDecl>(D), - T1, T2, Context)) - continue; - } else if (!isa<FunctionTemplateDecl>(D)) + if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) continue; Result.insert(D); @@ -3045,35 +2925,33 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { if (Pos == SM->end()) continue; - for (ShadowMapEntry::iterator I = Pos->second.begin(), - IEnd = Pos->second.end(); - I != IEnd; ++I) { + for (auto *D : Pos->second) { // A tag declaration does not hide a non-tag declaration. - if ((*I)->hasTagIdentifierNamespace() && + if (D->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; // Protocols are in distinct namespaces from everything else. - if ((((*I)->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) + if (((D->getIdentifierNamespace() & Decl::IDNS_ObjCProtocol) || (IDNS & Decl::IDNS_ObjCProtocol)) && - (*I)->getIdentifierNamespace() != IDNS) + D->getIdentifierNamespace() != IDNS) continue; // Functions and function templates in the same scope overload // rather than hide. FIXME: Look for hiding based on function // signatures! - if ((*I)->isFunctionOrFunctionTemplate() && - ND->isFunctionOrFunctionTemplate() && + if (D->getUnderlyingDecl()->isFunctionOrFunctionTemplate() && + ND->getUnderlyingDecl()->isFunctionOrFunctionTemplate() && SM == ShadowMaps.rbegin()) continue; // We've found a declaration that hides this one. - return *I; + return D; } } - return 0; + return nullptr; } static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, @@ -3092,13 +2970,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, Result.getSema().ForceDeclarationOfImplicitMembers(Class); // Enumerate all of the results in this context. - for (DeclContext::all_lookups_iterator L = Ctx->lookups_begin(), - LEnd = Ctx->lookups_end(); - L != LEnd; ++L) { - DeclContext::lookup_result R = *L; - for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; - ++I) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(*I)) { + for (const auto &R : Ctx->lookups()) { + for (auto *I : R) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(I)) { if ((ND = Result.getAcceptableDecl(ND))) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass); Visited.add(ND); @@ -3110,9 +2984,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Traverse using directives for qualified name lookup. if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); - DeclContext::udir_iterator I, E; - for (llvm::tie(I, E) = Ctx->getUsingDirectives(); I != E; ++I) { - LookupVisibleDecls((*I)->getNominatedNamespace(), Result, + for (auto I : Ctx->using_directives()) { + LookupVisibleDecls(I->getNominatedNamespace(), Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } } @@ -3122,10 +2995,8 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, if (!Record->hasDefinition()) return; - for (CXXRecordDecl::base_class_iterator B = Record->bases_begin(), - BEnd = Record->bases_end(); - B != BEnd; ++B) { - QualType BaseType = B->getType(); + for (const auto &B : Record->bases()) { + QualType BaseType = B.getType(); // Don't look into dependent bases, because name lookup can't look // there anyway. @@ -3165,21 +3036,16 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, // Traverse the contexts of Objective-C classes. if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) { // Traverse categories. - for (ObjCInterfaceDecl::visible_categories_iterator - Cat = IFace->visible_categories_begin(), - CatEnd = IFace->visible_categories_end(); - Cat != CatEnd; ++Cat) { + for (auto *Cat : IFace->visible_categories()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*Cat, Result, QualifiedNameLookup, false, + LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, Consumer, Visited); } // Traverse protocols. - for (ObjCInterfaceDecl::all_protocol_iterator - I = IFace->all_referenced_protocol_begin(), - E = IFace->all_referenced_protocol_end(); I != E; ++I) { + for (auto *I : IFace->all_referenced_protocols()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, Visited); } @@ -3198,17 +3064,15 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, QualifiedNameLookup, InBaseClass, 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) { + for (auto *I : Protocol->protocols()) { 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) { + for (auto *I : Category->protocols()) { ShadowContextRAII Shadow(Visited); - LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, + LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer, Visited); } @@ -3234,18 +3098,17 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, (S->getEntity())->isFunctionOrMethod()) { FindLocalExternScope FindLocals(Result); // Walk through the declarations in this Scope. - for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); - D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) + for (auto *D : S->decls()) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) if ((ND = Result.getAcceptableDecl(ND))) { - Consumer.FoundDecl(ND, Visited.checkHidden(ND), 0, false); + Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false); Visited.add(ND); } } } // FIXME: C++ [temp.local]p8 - DeclContext *Entity = 0; + DeclContext *Entity = nullptr; if (S->getEntity()) { // Look into this scope's declaration context, along with any of its // parent lookup contexts (e.g., enclosing classes), up to the point @@ -3297,7 +3160,7 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, // Lookup visible declarations in any namespaces found by using // directives. UnqualUsingDirectiveSet::const_iterator UI, UEnd; - llvm::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity); + std::tie(UI, UEnd) = UDirs.getNamespacesFor(Entity); for (; UI != UEnd; ++UI) LookupVisibleDecls(const_cast<DeclContext *>(UI->getNominatedNamespace()), Result, /*QualifiedNameLookup=*/false, @@ -3355,7 +3218,7 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, SourceLocation GnuLabelLoc) { // Do a lookup to see if we have a label with this name already. - NamedDecl *Res = 0; + NamedDecl *Res = nullptr; if (GnuLabelLoc.isValid()) { // Local label definitions always shadow existing labels. @@ -3370,8 +3233,8 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, // 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) { + Res = nullptr; + if (!Res) { // If not forward referenced or defined already, create the backing decl. Res = LabelDecl::Create(Context, CurContext, Loc, II); Scope *S = CurScope->getFnParent(); @@ -3385,54 +3248,106 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, // Typo correction //===----------------------------------------------------------------------===// -namespace { +static bool isCandidateViable(CorrectionCandidateCallback &CCC, + TypoCorrection &Candidate) { + Candidate.setCallbackDistance(CCC.RankCandidate(Candidate)); + return Candidate.getEditDistance(false) != TypoCorrection::InvalidDistance; +} -typedef SmallVector<TypoCorrection, 1> TypoResultList; -typedef llvm::StringMap<TypoResultList, llvm::BumpPtrAllocator> TypoResultsMap; -typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap; +static void LookupPotentialTypoResult(Sema &SemaRef, + LookupResult &Res, + IdentifierInfo *Name, + Scope *S, CXXScopeSpec *SS, + DeclContext *MemberContext, + bool EnteringContext, + bool isObjCIvarLookup, + bool FindHidden); -static const unsigned MaxTypoDistanceResultSets = 5; +// Fill the supplied vector with the IdentifierInfo pointers for each piece of +// the given NestedNameSpecifier (i.e. given a NestedNameSpecifier "foo::bar::", +// fill the vector with the IdentifierInfo pointers for "foo" and "bar"). +static void getNestedNameSpecifierIdentifiers( + NestedNameSpecifier *NNS, + SmallVectorImpl<const IdentifierInfo*> &Identifiers) { + if (NestedNameSpecifier *Prefix = NNS->getPrefix()) + getNestedNameSpecifierIdentifiers(Prefix, Identifiers); + else + Identifiers.clear(); -class TypoCorrectionConsumer : public VisibleDeclConsumer { - /// \brief The name written that is a typo in the source. - StringRef Typo; + const IdentifierInfo *II = nullptr; - /// \brief The results found that have the smallest edit distance - /// found (so far) with the typo name. - /// - /// The pointer value being set to the current DeclContext indicates - /// whether there is a keyword with this name. - TypoEditDistanceMap CorrectionResults; + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + II = NNS->getAsIdentifier(); + break; - Sema &SemaRef; + case NestedNameSpecifier::Namespace: + if (NNS->getAsNamespace()->isAnonymousNamespace()) + return; + II = NNS->getAsNamespace()->getIdentifier(); + break; + + case NestedNameSpecifier::NamespaceAlias: + II = NNS->getAsNamespaceAlias()->getIdentifier(); + break; + + case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::TypeSpec: + II = QualType(NNS->getAsType(), 0).getBaseTypeIdentifier(); + break; + + case NestedNameSpecifier::Global: + return; + } + + if (II) + Identifiers.push_back(II); +} + +namespace { + +static const unsigned MaxTypoDistanceResultSets = 5; + +class TypoCorrectionConsumer : public VisibleDeclConsumer { + typedef SmallVector<TypoCorrection, 1> TypoResultList; + typedef llvm::StringMap<TypoResultList> TypoResultsMap; + typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap; public: - explicit TypoCorrectionConsumer(Sema &SemaRef, IdentifierInfo *Typo) - : Typo(Typo->getName()), - SemaRef(SemaRef) {} + explicit TypoCorrectionConsumer(Sema &SemaRef, + const DeclarationNameInfo &TypoName, + Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + DeclContext *MemberContext, + bool EnteringContext) + : Typo(TypoName.getName().getAsIdentifierInfo()), SemaRef(SemaRef), S(S), + SS(SS), CorrectionValidator(CCC), MemberContext(MemberContext), + Result(SemaRef, TypoName, LookupKind), + Namespaces(SemaRef.Context, SemaRef.CurContext, SS), + EnteringContext(EnteringContext), SearchNamespaces(false) { + Result.suppressDiagnostics(); + } - bool includeHiddenDecls() const { return true; } + bool includeHiddenDecls() const override { return true; } - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, - bool InBaseClass); + // Methods for adding potential corrections to the consumer. + void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass) override; void FoundName(StringRef Name); void addKeywordResult(StringRef Keyword); - void addName(StringRef Name, NamedDecl *ND, NestedNameSpecifier *NNS = NULL, - bool isKeyword = false); void addCorrection(TypoCorrection Correction); - typedef TypoResultsMap::iterator result_iterator; - typedef TypoEditDistanceMap::iterator distance_iterator; - distance_iterator begin() { return CorrectionResults.begin(); } - distance_iterator end() { return CorrectionResults.end(); } - void erase(distance_iterator I) { CorrectionResults.erase(I); } - unsigned size() const { return CorrectionResults.size(); } bool empty() const { return CorrectionResults.empty(); } + /// \brief Return the list of TypoCorrections for the given identifier from + /// the set of corrections that have the closest edit distance, if any. TypoResultList &operator[](StringRef Name) { return CorrectionResults.begin()->second[Name]; } + /// \brief Return the edit distance of the corrections that have the + /// closest/best edit distance from the original typop. unsigned getBestEditDistance(bool Normalized) { if (CorrectionResults.empty()) return (std::numeric_limits<unsigned>::max)(); @@ -3441,10 +3356,101 @@ public: return Normalized ? TypoCorrection::NormalizeEditDistance(BestED) : BestED; } - TypoResultsMap &getBestResults() { - return CorrectionResults.begin()->second; - } + /// \brief Set-up method to add to the consumer the set of namespaces to use + /// in performing corrections to nested name specifiers. This method also + /// implicitly adds all of the known classes in the current AST context to the + /// to the consumer for correcting nested name specifiers. + void + addNamespaces(const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces); + + /// \brief Return the next typo correction that passes all internal filters + /// and is deemed valid by the consumer's CorrectionCandidateCallback, + /// starting with the corrections that have the closest edit distance. An + /// empty TypoCorrection is returned once no more viable corrections remain + /// in the consumer. + TypoCorrection getNextCorrection(); + +private: + class NamespaceSpecifierSet { + struct SpecifierInfo { + DeclContext* DeclCtx; + NestedNameSpecifier* NameSpecifier; + unsigned EditDistance; + }; + + typedef SmallVector<DeclContext*, 4> DeclContextList; + typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList; + + ASTContext &Context; + DeclContextList CurContextChain; + std::string CurNameSpecifier; + SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers; + SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers; + bool isSorted; + + SpecifierInfoList Specifiers; + llvm::SmallSetVector<unsigned, 4> Distances; + llvm::DenseMap<unsigned, SpecifierInfoList> DistanceMap; + + /// \brief Helper for building the list of DeclContexts between the current + /// context and the top of the translation unit + static DeclContextList buildContextChain(DeclContext *Start); + + void sortNamespaces(); + + unsigned buildNestedNameSpecifier(DeclContextList &DeclChain, + NestedNameSpecifier *&NNS); + + public: + NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext, + CXXScopeSpec *CurScopeSpec); + + /// \brief Add the DeclContext (a namespace or record) to the set, computing + /// the corresponding NestedNameSpecifier and its distance in the process. + void addNameSpecifier(DeclContext *Ctx); + + typedef SpecifierInfoList::iterator iterator; + iterator begin() { + if (!isSorted) sortNamespaces(); + return Specifiers.begin(); + } + iterator end() { return Specifiers.end(); } + }; + + void addName(StringRef Name, NamedDecl *ND, + NestedNameSpecifier *NNS = nullptr, bool isKeyword = false); + + /// \brief Find any visible decls for the given typo correction candidate. + /// If none are found, it to the set of candidates for which qualified lookups + /// will be performed to find possible nested name specifier changes. + bool resolveCorrection(TypoCorrection &Candidate); + + /// \brief Perform qualified lookups on the queued set of typo correction + /// candidates and add the nested name specifier changes to each candidate if + /// a lookup succeeds (at which point the candidate will be returned to the + /// main pool of potential corrections). + void performQualifiedLookups(); + /// \brief The name written that is a typo in the source. + IdentifierInfo *Typo; + + /// \brief The results found that have the smallest edit distance + /// found (so far) with the typo name. + /// + /// The pointer value being set to the current DeclContext indicates + /// whether there is a keyword with this name. + TypoEditDistanceMap CorrectionResults; + + Sema &SemaRef; + Scope *S; + CXXScopeSpec *SS; + CorrectionCandidateCallback &CorrectionValidator; + DeclContext *MemberContext; + LookupResult Result; + NamespaceSpecifierSet Namespaces; + SmallVector<TypoCorrection, 2> QualifiedResults; + bool EnteringContext; + bool SearchNamespaces; }; } @@ -3464,7 +3470,7 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, // Only consider visible declarations and declarations from modules with // names that exactly match. - if (!LookupResult::isVisible(SemaRef, ND) && Name->getName() != Typo && + if (!LookupResult::isVisible(SemaRef, ND) && Name != Typo && !findAcceptableDecl(SemaRef, ND)) return; @@ -3474,27 +3480,28 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, void TypoCorrectionConsumer::FoundName(StringRef Name) { // Compute the edit distance between the typo and the name of this // entity, and add the identifier to the list of results. - addName(Name, NULL); + addName(Name, nullptr); } void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) { // Compute the edit distance between the typo and this keyword, // and add the keyword to the list of results. - addName(Keyword, NULL, NULL, true); + addName(Keyword, nullptr, nullptr, true); } void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND, NestedNameSpecifier *NNS, bool isKeyword) { // 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 && Typo.size() / MinED < 3) + StringRef TypoStr = Typo->getName(); + unsigned MinED = abs((int)Name.size() - (int)TypoStr.size()); + if (MinED && TypoStr.size() / MinED < 3) return; // Compute an upper bound on the allowable edit distance, so that the // edit-distance algorithm can short-circuit. - unsigned UpperBound = (Typo.size() + 2) / 3 + 1; - unsigned ED = Typo.edit_distance(Name, true, UpperBound); + unsigned UpperBound = (TypoStr.size() + 2) / 3 + 1; + unsigned ED = TypoStr.edit_distance(Name, true, UpperBound); if (ED >= UpperBound) return; TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, ED); @@ -3503,7 +3510,21 @@ void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND, } void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { + StringRef TypoStr = Typo->getName(); StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName(); + + // For very short typos, ignore potential corrections that have a different + // base identifier from the typo or which have a normalized edit distance + // longer than the typo itself. + if (TypoStr.size() < 3 && + (Name != TypoStr || Correction.getEditDistance(true) > TypoStr.size())) + return; + + // If the correction is resolved but is not viable, ignore it. + if (Correction.isResolved() && + !isCandidateViable(CorrectionValidator, Correction)) + return; + TypoResultList &CList = CorrectionResults[Correction.getEditDistance(false)][Name]; @@ -3528,130 +3549,212 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) { CList.push_back(Correction); while (CorrectionResults.size() > MaxTypoDistanceResultSets) - erase(llvm::prior(CorrectionResults.end())); + CorrectionResults.erase(std::prev(CorrectionResults.end())); } -// Fill the supplied vector with the IdentifierInfo pointers for each piece of -// the given NestedNameSpecifier (i.e. given a NestedNameSpecifier "foo::bar::", -// fill the vector with the IdentifierInfo pointers for "foo" and "bar"). -static void getNestedNameSpecifierIdentifiers( - NestedNameSpecifier *NNS, - SmallVectorImpl<const IdentifierInfo*> &Identifiers) { - if (NestedNameSpecifier *Prefix = NNS->getPrefix()) - getNestedNameSpecifierIdentifiers(Prefix, Identifiers); - else - Identifiers.clear(); +void TypoCorrectionConsumer::addNamespaces( + const llvm::MapVector<NamespaceDecl *, bool> &KnownNamespaces) { + SearchNamespaces = true; - const IdentifierInfo *II = NULL; + for (auto KNPair : KnownNamespaces) + Namespaces.addNameSpecifier(KNPair.first); - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - II = NNS->getAsIdentifier(); - break; + bool SSIsTemplate = false; + if (NestedNameSpecifier *NNS = + (SS && SS->isValid()) ? SS->getScopeRep() : nullptr) { + if (const Type *T = NNS->getAsType()) + SSIsTemplate = T->getTypeClass() == Type::TemplateSpecialization; + } + for (const auto *TI : SemaRef.getASTContext().types()) { + if (CXXRecordDecl *CD = TI->getAsCXXRecordDecl()) { + CD = CD->getCanonicalDecl(); + if (!CD->isDependentType() && !CD->isAnonymousStructOrUnion() && + !CD->isUnion() && CD->getIdentifier() && + (SSIsTemplate || !isa<ClassTemplateSpecializationDecl>(CD)) && + (CD->isBeingDefined() || CD->isCompleteDefinition())) + Namespaces.addNameSpecifier(CD); + } + } +} - case NestedNameSpecifier::Namespace: - if (NNS->getAsNamespace()->isAnonymousNamespace()) - return; - II = NNS->getAsNamespace()->getIdentifier(); - break; +TypoCorrection TypoCorrectionConsumer::getNextCorrection() { + while (!CorrectionResults.empty()) { + auto DI = CorrectionResults.begin(); + if (DI->second.empty()) { + CorrectionResults.erase(DI); + continue; + } - case NestedNameSpecifier::NamespaceAlias: - II = NNS->getAsNamespaceAlias()->getIdentifier(); + auto RI = DI->second.begin(); + if (RI->second.empty()) { + DI->second.erase(RI); + performQualifiedLookups(); + continue; + } + + TypoCorrection TC = RI->second.pop_back_val(); + if (TC.isResolved() || resolveCorrection(TC)) + return TC; + } + return TypoCorrection(); +} + +bool TypoCorrectionConsumer::resolveCorrection(TypoCorrection &Candidate) { + IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo(); + DeclContext *TempMemberContext = MemberContext; + CXXScopeSpec *TempSS = SS; +retry_lookup: + LookupPotentialTypoResult(SemaRef, Result, Name, S, TempSS, TempMemberContext, + EnteringContext, + CorrectionValidator.IsObjCIvarLookup, + Name == Typo && !Candidate.WillReplaceSpecifier()); + switch (Result.getResultKind()) { + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::FoundUnresolvedValue: + if (TempSS) { + // Immediately retry the lookup without the given CXXScopeSpec + TempSS = nullptr; + Candidate.WillReplaceSpecifier(true); + goto retry_lookup; + } + if (TempMemberContext) { + if (SS && !TempSS) + TempSS = SS; + TempMemberContext = nullptr; + goto retry_lookup; + } + if (SearchNamespaces) + QualifiedResults.push_back(Candidate); break; - case NestedNameSpecifier::TypeSpecWithTemplate: - case NestedNameSpecifier::TypeSpec: - II = QualType(NNS->getAsType(), 0).getBaseTypeIdentifier(); + case LookupResult::Ambiguous: + // We don't deal with ambiguities. break; - case NestedNameSpecifier::Global: - return; + case LookupResult::Found: + case LookupResult::FoundOverloaded: + // Store all of the Decls for overloaded symbols + for (auto *TRD : Result) + Candidate.addCorrectionDecl(TRD); + if (!isCandidateViable(CorrectionValidator, Candidate)) { + if (SearchNamespaces) + QualifiedResults.push_back(Candidate); + break; + } + return true; } - - if (II) - Identifiers.push_back(II); + return false; } -namespace { - -class SpecifierInfo { - public: - DeclContext* DeclCtx; - NestedNameSpecifier* NameSpecifier; - unsigned EditDistance; +void TypoCorrectionConsumer::performQualifiedLookups() { + unsigned TypoLen = Typo->getName().size(); + for (auto QR : QualifiedResults) { + for (auto NSI : Namespaces) { + DeclContext *Ctx = NSI.DeclCtx; + const Type *NSType = NSI.NameSpecifier->getAsType(); + + // If the current NestedNameSpecifier refers to a class and the + // current correction candidate is the name of that class, then skip + // it as it is unlikely a qualified version of the class' constructor + // is an appropriate correction. + if (CXXRecordDecl *NSDecl = NSType ? NSType->getAsCXXRecordDecl() : 0) { + if (NSDecl->getIdentifier() == QR.getCorrectionAsIdentifierInfo()) + continue; + } - SpecifierInfo(DeclContext *Ctx, NestedNameSpecifier *NNS, unsigned ED) - : DeclCtx(Ctx), NameSpecifier(NNS), EditDistance(ED) {} -}; + TypoCorrection TC(QR); + TC.ClearCorrectionDecls(); + TC.setCorrectionSpecifier(NSI.NameSpecifier); + TC.setQualifierDistance(NSI.EditDistance); + TC.setCallbackDistance(0); // Reset the callback distance + + // If the current correction candidate and namespace combination are + // too far away from the original typo based on the normalized edit + // distance, then skip performing a qualified name lookup. + unsigned TmpED = TC.getEditDistance(true); + if (QR.getCorrectionAsIdentifierInfo() != Typo && TmpED && + TypoLen / TmpED < 3) + continue; -typedef SmallVector<DeclContext*, 4> DeclContextList; -typedef SmallVector<SpecifierInfo, 16> SpecifierInfoList; - -class NamespaceSpecifierSet { - ASTContext &Context; - DeclContextList CurContextChain; - std::string CurNameSpecifier; - SmallVector<const IdentifierInfo*, 4> CurContextIdentifiers; - SmallVector<const IdentifierInfo*, 4> CurNameSpecifierIdentifiers; - bool isSorted; - - SpecifierInfoList Specifiers; - llvm::SmallSetVector<unsigned, 4> Distances; - llvm::DenseMap<unsigned, SpecifierInfoList> DistanceMap; - - /// \brief Helper for building the list of DeclContexts between the current - /// context and the top of the translation unit - static DeclContextList BuildContextChain(DeclContext *Start); - - void SortNamespaces(); - - public: - NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext, - CXXScopeSpec *CurScopeSpec) - : Context(Context), CurContextChain(BuildContextChain(CurContext)), - isSorted(false) { - if (NestedNameSpecifier *NNS = - CurScopeSpec ? CurScopeSpec->getScopeRep() : 0) { - llvm::raw_string_ostream SpecifierOStream(CurNameSpecifier); - NNS->print(SpecifierOStream, Context.getPrintingPolicy()); + Result.clear(); + Result.setLookupName(QR.getCorrectionAsIdentifierInfo()); + if (!SemaRef.LookupQualifiedName(Result, Ctx)) + continue; - getNestedNameSpecifierIdentifiers(NNS, CurNameSpecifierIdentifiers); - } - // Build the list of identifiers that would be used for an absolute - // (from the global context) NestedNameSpecifier referring to the current - // context. - for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), - CEnd = CurContextChain.rend(); - C != CEnd; ++C) { - if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C)) - CurContextIdentifiers.push_back(ND->getIdentifier()); + // Any corrections added below will be validated in subsequent + // iterations of the main while() loop over the Consumer's contents. + switch (Result.getResultKind()) { + case LookupResult::Found: + case LookupResult::FoundOverloaded: { + if (SS && SS->isValid()) { + std::string NewQualified = TC.getAsString(SemaRef.getLangOpts()); + std::string OldQualified; + llvm::raw_string_ostream OldOStream(OldQualified); + SS->getScopeRep()->print(OldOStream, SemaRef.getPrintingPolicy()); + OldOStream << Typo->getName(); + // If correction candidate would be an identical written qualified + // identifer, then the existing CXXScopeSpec probably included a + // typedef that didn't get accounted for properly. + if (OldOStream.str() == NewQualified) + break; + } + for (LookupResult::iterator TRD = Result.begin(), TRDEnd = Result.end(); + TRD != TRDEnd; ++TRD) { + if (SemaRef.CheckMemberAccess(TC.getCorrectionRange().getBegin(), + NSType ? NSType->getAsCXXRecordDecl() + : nullptr, + TRD.getPair()) == Sema::AR_accessible) + TC.addCorrectionDecl(*TRD); + } + if (TC.isResolved()) + addCorrection(TC); + break; + } + case LookupResult::NotFound: + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::Ambiguous: + case LookupResult::FoundUnresolvedValue: + break; + } } - - // Add the global context as a NestedNameSpecifier - Distances.insert(1); - DistanceMap[1].push_back( - SpecifierInfo(cast<DeclContext>(Context.getTranslationUnitDecl()), - NestedNameSpecifier::GlobalSpecifier(Context), 1)); } + QualifiedResults.clear(); +} - /// \brief Add the DeclContext (a namespace or record) to the set, computing - /// the corresponding NestedNameSpecifier and its distance in the process. - void AddNameSpecifier(DeclContext *Ctx); +TypoCorrectionConsumer::NamespaceSpecifierSet::NamespaceSpecifierSet( + ASTContext &Context, DeclContext *CurContext, CXXScopeSpec *CurScopeSpec) + : Context(Context), CurContextChain(buildContextChain(CurContext)), + isSorted(false) { + if (NestedNameSpecifier *NNS = + CurScopeSpec ? CurScopeSpec->getScopeRep() : nullptr) { + llvm::raw_string_ostream SpecifierOStream(CurNameSpecifier); + NNS->print(SpecifierOStream, Context.getPrintingPolicy()); - typedef SpecifierInfoList::iterator iterator; - iterator begin() { - if (!isSorted) SortNamespaces(); - return Specifiers.begin(); + getNestedNameSpecifierIdentifiers(NNS, CurNameSpecifierIdentifiers); + } + // Build the list of identifiers that would be used for an absolute + // (from the global context) NestedNameSpecifier referring to the current + // context. + for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), + CEnd = CurContextChain.rend(); + C != CEnd; ++C) { + if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C)) + CurContextIdentifiers.push_back(ND->getIdentifier()); } - iterator end() { return Specifiers.end(); } -}; + // Add the global context as a NestedNameSpecifier + Distances.insert(1); + SpecifierInfo SI = {cast<DeclContext>(Context.getTranslationUnitDecl()), + NestedNameSpecifier::GlobalSpecifier(Context), 1}; + DistanceMap[1].push_back(SI); } -DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) { +auto TypoCorrectionConsumer::NamespaceSpecifierSet::buildContextChain( + DeclContext *Start) -> DeclContextList { assert(Start && "Building a context chain from a null context"); DeclContextList Chain; - for (DeclContext *DC = Start->getPrimaryContext(); DC != NULL; + for (DeclContext *DC = Start->getPrimaryContext(); DC != nullptr; DC = DC->getLookupParent()) { NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(DC); if (!DC->isInlineNamespace() && !DC->isTransparentContext() && @@ -3661,7 +3764,7 @@ DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) { return Chain; } -void NamespaceSpecifierSet::SortNamespaces() { +void TypoCorrectionConsumer::NamespaceSpecifierSet::sortNamespaces() { SmallVector<unsigned, 4> sortedDistances; sortedDistances.append(Distances.begin(), Distances.end()); @@ -3669,19 +3772,17 @@ void NamespaceSpecifierSet::SortNamespaces() { std::sort(sortedDistances.begin(), sortedDistances.end()); Specifiers.clear(); - for (SmallVectorImpl<unsigned>::iterator DI = sortedDistances.begin(), - DIEnd = sortedDistances.end(); - DI != DIEnd; ++DI) { - SpecifierInfoList &SpecList = DistanceMap[*DI]; + for (auto D : sortedDistances) { + SpecifierInfoList &SpecList = DistanceMap[D]; Specifiers.append(SpecList.begin(), SpecList.end()); } isSorted = true; } -static unsigned BuildNestedNameSpecifier(ASTContext &Context, - DeclContextList &DeclChain, - NestedNameSpecifier *&NNS) { +unsigned +TypoCorrectionConsumer::NamespaceSpecifierSet::buildNestedNameSpecifier( + DeclContextList &DeclChain, NestedNameSpecifier *&NNS) { unsigned NumSpecifiers = 0; for (DeclContextList::reverse_iterator C = DeclChain.rbegin(), CEnd = DeclChain.rend(); @@ -3698,10 +3799,11 @@ static unsigned BuildNestedNameSpecifier(ASTContext &Context, return NumSpecifiers; } -void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) { - NestedNameSpecifier *NNS = NULL; +void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( + DeclContext *Ctx) { + NestedNameSpecifier *NNS = nullptr; unsigned NumSpecifiers = 0; - DeclContextList NamespaceDeclChain(BuildContextChain(Ctx)); + DeclContextList NamespaceDeclChain(buildContextChain(Ctx)); DeclContextList FullNamespaceDeclChain(NamespaceDeclChain); // Eliminate common elements from the two DeclContext chains. @@ -3713,14 +3815,14 @@ void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) { } // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain - NumSpecifiers = BuildNestedNameSpecifier(Context, NamespaceDeclChain, NNS); + NumSpecifiers = buildNestedNameSpecifier(NamespaceDeclChain, NNS); // Add an explicit leading '::' specifier if needed. if (NamespaceDeclChain.empty()) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. NNS = NestedNameSpecifier::GlobalSpecifier(Context); NumSpecifiers = - BuildNestedNameSpecifier(Context, FullNamespaceDeclChain, NNS); + buildNestedNameSpecifier(FullNamespaceDeclChain, NNS); } else if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(NamespaceDeclChain.back())) { IdentifierInfo *Name = ND->getIdentifier(); @@ -3742,7 +3844,7 @@ void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. NNS = NestedNameSpecifier::GlobalSpecifier(Context); NumSpecifiers = - BuildNestedNameSpecifier(Context, FullNamespaceDeclChain, NNS); + buildNestedNameSpecifier(FullNamespaceDeclChain, NNS); } } @@ -3760,7 +3862,8 @@ void NamespaceSpecifierSet::AddNameSpecifier(DeclContext *Ctx) { isSorted = false; Distances.insert(NumSpecifiers); - DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers)); + SpecifierInfo SI = {Ctx, NNS, NumSpecifiers}; + DistanceMap[NumSpecifiers].push_back(SI); } /// \brief Perform name lookup for a possible result for typo correction. @@ -3960,17 +4063,10 @@ static void AddKeywordsToConsumer(Sema &SemaRef, } } -static bool isCandidateViable(CorrectionCandidateCallback &CCC, - TypoCorrection &Candidate) { - Candidate.setCallbackDistance(CCC.RankCandidate(Candidate)); - return Candidate.getEditDistance(false) != TypoCorrection::InvalidDistance; -} - /// \brief Check whether the declarations found for a typo correction are /// visible, and if none of them are, convert the correction to an 'import /// a module' correction. -static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC, - DeclarationName TypoName) { +static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) { if (TC.begin() == TC.end()) return; @@ -4045,6 +4141,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, CorrectionCandidateCallback &CCC, + CorrectTypoKind Mode, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, @@ -4064,7 +4161,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, // In Microsoft mode, don't perform typo correction in a template member // function dependent context because it interferes with the "lookup into // dependent bases of class templates" feature. - if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() && + if (getLangOpts().MSVCCompat && CurContext->isDependentContext() && isa<CXXMethodDecl>(CurContext)) return TypoCorrection(); @@ -4099,9 +4196,17 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, if (getLangOpts().AltiVec && Typo->isStr("vector")) return TypoCorrection(); - NamespaceSpecifierSet Namespaces(Context, CurContext, SS); + // If we're handling a missing symbol error, using modules, and the + // special search all modules option is used, look for a missing import. + if ((Mode == CTK_ErrorRecovery) && getLangOpts().Modules && + getLangOpts().ModulesSearchAll) { + // The following has the side effect of loading the missing module. + getModuleLoader().lookupMissingImports(Typo->getName(), + TypoName.getLocStart()); + } - TypoCorrectionConsumer Consumer(*this, Typo); + TypoCorrectionConsumer Consumer(*this, TypoName, LookupKind, S, SS, CCC, + MemberContext, EnteringContext); // If a callback object considers an empty typo correction candidate to be // viable, assume it does not do any actual validation of the candidates. @@ -4116,10 +4221,8 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, // Look in qualified interfaces. if (OPT) { - for (ObjCObjectPointerType::qual_iterator - I = OPT->qual_begin(), E = OPT->qual_end(); - I != E; ++I) - LookupVisibleDecls(*I, LookupKind, Consumer); + for (auto *I : OPT->quals()) + LookupVisibleDecls(I, LookupKind, Consumer); } } else if (SS && SS->isSet()) { QualifiedDC = computeDeclContext(*SS, EnteringContext); @@ -4182,16 +4285,14 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, // For unqualified lookup, look through all of the names that we have // seen in this translation unit. // FIXME: Re-add the ability to skip very unlikely potential corrections. - for (IdentifierTable::iterator I = Context.Idents.begin(), - IEnd = Context.Idents.end(); - I != IEnd; ++I) - Consumer.FoundName(I->getKey()); + for (const auto &I : Context.Idents) + Consumer.FoundName(I.getKey()); // Walk through identifiers in external identifier sources. // FIXME: Re-add the ability to skip very unlikely potential corrections. if (IdentifierInfoLookup *External = Context.Idents.getExternalIdentifierLookup()) { - OwningPtr<IdentifierIterator> Iter(External->getIdentifiers()); + std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers()); do { StringRef Name = Iter->Next(); if (Name.empty()) @@ -4224,240 +4325,19 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces; LoadedExternalKnownNamespaces = true; ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces); - for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I) - KnownNamespaces[ExternalKnownNamespaces[I]] = true; + for (auto *N : ExternalKnownNamespaces) + KnownNamespaces[N] = true; } - for (llvm::MapVector<NamespaceDecl*, bool>::iterator - KNI = KnownNamespaces.begin(), - KNIEnd = KnownNamespaces.end(); - KNI != KNIEnd; ++KNI) - Namespaces.AddNameSpecifier(KNI->first); - - for (ASTContext::type_iterator TI = Context.types_begin(), - TIEnd = Context.types_end(); - TI != TIEnd; ++TI) { - if (CXXRecordDecl *CD = (*TI)->getAsCXXRecordDecl()) { - CD = CD->getCanonicalDecl(); - if (!CD->isDependentType() && !CD->isAnonymousStructOrUnion() && - !CD->isUnion() && - (CD->isBeingDefined() || CD->isCompleteDefinition())) - Namespaces.AddNameSpecifier(CD); - } - } + Consumer.addNamespaces(KnownNamespaces); } - // Weed out any names that could not be found by name lookup or, if a - // CorrectionCandidateCallback object was provided, failed validation. - SmallVector<TypoCorrection, 16> QualifiedResults; - LookupResult TmpRes(*this, TypoName, LookupKind); - TmpRes.suppressDiagnostics(); - while (!Consumer.empty()) { - TypoCorrectionConsumer::distance_iterator DI = Consumer.begin(); - for (TypoCorrectionConsumer::result_iterator I = DI->second.begin(), - IEnd = DI->second.end(); - I != IEnd; /* Increment in loop. */) { - // If we only want nested name specifier corrections, ignore potential - // corrections that have a different base identifier from the typo. - if (AllowOnlyNNSChanges && - I->second.front().getCorrectionAsIdentifierInfo() != Typo) { - TypoCorrectionConsumer::result_iterator Prev = I; - ++I; - DI->second.erase(Prev); - continue; - } - - // If the item already has been looked up or is a keyword, keep it. - // If a validator callback object was given, drop the correction - // unless it passes validation. - bool Viable = false; - for (TypoResultList::iterator RI = I->second.begin(); - RI != I->second.end(); /* Increment in loop. */) { - TypoResultList::iterator Prev = RI; - ++RI; - if (Prev->isResolved()) { - if (!isCandidateViable(CCC, *Prev)) - RI = I->second.erase(Prev); - else - Viable = true; - } - } - if (Viable || I->second.empty()) { - TypoCorrectionConsumer::result_iterator Prev = I; - ++I; - if (!Viable) - DI->second.erase(Prev); - continue; - } - assert(I->second.size() == 1 && "Expected a single unresolved candidate"); - - // Perform name lookup on this name. - TypoCorrection &Candidate = I->second.front(); - IdentifierInfo *Name = Candidate.getCorrectionAsIdentifierInfo(); - DeclContext *TempMemberContext = MemberContext; - CXXScopeSpec *TempSS = SS; -retry_lookup: - LookupPotentialTypoResult(*this, TmpRes, Name, S, TempSS, - TempMemberContext, EnteringContext, - CCC.IsObjCIvarLookup, - Name == TypoName.getName() && - !Candidate.WillReplaceSpecifier()); - - switch (TmpRes.getResultKind()) { - case LookupResult::NotFound: - case LookupResult::NotFoundInCurrentInstantiation: - case LookupResult::FoundUnresolvedValue: - if (TempSS) { - // Immediately retry the lookup without the given CXXScopeSpec - TempSS = NULL; - Candidate.WillReplaceSpecifier(true); - goto retry_lookup; - } - if (TempMemberContext) { - if (SS && !TempSS) - TempSS = SS; - TempMemberContext = NULL; - goto retry_lookup; - } - QualifiedResults.push_back(Candidate); - // We didn't find this name in our scope, or didn't like what we found; - // ignore it. - { - TypoCorrectionConsumer::result_iterator Next = I; - ++Next; - DI->second.erase(I); - I = Next; - } - break; - - case LookupResult::Ambiguous: - // We don't deal with ambiguities. - return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); - - case LookupResult::FoundOverloaded: { - TypoCorrectionConsumer::result_iterator Prev = I; - // Store all of the Decls for overloaded symbols - for (LookupResult::iterator TRD = TmpRes.begin(), - TRDEnd = TmpRes.end(); - TRD != TRDEnd; ++TRD) - Candidate.addCorrectionDecl(*TRD); - ++I; - if (!isCandidateViable(CCC, Candidate)) { - QualifiedResults.push_back(Candidate); - DI->second.erase(Prev); - } - break; - } - - case LookupResult::Found: { - TypoCorrectionConsumer::result_iterator Prev = I; - Candidate.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>()); - ++I; - if (!isCandidateViable(CCC, Candidate)) { - QualifiedResults.push_back(Candidate); - DI->second.erase(Prev); - } - break; - } - - } - } - - if (DI->second.empty()) - Consumer.erase(DI); - else if (!getLangOpts().CPlusPlus || QualifiedResults.empty() || !DI->first) - // If there are results in the closest possible bucket, stop - break; - - // Only perform the qualified lookups for C++ - if (SearchNamespaces) { - TmpRes.suppressDiagnostics(); - for (SmallVector<TypoCorrection, - 16>::iterator QRI = QualifiedResults.begin(), - QRIEnd = QualifiedResults.end(); - QRI != QRIEnd; ++QRI) { - for (NamespaceSpecifierSet::iterator NI = Namespaces.begin(), - NIEnd = Namespaces.end(); - NI != NIEnd; ++NI) { - DeclContext *Ctx = NI->DeclCtx; - const Type *NSType = NI->NameSpecifier->getAsType(); - - // If the current NestedNameSpecifier refers to a class and the - // current correction candidate is the name of that class, then skip - // it as it is unlikely a qualified version of the class' constructor - // is an appropriate correction. - if (CXXRecordDecl *NSDecl = - NSType ? NSType->getAsCXXRecordDecl() : 0) { - if (NSDecl->getIdentifier() == QRI->getCorrectionAsIdentifierInfo()) - continue; - } - - TypoCorrection TC(*QRI); - TC.ClearCorrectionDecls(); - TC.setCorrectionSpecifier(NI->NameSpecifier); - TC.setQualifierDistance(NI->EditDistance); - TC.setCallbackDistance(0); // Reset the callback distance - - // If the current correction candidate and namespace combination are - // too far away from the original typo based on the normalized edit - // distance, then skip performing a qualified name lookup. - unsigned TmpED = TC.getEditDistance(true); - if (QRI->getCorrectionAsIdentifierInfo() != Typo && - TmpED && TypoLen / TmpED < 3) - continue; - - TmpRes.clear(); - TmpRes.setLookupName(QRI->getCorrectionAsIdentifierInfo()); - if (!LookupQualifiedName(TmpRes, Ctx)) continue; - - // Any corrections added below will be validated in subsequent - // iterations of the main while() loop over the Consumer's contents. - switch (TmpRes.getResultKind()) { - case LookupResult::Found: - case LookupResult::FoundOverloaded: { - if (SS && SS->isValid()) { - std::string NewQualified = TC.getAsString(getLangOpts()); - std::string OldQualified; - llvm::raw_string_ostream OldOStream(OldQualified); - SS->getScopeRep()->print(OldOStream, getPrintingPolicy()); - OldOStream << TypoName; - // If correction candidate would be an identical written qualified - // identifer, then the existing CXXScopeSpec probably included a - // typedef that didn't get accounted for properly. - if (OldOStream.str() == NewQualified) - break; - } - for (LookupResult::iterator TRD = TmpRes.begin(), - TRDEnd = TmpRes.end(); - TRD != TRDEnd; ++TRD) { - if (CheckMemberAccess(TC.getCorrectionRange().getBegin(), - NSType ? NSType->getAsCXXRecordDecl() : 0, - TRD.getPair()) == AR_accessible) - TC.addCorrectionDecl(*TRD); - } - if (TC.isResolved()) - Consumer.addCorrection(TC); - break; - } - case LookupResult::NotFound: - case LookupResult::NotFoundInCurrentInstantiation: - case LookupResult::Ambiguous: - case LookupResult::FoundUnresolvedValue: - break; - } - } - } - } - - QualifiedResults.clear(); - } - - // No corrections remain... - if (Consumer.empty()) + TypoCorrection BestTC = Consumer.getNextCorrection(); + TypoCorrection SecondBestTC = Consumer.getNextCorrection(); + if (!BestTC) return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); - TypoResultsMap &BestResults = Consumer.getBestResults(); - ED = Consumer.getBestEditDistance(true); + ED = BestTC.getEditDistance(); if (!AllowOnlyNNSChanges && ED > 0 && TypoLen / ED < 3) { // If this was an unqualified lookup and we believe the callback @@ -4468,11 +4348,9 @@ retry_lookup: } // If only a single name remains, return that result. - if (BestResults.size() == 1) { - const TypoResultList &CorrectionList = BestResults.begin()->second; - const TypoCorrection &Result = CorrectionList.front(); - if (CorrectionList.size() != 1) - return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); + if (!SecondBestTC || + SecondBestTC.getEditDistance(false) > BestTC.getEditDistance(false)) { + const TypoCorrection &Result = BestTC; // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. @@ -4485,39 +4363,42 @@ retry_lookup: TypoCorrection TC = Result; TC.setCorrectionRange(SS, TypoName); - checkCorrectionVisibility(*this, TC, TypoName.getName()); + checkCorrectionVisibility(*this, TC); return TC; } - else if (BestResults.size() > 1 - // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver; - // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for - // some instances of CTC_Unknown, while WantRemainingKeywords is true - // for CTC_Unknown but not for CTC_ObjCMessageReceiver. - && CCC.WantObjCSuper && !CCC.WantRemainingKeywords - && BestResults["super"].front().isKeyword()) { + // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver; + // WantObjCSuper is only true for CTC_ObjCMessageReceiver and for + // some instances of CTC_Unknown, while WantRemainingKeywords is true + // for CTC_Unknown but not for CTC_ObjCMessageReceiver. + else if (SecondBestTC && CCC.WantObjCSuper && !CCC.WantRemainingKeywords) { // Prefer 'super' when we're completing in a message-receiver // context. + if (BestTC.getCorrection().getAsString() != "super") { + if (SecondBestTC.getCorrection().getAsString() == "super") + BestTC = SecondBestTC; + else if (Consumer["super"].front().isKeyword()) + BestTC = Consumer["super"].front(); + } // Don't correct to a keyword that's the same as the typo; the keyword // wasn't actually in scope. - if (ED == 0) + if (BestTC.getEditDistance() == 0 || + BestTC.getCorrection().getAsString() != "super") return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); // Record the correction for unqualified lookup. if (IsUnqualifiedLookup) - UnqualifiedTyposCorrected[Typo] = BestResults["super"].front(); + UnqualifiedTyposCorrected[Typo] = BestTC; - TypoCorrection TC = BestResults["super"].front(); - TC.setCorrectionRange(SS, TypoName); - return TC; + BestTC.setCorrectionRange(SS, TypoName); + return BestTC; } - // If this was an unqualified lookup and we believe the callback object did - // not filter out possible corrections, note that no correction was found. - if (IsUnqualifiedLookup && !ValidatingCallback) - (void)UnqualifiedTyposCorrected[Typo]; - - return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure); + // Record the failure's location if needed and return an empty correction. If + // this was an unqualified lookup and we believe the callback object did not + // filter out possible corrections, also cache the failure for the typo. + return FailedCorrection(Typo, TypoName.getLoc(), RecordFailure, + IsUnqualifiedLookup && !ValidatingCallback); } void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { @@ -4552,19 +4433,34 @@ bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candid return WantTypeSpecifiers || WantExpressionKeywords || WantCXXNamedCasts || WantRemainingKeywords || WantObjCSuper; - for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(), - CDeclEnd = candidate.end(); - CDecl != CDeclEnd; ++CDecl) { - if (!isa<TypeDecl>(*CDecl)) - return true; + bool HasNonType = false; + bool HasStaticMethod = false; + bool HasNonStaticMethod = false; + for (Decl *D : candidate) { + if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D)) + D = FTD->getTemplatedDecl(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (Method->isStatic()) + HasStaticMethod = true; + else + HasNonStaticMethod = true; + } + if (!isa<TypeDecl>(D)) + HasNonType = true; } - return WantTypeSpecifiers; + if (IsAddressOfOperand && HasNonStaticMethod && !HasStaticMethod && + !candidate.getCorrectionSpecifier()) + return false; + + return WantTypeSpecifiers || HasNonType; } FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs, - bool HasExplicitTemplateArgs) - : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs) { + bool HasExplicitTemplateArgs, + MemberExpr *ME) + : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs), + CurContext(SemaRef.CurContext), MemberFn(ME) { WantTypeSpecifiers = SemaRef.getLangOpts().CPlusPlus; WantRemainingKeywords = false; } @@ -4573,11 +4469,9 @@ bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) { if (!candidate.getCorrectionDecl()) return candidate.isKeyword(); - for (TypoCorrection::const_decl_iterator DI = candidate.begin(), - DIEnd = candidate.end(); - DI != DIEnd; ++DI) { - FunctionDecl *FD = 0; - NamedDecl *ND = (*DI)->getUnderlyingDecl(); + for (auto *C : candidate) { + FunctionDecl *FD = nullptr; + NamedDecl *ND = C->getUnderlyingDecl(); if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND)) FD = FTD->getTemplatedDecl(); if (!HasExplicitTemplateArgs && !FD) { @@ -4589,13 +4483,35 @@ bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) { if (ValType->isAnyPointerType() || ValType->isReferenceType()) ValType = ValType->getPointeeType(); if (const FunctionProtoType *FPT = ValType->getAs<FunctionProtoType>()) - if (FPT->getNumArgs() == NumArgs) + if (FPT->getNumParams() == NumArgs) return true; } } - if (FD && FD->getNumParams() >= NumArgs && - FD->getMinRequiredArguments() <= NumArgs) - return true; + + // Skip the current candidate if it is not a FunctionDecl or does not accept + // the current number of arguments. + if (!FD || !(FD->getNumParams() >= NumArgs && + FD->getMinRequiredArguments() <= NumArgs)) + continue; + + // If the current candidate is a non-static C++ method, skip the candidate + // unless the method being corrected--or the current DeclContext, if the + // function being corrected is not a method--is a method in the same class + // or a descendent class of the candidate's parent class. + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (MemberFn || !MD->isStatic()) { + CXXMethodDecl *CurMD = + MemberFn + ? dyn_cast_or_null<CXXMethodDecl>(MemberFn->getMemberDecl()) + : dyn_cast_or_null<CXXMethodDecl>(CurContext); + CXXRecordDecl *CurRD = + CurMD ? CurMD->getParent()->getCanonicalDecl() : nullptr; + CXXRecordDecl *RD = MD->getParent()->getCanonicalDecl(); + if (!CurRD || (CurRD != RD && !CurRD->isDerivedFrom(RD))) + continue; + } + } + return true; } return false; } @@ -4613,7 +4529,7 @@ static const NamedDecl *getDefinitionToImport(const NamedDecl *D) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) return VD->getDefinition(); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - return FD->isDefined(FD) ? FD : 0; + return FD->isDefined(FD) ? FD : nullptr; if (const TagDecl *TD = dyn_cast<TagDecl>(D)) return TD->getDefinition(); if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) @@ -4622,7 +4538,7 @@ static const NamedDecl *getDefinitionToImport(const NamedDecl *D) { return PD->getDefinition(); if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) return getDefinitionToImport(TD->getTemplatedDecl()); - return 0; + return nullptr; } /// \brief Diagnose a successfully-corrected typo. Separated from the correction @@ -4665,9 +4581,9 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, Diag(Def->getLocation(), diag::note_previous_declaration); // Recover by implicitly importing this module. - if (!isSFINAEContext() && ErrorRecovery) - createImplicitModuleImport(Correction.getCorrectionRange().getBegin(), - Owner); + if (ErrorRecovery) + createImplicitModuleImportForErrorRecovery( + Correction.getCorrectionRange().getBegin(), Owner); return; } @@ -4675,7 +4591,7 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, << CorrectedQuotedStr << (ErrorRecovery ? FixTypo : FixItHint()); NamedDecl *ChosenDecl = - Correction.isKeyword() ? 0 : Correction.getCorrectionDecl(); + Correction.isKeyword() ? nullptr : Correction.getCorrectionDecl(); if (PrevNote.getDiagID() && ChosenDecl) Diag(ChosenDecl->getLocation(), PrevNote) << CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo); |