summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaelyn Uhrain <rikka@google.com>2011-08-03 20:36:05 +0000
committerKaelyn Uhrain <rikka@google.com>2011-08-03 20:36:05 +0000
commitacbdc5748e70fef350d7974106c7886451b53801 (patch)
tree7e36e71a496eaf62ff398282fd820a3df99d90d9
parentd855d82a160c66215551b41a2533f406b7ba27ac (diff)
downloadbcm5719-llvm-acbdc5748e70fef350d7974106c7886451b53801.tar.gz
bcm5719-llvm-acbdc5748e70fef350d7974106c7886451b53801.zip
Improve overloaded function handling in the typo correction code.
Change TypoCorrection to store a set of NamedDecls instead of a single NamedDecl. Also add initial support for performing function overload resolution to Sema::DiagnoseEmptyLookup. llvm-svn: 136807
-rw-r--r--clang/include/clang/Sema/Sema.h3
-rw-r--r--clang/include/clang/Sema/TypoCorrection.h71
-rw-r--r--clang/lib/Sema/SemaExpr.cpp24
-rw-r--r--clang/lib/Sema/SemaLookup.cpp48
-rw-r--r--clang/lib/Sema/SemaOverload.cpp3
-rw-r--r--clang/test/FixIt/typo-crash.cpp11
-rw-r--r--clang/test/SemaCXX/function-overload-typo-crash.cpp4
7 files changed, 126 insertions, 38 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 921cc716efe..d9b320d51de 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2236,7 +2236,8 @@ public:
const TemplateArgumentListInfo *&TemplateArgs);
bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- CorrectTypoContext CTC = CTC_Unknown);
+ CorrectTypoContext CTC = CTC_Unknown,
+ Expr **Args = 0, unsigned NumArgs = 0);
ExprResult LookupInObjCMethod(LookupResult &R, Scope *S, IdentifierInfo *II,
bool AllowBuiltinCreation=false);
diff --git a/clang/include/clang/Sema/TypoCorrection.h b/clang/include/clang/Sema/TypoCorrection.h
index 9965953538a..480a71af890 100644
--- a/clang/include/clang/Sema/TypoCorrection.h
+++ b/clang/include/clang/Sema/TypoCorrection.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_SEMA_TYPOCORRECTION_H
#include "clang/AST/DeclCXX.h"
+#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -23,29 +24,31 @@ namespace clang {
class TypoCorrection {
public:
TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
- NestedNameSpecifier *NNS=NULL, unsigned distance=0)
+ NestedNameSpecifier *NNS=0, unsigned distance=0)
: CorrectionName(Name),
CorrectionNameSpec(NNS),
- CorrectionDecl(NameDecl),
- EditDistance(distance) {}
+ EditDistance(distance) {
+ if (NameDecl)
+ CorrectionDecls.push_back(NameDecl);
+ }
- TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=NULL,
+ TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=0,
unsigned distance=0)
: CorrectionName(Name->getDeclName()),
CorrectionNameSpec(NNS),
- CorrectionDecl(Name),
- EditDistance(distance) {}
+ EditDistance(distance) {
+ if (Name)
+ CorrectionDecls.push_back(Name);
+ }
- TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=NULL,
+ TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=0,
unsigned distance=0)
: CorrectionName(Name),
CorrectionNameSpec(NNS),
- CorrectionDecl(NULL),
- EditDistance(distance) {}
+ EditDistance(distance) {}
TypoCorrection()
- : CorrectionName(), CorrectionNameSpec(NULL), CorrectionDecl(NULL),
- EditDistance(0) {}
+ : CorrectionNameSpec(0), EditDistance(0) {}
/// \brief Gets the DeclarationName of the typo correction
DeclarationName getCorrection() const { return CorrectionName; }
@@ -66,37 +69,67 @@ public:
/// \brief Gets the pointer to the declaration of the typo correction
NamedDecl* getCorrectionDecl() const {
- return isKeyword() ? NULL : CorrectionDecl;
+ return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : 0;
}
template <class DeclClass>
DeclClass *getCorrectionDeclAs() const {
return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
}
+ /// \brief Clears the list of NamedDecls before adding the new one.
void setCorrectionDecl(NamedDecl *CDecl) {
- CorrectionDecl = CDecl;
- if (!CorrectionName)
- CorrectionName = CDecl->getDeclName();
+ CorrectionDecls.clear();
+ addCorrectionDecl(CDecl);
}
+ /// \brief Add the given NamedDecl to the list of NamedDecls that are the
+ /// declarations associated with the DeclarationName of this TypoCorrection
+ void addCorrectionDecl(NamedDecl *CDecl);
+
std::string getAsString(const LangOptions &LO) const;
std::string getQuoted(const LangOptions &LO) const {
return "'" + getAsString(LO) + "'";
}
+ /// \brief Returns whether this TypoCorrection has a non-empty DeclarationName
operator bool() const { return bool(CorrectionName); }
- static inline NamedDecl *KeywordDecl() { return (NamedDecl*)-1; }
- bool isKeyword() const { return CorrectionDecl == KeywordDecl(); }
+ /// \brief Mark this TypoCorrection as being a keyword.
+ /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
+ /// added to the list of the correction's NamedDecl pointers, NULL is added
+ /// as the only element in the list to mark this TypoCorrection as a keyword.
+ void makeKeyword() {
+ CorrectionDecls.clear();
+ CorrectionDecls.push_back(0);
+ }
+
+ // 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() == 0;
+ }
// Returns true if the correction either is a keyword or has a known decl.
- bool isResolved() const { return CorrectionDecl != NULL; }
+ bool isResolved() const { return !CorrectionDecls.empty(); }
+
+ bool isOverloaded() const {
+ return CorrectionDecls.size() > 1;
+ }
+
+ typedef llvm::SmallVector<NamedDecl*, 1>::iterator decl_iterator;
+ decl_iterator begin() { return CorrectionDecls.begin(); }
+ decl_iterator end() { return CorrectionDecls.end(); }
private:
+ bool hasCorrectionDecl() const {
+ return (!isKeyword() && !CorrectionDecls.empty());
+ }
+
// Results.
DeclarationName CorrectionName;
NestedNameSpecifier *CorrectionNameSpec;
- NamedDecl *CorrectionDecl;
+ llvm::SmallVector<NamedDecl*, 1> CorrectionDecls;
unsigned EditDistance;
};
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 55e04b79de0..6ace3e92e60 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -1364,7 +1364,8 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id,
///
/// \return false if new lookup candidates were found
bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- CorrectTypoContext CTC) {
+ CorrectTypoContext CTC, Expr **Args,
+ unsigned NumArgs) {
DeclarationName Name = R.getLookupName();
unsigned diagnostic = diag::err_undeclared_var_use;
@@ -1450,6 +1451,27 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
R.setLookupName(Corrected.getCorrection());
if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ if (Corrected.isOverloaded()) {
+ OverloadCandidateSet OCS(R.getNameLoc());
+ OverloadCandidateSet::iterator Best;
+ for (TypoCorrection::decl_iterator CD = Corrected.begin(),
+ CDEnd = Corrected.end();
+ CD != CDEnd; ++CD) {
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*CD))
+ AddOverloadCandidate(FD, DeclAccessPair::make(*CD, AS_none),
+ Args, NumArgs, OCS);
+ // TODO: Handle FunctionTemplateDecl and other Decl types that
+ // support overloading and could be corrected by CorrectTypo.
+ }
+ switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) {
+ case OR_Success:
+ ND = Best->Function;
+ break;
+ default:
+ // Don't try to recover; it won't work.
+ return true;
+ }
+ }
R.addDecl(ND);
if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
if (SS.isEmpty())
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index c5ba95a1f4e..240eb5f1bf7 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3020,7 +3020,7 @@ public:
void FoundName(StringRef Name);
void addKeywordResult(StringRef Keyword);
void addName(StringRef Name, NamedDecl *ND, unsigned Distance,
- NestedNameSpecifier *NNS=NULL);
+ NestedNameSpecifier *NNS=NULL, bool isKeyword=false);
void addCorrection(TypoCorrection Correction);
typedef TypoResultsMap::iterator result_iterator;
@@ -3099,15 +3099,17 @@ void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) {
return;
}
- addName(Keyword, TypoCorrection::KeywordDecl(), ED);
+ addName(Keyword, NULL, ED, NULL, true);
}
void TypoCorrectionConsumer::addName(StringRef Name,
NamedDecl *ND,
unsigned Distance,
- NestedNameSpecifier *NNS) {
- addCorrection(TypoCorrection(&SemaRef.Context.Idents.get(Name),
- ND, NNS, Distance));
+ NestedNameSpecifier *NNS,
+ bool isKeyword) {
+ TypoCorrection TC(&SemaRef.Context.Idents.get(Name), ND, NNS, Distance);
+ if (isKeyword) TC.makeKeyword();
+ addCorrection(TC);
}
void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
@@ -3677,12 +3679,19 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// We don't deal with ambiguities.
return TypoCorrection();
+ case LookupResult::FoundOverloaded: {
+ // Store all of the Decls for overloaded symbols
+ for (LookupResult::iterator TRD = TmpRes.begin(),
+ TRDEnd = TmpRes.end();
+ TRD != TRDEnd; ++TRD)
+ I->second.addCorrectionDecl(*TRD);
+ ++I;
+ break;
+ }
+
case LookupResult::Found:
- case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
- // FIXME: This sets the CorrectionDecl to NULL for overloaded functions.
- // It would be nice to find the right one with overload resolution.
++I;
break;
}
@@ -3718,11 +3727,20 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
switch (TmpRes.getResultKind()) {
case LookupResult::Found:
- case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
Consumer.addName((*QRI)->getName(), TmpRes.getAsSingle<NamedDecl>(),
QualifiedED, NI->NameSpecifier);
break;
+ case LookupResult::FoundOverloaded: {
+ TypoCorrection corr(&Context.Idents.get((*QRI)->getName()), NULL,
+ NI->NameSpecifier, QualifiedED);
+ for (LookupResult::iterator TRD = TmpRes.begin(),
+ TRDEnd = TmpRes.end();
+ TRD != TRDEnd; ++TRD)
+ corr.addCorrectionDecl(*TRD);
+ Consumer.addCorrection(corr);
+ break;
+ }
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::Ambiguous:
@@ -3802,6 +3820,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
return TypoCorrection();
}
+void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) {
+ if (!CDecl) return;
+
+ if (isKeyword())
+ CorrectionDecls.clear();
+
+ CorrectionDecls.push_back(CDecl);
+
+ if (!CorrectionName)
+ CorrectionName = CDecl->getDeclName();
+}
+
std::string TypoCorrection::getAsString(const LangOptions &LO) const {
if (CorrectionNameSpec) {
std::string tmpBuffer;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 79aa305b86f..712720bf9e8 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -8220,7 +8220,8 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
ExplicitTemplateArgs, Args, NumArgs) &&
(!EmptyLookup ||
- SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression)))
+ SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression,
+ Args, NumArgs)))
return ExprError();
assert(!R.empty() && "lookup results empty despite recovery");
diff --git a/clang/test/FixIt/typo-crash.cpp b/clang/test/FixIt/typo-crash.cpp
index b156e1b44c4..8f0c989cce1 100644
--- a/clang/test/FixIt/typo-crash.cpp
+++ b/clang/test/FixIt/typo-crash.cpp
@@ -3,9 +3,10 @@
// FIXME: The diagnostics and recovery here are very, very poor.
// PR10355
-template<typename T> void template_id1() {
- template_id2<> t; // expected-error 2{{use of undeclared identifier 'template_id2'; did you mean 'template_id1'?}} \
- // expected-error{{expected expression}} \
- // expected-error{{use of undeclared identifier 't'}}
+template<typename T> void template_id1() { // expected-note {{'template_id1' declared here}} \
+ // expected-note {{candidate function}}
+ template_id2<> t; // expected-error {{no template named 'template_id2'; did you mean 'template_id1'?}} \
+ // expected-error {{expected ';' after expression}} \
+ // expected-error {{cannot resolve overloaded function 'template_id1' from context}} \
+ // expected-error {{use of undeclared identifier 't'}}
}
-
diff --git a/clang/test/SemaCXX/function-overload-typo-crash.cpp b/clang/test/SemaCXX/function-overload-typo-crash.cpp
index 0fea312a97f..580f27a12af 100644
--- a/clang/test/SemaCXX/function-overload-typo-crash.cpp
+++ b/clang/test/SemaCXX/function-overload-typo-crash.cpp
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// PR10283
-void min();
+void min(); //expected-note {{'min' declared here}}
void min(int);
-template <typename T> void max(T);
+template <typename T> void max(T); //expected-note {{'max' declared here}}
void f() {
fin(); //expected-error {{use of undeclared identifier 'fin'; did you mean 'min'}}
OpenPOWER on IntegriCloud