From b46f944564af3dfe88d21f05ddfb2f8e4a9ece35 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 29 Dec 2015 19:43:10 +0000 Subject: [PATCH] Teach typo correction to properly handle mapping declarations to their underlying decls. Preserve the found declaration throughout, and only map to the underlying declaration when we want to check whether it's the right kind. This allows us to provide the right source location for the found declaration, and prepares for the possibility of underlying decls with a different name from the found decl. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@256575 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/TypoCorrection.h | 18 ++++++++++++------ lib/Sema/SemaCXXScopeSpec.cpp | 2 +- lib/Sema/SemaDecl.cpp | 5 ++--- lib/Sema/SemaDeclCXX.cpp | 2 +- lib/Sema/SemaExpr.cpp | 29 ++++++++++++++--------------- lib/Sema/SemaExprCXX.cpp | 8 ++++---- lib/Sema/SemaLookup.cpp | 6 +++--- lib/Sema/SemaTemplate.cpp | 4 ++-- test/SemaCXX/typo-correction.cpp | 9 ++++++++- 9 files changed, 47 insertions(+), 36 deletions(-) diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h index 958aab0fce..3b0385ef2a 100644 --- a/include/clang/Sema/TypoCorrection.h +++ b/include/clang/Sema/TypoCorrection.h @@ -72,15 +72,15 @@ public: /// \brief Gets the DeclarationName of the typo correction DeclarationName getCorrection() const { return CorrectionName; } - IdentifierInfo* getCorrectionAsIdentifierInfo() const { + IdentifierInfo *getCorrectionAsIdentifierInfo() const { return CorrectionName.getAsIdentifierInfo(); } /// \brief Gets the NestedNameSpecifier needed to use the typo correction - NestedNameSpecifier* getCorrectionSpecifier() const { + NestedNameSpecifier *getCorrectionSpecifier() const { return CorrectionNameSpec; } - void setCorrectionSpecifier(NestedNameSpecifier* NNS) { + void setCorrectionSpecifier(NestedNameSpecifier *NNS) { CorrectionNameSpec = NNS; ForceSpecifierReplacement = (NNS != nullptr); } @@ -129,9 +129,16 @@ public: return Normalized ? NormalizeEditDistance(ED) : ED; } + /// \brief Get the correction declaration found by name lookup (before we + /// looked through using shadow declarations and the like). + NamedDecl *getFoundDecl() const { + return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr; + } + /// \brief Gets the pointer to the declaration of the typo correction NamedDecl *getCorrectionDecl() const { - return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : nullptr; + auto *D = getFoundDecl(); + return D ? D->getUnderlyingDecl() : nullptr; } template DeclClass *getCorrectionDeclAs() const { @@ -180,8 +187,7 @@ public: // Check if this TypoCorrection is a keyword by checking if the first // item in CorrectionDecls is NULL. bool isKeyword() const { - return !CorrectionDecls.empty() && - CorrectionDecls.front() == nullptr; + return !CorrectionDecls.empty() && CorrectionDecls.front() == nullptr; } // Check if this TypoCorrection is the given keyword. diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 68a1d7368e..f943a10deb 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -607,7 +607,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest) << Name); - if (NamedDecl *ND = Corrected.getCorrectionDecl()) + if (NamedDecl *ND = Corrected.getFoundDecl()) Found.addDecl(ND); Found.setLookupName(Corrected.getCorrection()); } else { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 203adeab8d..aa44f6628d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -813,9 +813,8 @@ Corrected: unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; - NamedDecl *FirstDecl = Corrected.getCorrectionDecl(); - NamedDecl *UnderlyingFirstDecl - = FirstDecl? FirstDecl->getUnderlyingDecl() : nullptr; + NamedDecl *FirstDecl = Corrected.getFoundDecl(); + NamedDecl *UnderlyingFirstDecl = Corrected.getCorrectionDecl(); if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && UnderlyingFirstDecl && isa(UnderlyingFirstDecl)) { UnqualifiedDiag = diag::err_no_template_suggest; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 9cd3002dd8..634e699056 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -7531,7 +7531,7 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc, S.PDiag(diag::err_using_directive_suggest) << Ident, S.PDiag(diag::note_namespace_defined_here)); } - R.addDecl(Corrected.getCorrectionDecl()); + R.addDecl(Corrected.getFoundDecl()); return true; } return false; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 434b421afb..888319b395 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1776,10 +1776,9 @@ static void emitEmptyLookupTypoDiagnostic( std::string CorrectedStr = TC.getAsString(SemaRef.getLangOpts()); bool DroppedSpecifier = TC.WillReplaceSpecifier() && Typo.getAsString() == CorrectedStr; - unsigned NoteID = - (TC.getCorrectionDecl() && isa(TC.getCorrectionDecl())) - ? diag::note_implicit_param_decl - : diag::note_previous_decl; + unsigned NoteID = TC.getCorrectionDeclAs() + ? diag::note_implicit_param_decl + : diag::note_previous_decl; if (!Ctx) SemaRef.diagnoseTypo(TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo, SemaRef.PDiag(NoteID)); @@ -1903,7 +1902,7 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, bool AcceptableWithRecovery = false; bool AcceptableWithoutRecovery = false; - NamedDecl *ND = Corrected.getCorrectionDecl(); + NamedDecl *ND = Corrected.getFoundDecl(); if (ND) { if (Corrected.isOverloaded()) { OverloadCandidateSet OCS(R.getNameLoc(), @@ -1922,7 +1921,7 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, } switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) { case OR_Success: - ND = Best->Function; + ND = Best->FoundDecl; Corrected.setCorrectionDecl(ND); break; default: @@ -1944,15 +1943,16 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, R.setNamingClass(Record); } - AcceptableWithRecovery = - isa(ND) || isa(ND); + auto *UnderlyingND = ND->getUnderlyingDecl(); + AcceptableWithRecovery = isa(UnderlyingND) || + isa(UnderlyingND); // FIXME: If we ended up with a typo for a type name or // Objective-C class name, we're in trouble because the parser // is in the wrong place to recover. Suggest the typo // correction, but don't make it a fix-it since we're not going // to recover well anyway. AcceptableWithoutRecovery = - isa(ND) || isa(ND); + isa(UnderlyingND) || isa(UnderlyingND); } else { // FIXME: We found a keyword. Suggest it, but don't provide a fix-it // because we aren't able to recover. @@ -1960,8 +1960,7 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, } if (AcceptableWithRecovery || AcceptableWithoutRecovery) { - unsigned NoteID = (Corrected.getCorrectionDecl() && - isa(Corrected.getCorrectionDecl())) + unsigned NoteID = Corrected.getCorrectionDeclAs() ? diag::note_implicit_param_decl : diag::note_previous_decl; if (SS.isEmpty()) @@ -4402,7 +4401,7 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn, llvm::make_unique(S, FuncName.getAsIdentifierInfo(), Args.size(), ME), Sema::CTK_ErrorRecovery)) { - if (NamedDecl *ND = Corrected.getCorrectionDecl()) { + if (NamedDecl *ND = Corrected.getFoundDecl()) { if (Corrected.isOverloaded()) { OverloadCandidateSet OCS(NameLoc, OverloadCandidateSet::CSK_Normal); OverloadCandidateSet::iterator Best; @@ -4413,16 +4412,16 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn, } switch (OCS.BestViableFunction(S, NameLoc, Best)) { case OR_Success: - ND = Best->Function; + ND = Best->FoundDecl; Corrected.setCorrectionDecl(ND); break; default: break; } } - if (isa(ND) || isa(ND)) { + ND = ND->getUnderlyingDecl(); + if (isa(ND) || isa(ND)) return Corrected; - } } } return TypoCorrection(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 47d15c363c..2ad595f3a8 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -6409,7 +6409,7 @@ static ExprResult attemptRecovery(Sema &SemaRef, else if (SS && !TC.WillReplaceSpecifier()) NewSS = *SS; - if (auto *ND = TC.getCorrectionDecl()) { + if (auto *ND = TC.getFoundDecl()) { R.setLookupName(ND->getDeclName()); R.addDecl(ND); if (ND->isCXXClassMember()) { @@ -6530,9 +6530,9 @@ class TransformTypos : public TreeTransform { if (!E) return nullptr; if (auto *DRE = dyn_cast(E)) - return DRE->getDecl(); + return DRE->getFoundDecl(); if (auto *ME = dyn_cast(E)) - return ME->getMemberDecl(); + return ME->getFoundDecl(); // FIXME: Add any other expr types that could be be seen by the delayed typo // correction TreeTransform for which the corresponding TypoCorrection could // contain multiple decls. @@ -6637,7 +6637,7 @@ public: // For the first TypoExpr and an uncached TypoExpr, find the next likely // typo correction and return it. while (TypoCorrection TC = State.Consumer->getNextCorrection()) { - if (InitDecl && TC.getCorrectionDecl() == InitDecl) + if (InitDecl && TC.getFoundDecl() == InitDecl) continue; ExprResult NE = State.RecoveryHandler ? State.RecoveryHandler(SemaRef, E, TC) : diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 2aeffd82b7..481ae6cd55 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -4719,7 +4719,7 @@ void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { if (isKeyword()) CorrectionDecls.clear(); - CorrectionDecls.push_back(CDecl->getUnderlyingDecl()); + CorrectionDecls.push_back(CDecl); if (!CorrectionName) CorrectionName = CDecl->getDeclName(); @@ -4948,7 +4948,7 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, // Maybe we're just missing a module import. if (Correction.requiresImport()) { - NamedDecl *Decl = Correction.getCorrectionDecl(); + NamedDecl *Decl = Correction.getFoundDecl(); assert(Decl && "import required but no declaration to import"); diagnoseMissingImport(Correction.getCorrectionRange().getBegin(), Decl, @@ -4960,7 +4960,7 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, << CorrectedQuotedStr << (ErrorRecovery ? FixTypo : FixItHint()); NamedDecl *ChosenDecl = - Correction.isKeyword() ? nullptr : Correction.getCorrectionDecl(); + Correction.isKeyword() ? nullptr : Correction.getFoundDecl(); if (PrevNote.getDiagID() && ChosenDecl) Diag(ChosenDecl->getLocation(), PrevNote) << CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 4b130229b6..6cc8588334 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -329,8 +329,8 @@ void Sema::LookupTemplateName(LookupResult &Found, Found.getLookupNameInfo(), Found.getLookupKind(), S, &SS, std::move(FilterCCC), CTK_ErrorRecovery, LookupCtx)) { Found.setLookupName(Corrected.getCorrection()); - if (Corrected.getCorrectionDecl()) - Found.addDecl(Corrected.getCorrectionDecl()); + if (auto *ND = Corrected.getFoundDecl()) + Found.addDecl(ND); FilterAcceptableTemplateNames(Found); if (!Found.empty()) { if (LookupCtx) { diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp index d5b42d0e53..07c1634431 100644 --- a/test/SemaCXX/typo-correction.cpp +++ b/test/SemaCXX/typo-correction.cpp @@ -307,14 +307,21 @@ struct A { void CreateBar(float, float); }; struct B : A { - using A::CreateFoo; + using A::CreateFoo; // expected-note {{'CreateFoo' declared here}} void CreateFoo(int, int); // expected-note {{'CreateFoo' declared here}} }; void f(B &x) { x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}} + x.Createfoo(0.f,0.f); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}} } } +namespace using_decl { + namespace somewhere { int foobar; } + using somewhere::foobar; // expected-note {{declared here}} + int k = goobar; // expected-error {{did you mean 'foobar'?}} +} + struct DataStruct {void foo();}; struct T { DataStruct data_struct; -- 2.40.0