I've addresses your comments and updated the patch. Thanks for reviewing it,
Chandler! :)
I've also attached the updated patch that e.g. doesn't dynamically allocate
the CorrectionDeclSet and doesn't maintain a separate flag for whether the
correction is a keyword. I've also changed the KeywordDecl to be ~0x3
instead of -1 to avoid issues with data structures (such as UnresolvedSet
that the first version of the patch used) assuming pointers are 64-bit
aligned and manipulating the low 3 bits internally.
Cheers,
Kaelyn
On Fri, Jul 15, 2011 at 6:34 PM, Chandler Carruth <[email protected]>wrote:
> FYI, comments on the codereview page. =] Thanks!
>
> On Fri, Jul 15, 2011 at 5:06 PM, Kaelyn Uhrain <[email protected]> wrote:
>
>> This patch improves how typo correction deals with overloaded functions,
>> e.g. Sema::CorrectTypo now returns a set of Decls in the TypoCorrection if
>> the lookup of a correction has a result kind of
>> LookupResult::FoundOverloaded, and Sema::DiagnoseEmptyLookup has been
>> modified to try to choose the best Decl from the set. With these changes,
>> TypoCorrection is one step closer to never returning a non-keyword
>> correction with a NULL Decl. I also ran memcheck using
>> test/FixIt/typo-crash.cpp as a quick sanity check that I didn't accidentally
>> introduce any memory leaks with the changes to the TypoCorrection class
>> (though I think dynamically allocating the UnresolvedSet may be a bit of
>> overkill and generally unnecessary--thoughts?).
>>
>> The changes can also be reviewed at:
>> http://codereview.appspot.com/4747047
>>
>> Cheers,
>> Kaelyn
>>
>> _______________________________________________
>> cfe-commits mailing list
>> [email protected]
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>
>>
>
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 263c1bd..d979192 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2205,7 +2205,8 @@ public:
const TemplateArgumentListInfo *&TemplateArgs);
bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
- CorrectTypoContext CTC = CTC_Unknown);
+ CorrectTypoContext CTC = CTC_Unknown,
+ Expr **Args = NULL, unsigned NumArgs = 0);
ExprResult LookupInObjCMethod(LookupResult &R, Scope *S, IdentifierInfo *II,
bool AllowBuiltinCreation=false);
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index 9965953..6813e83 100644
--- a/include/clang/Sema/TypoCorrection.h
+++ b/include/clang/Sema/TypoCorrection.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_SEMA_TYPOCORRECTION_H
#include "clang/AST/DeclCXX.h"
+#include "llvm/ADT/SmallPtrSet.h"
namespace clang {
@@ -26,26 +27,32 @@ public:
NestedNameSpecifier *NNS=NULL, unsigned distance=0)
: CorrectionName(Name),
CorrectionNameSpec(NNS),
- CorrectionDecl(NameDecl),
- EditDistance(distance) {}
+ CorrectionDecls(),
+ EditDistance(distance) {
+ if (NameDecl)
+ CorrectionDecls.insert(NameDecl);
+ }
TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=NULL,
unsigned distance=0)
: CorrectionName(Name->getDeclName()),
CorrectionNameSpec(NNS),
- CorrectionDecl(Name),
- EditDistance(distance) {}
+ CorrectionDecls(),
+ EditDistance(distance) {
+ if (Name)
+ CorrectionDecls.insert(Name);
+ }
TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=NULL,
unsigned distance=0)
: CorrectionName(Name),
CorrectionNameSpec(NNS),
- CorrectionDecl(NULL),
- EditDistance(distance) {}
+ CorrectionDecls(),
+ EditDistance(distance) {}
TypoCorrection()
- : CorrectionName(), CorrectionNameSpec(NULL), CorrectionDecl(NULL),
- EditDistance(0) {}
+ : CorrectionName(), CorrectionNameSpec(NULL),
+ CorrectionDecls(), EditDistance(0) {}
/// \brief Gets the DeclarationName of the typo correction
DeclarationName getCorrection() const { return CorrectionName; }
@@ -66,19 +73,20 @@ public:
/// \brief Gets the pointer to the declaration of the typo correction
NamedDecl* getCorrectionDecl() const {
- return isKeyword() ? NULL : CorrectionDecl;
+ return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : NULL;
}
template <class DeclClass>
DeclClass *getCorrectionDeclAs() const {
return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
}
- void setCorrectionDecl(NamedDecl *CDecl) {
- CorrectionDecl = CDecl;
- if (!CorrectionName)
- CorrectionName = CDecl->getDeclName();
+ void setCorrectionDecl(NamedDecl *CDecl){
+ CorrectionDecls.clear();
+ addCorrectionDecl(CDecl);
}
+ void addCorrectionDecl(NamedDecl *CDecl);
+
std::string getAsString(const LangOptions &LO) const;
std::string getQuoted(const LangOptions &LO) const {
return "'" + getAsString(LO) + "'";
@@ -86,17 +94,33 @@ public:
operator bool() const { return bool(CorrectionName); }
- static inline NamedDecl *KeywordDecl() { return (NamedDecl*)-1; }
- bool isKeyword() const { return CorrectionDecl == KeywordDecl(); }
+ static inline NamedDecl *KeywordDecl() { return (NamedDecl*)~0x3; }
+ bool isKeyword() const {
+ return !CorrectionDecls.empty() &&
+ *(CorrectionDecls.begin()) == KeywordDecl();
+ }
// 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;
+ }
+
+ const llvm::SmallPtrSet<NamedDecl*, 1> &getCorrectionDecls() const { return CorrectionDecls; }
+ typedef llvm::SmallPtrSet<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::SmallPtrSet<NamedDecl*, 1> CorrectionDecls;
unsigned EditDistance;
};
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 5efc365..c4c49ab 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1319,7 +1319,8 @@ void 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;
@@ -1405,6 +1406,25 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
R.setLookupName(Corrected.getCorrection());
if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+ if (Args && Corrected.isOverloaded()) {
+ OverloadCandidateSet OCS(R.getNameLoc());
+ OverloadCandidateSet::iterator Best;
+ for (TypoCorrection::decl_iterator CD = Corrected.begin(),
+ CDEnd = Corrected.end();
+ CD != CDEnd; ++CD)
+ AddOverloadCandidate(cast<FunctionDecl>(*CD),
+ DeclAccessPair::make(*CD, AS_none),
+ Args, NumArgs, OCS);
+ switch (OCS.BestViableFunction(*this, R.getNameLoc(), Best)) {
+ case OR_Success:
+ case OR_Ambiguous:
+ 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/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 0e448e3..2b465c8 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -3745,8 +3745,17 @@ 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.
@@ -3786,11 +3795,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:
@@ -3870,6 +3888,18 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
return TypoCorrection();
}
+void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) {
+ if (!CDecl) return;
+
+ if (isKeyword() || CDecl == KeywordDecl())
+ CorrectionDecls.clear();
+
+ CorrectionDecls.insert(CDecl);
+
+ if (!CorrectionName && CDecl != KeywordDecl())
+ CorrectionName = CDecl->getDeclName();
+}
+
std::string TypoCorrection::getAsString(const LangOptions &LO) const {
if (CorrectionNameSpec) {
std::string tmpBuffer;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 437b2b5..db45e79 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -8164,7 +8164,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/test/FixIt/typo-crash.cpp b/test/FixIt/typo-crash.cpp
index b156e1b..8f0c989 100644
--- a/test/FixIt/typo-crash.cpp
+++ b/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/test/SemaCXX/function-overload-typo-crash.cpp b/test/SemaCXX/function-overload-typo-crash.cpp
index 0fea312..580f27a 100644
--- a/test/SemaCXX/function-overload-typo-crash.cpp
+++ b/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'}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits