diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index b92bd4fcead1..4cecee46e468 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1209,6 +1209,7 @@ public: VisibleDeclConsumer &Consumer); bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS, + DeclContext *MemberContext = 0, bool EnteringContext = false); void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c87a274122b6..6bb6ea3e512a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -932,7 +932,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, // We didn't find anything, so try to correct for a typo. if (S && CorrectTypo(R, S, &SS) && - (isa(*R.begin()) || isa(*R.begin()))) { + (isa(*R.begin()) || isa(*R.begin()))) { if (SS.isEmpty()) Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() << CodeModificationHint::CreateReplacement(R.getNameLoc(), @@ -2346,6 +2346,23 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, // The record definition is complete, now look up the member. SemaRef.LookupQualifiedName(R, DC); + if (!R.empty()) + return false; + + // We didn't find anything with the given name, so try to correct + // for typos. + DeclarationName Name = R.getLookupName(); + if (SemaRef.CorrectTypo(R, 0, &SS, DC) && + (isa(*R.begin()) || isa(*R.begin()))) { + SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) + << Name << DC << R.getLookupName() << SS.getRange() + << CodeModificationHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + return false; + } else { + R.clear(); + } + return false; } diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 9abbd575dcca..1419ceb4b660 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2134,6 +2134,9 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) { /// \param SS the nested-name-specifier that precedes the name we're /// looking for, if present. /// +/// \param MemberContext if non-NULL, the context in which to look for +/// a member access expression. +/// /// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// @@ -2141,7 +2144,7 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding) { /// structure will contain the results of name lookup for the /// corrected name. Otherwise, returns false. bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, - bool EnteringContext) { + DeclContext *MemberContext, bool EnteringContext) { // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); if (!Typo) @@ -2158,7 +2161,9 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, return false; TypoCorrectionConsumer Consumer(Typo); - if (SS && SS->isSet()) { + if (MemberContext) + LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer); + else if (SS && SS->isSet()) { DeclContext *DC = computeDeclContext(*SS, EnteringContext); if (!DC) return false; @@ -2193,7 +2198,11 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, // success if we found something that was not ambiguous. Res.clear(); Res.setLookupName(BestName); - LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, EnteringContext); + if (MemberContext) + LookupQualifiedName(Res, MemberContext); + else + LookupParsedName(Res, S, SS, /*AllowBuiltinCreation=*/false, + EnteringContext); if (Res.isAmbiguous()) { Res.suppressDiagnostics(); diff --git a/clang/test/FixIt/typo.cpp b/clang/test/FixIt/typo.cpp index 6c232f74038f..e0c7bf64dc63 100644 --- a/clang/test/FixIt/typo.cpp +++ b/clang/test/FixIt/typo.cpp @@ -23,5 +23,6 @@ float area(float radius, float pi) { } bool test_string(std::string s) { - return s.find("hello") == std::string::pos; // expected-error{{no member named 'pos' in 'class std::basic_string'; did you mean 'npos'?}} + return s.fnd("hello") // expected-error{{no member named 'fnd' in 'class std::basic_string'; did you mean 'find'?}} + == std::string::pos; // expected-error{{no member named 'pos' in 'class std::basic_string'; did you mean 'npos'?}} }