]> granicus.if.org Git - clang/commitdiff
Add custom callback object for typo correction in BuildRecoveryCallExpr.
authorKaelyn Uhrain <rikka@google.com>
Wed, 25 Jan 2012 18:37:44 +0000 (18:37 +0000)
committerKaelyn Uhrain <rikka@google.com>
Wed, 25 Jan 2012 18:37:44 +0000 (18:37 +0000)
The new callback, in addition to limiting which keywords to include in
the pool of typo correction candidates, also filters out non-keyword
candidates that don't refer to (template) functions that accept the
number of arguments that are present for the call being recovered.

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

include/clang/Sema/TypoCorrection.h
lib/Sema/SemaOverload.cpp
test/SemaCXX/typo-correction.cpp

index c0c7790bb02856d29ff0f89fd26f21eb3f8f0c5f..24d7d5f387fbe25b67af44261a48c04242be191b 100644 (file)
@@ -128,6 +128,11 @@ public:
     return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
   }
   decl_iterator end() { return CorrectionDecls.end(); }
+  typedef llvm::SmallVector<NamedDecl*, 1>::const_iterator const_decl_iterator;
+  const_decl_iterator begin() const {
+    return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
+  }
+  const_decl_iterator end() const { return CorrectionDecls.end(); }
 
 private:
   bool hasCorrectionDecl() const {
index fac3c26d0e3abced2761d65f9b1a21c21b816d45..3333b4eea922218b64c7dca1c6d999edc834e6d4 100644 (file)
@@ -9169,6 +9169,54 @@ DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
                                 /*ExplicitTemplateArgs=*/0, Args, NumArgs);
 }
 
+namespace {
+// Callback to limit the allowed keywords and to only accept typo corrections
+// that are keywords or whose decls refer to functions (or template functions)
+// that accept the given number of arguments.
+class RecoveryCallCCC : public CorrectionCandidateCallback {
+ public:
+  RecoveryCallCCC(Sema &SemaRef, unsigned NumArgs, bool HasExplicitTemplateArgs)
+      : NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs) {
+    WantTypeSpecifiers = SemaRef.getLangOptions().CPlusPlus;
+    WantRemainingKeywords = false;
+  }
+
+  virtual bool 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();
+      if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND))
+        FD = FTD->getTemplatedDecl();
+      if (!HasExplicitTemplateArgs && !FD) {
+        if (!(FD = dyn_cast<FunctionDecl>(ND)) && isa<ValueDecl>(ND)) {
+          // If the Decl is neither a function nor a template function,
+          // determine if it is a pointer or reference to a function. If so,
+          // check against the number of arguments expected for the pointee.
+          QualType ValType = cast<ValueDecl>(ND)->getType();
+          if (ValType->isAnyPointerType() || ValType->isReferenceType())
+            ValType = ValType->getPointeeType();
+          if (const FunctionProtoType *FPT = ValType->getAs<FunctionProtoType>())
+            if (FPT->getNumArgs() == NumArgs)
+              return true;
+        }
+      }
+      if (FD && FD->getNumParams() >= NumArgs &&
+          FD->getMinRequiredArguments() <= NumArgs)
+        return true;
+    }
+    return false;
+  }
+
+ private:
+  unsigned NumArgs;
+  bool HasExplicitTemplateArgs;
+};
+}
+
 /// Attempts to recover from a call where no functions were found.
 ///
 /// Returns true if new candidates were found.
@@ -9192,9 +9240,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
 
   LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
                  Sema::LookupOrdinaryName);
-  CorrectionCandidateCallback Validator;
-  Validator.WantTypeSpecifiers = SemaRef.getLangOptions().CPlusPlus;
-  Validator.WantRemainingKeywords = false;
+  RecoveryCallCCC Validator(SemaRef, NumArgs, ExplicitTemplateArgs != 0);
   if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
                               ExplicitTemplateArgs, Args, NumArgs) &&
       (!EmptyLookup ||
index 56417cd87dc5949cf3d0643c0d720b8dbb0de592..b8795e7d006ca5cf282084e6265425d9512e1d40 100644 (file)
@@ -113,3 +113,27 @@ struct TestRedecl : public BaseDecl {
   void add_it(int i); // expected-note{{'add_it' declared here}}
 };
 void TestRedecl::add_in(int i) {} // expected-error{{out-of-line definition of 'add_in' does not match any declaration in 'TestRedecl'; did you mean 'add_it'?}}
+
+// Test the typo-correction callback in BuildRecoveryCallExpr.
+// Solves the main issue in PR 9320 of suggesting corrections that take the
+// wrong number of arguments.
+void revoke(const char*); // expected-note 2{{'revoke' declared here}}
+void Test() {
+  Invoke(); // expected-error{{use of undeclared identifier 'Invoke'}}
+  Invoke("foo"); // expected-error{{use of undeclared identifier 'Invoke'; did you mean 'revoke'?}}
+  Invoke("foo", "bar"); // expected-error{{use of undeclared identifier 'Invoke'}}
+}
+void Test2(void (*invoke)(const char *, int)) { // expected-note{{'invoke' declared here}}
+  Invoke(); // expected-error{{use of undeclared identifier 'Invoke'}}
+  Invoke("foo"); // expected-error{{use of undeclared identifier 'Invoke'; did you mean 'revoke'?}}
+  Invoke("foo", 7); // expected-error{{use of undeclared identifier 'Invoke'; did you mean 'invoke'?}}
+  Invoke("foo", 7, 22); // expected-error{{use of undeclared identifier 'Invoke'}}
+}
+
+void provoke(const char *x, bool y=false) {} // expected-note 2{{'provoke' declared here}}
+void Test3() {
+  Provoke(); // expected-error{{use of undeclared identifier 'Provoke'}}
+  Provoke("foo"); // expected-error{{use of undeclared identifier 'Provoke'; did you mean 'provoke'?}}
+  Provoke("foo", true); // expected-error{{use of undeclared identifier 'Provoke'; did you mean 'provoke'?}}
+  Provoke("foo", 7, 22); // expected-error{{use of undeclared identifier 'Provoke'}}
+}