]> granicus.if.org Git - clang/commitdiff
Typo correction for member access into classes/structs/unions, e.g.,
authorDouglas Gregor <dgregor@apple.com>
Thu, 31 Dec 2009 07:42:17 +0000 (07:42 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 31 Dec 2009 07:42:17 +0000 (07:42 +0000)
  s.fnd("hello")

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92345 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaLookup.cpp
test/FixIt/typo.cpp

index b92bd4fcead1dcf11f792b903a7b97d62901b538..4cecee46e4684f615b143edfdb9ca98270c02c91 100644 (file)
@@ -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,
index c87a274122b6e21641f5c36aff4b40fd1aa1e5a4..6bb6ea3e512a250069c13d52f3a6f7c5b82aebf4 100644 (file)
@@ -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<ValueDecl>(*R.begin()) || isa<TemplateDecl>(*R.begin()))) {
+      (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*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<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*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;
 }
 
index 9abbd575dcca76a0a21a530afd3b8545fc80d18a..1419ceb4b660e8bb4efdcffc88c825efad7cdcbb 100644 (file)
@@ -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();
index 6c232f74038f54c807e3889cf1a1301aed0337cb..e0c7bf64dc63facf829709e3f044b6c5770d82ae 100644 (file)
@@ -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<char>'; did you mean 'npos'?}}
+  return s.fnd("hello") // expected-error{{no member named 'fnd' in 'class std::basic_string<char>'; did you mean 'find'?}}
+    == std::string::pos; // expected-error{{no member named 'pos' in 'class std::basic_string<char>'; did you mean 'npos'?}}
 }