On Mon, Aug 1, 2011 at 3:54 PM, Chandler Carruth <[email protected]>wrote:

> On Thu, Jul 28, 2011 at 2:25 PM, Kaelyn Uhrain <[email protected]> wrote:
>
>> Here's an updated version of my patch to add function overload resolution
>> to the typo correction, eliminating one of the ways that Sema::CorrectTypo
>> returns a non-keyword correction without a corresponding NamedDecl. It
>> incorporates all of the changes and feedback from
>> http://codereview.appspot.com/4747047. Given it's been almost two weeks
>> since I sent out the first version and over a week since I made changes
>> based on Chandler's last feedback (I was hoping he'd get a chance to look at
>> those changes, but he's been swamped), I'd appreciate it of someone could
>> give it a once-over and let me know whether it is ready for submission.
>>
>
> I've made a few additional comments, but my primary concern with this patch
> is the representation of KeywordDecl. I think playing fast and loose with
> magical pointer values is going to come back to bite us. If we can't use
> 'NULL' as the magical pointer value, we should find some more robust way to
> represent a keyword in the correction results.
>
> I'd certainly appreciate ideas from dgregor and any others on the list on
> the best way to represent that.
>
> To make it easier for others to review, can you attach the latest patch to
> the email thread?
>

The use of a special non-NULL value for the CorrectionDecl* was needed when
the TypoCorrection stored just one NamedDecl pointer to avoid an extra
internal boolean flag and a bunch of handling for it, but is unneeded now
that TypoCorrection stores a list of NamedDecl pointers (can now do empty
list vs NULL first element). I've attached the updated patch for real this
time--sorry for accidentally sending my previous email with a missing
attachment.

Cheers,
Kaelyn
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index cbb096d..08514cd 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2235,7 +2235,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/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index 9965953..036b5ff 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/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,7 +69,7 @@ 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 {
@@ -74,11 +77,12 @@ public:
   }
   
   void setCorrectionDecl(NamedDecl *CDecl) {
-    CorrectionDecl = CDecl;
-    if (!CorrectionName)
-      CorrectionName = CDecl->getDeclName();
+    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 +90,40 @@ public:
 
   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.
+  void makeKeyword() {
+    CorrectionDecls.clear();
+    CorrectionDecls.push_back(0);
+  }
+
+  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;
+  }
+
+  const llvm::SmallVector<NamedDecl*, 1> &getCorrectionDecls() const {
+    return CorrectionDecls;
+  }
+  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/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index bfaf546..84fa8f2 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1333,7 +1333,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;
@@ -1419,6 +1420,27 @@ 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) {
+          assert(isa<FunctionDecl>(*CD) &&
+                 "Encountered a non-function as a function overload candidate");
+          AddOverloadCandidate(cast<FunctionDecl>(*CD),
+                               DeclAccessPair::make(*CD, AS_none),
+                               Args, NumArgs, OCS);
+        }
+        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/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index c5ba95a..240eb5f 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/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/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 79aa305..712720b 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/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/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