diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Sema/TypoCorrection.h | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaAccess.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 107 | ||||
-rw-r--r-- | clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp | 8 | ||||
-rw-r--r-- | clang/test/CXX/class/class.nested.type/p1.cpp | 8 | ||||
-rw-r--r-- | clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp | 6 | ||||
-rw-r--r-- | clang/test/FixIt/typo-using.cpp | 12 | ||||
-rw-r--r-- | clang/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp | 8 | ||||
-rw-r--r-- | clang/test/SemaCXX/typo-correction-pt2.cpp | 61 |
9 files changed, 191 insertions, 26 deletions
diff --git a/clang/include/clang/Sema/TypoCorrection.h b/clang/include/clang/Sema/TypoCorrection.h index 0deb74201c4..f0b77264984 100644 --- a/clang/include/clang/Sema/TypoCorrection.h +++ b/clang/include/clang/Sema/TypoCorrection.h @@ -137,6 +137,11 @@ public: return dyn_cast_or_null<DeclClass>(getCorrectionDecl()); } + /// \brief Clears the list of NamedDecls. + void ClearCorrectionDecls() { + CorrectionDecls.clear(); + } + /// \brief Clears the list of NamedDecls before adding the new one. void setCorrectionDecl(NamedDecl *CDecl) { CorrectionDecls.clear(); diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index 4ecbf0ba776..6dbfad4e18d 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -1390,6 +1390,8 @@ static AccessResult IsAccessible(Sema &S, CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths); if (!Path) return AR_dependent; + if (Path->Access == AS_none) // This can happen during typo correction. + return AR_inaccessible; assert(Path->Access <= UnprivilegedAccess && "access along best path worse than direct?"); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index a645986ac31..75b0f984f8c 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3601,6 +3601,10 @@ class NamespaceSpecifierSet { /// NestedNameSpecifier and its distance in the process. void AddNamespace(NamespaceDecl *ND); + /// \brief Add the record to the set, computing the corresponding + /// NestedNameSpecifier and its distance in the process. + void AddRecord(RecordDecl *RD); + typedef SpecifierInfoList::iterator iterator; iterator begin() { if (!isSorted) SortNamespaces(); @@ -3702,6 +3706,72 @@ void NamespaceSpecifierSet::AddNamespace(NamespaceDecl *ND) { DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers)); } +void NamespaceSpecifierSet::AddRecord(RecordDecl *RD) { + if (!RD->isBeingDefined() && !RD->isCompleteDefinition()) + return; + + DeclContext *Ctx = cast<DeclContext>(RD); + NestedNameSpecifier *NNS = NULL; + unsigned NumSpecifiers = 0; + DeclContextList NamespaceDeclChain(BuildContextChain(Ctx)); + DeclContextList FullNamespaceDeclChain(NamespaceDeclChain); + + // Eliminate common elements from the two DeclContext chains. + for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), + CEnd = CurContextChain.rend(); + C != CEnd && !NamespaceDeclChain.empty() && + NamespaceDeclChain.back() == *C; ++C) { + NamespaceDeclChain.pop_back(); + } + + // Add an explicit leading '::' specifier if needed. + if (NamespaceDeclChain.empty()) { + NamespaceDeclChain = FullNamespaceDeclChain; + NNS = NestedNameSpecifier::GlobalSpecifier(Context); + } else if (NamespaceDecl *ND = + dyn_cast_or_null<NamespaceDecl>(NamespaceDeclChain.back())) { + IdentifierInfo *Name = ND->getIdentifier(); + if (std::find(CurContextIdentifiers.begin(), CurContextIdentifiers.end(), + Name) != CurContextIdentifiers.end() || + std::find(CurNameSpecifierIdentifiers.begin(), + CurNameSpecifierIdentifiers.end(), + Name) != CurNameSpecifierIdentifiers.end()) { + NamespaceDeclChain = FullNamespaceDeclChain; + NNS = NestedNameSpecifier::GlobalSpecifier(Context); + } + } + + // Build the NestedNameSpecifier from what is left of the NamespaceDeclChain + for (DeclContextList::reverse_iterator C = NamespaceDeclChain.rbegin(), + CEnd = NamespaceDeclChain.rend(); + C != CEnd; ++C) { + if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C)) { + NNS = NestedNameSpecifier::Create(Context, NNS, ND); + ++NumSpecifiers; + } else if (RecordDecl *RD = dyn_cast_or_null<RecordDecl>(*C)) { + NNS = NestedNameSpecifier::Create(Context, NNS, RD->isTemplateDecl(), + RD->getTypeForDecl()); + ++NumSpecifiers; + } + } + + // If the built NestedNameSpecifier would be replacing an existing + // NestedNameSpecifier, use the number of component identifiers that + // would need to be changed as the edit distance instead of the number + // of components in the built NestedNameSpecifier. + if (NNS && !CurNameSpecifierIdentifiers.empty()) { + SmallVector<const IdentifierInfo*, 4> NewNameSpecifierIdentifiers; + getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers); + NumSpecifiers = llvm::ComputeEditDistance( + ArrayRef<const IdentifierInfo *>(CurNameSpecifierIdentifiers), + ArrayRef<const IdentifierInfo *>(NewNameSpecifierIdentifiers)); + } + + isSorted = false; + Distances.insert(NumSpecifiers); + DistanceMap[NumSpecifiers].push_back(SpecifierInfo(Ctx, NNS, NumSpecifiers)); +} + /// \brief Perform name lookup for a possible result for typo correction. static void LookupPotentialTypoResult(Sema &SemaRef, LookupResult &Res, @@ -4153,12 +4223,22 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, for (unsigned I = 0, N = ExternalKnownNamespaces.size(); I != N; ++I) KnownNamespaces[ExternalKnownNamespaces[I]] = true; } - - for (llvm::MapVector<NamespaceDecl*, bool>::iterator + + for (llvm::MapVector<NamespaceDecl*, bool>::iterator KNI = KnownNamespaces.begin(), KNIEnd = KnownNamespaces.end(); KNI != KNIEnd; ++KNI) Namespaces.AddNamespace(KNI->first); + + for (ASTContext::type_iterator TI = Context.types_begin(), + TIEnd = Context.types_end(); + TI != TIEnd; ++TI) { + if (CXXRecordDecl *CD = (*TI)->getAsCXXRecordDecl()) { + if (!CD->isDependentType() && !CD->isAnonymousStructOrUnion() && + !CD->isUnion()) + Namespaces.AddRecord(CD); + } + } } // Weed out any names that could not be found by name lookup or, if a @@ -4295,6 +4375,17 @@ retry_lookup: NIEnd = Namespaces.end(); NI != NIEnd; ++NI) { DeclContext *Ctx = NI->DeclCtx; + const Type *NSType = NI->NameSpecifier->getAsType(); + + // If the current NestedNameSpecifier refers to a class and the + // current correction candidate is the name of that class, then skip + // it as it is unlikely a qualified version of the class' constructor + // is an appropriate correction. + if (CXXRecordDecl *NSDecl = + NSType ? NSType->getAsCXXRecordDecl() : 0) { + if (NSDecl->getIdentifier() == QRI->getCorrectionAsIdentifierInfo()) + continue; + } // FIXME: Stop searching once the namespaces are too far away to create // acceptable corrections for this identifier (since the namespaces @@ -4310,14 +4401,20 @@ retry_lookup: case LookupResult::Found: case LookupResult::FoundOverloaded: { TypoCorrection TC(*QRI); + TC.ClearCorrectionDecls(); TC.setCorrectionSpecifier(NI->NameSpecifier); TC.setQualifierDistance(NI->EditDistance); TC.setCallbackDistance(0); // Reset the callback distance for (LookupResult::iterator TRD = TmpRes.begin(), TRDEnd = TmpRes.end(); - TRD != TRDEnd; ++TRD) - TC.addCorrectionDecl(*TRD); - Consumer.addCorrection(TC); + TRD != TRDEnd; ++TRD) { + if (CheckMemberAccess(TC.getCorrectionRange().getBegin(), + NSType ? NSType->getAsCXXRecordDecl() : 0, + *TRD) == AR_accessible) + TC.addCorrectionDecl(*TRD); + } + if (TC.isResolved()) + Consumer.addCorrection(TC); break; } case LookupResult::NotFound: diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp index df9a2cd14cd..e61df3e586a 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp @@ -5,7 +5,7 @@ namespace N { X operator+(X, X); - void f(X); + void f(X); // expected-note 2 {{'N::f' declared here}} void g(X); // expected-note{{candidate function}} void test_multiadd(X x) { @@ -17,7 +17,7 @@ namespace M { struct Y : N::X { }; } -void f(); // expected-note 2 {{'f' declared here}} +void f(); void test_operator_adl(N::X x, M::Y y) { (void)(x + x); @@ -27,8 +27,8 @@ void test_operator_adl(N::X x, M::Y y) { void test_func_adl(N::X x, M::Y y) { f(x); f(y); - (f)(x); // expected-error{{too many arguments to function call}} - ::f(x); // expected-error{{too many arguments to function call}} + (f)(x); // expected-error{{too many arguments to function call, expected 0, have 1; did you mean 'N::f'?}} + ::f(x); // expected-error{{too many arguments to function call, expected 0, have 1; did you mean 'N::f'?}} } namespace N { diff --git a/clang/test/CXX/class/class.nested.type/p1.cpp b/clang/test/CXX/class/class.nested.type/p1.cpp index 4a04a448595..92956544123 100644 --- a/clang/test/CXX/class/class.nested.type/p1.cpp +++ b/clang/test/CXX/class/class.nested.type/p1.cpp @@ -2,12 +2,12 @@ class X { public: - typedef int I; - class Y { }; + typedef int I; // expected-note{{'X::I' declared here}} + class Y { }; // expected-note{{'X::Y' declared here}} I a; }; -I b; // expected-error{{unknown type name 'I'}} -Y c; // expected-error{{unknown type name 'Y'}} +I b; // expected-error{{unknown type name 'I'; did you mean 'X::I'?}} +Y c; // expected-error{{unknown type name 'Y'; did you mean 'X::Y'?}} X::Y d; X::I e; diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp index 385e45dadfa..27ebb8e036f 100644 --- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp @@ -1,16 +1,16 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s struct A { - virtual void f(int a = 7); + virtual void f(int a = 7); // expected-note{{'A::f' declared here}} }; struct B : public A { - void f(int a); // expected-note{{'f' declared here}} + void f(int a); }; void m() { B* pb = new B; A* pa = pb; pa->f(); // OK, calls pa->B::f(7) - pb->f(); // expected-error{{too few arguments}} + pb->f(); // expected-error{{too few arguments to function call, expected 1, have 0; did you mean 'A::f'?}} } diff --git a/clang/test/FixIt/typo-using.cpp b/clang/test/FixIt/typo-using.cpp index 3644dea3b23..e676b1074f9 100644 --- a/clang/test/FixIt/typo-using.cpp +++ b/clang/test/FixIt/typo-using.cpp @@ -23,21 +23,21 @@ using N::FFG; // expected-error {{no member named 'FFG' in namespace 'using_sugg } namespace using_suggestion_ty_dropped_specifier { -class AAA {}; // expected-note {{'::using_suggestion_ty_dropped_specifier::AAA' declared here}} +class ABC {}; // expected-note {{'::using_suggestion_ty_dropped_specifier::ABC' declared here}} namespace N { } -using N::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_ty_dropped_specifier::N'; did you mean '::using_suggestion_ty_dropped_specifier::AAA'?}} +using N::ABC; // expected-error {{no member named 'ABC' in namespace 'using_suggestion_ty_dropped_specifier::N'; did you mean '::using_suggestion_ty_dropped_specifier::ABC'?}} } namespace using_suggestion_tyname_ty_dropped_specifier { -class AAA {}; // expected-note {{'::using_suggestion_tyname_ty_dropped_specifier::AAA' declared here}} +class BCD {}; // expected-note {{'::using_suggestion_tyname_ty_dropped_specifier::BCD' declared here}} namespace N { } -using typename N::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_tyname_ty_dropped_specifier::N'; did you mean '::using_suggestion_tyname_ty_dropped_specifier::AAA'?}} +using typename N::BCD; // expected-error {{no member named 'BCD' in namespace 'using_suggestion_tyname_ty_dropped_specifier::N'; did you mean '::using_suggestion_tyname_ty_dropped_specifier::BCD'?}} } namespace using_suggestion_val_dropped_specifier { -void FFF() {} // expected-note {{'::using_suggestion_val_dropped_specifier::FFF' declared here}} +void EFG() {} // expected-note {{'::using_suggestion_val_dropped_specifier::EFG' declared here}} namespace N { } -using N::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_specifier::N'; did you mean '::using_suggestion_val_dropped_specifier::FFF'?}} +using N::EFG; // expected-error {{no member named 'EFG' in namespace 'using_suggestion_val_dropped_specifier::N'; did you mean '::using_suggestion_val_dropped_specifier::EFG'?}} } namespace using_suggestion_member_ty { diff --git a/clang/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp b/clang/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp index 40bcf45bca3..6195e039551 100644 --- a/clang/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp +++ b/clang/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp @@ -19,7 +19,7 @@ namespace fizbin { // 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}} + static bool morebar() { return false; } // expected-note{{'morebar' declared here}} }; } void Check() { // expected-note{{'Check' declared here}} @@ -29,9 +29,9 @@ void Check() { // expected-note{{'Check' declared here}} 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 (dummy::morebar()) Double(7); // expected-error{{use of undeclared identifier 'dummy'; did you mean 'fizbin::dummy'?}} + if (dummy::mrebar()) Double(7); // expected-error{{use of undeclared identifier 'dummy'; did you mean 'fizbin::dummy'?}} \ + // expected-error{{no member named 'mrebar' in 'fizbin::dummy'; did you mean 'morebar'?}} if (moFoobin()) Double(7); // expected-error{{use of undeclared identifier 'moFoobin'}} } diff --git a/clang/test/SemaCXX/typo-correction-pt2.cpp b/clang/test/SemaCXX/typo-correction-pt2.cpp index 06f69d7186b..f475b41a9f2 100644 --- a/clang/test/SemaCXX/typo-correction-pt2.cpp +++ b/clang/test/SemaCXX/typo-correction-pt2.cpp @@ -33,3 +33,64 @@ void test(Foo F, int num) { F.B(num); // expected-error {{too many arguments to function call, expected 0, have 1; did you mean '::TemplateFunction::B'?}} } } +namespace using_suggestion_val_dropped_specifier { +void FFF() {} // expected-note {{'::using_suggestion_val_dropped_specifier::FFF' declared here}} +namespace N { } +using N::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_specifier::N'; did you mean '::using_suggestion_val_dropped_specifier::FFF'?}} +} + +namespace class_member_typo_corrections { +class Outer { +public: + class Inner {}; // expected-note {{'Outer::Inner' declared here}} + Inner MyMethod(Inner arg); +}; + +Inner Outer::MyMethod(Inner arg) { // expected-error {{unknown type name 'Inner'; did you mean 'Outer::Inner'?}} + // TODO: Recovery needs to be fixed/added for the typo-correction of the + // return type so the below error isn't still generated. + return Inner(); // expected-error {{no viable conversion from 'class_member_typo_corrections::Outer::Inner' to 'int'}} +} + +class Result { +public: + enum ResultType { + ENTITY, // expected-note {{'Result::ENTITY' declared here}} + PREDICATE, // expected-note {{'Result::PREDICATE' declared here}} + LITERAL // expected-note {{'Result::LITERAL' declared here}} + }; + + ResultType type(); +}; + +void test() { + Result result_cell; + switch (result_cell.type()) { + case ENTITY: // expected-error {{use of undeclared identifier 'ENTITY'; did you mean 'Result::ENTITY'?}} + case LITERAL: // expected-error {{use of undeclared identifier 'LITERAL'; did you mean 'Result::LITERAL'?}} + case PREDICAT: // expected-error {{use of undeclared identifier 'PREDICAT'; did you mean 'Result::PREDICATE'?}} + break; + } +} + +class Figure { + enum ResultType { + SQUARE, + TRIANGLE, + CIRCLE + }; + +public: + ResultType type(); +}; + +void testAccess() { + Figure obj; + switch (obj.type()) { // expected-warning {{enumeration values 'SQUARE', 'TRIANGLE', and 'CIRCLE' not handled in switch}} + case SQUARE: // expected-error-re {{use of undeclared identifier 'SQUARE'$}} + case TRIANGLE: // expected-error-re {{use of undeclared identifier 'TRIANGLE'$}} + case CIRCE: // expected-error-re {{use of undeclared identifier 'CIRCE'$}} + break; + } +} +} |