diff options
author | Kaelyn Uhrain <rikka@google.com> | 2011-08-03 20:36:05 +0000 |
---|---|---|
committer | Kaelyn Uhrain <rikka@google.com> | 2011-08-03 20:36:05 +0000 |
commit | acbdc5748e70fef350d7974106c7886451b53801 (patch) | |
tree | 7e36e71a496eaf62ff398282fd820a3df99d90d9 | |
parent | d855d82a160c66215551b41a2533f406b7ba27ac (diff) | |
download | bcm5719-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.h | 3 | ||||
-rw-r--r-- | clang/include/clang/Sema/TypoCorrection.h | 71 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 48 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 3 | ||||
-rw-r--r-- | clang/test/FixIt/typo-crash.cpp | 11 | ||||
-rw-r--r-- | clang/test/SemaCXX/function-overload-typo-crash.cpp | 4 |
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'}} |