From 50dc12ad05d4a3a57e83852756498afce4307a77 Mon Sep 17 00:00:00 2001 From: Kaelyn Uhrain Date: Fri, 15 Jun 2012 23:45:58 +0000 Subject: [PATCH] Recover when correcting an unknown type name to a keyword like "struct". git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158573 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 2 +- lib/Parse/ParseDecl.cpp | 10 +++++++--- lib/Sema/SemaDecl.cpp | 28 ++++++++++++++++------------ test/Parser/recovery.cpp | 12 ++++++------ 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 72ed636e60..c6af1d861a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1124,7 +1124,7 @@ public: IdentifierInfo **CorrectedII = 0); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); - bool DiagnoseUnknownTypeName(const IdentifierInfo &II, + bool DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 3eeef7bff3..f48f9e8c68 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1751,8 +1751,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // This is almost certainly an invalid type name. Let the action emit a // diagnostic and attempt to recover. ParsedType T; - if (Actions.DiagnoseUnknownTypeName(*Tok.getIdentifierInfo(), Loc, - getCurScope(), SS, T)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (Actions.DiagnoseUnknownTypeName(II, Loc, getCurScope(), SS, T)) { // The action emitted a diagnostic, so we don't have to. if (T) { // The action has suggested that the type T could be used. Set that as @@ -1763,7 +1763,11 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T); DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); - + // There may be other declaration specifiers after this. + return true; + } else if (II != Tok.getIdentifierInfo()) { + // If no type was suggested, the correction is to a keyword + Tok.setKind(II->getTokenID()); // There may be other declaration specifiers after this. return true; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5221322a14..399f518fcc 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -395,7 +395,7 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); } -bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, +bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, @@ -406,7 +406,7 @@ 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), + if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS, Validator)) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); @@ -414,19 +414,23 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, if (Corrected.isKeyword()) { // We corrected to a keyword. - // FIXME: Actually recover with the keyword we suggest, and emit a fix-it. + IdentifierInfo *NewII = Corrected.getCorrectionAsIdentifierInfo(); + if (!isSimpleTypeSpecifier(NewII->getTokenID())) + CorrectedQuotedStr = "the keyword " + CorrectedQuotedStr; Diag(IILoc, diag::err_unknown_typename_suggest) - << &II << CorrectedQuotedStr; + << II << CorrectedQuotedStr + << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); + II = NewII; } else { NamedDecl *Result = Corrected.getCorrectionDecl(); // We found a similarly-named type or interface; suggest that. if (!SS || !SS->isSet()) Diag(IILoc, diag::err_unknown_typename_suggest) - << &II << CorrectedQuotedStr + << 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() + << II << DC << CorrectedQuotedStr << SS->getRange() << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); else llvm_unreachable("could not have corrected a typo here"); @@ -445,7 +449,7 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, if (getLangOpts().CPlusPlus) { // See if II is a class template that the user forgot to pass arguments to. UnqualifiedId Name; - Name.setIdentifier(&II, IILoc); + Name.setIdentifier(II, IILoc); CXXScopeSpec EmptySS; TemplateTy TemplateResult; bool MemberOfUnknownSpecialization; @@ -466,21 +470,21 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, // (struct, union, enum) from Parser::ParseImplicitInt here, instead? if (!SS || (!SS->isSet() && !SS->isInvalid())) - Diag(IILoc, diag::err_unknown_typename) << &II; + Diag(IILoc, diag::err_unknown_typename) << II; else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_typename_nested_not_found) - << &II << DC << SS->getRange(); + << II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; if (getLangOpts().MicrosoftMode && isMicrosoftMissingTypename(SS, S)) DiagID = diag::warn_typename_missing; Diag(SS->getRange().getBegin(), DiagID) - << (NestedNameSpecifier *)SS->getScopeRep() << II.getName() + << (NestedNameSpecifier *)SS->getScopeRep() << II->getName() << SourceRange(SS->getRange().getBegin(), IILoc) << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename "); - SuggestedType = ActOnTypenameType(S, SourceLocation(), *SS, II, IILoc) - .get(); + SuggestedType = ActOnTypenameType(S, SourceLocation(), + *SS, *II, IILoc).get(); } else { assert(SS && SS->isInvalid() && "Invalid scope specifier has already been diagnosed"); diff --git a/test/Parser/recovery.cpp b/test/Parser/recovery.cpp index ffa1bab55a..ff687583c2 100644 --- a/test/Parser/recovery.cpp +++ b/test/Parser/recovery.cpp @@ -12,13 +12,12 @@ inline namespace Std { // expected-error {{cannot be reopened as inline}} int x; Std::Important y; -// FIXME: Recover as if the typo correction were applied. -extenr "C" { // expected-error {{did you mean 'extern'}} expected-error {{unqualified-id}} +extenr "C" { // expected-error {{did you mean the keyword 'extern'}} void f(); } void g() { z = 1; // expected-error {{undeclared}} - f(); // expected-error {{undeclared}} + f(); } struct S { @@ -37,6 +36,7 @@ namespace N { int } // expected-error {{unqualified-id}} -// FIXME: Recover as if the typo correction were applied. -strcut U { // expected-error {{did you mean 'struct'}} -} *u[3]; // expected-error {{expected ';'}} +strcut Uuuu { // expected-error {{did you mean the keyword 'struct'}} \ + // expected-note {{'Uuuu' declared here}} +} *u[3]; +uuuu v; // expected-error {{did you mean 'Uuuu'}} -- 2.40.0