diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 8084a8fa5e71bc08707ec7b9aa7922ed7bfe4646..63fd1a51e49411e738ea65e01337a4813eea85f7 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -111,6 +111,33 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement, return Actions.ProcessStmtAttributes(Res.get(), Attrs.getList(), Attrs.Range); } +namespace { +class StatementFilterCCC : public CorrectionCandidateCallback { +public: + StatementFilterCCC(Token nextTok) : NextToken(nextTok) { + WantTypeSpecifiers = nextTok.is(tok::l_paren) || nextTok.is(tok::less) || + nextTok.is(tok::identifier) || nextTok.is(tok::star) || + nextTok.is(tok::amp) || nextTok.is(tok::l_square); + WantExpressionKeywords = nextTok.is(tok::l_paren) || + nextTok.is(tok::identifier) || + nextTok.is(tok::arrow) || nextTok.is(tok::period); + WantRemainingKeywords = nextTok.is(tok::l_paren) || nextTok.is(tok::semi) || + nextTok.is(tok::identifier) || + nextTok.is(tok::l_brace); + WantCXXNamedCasts = false; + } + + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + if (FieldDecl *FD = candidate.getCorrectionDeclAs()) + return isa(FD); + return CorrectionCandidateCallback::ValidateCandidate(candidate); + } + +private: + Token NextToken; +}; +} + StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts, bool OnlyStatement, SourceLocation *TrailingElseLoc, @@ -149,21 +176,8 @@ Retry: if (Next.isNot(tok::coloncolon)) { // Try to limit which sets of keywords should be included in typo // correction based on what the next token is. - // FIXME: Pass the next token into the CorrectionCandidateCallback and - // do this filtering in a more fine-grained manner. - CorrectionCandidateCallback DefaultValidator; - DefaultValidator.WantTypeSpecifiers = - Next.is(tok::l_paren) || Next.is(tok::less) || - Next.is(tok::identifier) || Next.is(tok::star) || - Next.is(tok::amp) || Next.is(tok::l_square); - DefaultValidator.WantExpressionKeywords = - Next.is(tok::l_paren) || Next.is(tok::identifier) || - Next.is(tok::arrow) || Next.is(tok::period); - DefaultValidator.WantRemainingKeywords = - Next.is(tok::l_paren) || Next.is(tok::semi) || - Next.is(tok::identifier) || Next.is(tok::l_brace); - DefaultValidator.WantCXXNamedCasts = false; - if (TryAnnotateName(/*IsAddressOfOperand*/false, &DefaultValidator) + StatementFilterCCC Validator(Next); + if (TryAnnotateName(/*IsAddressOfOperand*/false, &Validator) == ANK_Error) { // Handle errors here by skipping up to the next semicolon or '}', and // eat the semicolon if that's what stopped us. diff --git a/clang/test/SemaCXX/typo-correction-pt2.cpp b/clang/test/SemaCXX/typo-correction-pt2.cpp index 543a5823f71b5c5bfa312aad8248a58b9870ab5c..59eb0609c35d5ed25eeaadf10e9a3ebd0ae0aa8a 100644 --- a/clang/test/SemaCXX/typo-correction-pt2.cpp +++ b/clang/test/SemaCXX/typo-correction-pt2.cpp @@ -5,6 +5,37 @@ // attempt within a single file (which is to avoid having very broken files take // minutes to finally be rejected by the parser). +namespace bogus_keyword_suggestion { +void test() { + status = "OK"; // expected-error-re {{use of undeclared identifier 'status'$}} + return status; // expected-error-re {{use of undeclared identifier 'status'$}} + } +} + +namespace PR13387 { +struct A { + void CreateFoo(float, float); + void CreateBar(float, float); +}; +struct B : A { + using A::CreateFoo; + void CreateFoo(int, int); +}; +void f(B &x) { + x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}} +} +} + +struct DataStruct {void foo();}; +struct T { + DataStruct data_struct; + void f(); +}; +// should be void T::f(); +void f() { + data_struct->foo(); // expected-error-re{{use of undeclared identifier 'data_struct'$}} +} + namespace PR12287 { class zif { void nab(int); diff --git a/clang/test/SemaCXX/typo-correction.cpp b/clang/test/SemaCXX/typo-correction.cpp index c2c79d2203057e8c44f8f240d46901319c3320fd..d779e2a4480a6a5be533e77e7bf1e5a16f14eb86 100644 --- a/clang/test/SemaCXX/typo-correction.cpp +++ b/clang/test/SemaCXX/typo-correction.cpp @@ -246,37 +246,6 @@ namespace outer { } } -namespace bogus_keyword_suggestion { -void test() { - status = "OK"; // expected-error-re{{use of undeclared identifier 'status'$}} - return status; // expected-error-re{{use of undeclared identifier 'status'$}} - } -} - -namespace PR13387 { -struct A { - void CreateFoo(float, float); - void CreateBar(float, float); -}; -struct B : A { - using A::CreateFoo; - void CreateFoo(int, int); -}; -void f(B &x) { - x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}} -} -} - -struct DataStruct {void foo();}; -struct T { - DataStruct data_struct; - void f(); -}; -// should be void T::f(); -void f() { - data_struct->foo(); // expected-error-re{{use of undeclared identifier 'data_struct'$}} -} - namespace b6956809_test1 { struct A {}; struct B {}; @@ -319,9 +288,13 @@ namespace b6956809_test2 { } } +// This test should have one correction, followed by an error without a +// suggestion due to exceeding the maximum number of typos for which correction +// is attempted. namespace CorrectTypo_has_reached_its_limit { -int flibberdy(); // no note here +int flibberdy(); // expected-note{{'flibberdy' declared here}} int no_correction() { - return gibberdy(); // expected-error-re{{use of undeclared identifier 'gibberdy'$}} + return hibberdy() + // expected-error{{use of undeclared identifier 'hibberdy'; did you mean 'flibberdy'?}} + gibberdy(); // expected-error-re{{use of undeclared identifier 'gibberdy'$}} }; }