From: Kaelyn Uhrain Date: Thu, 7 Jun 2012 23:57:08 +0000 (+0000) Subject: Ignore corrections to functions with bodies when deciding which X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ef094a1ab79c57269b627cb19748384d9a26fb31;p=clang Ignore corrections to functions with bodies when deciding which correction to use for an invalid function redeclaration. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158177 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 8d4ce2873b..44a2bb5d5a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4604,22 +4604,39 @@ namespace { // Also only accept corrections that have the same parent decl. class DifferentNameValidatorCCC : public CorrectionCandidateCallback { public: - DifferentNameValidatorCCC(CXXRecordDecl *Parent) - : ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) {} + DifferentNameValidatorCCC(ASTContext &Context, FunctionDecl *TypoFD, + CXXRecordDecl *Parent) + : Context(Context), OriginalFD(TypoFD), + ExpectedParent(Parent ? Parent->getCanonicalDecl() : 0) {} virtual bool ValidateCandidate(const TypoCorrection &candidate) { if (candidate.getEditDistance() == 0) return false; - if (CXXMethodDecl *MD = candidate.getCorrectionDeclAs()) { - CXXRecordDecl *Parent = MD->getParent(); - return Parent && Parent->getCanonicalDecl() == ExpectedParent; + llvm::SmallVector MismatchedParams; + for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(), + CDeclEnd = candidate.end(); + CDecl != CDeclEnd; ++CDecl) { + FunctionDecl *FD = dyn_cast(*CDecl); + + if (FD && !FD->hasBody() && + hasSimilarParameters(Context, FD, OriginalFD, MismatchedParams)) { + if (CXXMethodDecl *MD = dyn_cast(FD)) { + CXXRecordDecl *Parent = MD->getParent(); + if (Parent && Parent->getCanonicalDecl() == ExpectedParent) + return true; + } else if (!ExpectedParent) { + return true; + } + } } - return !ExpectedParent; + return false; } private: + ASTContext &Context; + FunctionDecl *OriginalFD; CXXRecordDecl *ExpectedParent; }; @@ -4655,7 +4672,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration( assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); CXXMethodDecl *MD = dyn_cast(NewFD); - DifferentNameValidatorCCC Validator(MD ? MD->getParent() : 0); + DifferentNameValidatorCCC Validator(SemaRef.Context, NewFD, + MD ? MD->getParent() : 0); if (!Prev.empty()) { for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); Func != FuncEnd; ++Func) { @@ -4685,8 +4703,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration( CDeclEnd = Correction.end(); CDecl != CDeclEnd; ++CDecl) { FunctionDecl *FD = dyn_cast(*CDecl); - if (FD && hasSimilarParameters(SemaRef.Context, FD, NewFD, - MismatchedParams)) { + if (FD && !FD->hasBody() && + hasSimilarParameters(SemaRef.Context, FD, NewFD, MismatchedParams)) { Previous.addDecl(FD); } } diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp index 0eb109d263..b9d1f23af4 100644 --- a/test/SemaCXX/function-redecl.cpp +++ b/test/SemaCXX/function-redecl.cpp @@ -76,12 +76,9 @@ class Crash { void GetCart(int count) const; }; // This out-of-line definition was fine... -void Crash::cart(int count) const {} // expected-error {{out-of-line definition of 'cart' does not match any declaration in 'Crash'}} \ - // expected-note {{'cart' declared here}} \ - // expected-note {{previous definition is here}} +void Crash::cart(int count) const {} // expected-error {{out-of-line definition of 'cart' does not match any declaration in 'Crash'}} // ...while this one crashed clang -void Crash::chart(int count) const {} // expected-error {{out-of-line definition of 'chart' does not match any declaration in 'Crash'; did you mean 'cart'?}} \ - // expected-error {{redefinition of 'cart'}} +void Crash::chart(int count) const {} // expected-error {{out-of-line definition of 'chart' does not match any declaration in 'Crash'}} class TestConst { public: @@ -98,3 +95,24 @@ void TestConst::setit(int) const { // expected-error {{out-of-line definition of struct J { int typo() const; }; int J::typo_() { return 3; } // expected-error {{out-of-line definition of 'typo_' does not match any declaration in 'J'}} + +// Ensure we correct the redecl of Foo::isGood to Bar::Foo::isGood and not +// Foo::IsGood even though Foo::IsGood is technically a closer match since it +// already has a body. Also make sure Foo::beEvil is corrected to Foo::BeEvil +// since it is a closer match than Bar::Foo::beEvil and neither have a body. +namespace redecl_typo { +namespace Foo { + bool IsGood() { return false; } + void BeEvil(); // expected-note {{'BeEvil' declared here}} +} +namespace Bar { + namespace Foo { + bool isGood(); // expected-note {{'Bar::Foo::isGood' declared here}} + void beEvil(); + } +} +bool Foo::isGood() { // expected-error {{out-of-line definition of 'isGood' does not match any declaration in namespace 'redecl_typo::Foo'; did you mean 'Bar::Foo::isGood'?}} + return true; +} +void Foo::beEvil() {} // expected-error {{out-of-line definition of 'beEvil' does not match any declaration in namespace 'redecl_typo::Foo'; did you mean 'BeEvil'?}} +} diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index d57a8523bb..4e1abc5e5b 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -113,8 +113,7 @@ namespace E { X = 0 }; - void f() { // expected-note{{'E::Nested::f' declared here}} \ - // expected-note{{previous definition is here}} + void f() { return E::X; // expected-error{{expected a class or namespace}} } } @@ -144,10 +143,7 @@ namespace A { void g(int&); // expected-note{{type of 1st parameter of member declaration does not match definition ('int &' vs 'const int &')}} } -// TODO: Suppress the typo correction for an invalid redeclaration if the chosen -// correction is a function that already has a body. -void A::f() {} // expected-error{{out-of-line definition of 'f' does not match any declaration in namespace 'A'; did you mean 'E::Nested::f'?}} \ - // expected-error{{redefinition of 'f'}} +void A::f() {} // expected-error-re{{out-of-line definition of 'f' does not match any declaration in namespace 'A'$}} void A::g(const int&) { } // expected-error{{out-of-line definition of 'g' does not match any declaration in namespace 'A'}}