[cfe-commits] r134007 - in /cfe/trunk: include/clang/Sema/ include/clang/Serialization/ lib/Sema/ lib/Serialization/ test/CXX/basic/basic.lookup/basic.lookup.argdep/ test/FixIt/ test/PCH/ test/PCH/Inputs/ test/SemaCXX/ test/SemaObjC/

Douglas Gregor dgregor at apple.com
Tue Jun 28 09:20:03 PDT 2011


Author: dgregor
Date: Tue Jun 28 11:20:02 2011
New Revision: 134007

URL: http://llvm.org/viewvc/llvm-project?rev=134007&view=rev
Log:
Add support for C++ namespace-aware typo correction, e.g., correcting

  vector<int>

to

  std::vector<int>

Patch by Kaelyn Uhrain, with minor tweaks + PCH support from me. Fixes
PR5776/<rdar://problem/8652971>.

Thanks Kaelyn!

Added:
    cfe/trunk/include/clang/Sema/TypoCorrection.h   (with props)
    cfe/trunk/test/PCH/Inputs/typo.hpp   (with props)
    cfe/trunk/test/PCH/typo.cpp   (with props)
    cfe/trunk/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Sema/ExternalSemaSource.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprMember.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
    cfe/trunk/test/FixIt/typo.cpp
    cfe/trunk/test/SemaObjC/ivar-ref-misuse.m

Modified: cfe/trunk/include/clang/Sema/ExternalSemaSource.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ExternalSemaSource.h?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ExternalSemaSource.h (original)
+++ cfe/trunk/include/clang/Sema/ExternalSemaSource.h Tue Jun 28 11:20:02 2011
@@ -49,6 +49,11 @@
   /// instance and factory methods, respectively, with this selector.
   virtual std::pair<ObjCMethodList,ObjCMethodList> ReadMethodPool(Selector Sel);
 
+  /// \brief Load the set of namespaces that are known to the external source,
+  /// which will be used during typo correction.
+  virtual void ReadKnownNamespaces(
+                           llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces);
+  
   /// \brief Do last resort, unqualified lookup on a LookupResult that
   /// Sema cannot find.
   ///

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Jun 28 11:20:02 2011
@@ -21,6 +21,7 @@
 #include "clang/Sema/ObjCMethodList.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/LocInfoType.h"
+#include "clang/Sema/TypoCorrection.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExternalASTSource.h"
@@ -46,6 +47,8 @@
   class ASTConsumer;
   class ASTContext;
   class ASTMutationListener;
+  class ASTReader;
+  class ASTWriter;
   class ArrayType;
   class AttributeList;
   class BlockDecl;
@@ -1623,6 +1626,16 @@
                                                    bool ConstThis,
                                                    bool VolatileThis);
 
+  // \brief The set of known/encountered (unique, canonicalized) NamespaceDecls.
+  //
+  // The boolean value will be true to indicate that the namespace was loaded
+  // from an AST/PCH file, or false otherwise.
+  llvm::DenseMap<NamespaceDecl*, bool> KnownNamespaces;
+
+  /// \brief Whether we have already loaded known namespaces from an extenal
+  /// source.
+  bool LoadedExternalKnownNamespaces;
+  
 public:
   /// \brief Look up a name, looking for a single declaration.  Return
   /// null if the results were absent, ambiguous, or overloaded.
@@ -1699,11 +1712,13 @@
     CTC_ObjCMessageReceiver
   };
 
-  DeclarationName CorrectTypo(LookupResult &R, Scope *S, CXXScopeSpec *SS,
-                              DeclContext *MemberContext = 0,
-                              bool EnteringContext = false,
-                              CorrectTypoContext CTC = CTC_Unknown,
-                              const ObjCObjectPointerType *OPT = 0);
+  TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
+                             Sema::LookupNameKind LookupKind,
+                             Scope *S, CXXScopeSpec *SS,
+                             DeclContext *MemberContext = NULL,
+                             bool EnteringContext = false,
+                             CorrectTypoContext CTC = CTC_Unknown,
+                             const ObjCObjectPointerType *OPT = NULL);
 
   void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs,
                                    AssociatedNamespaceSet &AssociatedNamespaces,
@@ -4721,7 +4736,7 @@
   /// \brief The number of typos corrected by CorrectTypo.
   unsigned TyposCorrected;
 
-  typedef llvm::DenseMap<IdentifierInfo *, std::pair<llvm::StringRef, bool> >
+  typedef llvm::DenseMap<IdentifierInfo *, TypoCorrection>
     UnqualifiedTyposCorrectedMap;
   
   /// \brief A cache containing the results of typo correction for unqualified
@@ -5918,6 +5933,8 @@
 protected:
   friend class Parser;
   friend class InitializationSequence;  
+  friend class ASTReader;
+  friend class ASTWriter;
   
 public:
   /// \brief Retrieve the parser's current scope.

Added: cfe/trunk/include/clang/Sema/TypoCorrection.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/TypoCorrection.h?rev=134007&view=auto
==============================================================================
--- cfe/trunk/include/clang/Sema/TypoCorrection.h (added)
+++ cfe/trunk/include/clang/Sema/TypoCorrection.h Tue Jun 28 11:20:02 2011
@@ -0,0 +1,105 @@
+//===--- TypoCorrection.h - Class for typo correction results ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the TypoCorrection class, which stores the results of
+// Sema's typo correction (Sema::CorrectTypo).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H
+#define LLVM_CLANG_SEMA_TYPOCORRECTION_H
+
+#include "clang/AST/DeclCXX.h"
+
+namespace clang {
+
+/// @brief Simple class containing the result of Sema::CorrectTypo
+class TypoCorrection {
+public:
+  TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
+                 NestedNameSpecifier *NNS=NULL, unsigned distance=0)
+      : CorrectionName(Name),
+        CorrectionNameSpec(NNS),
+        CorrectionDecl(NameDecl),
+        EditDistance(distance) {}
+
+  TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=NULL,
+                 unsigned distance=0)
+      : CorrectionName(Name->getDeclName()),
+        CorrectionNameSpec(NNS),
+        CorrectionDecl(Name),
+        EditDistance(distance)  {}
+
+  TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=NULL,
+                 unsigned distance=0)
+      : CorrectionName(Name),
+        CorrectionNameSpec(NNS),
+        CorrectionDecl(NULL),
+        EditDistance(distance)  {}
+
+  TypoCorrection()
+      : CorrectionName(), CorrectionNameSpec(NULL), CorrectionDecl(NULL),
+        EditDistance(0) {}
+
+  /// \brief Gets the DeclarationName of the typo correction
+  DeclarationName getCorrection() const { return CorrectionName; }
+  IdentifierInfo* getCorrectionAsIdentifierInfo() const {
+    return CorrectionName.getAsIdentifierInfo();
+  }
+
+  /// \brief Gets the NestedNameSpecifier needed to use the typo correction
+  NestedNameSpecifier* getCorrectionSpecifier() const {
+    return CorrectionNameSpec;
+  }
+  void setCorrectionSpecifier(NestedNameSpecifier* NNS) {
+    CorrectionNameSpec = NNS;
+  }
+
+  /// \brief Gets the "edit distance" of the typo correction from the typo
+  unsigned getEditDistance() const { return EditDistance; }
+
+  /// \brief Gets the pointer to the declaration of the typo correction
+  NamedDecl* getCorrectionDecl() const {
+    return isKeyword() ? NULL : CorrectionDecl;
+  }
+  template <class DeclClass>
+  DeclClass *getCorrectionDeclAs() const {
+    return dyn_cast_or_null<DeclClass>(getCorrectionDecl());
+  }
+  
+  void setCorrectionDecl(NamedDecl *CDecl) {
+    CorrectionDecl = CDecl;
+    if (!CorrectionName)
+      CorrectionName = CDecl->getDeclName();
+  }
+
+  std::string getAsString(const LangOptions &LO) const;
+  std::string getQuoted(const LangOptions &LO) const {
+    return "'" + getAsString(LO) + "'";
+  }
+
+  operator bool() const { return bool(CorrectionName); }
+
+  static inline NamedDecl *KeywordDecl() { return (NamedDecl*)-1; }
+  bool isKeyword() const { return CorrectionDecl == KeywordDecl(); }
+
+  // Returns true if the correction either is a keyword or has a known decl.
+  bool isResolved() const { return CorrectionDecl != NULL; }
+
+private:
+  // Results.
+  DeclarationName CorrectionName;
+  NestedNameSpecifier *CorrectionNameSpec;
+  NamedDecl *CorrectionDecl;
+  unsigned EditDistance;
+};
+
+}
+
+#endif

Propchange: cfe/trunk/include/clang/Sema/TypoCorrection.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/include/clang/Sema/TypoCorrection.h
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/include/clang/Sema/TypoCorrection.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Tue Jun 28 11:20:02 2011
@@ -371,7 +371,11 @@
 
       /// \brief Record code for the table of offsets into the block
       /// of file source-location information.
-      FILE_SOURCE_LOCATION_OFFSETS = 45
+      FILE_SOURCE_LOCATION_OFFSETS = 45,
+      
+      /// \brief Record code for the set of known namespaces, which are used
+      /// for typo correction.
+      KNOWN_NAMESPACES = 46
 
     };
 

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Tue Jun 28 11:20:02 2011
@@ -625,6 +625,9 @@
   /// \brief The OpenCL extension settings.
   llvm::SmallVector<uint64_t, 1> OpenCLExtensions;
 
+  /// \brief A list of the namespaces we've seen.
+  llvm::SmallVector<uint64_t, 4> KnownNamespaces;
+
   //@}
 
   /// \brief Diagnostic IDs and their mappings that the user changed.
@@ -1125,6 +1128,11 @@
   virtual std::pair<ObjCMethodList, ObjCMethodList>
     ReadMethodPool(Selector Sel);
 
+  /// \brief Load the set of namespaces that are known to the external source,
+  /// which will be used during typo correction.
+  virtual void ReadKnownNamespaces(
+                           llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces);
+
   /// \brief Load a selector from disk, registering its ID if it exists.
   void LoadSelector(Selector Sel);
 

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Tue Jun 28 11:20:02 2011
@@ -154,6 +154,8 @@
     AnalysisWarnings(*this)
 {
   TUScope = 0;
+  LoadedExternalKnownNamespaces = false;
+  
   if (getLangOptions().CPlusPlus)
     FieldCollector.reset(new CXXFieldCollector());
 
@@ -778,6 +780,10 @@
   return std::pair<ObjCMethodList, ObjCMethodList>();
 }
 
+void ExternalSemaSource::ReadKnownNamespaces(
+                           llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) {  
+}
+
 void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const {
   SourceLocation Loc = this->Loc;
   if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation();

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Tue Jun 28 11:20:02 2011
@@ -464,26 +464,29 @@
     // We haven't found anything, and we're not recovering from a
     // different kind of error, so look for typos.
     DeclarationName Name = Found.getLookupName();
-    if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext,  
-                    CTC_NoKeywords) &&
-        Found.isSingleResult() &&
-        isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) {
+    TypoCorrection Corrected;
+    Found.clear();
+    if ((Corrected = CorrectTypo(Found.getLookupNameInfo(),
+                                 Found.getLookupKind(), S, &SS, LookupCtx,
+                                 EnteringContext, CTC_NoKeywords)) &&
+        isAcceptableNestedNameSpecifier(Corrected.getCorrectionDecl())) {
+      std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+      std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
       if (LookupCtx)
         Diag(Found.getNameLoc(), diag::err_no_member_suggest)
-          << Name << LookupCtx << Found.getLookupName() << SS.getRange()
-          << FixItHint::CreateReplacement(Found.getNameLoc(),
-                                          Found.getLookupName().getAsString());
+          << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
+          << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
       else
         Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest)
-          << Name << Found.getLookupName()
-          << FixItHint::CreateReplacement(Found.getNameLoc(),
-                                          Found.getLookupName().getAsString());
+          << Name << CorrectedQuotedStr
+          << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
       
-      if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
-        Diag(ND->getLocation(), diag::note_previous_decl)
-          << ND->getDeclName();
+      if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
+        Diag(ND->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr;
+        Found.addDecl(ND);
+      }
+      Found.setLookupName(Corrected.getCorrection());
     } else {
-      Found.clear();
       Found.setLookupName(&Identifier);
     }
   }

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jun 28 11:20:02 2011
@@ -287,41 +287,42 @@
   
   // There may have been a typo in the name of the type. Look up typo
   // results, in case we have something that we can suggest.
-  LookupResult Lookup(*this, &II, IILoc, LookupOrdinaryName, 
-                      NotForRedeclaration);
+  if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(&II, IILoc),
+                                             LookupOrdinaryName, S, SS, NULL,
+                                             false, CTC_Type)) {
+    std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+    std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
 
-  if (DeclarationName Corrected = CorrectTypo(Lookup, S, SS, 0, 0, CTC_Type)) {
-    if (NamedDecl *Result = Lookup.getAsSingle<NamedDecl>()) {
+    if (Corrected.isKeyword()) {
+      // We corrected to a keyword.
+      // FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
+      Diag(IILoc, diag::err_unknown_typename_suggest)
+        << &II << CorrectedQuotedStr;
+      return true;      
+    } else {
+      NamedDecl *Result = Corrected.getCorrectionDecl();
       if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) &&
           !Result->isInvalidDecl()) {
         // We found a similarly-named type or interface; suggest that.
         if (!SS || !SS->isSet())
           Diag(IILoc, diag::err_unknown_typename_suggest)
-            << &II << Lookup.getLookupName()
-            << FixItHint::CreateReplacement(SourceRange(IILoc),
-                                            Result->getNameAsString());
+            << &II << CorrectedQuotedStr
+            << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
         else if (DeclContext *DC = computeDeclContext(*SS, false))
           Diag(IILoc, diag::err_unknown_nested_typename_suggest) 
-            << &II << DC << Lookup.getLookupName() << SS->getRange()
-            << FixItHint::CreateReplacement(SourceRange(IILoc),
-                                            Result->getNameAsString());
+            << &II << DC << CorrectedQuotedStr << SS->getRange()
+            << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr);
         else
           llvm_unreachable("could not have corrected a typo here");
 
         Diag(Result->getLocation(), diag::note_previous_decl)
-          << Result->getDeclName();
+          << CorrectedQuotedStr;
         
         SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS,
                                     false, false, ParsedType(),
                                     /*NonTrivialTypeSourceInfo=*/true);
         return true;
       }
-    } else if (Lookup.empty()) {
-      // We corrected to a keyword.
-      // FIXME: Actually recover with the keyword we suggest, and emit a fix-it.
-      Diag(IILoc, diag::err_unknown_typename_suggest)
-        << &II << Corrected;
-      return true;      
     }
   }
 
@@ -509,11 +510,14 @@
     // Perform typo correction to determine if there is another name that is
     // close to this name.
     if (!SecondTry) {
-      if (DeclarationName Corrected = CorrectTypo(Result, S, &SS)) {
+      if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
+                                                 Result.getLookupKind(), S, &SS)) {
         unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
         unsigned QualifiedDiag = diag::err_no_member_suggest;
+        std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+        std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
         
-        NamedDecl *FirstDecl = Result.empty()? 0 : *Result.begin();
+        NamedDecl *FirstDecl = Corrected.getCorrectionDecl();
         NamedDecl *UnderlyingFirstDecl
           = FirstDecl? FirstDecl->getUnderlyingDecl() : 0;
         if (getLangOptions().CPlusPlus && NextToken.is(tok::less) &&
@@ -528,25 +532,34 @@
            QualifiedDiag = diag::err_unknown_nested_typename_suggest;
          }
         
+        if (Corrected.getCorrectionSpecifier())
+          SS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(), SourceRange(NameLoc));
+
         if (SS.isEmpty())
           Diag(NameLoc, UnqualifiedDiag)
-            << Name << Corrected
-            << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString());
+            << Name << CorrectedQuotedStr
+            << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
         else
           Diag(NameLoc, QualifiedDiag)
-            << Name << computeDeclContext(SS, false) << Corrected
+            << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
             << SS.getRange()
-            << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString());
+            << FixItHint::CreateReplacement(NameLoc, CorrectedStr);
 
         // Update the name, so that the caller has the new name.
-        Name = Corrected.getAsIdentifierInfo();
+        Name = Corrected.getCorrectionAsIdentifierInfo();
         
+        // Also update the LookupResult...
+        // FIXME: This should probably go away at some point
+        Result.clear();
+        Result.setLookupName(Corrected.getCorrection());
+        if (FirstDecl) Result.addDecl(FirstDecl);
+
         // Typo correction corrected to a keyword.
-        if (Result.empty())
-          return Corrected.getAsIdentifierInfo();
+        if (Corrected.isKeyword())
+          return Corrected.getCorrectionAsIdentifierInfo();
         
         Diag(FirstDecl->getLocation(), diag::note_previous_decl)
-          << FirstDecl->getDeclName();
+          << CorrectedQuotedStr;
 
         // If we found an Objective-C instance variable, let
         // LookupInObjCMethod build the appropriate expression to
@@ -1137,17 +1150,18 @@
 /// class could not be found.
 ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
                                               SourceLocation IdLoc,
-                                              bool TypoCorrection) {
+                                              bool DoTypoCorrection) {
   // The third "scope" argument is 0 since we aren't enabling lazy built-in
   // creation from this context.
   NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName);
 
-  if (!IDecl && TypoCorrection) {
+  if (!IDecl && DoTypoCorrection) {
     // Perform typo correction at the given location, but only if we
     // find an Objective-C class name.
-    LookupResult R(*this, Id, IdLoc, LookupOrdinaryName);
-    if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
-        (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+    TypoCorrection C;
+    if ((C = CorrectTypo(DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName,
+                         TUScope, NULL, NULL, false, CTC_NoKeywords)) &&
+        (IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
       Diag(IdLoc, diag::err_undef_interface_suggest)
         << Id << IDecl->getDeclName() 
         << FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString());

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Jun 28 11:20:02 2011
@@ -1426,25 +1426,27 @@
       }
 
       // If no results were found, try to correct typos.
+      TypoCorrection Corr;
       if (R.empty() && BaseType.isNull() &&
-          CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) && 
-          R.isSingleResult()) {
-        if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) {
+          (Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
+                              ClassDecl, false, CTC_NoKeywords))) {
+        std::string CorrectedStr(Corr.getAsString(getLangOptions()));
+        std::string CorrectedQuotedStr(Corr.getQuoted(getLangOptions()));
+        if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
           if (Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl)) {
             // We have found a non-static data member with a similar
             // name to what was typed; complain and initialize that
             // member.
             Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
-              << MemberOrBase << true << R.getLookupName()
-              << FixItHint::CreateReplacement(R.getNameLoc(),
-                                              R.getLookupName().getAsString());
+              << MemberOrBase << true << CorrectedQuotedStr
+              << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
             Diag(Member->getLocation(), diag::note_previous_decl)
-              << Member->getDeclName();
+              << CorrectedQuotedStr;
 
             return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
                                           LParenLoc, RParenLoc);
           }
-        } else if (TypeDecl *Type = R.getAsSingle<TypeDecl>()) {
+        } else if (TypeDecl *Type = Corr.getCorrectionDeclAs<TypeDecl>()) {
           const CXXBaseSpecifier *DirectBaseSpec;
           const CXXBaseSpecifier *VirtualBaseSpec;
           if (FindBaseInitializer(*this, ClassDecl, 
@@ -1454,9 +1456,8 @@
             // similar name to what was typed; complain and initialize
             // that base class.
             Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
-              << MemberOrBase << false << R.getLookupName()
-              << FixItHint::CreateReplacement(R.getNameLoc(),
-                                              R.getLookupName().getAsString());
+              << MemberOrBase << false << CorrectedQuotedStr
+              << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
 
             const CXXBaseSpecifier *BaseSpec = DirectBaseSpec? DirectBaseSpec 
                                                              : VirtualBaseSpec;
@@ -4706,6 +4707,13 @@
       // Make our StdNamespace cache point at the first real definition of the
       // "std" namespace.
       StdNamespace = Namespc;
+
+      // Add this instance of "std" to the set of known namespaces
+      KnownNamespaces[Namespc] = false;
+    } else if (!Namespc->isInline()) {
+      // Since this is an "original" namespace, add it to the known set of
+      // namespaces if it is not an inline namespace.
+      KnownNamespaces[Namespc] = false;
     }
 
     PushOnScopeChains(Namespc, DeclRegionScope);
@@ -4841,6 +4849,39 @@
   }
 }
 
+static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
+                                       CXXScopeSpec &SS,
+                                       SourceLocation IdentLoc,
+                                       IdentifierInfo *Ident) {
+  R.clear();
+  if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
+                                               R.getLookupKind(), Sc, &SS, NULL,
+                                               false, S.CTC_NoKeywords, NULL)) {
+    if (Corrected.getCorrectionDeclAs<NamespaceDecl>() ||
+        Corrected.getCorrectionDeclAs<NamespaceAliasDecl>()) {
+      std::string CorrectedStr(Corrected.getAsString(S.getLangOptions()));
+      std::string CorrectedQuotedStr(Corrected.getQuoted(S.getLangOptions()));
+      if (DeclContext *DC = S.computeDeclContext(SS, false))
+        S.Diag(IdentLoc, diag::err_using_directive_member_suggest)
+          << Ident << DC << CorrectedQuotedStr << SS.getRange()
+          << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+      else
+        S.Diag(IdentLoc, diag::err_using_directive_suggest)
+          << Ident << CorrectedQuotedStr
+          << FixItHint::CreateReplacement(IdentLoc, CorrectedStr);
+
+      S.Diag(Corrected.getCorrectionDecl()->getLocation(),
+           diag::note_namespace_defined_here) << CorrectedQuotedStr;
+
+      Ident = Corrected.getCorrectionAsIdentifierInfo();
+      R.addDecl(Corrected.getCorrectionDecl());
+      return true;
+    }
+    R.setLookupName(Ident);
+  }
+  return false;
+}
+
 Decl *Sema::ActOnUsingDirective(Scope *S,
                                           SourceLocation UsingLoc,
                                           SourceLocation NamespcLoc,
@@ -4869,6 +4910,7 @@
     return 0;
 
   if (R.empty()) {
+    R.clear();
     // Allow "using namespace std;" or "using namespace ::std;" even if 
     // "std" hasn't been defined yet, for GCC compatibility.
     if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) &&
@@ -4878,27 +4920,7 @@
       R.resolveKind();
     } 
     // Otherwise, attempt typo correction.
-    else if (DeclarationName Corrected = CorrectTypo(R, S, &SS, 0, false, 
-                                                       CTC_NoKeywords, 0)) {
-      if (R.getAsSingle<NamespaceDecl>() || 
-          R.getAsSingle<NamespaceAliasDecl>()) {
-        if (DeclContext *DC = computeDeclContext(SS, false))
-          Diag(IdentLoc, diag::err_using_directive_member_suggest)
-            << NamespcName << DC << Corrected << SS.getRange()
-            << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());        
-        else
-          Diag(IdentLoc, diag::err_using_directive_suggest)
-            << NamespcName << Corrected
-            << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
-        Diag(R.getFoundDecl()->getLocation(), diag::note_namespace_defined_here)
-          << Corrected;
-        
-        NamespcName = Corrected.getAsIdentifierInfo();
-      } else {
-        R.clear();
-        R.setLookupName(NamespcName);
-      }
-    }
+    else TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, NamespcName);
   }
   
   if (!R.empty()) {
@@ -5816,30 +5838,7 @@
     return 0;
 
   if (R.empty()) {
-    if (DeclarationName Corrected = CorrectTypo(R, S, &SS, 0, false, 
-                                                CTC_NoKeywords, 0)) {
-      if (R.getAsSingle<NamespaceDecl>() || 
-          R.getAsSingle<NamespaceAliasDecl>()) {
-        if (DeclContext *DC = computeDeclContext(SS, false))
-          Diag(IdentLoc, diag::err_using_directive_member_suggest)
-            << Ident << DC << Corrected << SS.getRange()
-            << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());        
-        else
-          Diag(IdentLoc, diag::err_using_directive_suggest)
-            << Ident << Corrected
-            << FixItHint::CreateReplacement(IdentLoc, Corrected.getAsString());
-        
-        Diag(R.getFoundDecl()->getLocation(), diag::note_namespace_defined_here)
-          << Corrected;
-        
-        Ident = Corrected.getAsIdentifierInfo();
-      } else {
-        R.clear();
-        R.setLookupName(Ident);
-      }
-    }
-    
-    if (R.empty()) {
+    if (!TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, Ident)) {
       Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange();
       return 0;
     }

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Tue Jun 28 11:20:02 2011
@@ -442,9 +442,10 @@
 
     if (!PrevDecl) {
       // Try to correct for a typo in the superclass name.
-      LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName);
-      if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
-          (PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+      TypoCorrection Corrected = CorrectTypo(
+          DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
+          NULL, NULL, false, CTC_NoKeywords);
+      if ((PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
         Diag(SuperLoc, diag::err_undef_superclass_suggest)
           << SuperName << ClassName << PrevDecl->getDeclName();
         Diag(PrevDecl->getLocation(), diag::note_previous_decl)
@@ -655,12 +656,12 @@
     ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
                                              ProtocolId[i].second);
     if (!PDecl) {
-      LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second,
-                     LookupObjCProtocolName);
-      if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
-          (PDecl = R.getAsSingle<ObjCProtocolDecl>())) {
+      TypoCorrection Corrected = CorrectTypo(
+          DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
+          LookupObjCProtocolName, TUScope, NULL, NULL, false, CTC_NoKeywords);
+      if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) {
         Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
-          << ProtocolId[i].first << R.getLookupName();
+          << ProtocolId[i].first << Corrected.getCorrection();
         Diag(PDecl->getLocation(), diag::note_previous_decl)
           << PDecl->getDeclName();
       }
@@ -897,20 +898,20 @@
   } else {
     // We did not find anything with the name ClassName; try to correct for 
     // typos in the class name.
-    LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName);
-    if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
-        (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
+    TypoCorrection Corrected = CorrectTypo(
+        DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope,
+        NULL, NULL, false, CTC_NoKeywords);
+    if ((IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
       // Suggest the (potentially) correct interface name. However, put the
       // fix-it hint itself in a separate note, since changing the name in 
       // the warning would make the fix-it change semantics.However, don't
       // provide a code-modification hint or use the typo name for recovery,
       // because this is just a warning. The program may actually be correct.
+      DeclarationName CorrectedName = Corrected.getCorrection();
       Diag(ClassLoc, diag::warn_undef_interface_suggest)
-        << ClassName << R.getLookupName();
-      Diag(IDecl->getLocation(), diag::note_previous_decl)
-        << R.getLookupName()
-        << FixItHint::CreateReplacement(ClassLoc,
-                                        R.getLookupName().getAsString());
+        << ClassName << CorrectedName;
+      Diag(IDecl->getLocation(), diag::note_previous_decl) << CorrectedName
+        << FixItHint::CreateReplacement(ClassLoc, CorrectedName.getAsString());
       IDecl = 0;
     } else {
       Diag(ClassLoc, diag::warn_undef_interface) << ClassName;

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jun 28 11:20:02 2011
@@ -1397,39 +1397,44 @@
   }
 
   // We didn't find anything, so try to correct for a typo.
-  DeclarationName Corrected;
-  if (S && (Corrected = CorrectTypo(R, S, &SS, 0, false, CTC))) {
-    if (!R.empty()) {
-      if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) {
+  TypoCorrection Corrected;
+  if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
+                                    S, &SS, NULL, false, CTC))) {
+    std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+    std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
+    R.setLookupName(Corrected.getCorrection());
+
+    if (!Corrected.isKeyword()) {
+      NamedDecl *ND = Corrected.getCorrectionDecl();
+      R.addDecl(ND);
+      if (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND)) {
         if (SS.isEmpty())
-          Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName()
-            << FixItHint::CreateReplacement(R.getNameLoc(),
-                                            R.getLookupName().getAsString());
+          Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr
+            << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
         else
           Diag(R.getNameLoc(), diag::err_no_member_suggest)
-            << Name << computeDeclContext(SS, false) << R.getLookupName()
+            << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
             << SS.getRange()
-            << FixItHint::CreateReplacement(R.getNameLoc(),
-                                            R.getLookupName().getAsString());
-        if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+            << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+        if (ND)
           Diag(ND->getLocation(), diag::note_previous_decl)
-            << ND->getDeclName();
+            << CorrectedQuotedStr;
 
         // Tell the callee to try to recover.
         return false;
       }
 
-      if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) {
+      if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) {
         // FIXME: If we ended up with a typo for a type name or
         // Objective-C class name, we're in trouble because the parser
         // is in the wrong place to recover. Suggest the typo
         // correction, but don't make it a fix-it since we're not going
         // to recover well anyway.
         if (SS.isEmpty())
-          Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName();
+          Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
         else
           Diag(R.getNameLoc(), diag::err_no_member_suggest)
-            << Name << computeDeclContext(SS, false) << R.getLookupName()
+            << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
             << SS.getRange();
 
         // Don't try to recover; it won't work.
@@ -1439,15 +1444,15 @@
       // FIXME: We found a keyword. Suggest it, but don't provide a fix-it
       // because we aren't able to recover.
       if (SS.isEmpty())
-        Diag(R.getNameLoc(), diagnostic_suggest) << Name << Corrected;
+        Diag(R.getNameLoc(), diagnostic_suggest) << Name << CorrectedQuotedStr;
       else
         Diag(R.getNameLoc(), diag::err_no_member_suggest)
-        << Name << computeDeclContext(SS, false) << Corrected
+        << Name << computeDeclContext(SS, false) << CorrectedQuotedStr
         << SS.getRange();
       return true;
     }
-    R.clear();
   }
+  R.clear();
 
   // Emit a special diagnostic for failed member lookups.
   // FIXME: computing the declaration context might fail here (?)

Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprMember.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprMember.cpp Tue Jun 28 11:20:02 2011
@@ -555,20 +555,24 @@
   // We didn't find anything with the given name, so try to correct
   // for typos.
   DeclarationName Name = R.getLookupName();
-  if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) &&
-      !R.empty() &&
-      (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) {
+  TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
+                                                 R.getLookupKind(), NULL,
+                                                 &SS, DC, false,
+                                                 Sema::CTC_MemberLookup);
+  NamedDecl *ND = Corrected.getCorrectionDecl();
+  R.clear();
+  if (ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND))) {
+    std::string CorrectedStr(
+        Corrected.getAsString(SemaRef.getLangOptions()));
+    std::string CorrectedQuotedStr(
+        Corrected.getQuoted(SemaRef.getLangOptions()));
+    R.setLookupName(Corrected.getCorrection());
+    R.addDecl(ND);
     SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest)
-      << Name << DC << R.getLookupName() << SS.getRange()
-      << FixItHint::CreateReplacement(R.getNameLoc(),
-                                      R.getLookupName().getAsString());
-    if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
-      SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
-        << ND->getDeclName();
-    return false;
-  } else {
-    R.clear();
-    R.setLookupName(Name);
+      << Name << DC << CorrectedQuotedStr << SS.getRange()
+      << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr);
+    SemaRef.Diag(ND->getLocation(), diag::note_previous_decl)
+      << ND->getDeclName();
   }
 
   return false;
@@ -1068,10 +1072,10 @@
       // Attempt to correct for typos in ivar names.
       LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
                        LookupMemberName);
-      if (CorrectTypo(Res, 0, 0, IDecl, false, 
-                      IsArrow ? CTC_ObjCIvarLookup
-                              : CTC_ObjCPropertyLookup) &&
-          (IV = Res.getAsSingle<ObjCIvarDecl>())) {
+      TypoCorrection Corrected = CorrectTypo(
+          R.getLookupNameInfo(), LookupMemberName, NULL, NULL, IDecl, false,
+          IsArrow ? CTC_ObjCIvarLookup : CTC_ObjCPropertyLookup);
+      if ((IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>())) {
         Diag(R.getNameLoc(),
              diag::err_typecheck_member_reference_ivar_suggest)
           << IDecl->getDeclName() << MemberName << IV->getDeclName()

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Tue Jun 28 11:20:02 2011
@@ -663,14 +663,15 @@
   }
 
   // Attempt to correct for typos in property names.
-  LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName);
-  if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) &&
-      Res.getAsSingle<ObjCPropertyDecl>()) {
-    DeclarationName TypoResult = Res.getLookupName();
+  TypoCorrection Corrected = CorrectTypo(
+      DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
+      NULL, IFace, false, CTC_NoKeywords, OPT);
+  if (ObjCPropertyDecl *Property =
+      Corrected.getCorrectionDeclAs<ObjCPropertyDecl>()) {
+    DeclarationName TypoResult = Corrected.getCorrection();
     Diag(MemberLoc, diag::err_property_not_found_suggest)
       << MemberName << QualType(OPT, 0) << TypoResult
       << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString());
-    ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>();
     Diag(Property->getLocation(), diag::note_previous_decl)
       << Property->getDeclName();
     return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc,
@@ -898,29 +899,30 @@
         Method->getClassInterface()->getSuperClass())
       CTC = CTC_ObjCMessageReceiver;
       
-  if (DeclarationName Corrected = CorrectTypo(Result, S, 0, 0, false, CTC)) {
-    if (Result.isSingleResult()) {
+  if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
+                                             Result.getLookupKind(), S, NULL,
+                                             NULL, false, CTC)) {
+    if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
       // If we found a declaration, correct when it refers to an Objective-C
       // class.
-      NamedDecl *ND = Result.getFoundDecl();
       if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) {
         Diag(NameLoc, diag::err_unknown_receiver_suggest)
-          << Name << Result.getLookupName()
+          << Name << Corrected.getCorrection()
           << FixItHint::CreateReplacement(SourceRange(NameLoc),
                                           ND->getNameAsString());
         Diag(ND->getLocation(), diag::note_previous_decl)
-          << Corrected;
+          << Corrected.getCorrection();
 
         QualType T = Context.getObjCInterfaceType(Class);
         TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc);
         ReceiverType = CreateParsedType(T, TSInfo);
         return ObjCClassMessage;
       }
-    } else if (Result.empty() && Corrected.getAsIdentifierInfo() &&
-               Corrected.getAsIdentifierInfo()->isStr("super")) {
+    } else if (Corrected.isKeyword() &&
+               Corrected.getCorrectionAsIdentifierInfo()->isStr("super")) {
       // If we've found the keyword "super", this is a send to super.
       Diag(NameLoc, diag::err_unknown_receiver_suggest)
-        << Name << Corrected
+        << Name << Corrected.getCorrection()
         << FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
       return ObjCSuperMessage;
     }

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Jun 28 11:20:02 2011
@@ -1443,19 +1443,23 @@
         // was a typo for another field name.
         LookupResult R(SemaRef, FieldName, D->getFieldLoc(),
                        Sema::LookupMemberName);
-        if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false,
-                                Sema::CTC_NoKeywords) &&
-            (ReplacementField = R.getAsSingle<FieldDecl>()) &&
+        TypoCorrection Corrected = SemaRef.CorrectTypo(
+            DeclarationNameInfo(FieldName, D->getFieldLoc()),
+            Sema::LookupMemberName, /*Scope=*/NULL, /*SS=*/NULL,
+            RT->getDecl(), false, Sema::CTC_NoKeywords);
+        if ((ReplacementField = Corrected.getCorrectionDeclAs<FieldDecl>()) &&
             ReplacementField->getDeclContext()->getRedeclContext()
                                                       ->Equals(RT->getDecl())) {
+          std::string CorrectedStr(
+              Corrected.getAsString(SemaRef.getLangOptions()));
+          std::string CorrectedQuotedStr(
+              Corrected.getQuoted(SemaRef.getLangOptions()));
           SemaRef.Diag(D->getFieldLoc(),
                        diag::err_field_designator_unknown_suggest)
-            << FieldName << CurrentObjectType << R.getLookupName()
-            << FixItHint::CreateReplacement(D->getFieldLoc(),
-                                            R.getLookupName().getAsString());
+            << FieldName << CurrentObjectType << CorrectedQuotedStr
+            << FixItHint::CreateReplacement(D->getFieldLoc(), CorrectedStr);
           SemaRef.Diag(ReplacementField->getLocation(),
-                       diag::note_previous_decl)
-            << ReplacementField->getDeclName();
+                       diag::note_previous_decl) << CorrectedQuotedStr;
         } else {
           SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown)
             << FieldName << CurrentObjectType;

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Tue Jun 28 11:20:02 2011
@@ -20,6 +20,7 @@
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/TemplateDeduction.h"
 #include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/TypoCorrection.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/Decl.h"
@@ -42,6 +43,7 @@
 #include <iterator>
 #include <utility>
 #include <algorithm>
+#include <map>
 
 using namespace clang;
 using namespace sema;
@@ -3041,6 +3043,12 @@
 //===----------------------------------------------------------------------===//
 
 namespace {
+
+typedef llvm::StringMap<TypoCorrection, llvm::BumpPtrAllocator> TypoResultsMap;
+typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
+
+static const unsigned MaxTypoDistanceResultSets = 5;
+
 class TypoCorrectionConsumer : public VisibleDeclConsumer {
   /// \brief The name written that is a typo in the source.
   llvm::StringRef Typo;
@@ -3048,33 +3056,47 @@
   /// \brief The results found that have the smallest edit distance
   /// found (so far) with the typo name.
   ///
-  /// The boolean value indicates whether there is a keyword with this name.
-  llvm::StringMap<bool, llvm::BumpPtrAllocator> BestResults;
+  /// The pointer value being set to the current DeclContext indicates
+  /// whether there is a keyword with this name.
+  TypoEditDistanceMap BestResults;
 
-  /// \brief The best edit distance found so far.
-  unsigned BestEditDistance;
+  /// \brief The worst of the best N edit distances found so far.
+  unsigned MaxEditDistance;
+
+  Sema &SemaRef;
 
 public:
-  explicit TypoCorrectionConsumer(IdentifierInfo *Typo)
+  explicit TypoCorrectionConsumer(Sema &SemaRef, IdentifierInfo *Typo)
     : Typo(Typo->getName()),
-      BestEditDistance((std::numeric_limits<unsigned>::max)()) { }
+      MaxEditDistance((std::numeric_limits<unsigned>::max)()),
+      SemaRef(SemaRef) { }
 
   virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass);
   void FoundName(llvm::StringRef Name);
-  void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword);
-
-  typedef llvm::StringMap<bool, llvm::BumpPtrAllocator>::iterator iterator;
-  iterator begin() { return BestResults.begin(); }
-  iterator end()  { return BestResults.end(); }
-  void erase(iterator I) { BestResults.erase(I); }
+  void addKeywordResult(llvm::StringRef Keyword);
+  void addName(llvm::StringRef Name, NamedDecl *ND, unsigned Distance,
+               NestedNameSpecifier *NNS=NULL);
+  void addCorrection(TypoCorrection Correction);
+
+  typedef TypoResultsMap::iterator result_iterator;
+  typedef TypoEditDistanceMap::iterator distance_iterator;
+  distance_iterator begin() { return BestResults.begin(); }
+  distance_iterator end()  { return BestResults.end(); }
+  void erase(distance_iterator I) { BestResults.erase(I); }
   unsigned size() const { return BestResults.size(); }
   bool empty() const { return BestResults.empty(); }
 
-  bool &operator[](llvm::StringRef Name) {
-    return BestResults[Name];
+  TypoCorrection &operator[](llvm::StringRef Name) {
+    return BestResults.begin()->second[Name];
   }
 
-  unsigned getBestEditDistance() const { return BestEditDistance; }
+  unsigned getMaxEditDistance() const {
+    return MaxEditDistance;
+  }
+
+  unsigned getBestEditDistance() {
+    return (BestResults.empty()) ? MaxEditDistance : BestResults.begin()->first;
+  }
 };
 
 }
@@ -3099,55 +3121,164 @@
   // Use a simple length-based heuristic to determine the minimum possible
   // edit distance. If the minimum isn't good enough, bail out early.
   unsigned MinED = abs((int)Name.size() - (int)Typo.size());
-  if (MinED > BestEditDistance || (MinED && Typo.size() / MinED < 3))
+  if (MinED > MaxEditDistance || (MinED && Typo.size() / MinED < 3))
     return;
 
   // Compute an upper bound on the allowable edit distance, so that the
   // edit-distance algorithm can short-circuit.
   unsigned UpperBound =
-    std::min(unsigned((Typo.size() + 2) / 3), BestEditDistance);
+    std::min(unsigned((Typo.size() + 2) / 3), MaxEditDistance);
 
   // Compute the edit distance between the typo and the name of this
   // entity. If this edit distance is not worse than the best edit
   // distance we've seen so far, add it to the list of results.
   unsigned ED = Typo.edit_distance(Name, true, UpperBound);
-  if (ED == 0)
-    return;
 
-  if (ED < BestEditDistance) {
-    // This result is better than any we've seen before; clear out
-    // the previous results.
-    BestResults.clear();
-    BestEditDistance = ED;
-  } else if (ED > BestEditDistance) {
+  if (ED > MaxEditDistance) {
     // This result is worse than the best results we've seen so far;
     // ignore it.
     return;
   }
 
-  // Add this name to the list of results. By not assigning a value, we
-  // keep the current value if we've seen this name before (either as a
-  // keyword or as a declaration), or get the default value (not a keyword)
-  // if we haven't seen it before.
-  (void)BestResults[Name];
+  addName(Name, NULL, ED);
 }
 
-void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context,
-                                              llvm::StringRef Keyword) {
+void TypoCorrectionConsumer::addKeywordResult(llvm::StringRef Keyword) {
   // Compute the edit distance between the typo and this keyword.
   // If this edit distance is not worse than the best edit
   // distance we've seen so far, add it to the list of results.
   unsigned ED = Typo.edit_distance(Keyword);
-  if (ED < BestEditDistance) {
-    BestResults.clear();
-    BestEditDistance = ED;
-  } else if (ED > BestEditDistance) {
+  if (ED > MaxEditDistance) {
     // This result is worse than the best results we've seen so far;
     // ignore it.
     return;
   }
 
-  BestResults[Keyword] = true;
+  addName(Keyword, TypoCorrection::KeywordDecl(), ED);
+}
+
+void TypoCorrectionConsumer::addName(llvm::StringRef Name,
+                                     NamedDecl *ND,
+                                     unsigned Distance,
+                                     NestedNameSpecifier *NNS) {
+  addCorrection(TypoCorrection(&SemaRef.Context.Idents.get(Name),
+                               ND, NNS, Distance));
+}
+
+void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
+  llvm::StringRef Name = Correction.getCorrectionAsIdentifierInfo()->getName();
+  BestResults[Correction.getEditDistance()][Name] = Correction;
+
+  while (BestResults.size() > MaxTypoDistanceResultSets) {
+    BestResults.erase(--BestResults.end());
+  }
+}
+
+namespace {
+
+class SpecifierInfo {
+ public:
+  DeclContext* DeclCtx;
+  NestedNameSpecifier* NameSpecifier;
+  unsigned EditDistance;
+
+  SpecifierInfo(DeclContext *Ctx, NestedNameSpecifier *NNS, unsigned ED)
+      : DeclCtx(Ctx), NameSpecifier(NNS), EditDistance(ED) {}
+};
+
+typedef llvm::SmallVector<DeclContext*, 4> DeclContextList;
+typedef llvm::SmallVector<SpecifierInfo, 16> SpecifierInfoList;
+
+class NamespaceSpecifierSet {
+  ASTContext &Context;
+  DeclContextList CurContextChain;
+  bool isSorted;
+
+  SpecifierInfoList Specifiers;
+  llvm::SmallSetVector<unsigned, 4> Distances;
+  llvm::DenseMap<unsigned, SpecifierInfoList> DistanceMap;
+
+  /// \brief Helper for building the list of DeclContexts between the current
+  /// context and the top of the translation unit
+  static DeclContextList BuildContextChain(DeclContext *Start);
+
+  void SortNamespaces();
+
+ public:
+  explicit NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext)
+      : Context(Context), CurContextChain(BuildContextChain(CurContext)) {}
+
+  /// \brief Add the namespace to the set, computing the corresponding
+  /// NestedNameSpecifier and its distance in the process.
+  void AddNamespace(NamespaceDecl *ND);
+
+  typedef SpecifierInfoList::iterator iterator;
+  iterator begin() {
+    if (!isSorted) SortNamespaces();
+    return Specifiers.begin();
+  }
+  iterator end() { return Specifiers.end(); }
+};
+
+}
+
+DeclContextList NamespaceSpecifierSet::BuildContextChain(DeclContext *Start) {
+  DeclContextList Chain;
+  for (DeclContext *DC = Start->getPrimaryContext(); DC != NULL;
+       DC = DC->getLookupParent()) {
+    NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(DC);
+    if (!DC->isInlineNamespace() && !DC->isTransparentContext() &&
+        !(ND && ND->isAnonymousNamespace()))
+      Chain.push_back(DC->getPrimaryContext());
+  }
+  return Chain;
+}
+
+void NamespaceSpecifierSet::SortNamespaces() {
+  llvm::SmallVector<unsigned, 4> sortedDistances;
+  sortedDistances.append(Distances.begin(), Distances.end());
+
+  if (sortedDistances.size() > 1)
+    std::sort(sortedDistances.begin(), sortedDistances.end());
+
+  Specifiers.clear();
+  for (llvm::SmallVector<unsigned, 4>::iterator DI = sortedDistances.begin(),
+                                             DIEnd = sortedDistances.end();
+       DI != DIEnd; ++DI) {
+    SpecifierInfoList &SpecList = DistanceMap[*DI];
+    Specifiers.append(SpecList.begin(), SpecList.end());
+  }
+
+  isSorted = true;
+}
+
+void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) {
+  DeclContext *Ctx = dyn_cast<DeclContext>(ND);
+  NestedNameSpecifier *NNS = NULL;
+  unsigned NumSpecifiers = 0;
+  DeclContextList NamespaceDeclChain(BuildContextChain(Ctx));
+
+  // Eliminate common elements from the two DeclContext chains
+  for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(),
+                                      CEnd = CurContextChain.rend();
+       C != CEnd && NamespaceDeclChain.back() == *C; ++C) {
+    NamespaceDeclChain.pop_back();
+  }
+
+  // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain
+  for (DeclContextList::reverse_iterator C = NamespaceDeclChain.rbegin(),
+                                      CEnd = NamespaceDeclChain.rend();
+       C != CEnd; ++C) {
+    NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C);
+    if (ND) {
+      NNS = NestedNameSpecifier::Create(Context, NNS, ND);
+      ++NumSpecifiers;
+    }
+  }
+
+  isSorted = false;
+  Distances.insert(NumSpecifiers);
+  DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers));
 }
 
 /// \brief Perform name lookup for a possible result for typo correction.
@@ -3201,177 +3332,60 @@
   }
 }
 
-/// \brief Try to "correct" a typo in the source code by finding
-/// visible declarations whose names are similar to the name that was
-/// present in the source code.
-///
-/// \param Res the \c LookupResult structure that contains the name
-/// that was present in the source code along with the name-lookup
-/// criteria used to search for the name. On success, this structure
-/// will contain the results of name lookup.
-///
-/// \param S the scope in which name lookup occurs.
-///
-/// \param SS the nested-name-specifier that precedes the name we're
-/// looking for, if present.
-///
-/// \param MemberContext if non-NULL, the context in which to look for
-/// a member access expression.
-///
-/// \param EnteringContext whether we're entering the context described by
-/// the nested-name-specifier SS.
-///
-/// \param CTC The context in which typo correction occurs, which impacts the
-/// set of keywords permitted.
-///
-/// \param OPT when non-NULL, the search for visible declarations will
-/// also walk the protocols in the qualified interfaces of \p OPT.
-///
-/// \returns the corrected name if the typo was corrected, otherwise returns an
-/// empty \c DeclarationName. When a typo was corrected, the result structure
-/// may contain the results of name lookup for the correct name or it may be
-/// empty.
-DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS,
-                                  DeclContext *MemberContext,
-                                  bool EnteringContext,
-                                  CorrectTypoContext CTC,
-                                  const ObjCObjectPointerType *OPT) {
-  if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking)
-    return DeclarationName();
-
-  // We only attempt to correct typos for identifiers.
-  IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo();
-  if (!Typo)
-    return DeclarationName();
-
-  // If the scope specifier itself was invalid, don't try to correct
-  // typos.
-  if (SS && SS->isInvalid())
-    return DeclarationName();
-
-  // Never try to correct typos during template deduction or
-  // instantiation.
-  if (!ActiveTemplateInstantiations.empty())
-    return DeclarationName();
-
-  TypoCorrectionConsumer Consumer(Typo);
-
-  // Perform name lookup to find visible, similarly-named entities.
-  bool IsUnqualifiedLookup = false;
-  if (MemberContext) {
-    LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer);
-
-    // Look in qualified interfaces.
-    if (OPT) {
-      for (ObjCObjectPointerType::qual_iterator
-             I = OPT->qual_begin(), E = OPT->qual_end();
-           I != E; ++I)
-        LookupVisibleDecls(*I, Res.getLookupKind(), Consumer);
-    }
-  } else if (SS && SS->isSet()) {
-    DeclContext *DC = computeDeclContext(*SS, EnteringContext);
-    if (!DC)
-      return DeclarationName();
-
-    // Provide a stop gap for files that are just seriously broken.  Trying
-    // to correct all typos can turn into a HUGE performance penalty, causing
-    // some files to take minutes to get rejected by the parser.
-    if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
-      return DeclarationName();
-    ++TyposCorrected;
-
-    LookupVisibleDecls(DC, Res.getLookupKind(), Consumer);
-  } else {
-    IsUnqualifiedLookup = true;
-    UnqualifiedTyposCorrectedMap::iterator Cached
-      = UnqualifiedTyposCorrected.find(Typo);
-    if (Cached == UnqualifiedTyposCorrected.end()) {
-      // Provide a stop gap for files that are just seriously broken.  Trying
-      // to correct all typos can turn into a HUGE performance penalty, causing
-      // some files to take minutes to get rejected by the parser.
-      if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
-        return DeclarationName();
-
-      // For unqualified lookup, look through all of the names that we have
-      // seen in this translation unit.
-      for (IdentifierTable::iterator I = Context.Idents.begin(),
-                                  IEnd = Context.Idents.end();
-           I != IEnd; ++I)
-        Consumer.FoundName(I->getKey());
-
-      // Walk through identifiers in external identifier sources.
-      if (IdentifierInfoLookup *External
-                              = Context.Idents.getExternalIdentifierLookup()) {
-        llvm::OwningPtr<IdentifierIterator> Iter(External->getIdentifiers());
-        do {
-          llvm::StringRef Name = Iter->Next();
-          if (Name.empty())
-            break;
-
-          Consumer.FoundName(Name);
-        } while (true);
-      }
-    } else {
-      // Use the cached value, unless it's a keyword. In the keyword case, we'll
-      // end up adding the keyword below.
-      if (Cached->second.first.empty())
-        return DeclarationName();
-
-      if (!Cached->second.second)
-        Consumer.FoundName(Cached->second.first);
-    }
-  }
-
+/// \brief Add keywords to the consumer as possible typo corrections.
+static void AddKeywordsToConsumer(Sema &SemaRef,
+                                  TypoCorrectionConsumer &Consumer,
+                                  Scope *S, Sema::CorrectTypoContext CTC) {
   // Add context-dependent keywords.
   bool WantTypeSpecifiers = false;
   bool WantExpressionKeywords = false;
   bool WantCXXNamedCasts = false;
   bool WantRemainingKeywords = false;
   switch (CTC) {
-    case CTC_Unknown:
+    case Sema::CTC_Unknown:
       WantTypeSpecifiers = true;
       WantExpressionKeywords = true;
       WantCXXNamedCasts = true;
       WantRemainingKeywords = true;
 
-      if (ObjCMethodDecl *Method = getCurMethodDecl())
+      if (ObjCMethodDecl *Method = SemaRef.getCurMethodDecl())
         if (Method->getClassInterface() &&
             Method->getClassInterface()->getSuperClass())
-          Consumer.addKeywordResult(Context, "super");
+          Consumer.addKeywordResult("super");
 
       break;
 
-    case CTC_NoKeywords:
+    case Sema::CTC_NoKeywords:
       break;
 
-    case CTC_Type:
+    case Sema::CTC_Type:
       WantTypeSpecifiers = true;
       break;
 
-    case CTC_ObjCMessageReceiver:
-      Consumer.addKeywordResult(Context, "super");
+    case Sema::CTC_ObjCMessageReceiver:
+      Consumer.addKeywordResult("super");
       // Fall through to handle message receivers like expressions.
 
-    case CTC_Expression:
-      if (getLangOptions().CPlusPlus)
+    case Sema::CTC_Expression:
+      if (SemaRef.getLangOptions().CPlusPlus)
         WantTypeSpecifiers = true;
       WantExpressionKeywords = true;
       // Fall through to get C++ named casts.
 
-    case CTC_CXXCasts:
+    case Sema::CTC_CXXCasts:
       WantCXXNamedCasts = true;
       break;
 
-    case CTC_ObjCPropertyLookup:
+    case Sema::CTC_ObjCPropertyLookup:
       // FIXME: Add "isa"?
       break;
 
-    case CTC_MemberLookup:
-      if (getLangOptions().CPlusPlus)
-        Consumer.addKeywordResult(Context, "template");
+    case Sema::CTC_MemberLookup:
+      if (SemaRef.getLangOptions().CPlusPlus)
+        Consumer.addKeywordResult("template");
       break;
 
-    case CTC_ObjCIvarLookup:
+    case Sema::CTC_ObjCIvarLookup:
       break;
   }
 
@@ -3387,240 +3401,449 @@
 
     const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]);
     for (unsigned I = 0; I != NumCTypeSpecs; ++I)
-      Consumer.addKeywordResult(Context, CTypeSpecs[I]);
+      Consumer.addKeywordResult(CTypeSpecs[I]);
 
-    if (getLangOptions().C99)
-      Consumer.addKeywordResult(Context, "restrict");
-    if (getLangOptions().Bool || getLangOptions().CPlusPlus)
-      Consumer.addKeywordResult(Context, "bool");
+    if (SemaRef.getLangOptions().C99)
+      Consumer.addKeywordResult("restrict");
+    if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus)
+      Consumer.addKeywordResult("bool");
 
-    if (getLangOptions().CPlusPlus) {
-      Consumer.addKeywordResult(Context, "class");
-      Consumer.addKeywordResult(Context, "typename");
-      Consumer.addKeywordResult(Context, "wchar_t");
+    if (SemaRef.getLangOptions().CPlusPlus) {
+      Consumer.addKeywordResult("class");
+      Consumer.addKeywordResult("typename");
+      Consumer.addKeywordResult("wchar_t");
 
-      if (getLangOptions().CPlusPlus0x) {
-        Consumer.addKeywordResult(Context, "char16_t");
-        Consumer.addKeywordResult(Context, "char32_t");
-        Consumer.addKeywordResult(Context, "constexpr");
-        Consumer.addKeywordResult(Context, "decltype");
-        Consumer.addKeywordResult(Context, "thread_local");
+      if (SemaRef.getLangOptions().CPlusPlus0x) {
+        Consumer.addKeywordResult("char16_t");
+        Consumer.addKeywordResult("char32_t");
+        Consumer.addKeywordResult("constexpr");
+        Consumer.addKeywordResult("decltype");
+        Consumer.addKeywordResult("thread_local");
       }
     }
 
-    if (getLangOptions().GNUMode)
-      Consumer.addKeywordResult(Context, "typeof");
+    if (SemaRef.getLangOptions().GNUMode)
+      Consumer.addKeywordResult("typeof");
   }
 
-  if (WantCXXNamedCasts && getLangOptions().CPlusPlus) {
-    Consumer.addKeywordResult(Context, "const_cast");
-    Consumer.addKeywordResult(Context, "dynamic_cast");
-    Consumer.addKeywordResult(Context, "reinterpret_cast");
-    Consumer.addKeywordResult(Context, "static_cast");
+  if (WantCXXNamedCasts && SemaRef.getLangOptions().CPlusPlus) {
+    Consumer.addKeywordResult("const_cast");
+    Consumer.addKeywordResult("dynamic_cast");
+    Consumer.addKeywordResult("reinterpret_cast");
+    Consumer.addKeywordResult("static_cast");
   }
 
   if (WantExpressionKeywords) {
-    Consumer.addKeywordResult(Context, "sizeof");
-    if (getLangOptions().Bool || getLangOptions().CPlusPlus) {
-      Consumer.addKeywordResult(Context, "false");
-      Consumer.addKeywordResult(Context, "true");
+    Consumer.addKeywordResult("sizeof");
+    if (SemaRef.getLangOptions().Bool || SemaRef.getLangOptions().CPlusPlus) {
+      Consumer.addKeywordResult("false");
+      Consumer.addKeywordResult("true");
     }
 
-    if (getLangOptions().CPlusPlus) {
+    if (SemaRef.getLangOptions().CPlusPlus) {
       const char *CXXExprs[] = {
         "delete", "new", "operator", "throw", "typeid"
       };
       const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]);
       for (unsigned I = 0; I != NumCXXExprs; ++I)
-        Consumer.addKeywordResult(Context, CXXExprs[I]);
+        Consumer.addKeywordResult(CXXExprs[I]);
 
-      if (isa<CXXMethodDecl>(CurContext) &&
-          cast<CXXMethodDecl>(CurContext)->isInstance())
-        Consumer.addKeywordResult(Context, "this");
-
-      if (getLangOptions().CPlusPlus0x) {
-        Consumer.addKeywordResult(Context, "alignof");
-        Consumer.addKeywordResult(Context, "nullptr");
+      if (isa<CXXMethodDecl>(SemaRef.CurContext) &&
+          cast<CXXMethodDecl>(SemaRef.CurContext)->isInstance())
+        Consumer.addKeywordResult("this");
+
+      if (SemaRef.getLangOptions().CPlusPlus0x) {
+        Consumer.addKeywordResult("alignof");
+        Consumer.addKeywordResult("nullptr");
       }
     }
   }
 
   if (WantRemainingKeywords) {
-    if (getCurFunctionOrMethodDecl() || getCurBlock()) {
+    if (SemaRef.getCurFunctionOrMethodDecl() || SemaRef.getCurBlock()) {
       // Statements.
       const char *CStmts[] = {
         "do", "else", "for", "goto", "if", "return", "switch", "while" };
       const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]);
       for (unsigned I = 0; I != NumCStmts; ++I)
-        Consumer.addKeywordResult(Context, CStmts[I]);
+        Consumer.addKeywordResult(CStmts[I]);
 
-      if (getLangOptions().CPlusPlus) {
-        Consumer.addKeywordResult(Context, "catch");
-        Consumer.addKeywordResult(Context, "try");
+      if (SemaRef.getLangOptions().CPlusPlus) {
+        Consumer.addKeywordResult("catch");
+        Consumer.addKeywordResult("try");
       }
 
       if (S && S->getBreakParent())
-        Consumer.addKeywordResult(Context, "break");
+        Consumer.addKeywordResult("break");
 
       if (S && S->getContinueParent())
-        Consumer.addKeywordResult(Context, "continue");
+        Consumer.addKeywordResult("continue");
 
-      if (!getCurFunction()->SwitchStack.empty()) {
-        Consumer.addKeywordResult(Context, "case");
-        Consumer.addKeywordResult(Context, "default");
+      if (!SemaRef.getCurFunction()->SwitchStack.empty()) {
+        Consumer.addKeywordResult("case");
+        Consumer.addKeywordResult("default");
       }
     } else {
-      if (getLangOptions().CPlusPlus) {
-        Consumer.addKeywordResult(Context, "namespace");
-        Consumer.addKeywordResult(Context, "template");
+      if (SemaRef.getLangOptions().CPlusPlus) {
+        Consumer.addKeywordResult("namespace");
+        Consumer.addKeywordResult("template");
       }
 
       if (S && S->isClassScope()) {
-        Consumer.addKeywordResult(Context, "explicit");
-        Consumer.addKeywordResult(Context, "friend");
-        Consumer.addKeywordResult(Context, "mutable");
-        Consumer.addKeywordResult(Context, "private");
-        Consumer.addKeywordResult(Context, "protected");
-        Consumer.addKeywordResult(Context, "public");
-        Consumer.addKeywordResult(Context, "virtual");
+        Consumer.addKeywordResult("explicit");
+        Consumer.addKeywordResult("friend");
+        Consumer.addKeywordResult("mutable");
+        Consumer.addKeywordResult("private");
+        Consumer.addKeywordResult("protected");
+        Consumer.addKeywordResult("public");
+        Consumer.addKeywordResult("virtual");
       }
     }
 
-    if (getLangOptions().CPlusPlus) {
-      Consumer.addKeywordResult(Context, "using");
+    if (SemaRef.getLangOptions().CPlusPlus) {
+      Consumer.addKeywordResult("using");
+
+      if (SemaRef.getLangOptions().CPlusPlus0x)
+        Consumer.addKeywordResult("static_assert");
+    }
+  }
+}
+
+/// \brief Try to "correct" a typo in the source code by finding
+/// visible declarations whose names are similar to the name that was
+/// present in the source code.
+///
+/// \param TypoName the \c DeclarationNameInfo structure that contains
+/// the name that was present in the source code along with its location.
+///
+/// \param LookupKind the name-lookup criteria used to search for the name.
+///
+/// \param S the scope in which name lookup occurs.
+///
+/// \param SS the nested-name-specifier that precedes the name we're
+/// looking for, if present.
+///
+/// \param MemberContext if non-NULL, the context in which to look for
+/// a member access expression.
+///
+/// \param EnteringContext whether we're entering the context described by
+/// the nested-name-specifier SS.
+///
+/// \param CTC The context in which typo correction occurs, which impacts the
+/// set of keywords permitted.
+///
+/// \param OPT when non-NULL, the search for visible declarations will
+/// also walk the protocols in the qualified interfaces of \p OPT.
+///
+/// \returns a \c TypoCorrection containing the corrected name if the typo
+/// along with information such as the \c NamedDecl where the corrected name
+/// was declared, and any additional \c NestedNameSpecifier needed to access
+/// it (C++ only). The \c TypoCorrection is empty if there is no correction.
+TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
+                                 Sema::LookupNameKind LookupKind,
+                                 Scope *S, CXXScopeSpec *SS,
+                                 DeclContext *MemberContext,
+                                 bool EnteringContext,
+                                 CorrectTypoContext CTC,
+                                 const ObjCObjectPointerType *OPT) {
+  if (Diags.hasFatalErrorOccurred() || !getLangOptions().SpellChecking)
+    return TypoCorrection();
+
+  // We only attempt to correct typos for identifiers.
+  IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
+  if (!Typo)
+    return TypoCorrection();
 
-      if (getLangOptions().CPlusPlus0x)
-        Consumer.addKeywordResult(Context, "static_assert");
+  // If the scope specifier itself was invalid, don't try to correct
+  // typos.
+  if (SS && SS->isInvalid())
+    return TypoCorrection();
+
+  // Never try to correct typos during template deduction or
+  // instantiation.
+  if (!ActiveTemplateInstantiations.empty())
+    return TypoCorrection();
+
+  NamespaceSpecifierSet Namespaces(Context, CurContext);
+
+  TypoCorrectionConsumer Consumer(*this, Typo);
+
+  // Perform name lookup to find visible, similarly-named entities.
+  bool IsUnqualifiedLookup = false;
+  if (MemberContext) {
+    LookupVisibleDecls(MemberContext, LookupKind, Consumer);
+
+    // Look in qualified interfaces.
+    if (OPT) {
+      for (ObjCObjectPointerType::qual_iterator
+             I = OPT->qual_begin(), E = OPT->qual_end();
+           I != E; ++I)
+        LookupVisibleDecls(*I, LookupKind, Consumer);
+    }
+  } else if (SS && SS->isSet()) {
+    DeclContext *DC = computeDeclContext(*SS, EnteringContext);
+    if (!DC)
+      return TypoCorrection();
+
+    // Provide a stop gap for files that are just seriously broken.  Trying
+    // to correct all typos can turn into a HUGE performance penalty, causing
+    // some files to take minutes to get rejected by the parser.
+    if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
+      return TypoCorrection();
+    ++TyposCorrected;
+
+    LookupVisibleDecls(DC, LookupKind, Consumer);
+  } else {
+    IsUnqualifiedLookup = true;
+    UnqualifiedTyposCorrectedMap::iterator Cached
+      = UnqualifiedTyposCorrected.find(Typo);
+    if (Cached == UnqualifiedTyposCorrected.end()) {
+      // Provide a stop gap for files that are just seriously broken.  Trying
+      // to correct all typos can turn into a HUGE performance penalty, causing
+      // some files to take minutes to get rejected by the parser.
+      if (TyposCorrected + UnqualifiedTyposCorrected.size() >= 20)
+        return TypoCorrection();
+
+      // For unqualified lookup, look through all of the names that we have
+      // seen in this translation unit.
+      for (IdentifierTable::iterator I = Context.Idents.begin(),
+                                  IEnd = Context.Idents.end();
+           I != IEnd; ++I)
+        Consumer.FoundName(I->getKey());
+
+      // Walk through identifiers in external identifier sources.
+      if (IdentifierInfoLookup *External
+                              = Context.Idents.getExternalIdentifierLookup()) {
+        llvm::OwningPtr<IdentifierIterator> Iter(External->getIdentifiers());
+        do {
+          llvm::StringRef Name = Iter->Next();
+          if (Name.empty())
+            break;
+
+          Consumer.FoundName(Name);
+        } while (true);
+      }
+    } else {
+      // Use the cached value, unless it's a keyword. In the keyword case, we'll
+      // end up adding the keyword below.
+      if (!Cached->second)
+        return TypoCorrection();
+
+      if (!Cached->second.isKeyword())
+        Consumer.addCorrection(Cached->second);
     }
   }
 
+  AddKeywordsToConsumer(*this, Consumer, S,  CTC);
+
   // If we haven't found anything, we're done.
   if (Consumer.empty()) {
     // If this was an unqualified lookup, note that no correction was found.
     if (IsUnqualifiedLookup)
       (void)UnqualifiedTyposCorrected[Typo];
 
-    return DeclarationName();
+    return TypoCorrection();
   }
 
   // Make sure that the user typed at least 3 characters for each correction
   // made. Otherwise, we don't even both looking at the results.
-
-  // We also suppress exact matches; those should be handled by a
-  // different mechanism (e.g., one that introduces qualification in
-  // C++).
   unsigned ED = Consumer.getBestEditDistance();
   if (ED > 0 && Typo->getName().size() / ED < 3) {
     // If this was an unqualified lookup, note that no correction was found.
     if (IsUnqualifiedLookup)
       (void)UnqualifiedTyposCorrected[Typo];
 
-    return DeclarationName();
+    return TypoCorrection();
+  }
+
+  // Build the NestedNameSpecifiers for the KnownNamespaces
+  if (getLangOptions().CPlusPlus) {
+    // Load any externally-known namespaces.
+    if (ExternalSource && !LoadedExternalKnownNamespaces) {
+      llvm::SmallVector<NamespaceDecl *, 4> ExternalKnownNamespaces;
+      LoadedExternalKnownNamespaces = true;
+      ExternalSource->ReadKnownNamespaces(ExternalKnownNamespaces);
+      for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I)
+        KnownNamespaces[ExternalKnownNamespaces[I]] = true;
+    }
+    
+    for (llvm::DenseMap<NamespaceDecl*, bool>::iterator 
+           KNI = KnownNamespaces.begin(),
+           KNIEnd = KnownNamespaces.end();
+         KNI != KNIEnd; ++KNI)
+      Namespaces.AddNamespace(KNI->first);
   }
 
   // Weed out any names that could not be found by name lookup.
-  bool LastLookupWasAccepted = false;
-  for (TypoCorrectionConsumer::iterator I = Consumer.begin(),
-                                     IEnd = Consumer.end();
-       I != IEnd; /* Increment in loop. */) {
-    // Keywords are always found.
-    if (I->second) {
-      ++I;
-      continue;
+  llvm::SmallPtrSet<IdentifierInfo*, 16> QualifiedResults;
+  LookupResult TmpRes(*this, TypoName, LookupKind);
+  TmpRes.suppressDiagnostics();
+  while (!Consumer.empty()) {
+    TypoCorrectionConsumer::distance_iterator DI = Consumer.begin();
+    unsigned ED = DI->first;
+    for (TypoCorrectionConsumer::result_iterator I = DI->second.begin(),
+                                              IEnd = DI->second.end();
+         I != IEnd; /* Increment in loop. */) {
+      // If the item already has been looked up or is a keyword, keep it
+      if (I->second.isResolved()) {
+        ++I;
+        continue;
+      }
+
+      // Perform name lookup on this name.
+      IdentifierInfo *Name = I->second.getCorrectionAsIdentifierInfo();
+      LookupPotentialTypoResult(*this, TmpRes, Name, S, SS, MemberContext,
+                                EnteringContext, CTC);
+
+      switch (TmpRes.getResultKind()) {
+      case LookupResult::NotFound:
+      case LookupResult::NotFoundInCurrentInstantiation:
+        QualifiedResults.insert(Name);
+        // We didn't find this name in our scope, or didn't like what we found;
+        // ignore it.
+        {
+          TypoCorrectionConsumer::result_iterator Next = I;
+          ++Next;
+          DI->second.erase(I);
+          I = Next;
+        }
+        break;
+
+      case LookupResult::Ambiguous:
+        // We don't deal with ambiguities.
+        return TypoCorrection();
+
+      case LookupResult::Found:
+      case LookupResult::FoundOverloaded:
+      case LookupResult::FoundUnresolvedValue:
+        I->second.setCorrectionDecl(TmpRes.getAsSingle<NamedDecl>());
+        ++I;
+        break;
+      }
     }
 
-    // Perform name lookup on this name.
-    IdentifierInfo *Name = &Context.Idents.get(I->getKey());
-    LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext,
-                              EnteringContext, CTC);
-
-    switch (Res.getResultKind()) {
-    case LookupResult::NotFound:
-    case LookupResult::NotFoundInCurrentInstantiation:
-    case LookupResult::Ambiguous:
-      // We didn't find this name in our scope, or didn't like what we found;
-      // ignore it.
-      Res.suppressDiagnostics();
-      {
-        TypoCorrectionConsumer::iterator Next = I;
-        ++Next;
-        Consumer.erase(I);
-        I = Next;
-      }
-      LastLookupWasAccepted = false;
-      break;
-
-    case LookupResult::Found:
-    case LookupResult::FoundOverloaded:
-    case LookupResult::FoundUnresolvedValue:
-      ++I;
-      LastLookupWasAccepted = true;
+    if (DI->second.empty())
+      Consumer.erase(DI);
+    else if (!getLangOptions().CPlusPlus || QualifiedResults.empty() || !ED)
+      // If there are results in the closest possible bucket, stop
       break;
+
+    // Only perform the qualified lookups for C++
+    if (getLangOptions().CPlusPlus) {
+      TmpRes.suppressDiagnostics();
+      for (llvm::SmallPtrSet<IdentifierInfo*,
+                             16>::iterator QRI = QualifiedResults.begin(),
+                                        QRIEnd = QualifiedResults.end();
+           QRI != QRIEnd; ++QRI) {
+        for (NamespaceSpecifierSet::iterator NI = Namespaces.begin(),
+                                          NIEnd = Namespaces.end();
+             NI != NIEnd; ++NI) {
+          DeclContext *Ctx = NI->DeclCtx;
+          unsigned QualifiedED = ED + NI->EditDistance;
+
+          // Stop searching once the namespaces are too far away to create
+          // acceptable corrections for this identifier (since the namespaces
+          // are sorted in ascending order by edit distance)
+          if (QualifiedED > Consumer.getMaxEditDistance()) break;
+
+          TmpRes.clear();
+          TmpRes.setLookupName(*QRI);
+          if (!LookupQualifiedName(TmpRes, Ctx)) continue;
+
+          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::NotFound:
+          case LookupResult::NotFoundInCurrentInstantiation:
+          case LookupResult::Ambiguous:
+            break;
+          }
+        }
+      }
     }
 
-    if (Res.isAmbiguous()) {
-      // We don't deal with ambiguities.
-      Res.suppressDiagnostics();
-      Res.clear();
-      return DeclarationName();
+    QualifiedResults.clear();
+  }
+
+  // No corrections remain...
+  if (Consumer.empty()) return TypoCorrection();
+
+  TypoResultsMap &BestResults = Consumer.begin()->second;
+  ED = Consumer.begin()->first;
+
+  if (ED > 0 && Typo->getName().size() / ED < 3) {
+    // If this was an unqualified lookup, note that no correction was found.
+    if (IsUnqualifiedLookup)
+      (void)UnqualifiedTyposCorrected[Typo];
+
+    return TypoCorrection();
+  }
+
+  // If we have multiple possible corrections, eliminate the ones where we
+  // added namespace qualifiers to try to resolve the ambiguity (and to favor
+  // corrections without additional namespace qualifiers)
+  if (getLangOptions().CPlusPlus && BestResults.size() > 1) {
+    TypoCorrectionConsumer::distance_iterator DI = Consumer.begin();
+    for (TypoCorrectionConsumer::result_iterator I = DI->second.begin(),
+                                              IEnd = DI->second.end();
+         I != IEnd; /* Increment in loop. */) {
+      if (I->second.getCorrectionSpecifier() != NULL) {
+        TypoCorrectionConsumer::result_iterator Cur = I;
+        ++I;
+        DI->second.erase(Cur);
+      } else ++I;
     }
   }
 
   // If only a single name remains, return that result.
-  if (Consumer.size() == 1) {
-    IdentifierInfo *Name = &Context.Idents.get(Consumer.begin()->getKey());
-    if (Consumer.begin()->second) {
-      Res.suppressDiagnostics();
-      Res.clear();
-
-      // Don't correct to a keyword that's the same as the typo; the keyword
-      // wasn't actually in scope.
-      if (ED == 0) {
-        Res.setLookupName(Typo);
-        return DeclarationName();
-      }
+  if (BestResults.size() == 1) {
+    const llvm::StringMapEntry<TypoCorrection> &Correction = *(BestResults.begin());
+    const TypoCorrection &Result = Correction.second;
 
-    } else if (!LastLookupWasAccepted) {
-      // Perform name lookup on this name.
-      LookupPotentialTypoResult(*this, Res, Name, S, SS, MemberContext,
-                                EnteringContext, CTC);
-    }
+    // Don't correct to a keyword that's the same as the typo; the keyword
+    // wasn't actually in scope.
+    if (ED == 0 && Result.isKeyword()) return TypoCorrection();
 
+    assert(Result.isResolved() && "correction has not been looked up");
     // Record the correction for unqualified lookup.
     if (IsUnqualifiedLookup)
-      UnqualifiedTyposCorrected[Typo]
-        = std::make_pair(Name->getName(), Consumer.begin()->second);
+      UnqualifiedTyposCorrected[Typo] = Result;
 
-    return &Context.Idents.get(Consumer.begin()->getKey());
+    return Result;
   }
-  else if (Consumer.size() > 1 && CTC == CTC_ObjCMessageReceiver
-           && Consumer["super"]) {
-    // Prefix 'super' when we're completing in a message-receiver
+  else if (BestResults.size() > 1 && CTC == CTC_ObjCMessageReceiver
+           && BestResults["super"].isKeyword()) {
+    // Prefer 'super' when we're completing in a message-receiver
     // context.
-    Res.suppressDiagnostics();
-    Res.clear();
 
     // Don't correct to a keyword that's the same as the typo; the keyword
     // wasn't actually in scope.
-    if (ED == 0) {
-      Res.setLookupName(Typo);
-      return DeclarationName();
-    }
+    if (ED == 0) return TypoCorrection();
 
     // Record the correction for unqualified lookup.
     if (IsUnqualifiedLookup)
-      UnqualifiedTyposCorrected[Typo]
-        = std::make_pair("super", Consumer.begin()->second);
+      UnqualifiedTyposCorrected[Typo] = BestResults["super"];
 
-    return &Context.Idents.get("super");
+    return BestResults["super"];
   }
 
-  Res.suppressDiagnostics();
-  Res.setLookupName(Typo);
-  Res.clear();
-  // Record the correction for unqualified lookup.
   if (IsUnqualifiedLookup)
     (void)UnqualifiedTyposCorrected[Typo];
 
-  return DeclarationName();
+  return TypoCorrection();
+}
+
+std::string TypoCorrection::getAsString(const LangOptions &LO) const {
+  if (CorrectionNameSpec) {
+    std::string tmpBuffer;
+    llvm::raw_string_ostream PrefixOStream(tmpBuffer);
+    CorrectionNameSpec->print(PrefixOStream, PrintingPolicy(LO));
+    return PrefixOStream.str() + CorrectionName.getAsString();
+  }
+
+  return CorrectionName.getAsString();
 }

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Jun 28 11:20:02 2011
@@ -294,26 +294,31 @@
   if (Found.empty() && !isDependent) {
     // If we did not find any names, attempt to correct any typos.
     DeclarationName Name = Found.getLookupName();
-    if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx,
-                                                false, CTC_CXXCasts)) {
+    Found.clear();
+    if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(),
+                                               Found.getLookupKind(), S, &SS,
+                                               LookupCtx, false,
+                                               CTC_CXXCasts)) {
+      Found.setLookupName(Corrected.getCorrection());
+      if (Corrected.getCorrectionDecl())
+        Found.addDecl(Corrected.getCorrectionDecl());
       FilterAcceptableTemplateNames(Found);
       if (!Found.empty()) {
+        std::string CorrectedStr(Corrected.getAsString(getLangOptions()));
+        std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
         if (LookupCtx)
           Diag(Found.getNameLoc(), diag::err_no_member_template_suggest)
-            << Name << LookupCtx << Found.getLookupName() << SS.getRange()
-            << FixItHint::CreateReplacement(Found.getNameLoc(),
-                                          Found.getLookupName().getAsString());
+            << Name << LookupCtx << CorrectedQuotedStr << SS.getRange()
+            << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
         else
           Diag(Found.getNameLoc(), diag::err_no_template_suggest)
-            << Name << Found.getLookupName()
-            << FixItHint::CreateReplacement(Found.getNameLoc(),
-                                          Found.getLookupName().getAsString());
+            << Name << CorrectedQuotedStr
+            << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr);
         if (TemplateDecl *Template = Found.getAsSingle<TemplateDecl>())
           Diag(Template->getLocation(), diag::note_previous_decl)
-            << Template->getDeclName();
+            << CorrectedQuotedStr;
       }
     } else {
-      Found.clear();
       Found.setLookupName(Name);
     }
   }

Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Tue Jun 28 11:20:02 2011
@@ -716,17 +716,19 @@
     
   case LookupResult::NotFound:
   case LookupResult::NotFoundInCurrentInstantiation:
-    if (DeclarationName CorrectedName = CorrectTypo(R, S, 0, 0, false, 
-                                                    CTC_NoKeywords)) {
-      if (NamedDecl *CorrectedResult = R.getAsSingle<NamedDecl>())
+    if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
+                                               R.getLookupKind(), S, 0, 0,
+                                               false, CTC_NoKeywords)) {
+      if (NamedDecl *CorrectedResult = Corrected.getCorrectionDecl())
         if (CorrectedResult->isParameterPack()) {
+          std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions()));
           ParameterPack = CorrectedResult;
           Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest)
-            << &Name << CorrectedName
-            << FixItHint::CreateReplacement(NameLoc, 
-                                            CorrectedName.getAsString());
+            << &Name << CorrectedQuotedStr
+            << FixItHint::CreateReplacement(
+                NameLoc, Corrected.getAsString(getLangOptions()));
           Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here)
-            << CorrectedName;
+            << CorrectedQuotedStr;
         }
     }
       

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Tue Jun 28 11:20:02 2011
@@ -2369,6 +2369,15 @@
         TentativeDefinitions.insert(TentativeDefinitions.end(),
                                     Record.begin(), Record.end());
       break;
+        
+    case KNOWN_NAMESPACES:
+      // Optimization for the first block.
+      if (KnownNamespaces.empty())
+        KnownNamespaces.swap(Record);
+      else
+        KnownNamespaces.insert(KnownNamespaces.end(), 
+                               Record.begin(), Record.end());
+      break;
     }
     First = false;
   }
@@ -4452,6 +4461,17 @@
   return std::pair<ObjCMethodList, ObjCMethodList>();
 }
 
+void ASTReader::ReadKnownNamespaces(
+                          llvm::SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+  Namespaces.clear();
+  
+  for (unsigned I = 0, N = KnownNamespaces.size(); I != N; ++I) {
+    if (NamespaceDecl *Namespace 
+                = dyn_cast_or_null<NamespaceDecl>(GetDecl(KnownNamespaces[I])))
+      Namespaces.push_back(Namespace);
+  }
+}
+
 void ASTReader::LoadSelector(Selector Sel) {
   // It would be complicated to avoid reading the methods anyway. So don't.
   ReadMethodPool(Sel);

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Jun 28 11:20:02 2011
@@ -781,6 +781,8 @@
   RECORD(FP_PRAGMA_OPTIONS);
   RECORD(OPENCL_EXTENSIONS);
   RECORD(DELEGATING_CTORS);
+  RECORD(FILE_SOURCE_LOCATION_OFFSETS);
+  RECORD(KNOWN_NAMESPACES);
   
   // SourceManager Block.
   BLOCK(SOURCE_MANAGER_BLOCK);
@@ -2845,6 +2847,16 @@
     AddDeclRef(Context.getcudaConfigureCallDecl(), CUDASpecialDeclRefs);
   }
 
+  // Build a record containing all of the known namespaces.
+  RecordData KnownNamespaces;
+  for (llvm::DenseMap<NamespaceDecl*, bool>::iterator 
+            I = SemaRef.KnownNamespaces.begin(),
+         IEnd = SemaRef.KnownNamespaces.end();
+       I != IEnd; ++I) {
+    if (!I->second)
+      AddDeclRef(I->first, KnownNamespaces);
+  }
+  
   // Write the remaining AST contents.
   RecordData Record;
   Stream.EnterSubblock(AST_BLOCK_ID, 5);
@@ -2954,6 +2966,10 @@
   if (!DelegatingCtorDecls.empty())
     Stream.EmitRecord(DELEGATING_CTORS, DelegatingCtorDecls);
 
+  // Write the known namespaces.
+  if (!KnownNamespaces.empty())
+    Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces);
+  
   // Some simple statistics
   Record.clear();
   Record.push_back(NumStatements);

Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp Tue Jun 28 11:20:02 2011
@@ -19,8 +19,9 @@
 }
 
 namespace C {
-  class C {};
-  void func(C);
+  class C {}; // expected-note {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'B::B' to 'const C::C &' for 1st argument}}
+  void func(C); // expected-note {{'C::func' declared here}} \
+                // expected-note {{passing argument to parameter here}}
   C operator+(C,C);
   D::D operator+(D::D,D::D);
 }
@@ -32,7 +33,13 @@
 namespace Test {
   void test() {
     func(A::A());
-    func(B::B()); // expected-error {{use of undeclared identifier 'func'}}
+    // FIXME: namespace-aware typo correction causes an extra, misleading
+    // message in this case; some form of backtracking, diagnostic message
+    // delaying, or argument checking before emitting diagnostics is needed to
+    // avoid accepting and printing out a typo correction that proves to be
+    // incorrect once argument-dependent lookup resolution has occurred.
+    func(B::B()); // expected-error {{use of undeclared identifier 'func'; did you mean 'C::func'?}} \
+                  // expected-error {{no viable conversion from 'B::B' to 'C::C'}}
     func(C::C());
     A::A() + A::A();
     B::B() + B::B();

Modified: cfe/trunk/test/FixIt/typo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/typo.cpp?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/typo.cpp (original)
+++ cfe/trunk/test/FixIt/typo.cpp Tue Jun 28 11:20:02 2011
@@ -74,3 +74,9 @@
   unsinged *ptr = 0; // expected-error{{use of undeclared identifier 'unsinged'; did you mean 'unsigned'?}}
   return *i + *ptr + global_val; // expected-error{{use of undeclared identifier 'global_val'; did you mean 'global_value'?}}
 }
+
+namespace nonstd {
+  typedef std::basic_string<char> yarn; // expected-note{{'nonstd::yarn' declared here}}
+}
+
+yarn str4; // expected-error{{unknown type name 'yarn'; did you mean 'nonstd::yarn'?}}

Added: cfe/trunk/test/PCH/Inputs/typo.hpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/Inputs/typo.hpp?rev=134007&view=auto
==============================================================================
--- cfe/trunk/test/PCH/Inputs/typo.hpp (added)
+++ cfe/trunk/test/PCH/Inputs/typo.hpp Tue Jun 28 11:20:02 2011
@@ -0,0 +1,8 @@
+namespace boost {
+  template<typename F> class function {};
+
+  namespace graph {
+    template<typename V, typename E> class adjacency_list { }; 
+  };
+}
+

Propchange: cfe/trunk/test/PCH/Inputs/typo.hpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/PCH/Inputs/typo.hpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/PCH/Inputs/typo.hpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/PCH/typo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/typo.cpp?rev=134007&view=auto
==============================================================================
--- cfe/trunk/test/PCH/typo.cpp (added)
+++ cfe/trunk/test/PCH/typo.cpp Tue Jun 28 11:20:02 2011
@@ -0,0 +1,17 @@
+
+// In header: expected-note{{ 'boost::function' declared here}}
+
+
+// In header: expected-note{{ 'boost::graph::adjacency_list' declared here}}
+
+
+
+adjacent_list<int, int> g; // expected-error{{no template named 'adjacent_list'; did you mean 'boost::graph::adjacency_list'?}}
+Function<int(int)> f; // expected-error{{no template named 'Function'; did you mean 'boost::function'?}}
+
+// Without PCH
+// RUN: %clang_cc1 -include %S/Inputs/typo.hpp -verify %s
+
+// With PCH
+// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/Inputs/typo.hpp
+// RUN: %clang_cc1 -include-pch %t -verify %s

Propchange: cfe/trunk/test/PCH/typo.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/PCH/typo.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/PCH/typo.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: cfe/trunk/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp?rev=134007&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp (added)
+++ cfe/trunk/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp Tue Jun 28 11:20:02 2011
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++0x-extensions %s
+
+namespace fizbin { class Foobar; } // expected-note{{'fizbin::Foobar' declared here}}
+Foobar *my_bar = new Foobar; // expected-error{{unknown type name 'Foobar'; did you mean 'fizbin::Foobar'?}} \
+                             // expected-error{{expected a type}}
+
+namespace barstool { int toFoobar() { return 1; } } // expected-note 3 {{'barstool::toFoobar' declared here}}
+int Double(int x) { return x + x; }
+void empty() {
+  Double(toFoobar()); // expected-error{{{use of undeclared identifier 'toFoobar'; did you mean 'barstool::toFoobar'?}}
+}
+
+namespace fizbin {
+  namespace baztool { bool toFoobar() { return true; } } // expected-note{{'fizbin::baztool' declared here}}
+  namespace nested { bool moreFoobar() { return true; } } // expected-note{{'fizbin::nested::moreFoobar' declared here}}
+  namespace nested { bool lessFoobar() { return true; } } // expected-note{{'fizbin::nested' declared here}} \
+                                                          // expected-note{{'fizbin::nested::lessFoobar' declared here}}
+  class dummy { // expected-note 2 {{'fizbin::dummy' declared here}}
+   public:
+    static bool moreFoobar() { return false; } // expected-note{{'moreFoobar' declared here}}
+  };
+}
+void Check() { // expected-note{{'Check' declared here}}
+  if (toFoobar()) Double(7); // expected-error{{use of undeclared identifier 'toFoobar'; did you mean 'barstool::toFoobar'?}}
+  if (noFoobar()) Double(7); // expected-error{{use of undeclared identifier 'noFoobar'; did you mean 'barstool::toFoobar'?}}
+  if (moreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'moreFoobar'; did you mean 'fizbin::nested::moreFoobar'}}
+  if (lessFoobar()) Double(7); // expected-error{{use of undeclared identifier 'lessFoobar'; did you mean 'fizbin::nested::lessFoobar'?}}
+  if (baztool::toFoobar()) Double(7); // expected-error{{use of undeclared identifier 'baztool'; did you mean 'fizbin::baztool'?}}
+  if (nested::moreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'nested'; did you mean 'fizbin::nested'?}}
+  if (dummy::moreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'dummy'; did you mean 'fizbin::dummy'?}}
+  if (dummy::mreFoobar()) Double(7); // expected-error{{use of undeclared identifier 'dummy'; did you mean 'fizbin::dummy'?}} \
+                                     // expected-error{{no member named 'mreFoobar' in 'fizbin::dummy'; did you mean 'moreFoobar'?}}
+  if (moFoobin()) Double(7); // expected-error{{use of undeclared identifier 'moFoobin'}}
+}
+
+void Alt() {
+  Cleck(); // expected-error{{{use of undeclared identifier 'Cleck'; did you mean 'Check'?}}
+}
+
+namespace N {
+  namespace inner {
+    class myvector { /* ... */ }; // expected-note{{'inner::myvector' declared here}}
+  }
+
+  void f() {
+    myvector v; // expected-error{{no type named 'myvector' in namespace 'N::inner'; did you mean 'inner::myvector'?}}
+  }
+}
+
+namespace realstd {
+  inline namespace __1 {
+    class mylinkedlist { /* ... */ }; // expected-note 2 {{'realstd::mylinkedlist' declared here}}
+  }
+
+  class linkedlist { /* ... */ };
+}
+
+void f() {
+  mylinkedlist v; // expected-error{{no type named 'mylinkedlist' in namespace 'realstd'; did you mean 'realstd::mylinkedlist'?}}
+  nylinkedlist w; // expected-error{{no type named 'nylinkedlist' in namespace 'realstd'; did you mean 'realstd::mylinkedlist'?}}
+}

Propchange: cfe/trunk/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/SemaObjC/ivar-ref-misuse.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/ivar-ref-misuse.m?rev=134007&r1=134006&r2=134007&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/ivar-ref-misuse.m (original)
+++ cfe/trunk/test/SemaObjC/ivar-ref-misuse.m Tue Jun 28 11:20:02 2011
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
- at interface Sprite {
+ at interface Sprite { // expected-note{{'Sprite' declared here}}
   int sprite, spree;
   int UseGlobalBar;
 }
@@ -17,7 +17,8 @@
 + (void)setFoo:(int)foo {
   sprite = foo;   // expected-error {{instance variable 'sprite' accessed in class method}}
   spree = foo;
-  Xsprite = foo; // expected-error {{use of undeclared identifier 'Xsprite'}} 
+  Xsprite = foo; // expected-error {{unknown type name 'Xsprite'; did you mean 'Sprite'?}}  \
+  // expected-error{{expected identifier or '('}}
   UseGlobalBar = 10;
 }
 + (void)setSprite:(int)sprite {





More information about the cfe-commits mailing list