From: Kaelyn Uhrain Date: Wed, 18 Jan 2012 21:41:41 +0000 (+0000) Subject: Convert SemaDecl.cpp to pass callback objects to CorrectTypo. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=43e875d2610afcf9e7017b71f46116dc86624fd9;p=clang Convert SemaDecl.cpp to pass callback objects to CorrectTypo. Includes tests highlighting the cases where accuracy has improved (there is one call that does no filtering beyond selecting the set of allowed keywords, and one call that only triggers for ObjC code for which a test by someone who knows ObjC would be welcome). Also fixes a small typo in one of the suggestion messages, and drops a malformed "expected-note" for a suggestion that did not occur even when the malformed note was committed as r145930. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148420 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fcc9e948fb..7ff22eb74e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3480,7 +3480,7 @@ def err_member_def_does_not_match : Error< "out-of-line definition of %0 does not match any declaration in %1">; def err_member_def_does_not_match_suggest : Error< "out-of-line definition of %0 does not match any declaration in %1; " - "did you mean %2">; + "did you mean %2?">; def err_member_def_does_not_match_ret_type : Error< "out-of-line definition of %q0 differs from the declaration in the return type">; def err_nonstatic_member_out_of_line : Error< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 61e104fd1d..f2af0a7075 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -55,6 +55,30 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) { return DeclGroupPtrTy::make(DeclGroupRef(Ptr)); } +namespace { + +class TypeNameValidatorCCC : public CorrectionCandidateCallback { + public: + TypeNameValidatorCCC(bool AllowInvalid) : AllowInvalidDecl(AllowInvalid) { + WantExpressionKeywords = false; + WantCXXNamedCasts = false; + WantRemainingKeywords = false; + } + + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + if (NamedDecl *ND = candidate.getCorrectionDecl()) + return (isa(ND) || isa(ND)) && + (AllowInvalidDecl || !ND->isInvalidDecl()); + else + return candidate.isKeyword(); + } + + private: + bool AllowInvalidDecl; +}; + +} + /// \brief If the identifier refers to a type name within this scope, /// return the declaration of that type. /// @@ -147,9 +171,9 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: if (CorrectedII) { + TypeNameValidatorCCC Validator(true); TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(), - Kind, S, SS, 0, false, - Sema::CTC_Type); + Kind, S, SS, &Validator); IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo(); TemplateTy Template; bool MemberOfUnknownSpecialization; @@ -339,9 +363,10 @@ 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. + TypeNameValidatorCCC Validator(false); if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(&II, IILoc), - LookupOrdinaryName, S, SS, NULL, - false, CTC_Type)) { + LookupOrdinaryName, S, SS, + &Validator)) { std::string CorrectedStr(Corrected.getAsString(getLangOptions())); std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOptions())); @@ -350,32 +375,28 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, // 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(Result) || isa(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 << CorrectedQuotedStr - << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); - else if (DeclContext *DC = computeDeclContext(*SS, false)) - Diag(IILoc, diag::err_unknown_nested_typename_suggest) - << &II << DC << CorrectedQuotedStr << SS->getRange() - << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); - else - llvm_unreachable("could not have corrected a typo here"); + // We found a similarly-named type or interface; suggest that. + if (!SS || !SS->isSet()) + Diag(IILoc, diag::err_unknown_typename_suggest) + << &II << CorrectedQuotedStr + << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); + else if (DeclContext *DC = computeDeclContext(*SS, false)) + Diag(IILoc, diag::err_unknown_nested_typename_suggest) + << &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) - << CorrectedQuotedStr; - - SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS, - false, false, ParsedType(), - /*NonTrivialTypeSourceInfo=*/true); - return true; - } + Diag(Result->getLocation(), diag::note_previous_decl) + << CorrectedQuotedStr; + + SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS, + false, false, ParsedType(), + /*NonTrivialTypeSourceInfo=*/true); } + return true; } if (getLangOptions().CPlusPlus) { @@ -546,9 +567,10 @@ Corrected: // close to this name. if (!SecondTry) { SecondTry = true; + CorrectionCandidateCallback DefaultValidator; if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, - &SS)) { + &SS, &DefaultValidator)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; std::string CorrectedStr(Corrected.getAsString(getLangOptions())); @@ -1241,10 +1263,11 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, if (!IDecl && DoTypoCorrection) { // Perform typo correction at the given location, but only if we // find an Objective-C class name. - TypoCorrection C; - if ((C = CorrectTypo(DeclarationNameInfo(Id, IdLoc), LookupOrdinaryName, - TUScope, NULL, NULL, false, CTC_NoKeywords)) && - (IDecl = C.getCorrectionDeclAs())) { + DeclFilterCCC Validator; + if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc), + LookupOrdinaryName, TUScope, NULL, + &Validator)) { + IDecl = C.getCorrectionDeclAs(); Diag(IdLoc, diag::err_undef_interface_suggest) << Id << IDecl->getDeclName() << FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString()); @@ -4409,6 +4432,18 @@ namespace { }; } +namespace { + +// Callback to only accept typo corrections that have a non-zero edit distance. +class DifferentNameValidatorCCC : public CorrectionCandidateCallback { + public: + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + return candidate.getEditDistance() > 0; + } +}; + +} + /// \brief Generate diagnostics for an invalid function redeclaration. /// /// This routine handles generating the diagnostic messages for an invalid @@ -4438,6 +4473,7 @@ static NamedDecl* DiagnoseInvalidRedeclaration( SemaRef.LookupQualifiedName(Prev, NewDC); assert(!Prev.isAmbiguous() && "Cannot have an ambiguity in previous-declaration lookup"); + DifferentNameValidatorCCC Validator; if (!Prev.empty()) { for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end(); Func != FuncEnd; ++Func) { @@ -4453,8 +4489,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration( } // If the qualified name lookup yielded nothing, try typo correction } else if ((Correction = SemaRef.CorrectTypo(Prev.getLookupNameInfo(), - Prev.getLookupKind(), 0, 0, NewDC)) && - Correction.getCorrection() != Name) { + Prev.getLookupKind(), 0, 0, + &Validator, NewDC))) { // Trap errors. Sema::SFINAETrap Trap(SemaRef); @@ -7309,21 +7345,20 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, // function declaration is going to be treated as an error. if (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error) { TypoCorrection Corrected; + DeclFilterCCC Validator; if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc), - LookupOrdinaryName, S, 0))) { - NamedDecl *Decl = Corrected.getCorrectionDecl(); - if (FunctionDecl *Func = dyn_cast_or_null(Decl)) { - std::string CorrectedStr = Corrected.getAsString(getLangOptions()); - std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOptions()); - - Diag(Loc, diag::note_function_suggestion) << CorrectedQuotedStr - << FixItHint::CreateReplacement(Loc, CorrectedStr); - - if (Func->getLocation().isValid() - && !II.getName().startswith("__builtin_")) - Diag(Func->getLocation(), diag::note_previous_decl) - << CorrectedQuotedStr; - } + LookupOrdinaryName, S, 0, &Validator))) { + std::string CorrectedStr = Corrected.getAsString(getLangOptions()); + std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOptions()); + FunctionDecl *Func = Corrected.getCorrectionDeclAs(); + + Diag(Loc, diag::note_function_suggestion) << CorrectedQuotedStr + << FixItHint::CreateReplacement(Loc, CorrectedStr); + + if (Func->getLocation().isValid() + && !II.getName().startswith("__builtin_")) + Diag(Func->getLocation(), diag::note_previous_decl) + << CorrectedQuotedStr; } } diff --git a/test/Sema/implicit-decl.c b/test/Sema/implicit-decl.c index 2e1a865254..ffab9a6f91 100644 --- a/test/Sema/implicit-decl.c +++ b/test/Sema/implicit-decl.c @@ -16,9 +16,17 @@ void func() { printg("Hello, World!\n"); // expected-error{{implicit declaration of function 'printg' is invalid in C99}} \ // expected-note{{did you mean 'printf'?}} - __builtin_is_les(1, 3); // expected-error{{use of unknown builtin '__builtin_is_les'}} \ - // expected-note{did you mean '__builtin_is_less'?}} + __builtin_is_les(1, 3); // expected-error{{use of unknown builtin '__builtin_is_les'}} } Boolean _CFCalendarDecomposeAbsoluteTimeV(const char *componentDesc, int32_t **vector, int32_t count) { // expected-error{{conflicting types for '_CFCalendarDecomposeAbsoluteTimeV'}} return 0; } + + +// Test the typo-correction callback in Sema::ImplicitlyDefineFunction +extern int sformatf(char *str, __const char *__restrict __format, ...); // expected-note{{'sformatf' declared here}} +void test_implicit() { + int formats = 0; + formatd("Hello, World!\n"); // expected-error{{implicit declaration of function 'formatd' is invalid in C99}} \ + // expected-note{{did you mean 'sformatf'?}} +} diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp index 618e30a25a..edf4c6460a 100644 --- a/test/SemaCXX/typo-correction.cpp +++ b/test/SemaCXX/typo-correction.cpp @@ -67,12 +67,14 @@ struct st { st var = { .fielda = 0.0 }; // expected-error{{field designator 'fielda' does not refer to any field in type 'st'; did you mean 'FieldA'?}} // Test the improvement from passing a callback object to CorrectTypo in -// Sema::BuildCXXNestedNameSpecifier. -typedef char* another_str; +// Sema::BuildCXXNestedNameSpecifier. And also for the improvement by doing +// so in Sema::getTypeName. +typedef char* another_str; // expected-note{{'another_str' declared here}} namespace AnotherStd { // expected-note{{'AnotherStd' declared here}} class string {}; } another_std::string str; // expected-error{{use of undeclared identifier 'another_std'; did you mean 'AnotherStd'?}} +another_str *cstr = new AnotherStr; // expected-error{{unknown type name 'AnotherStr'; did you mean 'another_str'?}} // Test the improvement from passing a callback object to CorrectTypo in // Sema::ActOnSizeofParameterPackExpr. @@ -80,3 +82,19 @@ char* TireNames; template struct count { // expected-note{{parameter pack 'TypeNames' declared here}} static const unsigned value = sizeof...(TyreNames); // expected-error{{'TyreNames' does not refer to the name of a parameter pack; did you mean 'TypeNames'?}} }; + +// Test the typo-correction callback in Sema::DiagnoseUnknownTypeName. +namespace unknown_type_test { + class StreamOut {}; // expected-note{{'StreamOut' declared here}} + long stream_count; +}; +unknown_type_test::stream_out out; // expected-error{{no type named 'stream_out' in namespace 'unknown_type_test'; did you mean 'StreamOut'?}} + +// Test the typo-correction callback in Sema::DiagnoseInvalidRedeclaration. +struct BaseDecl { + void add_in(int i); +}; +struct TestRedecl : public BaseDecl { + void add_it(int i); // expected-note{{'add_it' declared here}} +}; +void TestRedecl::add_in(int i) {} // expected-error{{out-of-line definition of 'add_in' does not match any declaration in 'TestRedecl'; did you mean 'add_it'?}}