diff --git a/clang/include/clang/Sema/TypoCorrection.h b/clang/include/clang/Sema/TypoCorrection.h index a8f6e1178b72..a333c8182b0c 100644 --- a/clang/include/clang/Sema/TypoCorrection.h +++ b/clang/include/clang/Sema/TypoCorrection.h @@ -205,7 +205,7 @@ class CorrectionCandidateCallback { : WantTypeSpecifiers(true), WantExpressionKeywords(true), WantCXXNamedCasts(true), WantRemainingKeywords(true), WantObjCSuper(false), - IsObjCIvarLookup(false) {} + IsObjCIvarLookup(false), AllowAddedQualifier(true) {} virtual ~CorrectionCandidateCallback() {} @@ -239,6 +239,10 @@ class CorrectionCandidateCallback { // Temporary hack for the one case where a CorrectTypoContext enum is used // when looking up results. bool IsObjCIvarLookup; + + /// \brief Whether to allow this typo correction to add a + /// nested-name-specifier. + bool AllowAddedQualifier; }; /// @brief Simple template class for restricting typo correction candidates diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e92b3e4acab7..d4159bf1895e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4478,7 +4478,14 @@ namespace { class DifferentNameValidatorCCC : public CorrectionCandidateCallback { public: DifferentNameValidatorCCC(CXXRecordDecl *Parent) - : ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) {} + : ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) { + // Don't allow any additional qualification. + // FIXME: It would be nice to perform this additional qualification. + // However, DiagnoseInvalidRedeclaration is unable to handle the + // qualification, because it doesn't know how to pass the corrected + // nested-name-specifier through to ActOnFunctionDeclarator. + AllowAddedQualifier = false; + } virtual bool ValidateCandidate(const TypoCorrection &candidate) { if (candidate.getEditDistance() == 0) diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index e47bc1c8b125..ed5a8da61c3d 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3806,7 +3806,13 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, } } - if (IsUnqualifiedLookup || (QualifiedDC && QualifiedDC->isNamespace())) { + // Determine whether we are going to search in the various namespaces for + // corrections. + bool SearchNamespaces + = getLangOpts().CPlusPlus && CCC.AllowAddedQualifier && + (IsUnqualifiedLookup || (QualifiedDC && QualifiedDC->isNamespace())); + + if (IsUnqualifiedLookup || SearchNamespaces) { // For unqualified lookup, look through all of the names that we have // seen in this translation unit. // FIXME: Re-add the ability to skip very unlikely potential corrections. @@ -3852,8 +3858,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, return TypoCorrection(); } - // Build the NestedNameSpecifiers for the KnownNamespaces - if (getLangOpts().CPlusPlus) { + // Build the NestedNameSpecifiers for the KnownNamespaces, if we're going + // to search those namespaces. + if (SearchNamespaces) { // Load any externally-known namespaces. if (ExternalSource && !LoadedExternalKnownNamespaces) { SmallVector ExternalKnownNamespaces; @@ -3948,7 +3955,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, break; // Only perform the qualified lookups for C++ - if (getLangOpts().CPlusPlus) { + if (SearchNamespaces) { TmpRes.suppressDiagnostics(); for (llvm::SmallVector::iterator QRI = QualifiedResults.begin(), diff --git a/clang/test/FixIt/typo-crash.cpp b/clang/test/FixIt/typo-crash.cpp index 92d20377e886..2e6f34a2a0a2 100644 --- a/clang/test/FixIt/typo-crash.cpp +++ b/clang/test/FixIt/typo-crash.cpp @@ -10,3 +10,20 @@ template void template_id1() { // expected-note {{'template_id1' dec // expected-error {{reference to overloaded function could not be resolved; did you mean to call it?}} \ // expected-error {{use of undeclared identifier 't'}} } + +// FIXME: It would be nice if we could get this correction right. +namespace PR12297 { + namespace A { + typedef short T; + + namespace B { + typedef short T; + + T global(); + } + } + + using namespace A::B; + + T A::global(); // expected-error{{out-of-line definition of 'global' does not match any declaration in namespace 'PR12297::A'}} +}