[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/

Chad Rosier mcrosier at apple.com
Tue Jun 28 12:36:24 PDT 2011


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

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


More information about the cfe-commits mailing list