[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 13:04:28 PDT 2011


This was a real problem that I fixed in r134009.

	- Doug

On Jun 28, 2011, at 1:03 PM, Chad Rosier wrote:

> Please disregard.  Looks as if an overlapping failure is causing the problem.
> 
> On Jun 28, 2011, at 12:36 PM, Chad Rosier wrote:
> 
>> Doug,
>> I believe this is causing a make failure due to:
>> llvm[4]: Compiling ASTLocation.cpp for Release+Asserts build
>> /usr/include/c++/4.2.1/bits/stl_map.h: In member function '_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = unsigned int, _Tp = llvm::StringMap<clang::TypoCorrection, llvm::BumpPtrAllocator>, _Compare = std::less<unsigned int>, _Alloc = std::allocator<std::pair<const unsigned int, llvm::StringMap<clang::TypoCorrection, llvm::BumpPtrAllocator> > >]':
>> /lib/Sema/SemaLookup.cpp:3170:   instantiated from here
>> /usr/include/c++/4.2.1/bits/stl_map.h:350: error: no matching function for call to 'llvm::StringMap<clang::TypoCorrection, llvm::BumpPtrAllocator>::StringMap(llvm::StringMap<clang::TypoCorrection, llvm::BumpPtrAllocator>)'
>> Please take a look.
>> 
>> Chad
>> 
>> On Jun 28, 2011, at 9:20 AM, Douglas Gregor wrote:
>> 
>>> 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 {
>>> 
>>> 
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>> 
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20110628/ac450b84/attachment.html>


More information about the cfe-commits mailing list