diff options
25 files changed, 1060 insertions, 517 deletions
diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h index e2b083e830..072e1b58d1 100644 --- a/include/clang/Sema/ExternalSemaSource.h +++ b/include/clang/Sema/ExternalSemaSource.h @@ -49,6 +49,11 @@ public: /// 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. /// diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 2e51117f26..65ce34a7a2 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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 @@ namespace clang { class ASTConsumer; class ASTContext; class ASTMutationListener; + class ASTReader; + class ASTWriter; class ArrayType; class AttributeList; class BlockDecl; @@ -1623,6 +1626,16 @@ private: 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 @@ public: 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 @@ public: /// \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 @@ private: protected: friend class Parser; friend class InitializationSequence; + friend class ASTReader; + friend class ASTWriter; public: /// \brief Retrieve the parser's current scope. diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h new file mode 100644 index 0000000000..9965953538 --- /dev/null +++ b/include/clang/Sema/TypoCorrection.h @@ -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 diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 15fe3c61ae..a4e90aa265 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -371,7 +371,11 @@ namespace clang { /// \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 }; diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 8923e2ab0d..a6c32aafd3 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -625,6 +625,9 @@ private: /// \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 @@ public: 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); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 7d22031ecb..9550f9aad2 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -154,6 +154,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, AnalysisWarnings(*this) { TUScope = 0; + LoadedExternalKnownNamespaces = false; + if (getLangOptions().CPlusPlus) FieldCollector.reset(new CXXFieldCollector()); @@ -778,6 +780,10 @@ ExternalSemaSource::ReadMethodPool(Selector Sel) { 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(); diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 61d9e93f2f..e54857196a 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -464,26 +464,29 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, // 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); } } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index efb06f6687..2779faeb15 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -287,41 +287,42 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, // 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 @@ Corrected: // 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 @@ Corrected: 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 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { /// 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()); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c0d34da922..ac51138b91 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1426,25 +1426,27 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, } // 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 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, // 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 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // 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 IsUsingDirectiveInToplevelContext(DeclContext *CurContext) { } } +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 @@ Decl *Sema::ActOnUsingDirective(Scope *S, 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 @@ Decl *Sema::ActOnUsingDirective(Scope *S, 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 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, 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; } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index a3f53ec234..a9f4f95c20 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -442,9 +442,10 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, 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 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, 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 @@ Decl *Sema::ActOnStartClassImplementation( } 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) |