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

Reply via email to