aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/TypoCorrection.h5
-rw-r--r--lib/Sema/SemaOverload.cpp52
-rw-r--r--test/SemaCXX/typo-correction.cpp24
3 files changed, 78 insertions, 3 deletions
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index c0c7790bb0..24d7d5f387 100644
--- a/include/clang/Sema/TypoCorrection.h
+++ b/include/clang/Sema/TypoCorrection.h
@@ -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 {
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index fac3c26d0e..3333b4eea9 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -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 ||
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index 56417cd87d..b8795e7d00 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -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'}}
+}