diff options
author | Kaelyn Takata <rikka@google.com> | 2014-11-20 22:06:40 +0000 |
---|---|---|
committer | Kaelyn Takata <rikka@google.com> | 2014-11-20 22:06:40 +0000 |
commit | b11b40a67ef9847447d3066fad06698dd9c317d2 (patch) | |
tree | f70db662f7ba6f6e82e24fa5fdc977819d57aa86 /lib/Sema/SemaExpr.cpp | |
parent | dcc69e9eb1b2bbbd1cc714744345cb4165214af5 (diff) |
Wire up delayed typo correction to DiagnoseEmptyLookup and set up
Sema::ActOnIdExpression to use the new functionality.
Among other things, this allows recovery in several cases where it
wasn't possible before (e.g. correcting a mistyped static_cast<>).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@222464 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 96 |
1 files changed, 88 insertions, 8 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 22657ba369..dc02f4ecc2 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1673,6 +1673,40 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, } } +static void emitEmptyLookupTypoDiagnostic( + const TypoCorrection &TC, Sema &SemaRef, const CXXScopeSpec &SS, + DeclarationName Typo, SourceLocation TypoLoc, ArrayRef<Expr *> Args, + unsigned DiagnosticID, unsigned DiagnosticSuggestID) { + DeclContext *Ctx = + SS.isEmpty() ? nullptr : SemaRef.computeDeclContext(SS, false); + if (!TC) { + // Emit a special diagnostic for failed member lookups. + // FIXME: computing the declaration context might fail here (?) + if (Ctx) + SemaRef.Diag(TypoLoc, diag::err_no_member) << Typo << Ctx + << SS.getRange(); + else + SemaRef.Diag(TypoLoc, DiagnosticID) << Typo; + return; + } + + std::string CorrectedStr = TC.getAsString(SemaRef.getLangOpts()); + bool DroppedSpecifier = + TC.WillReplaceSpecifier() && Typo.getAsString() == CorrectedStr; + unsigned NoteID = + (TC.getCorrectionDecl() && isa<ImplicitParamDecl>(TC.getCorrectionDecl())) + ? diag::note_implicit_param_decl + : diag::note_previous_decl; + if (!Ctx) + SemaRef.diagnoseTypo(TC, SemaRef.PDiag(DiagnosticSuggestID) << Typo, + SemaRef.PDiag(NoteID)); + else + SemaRef.diagnoseTypo(TC, SemaRef.PDiag(diag::err_no_member_suggest) + << Typo << Ctx << DroppedSpecifier + << SS.getRange(), + SemaRef.PDiag(NoteID)); +} + /// Diagnose an empty lookup. /// /// \return false if new lookup candidates were found @@ -1680,7 +1714,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, std::unique_ptr<CorrectionCandidateCallback> CCC, TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef<Expr *> Args) { + ArrayRef<Expr *> Args, TypoExpr **Out) { DeclarationName Name = R.getLookupName(); unsigned diagnostic = diag::err_undeclared_var_use; @@ -1797,8 +1831,22 @@ Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // We didn't find anything, so try to correct for a typo. TypoCorrection Corrected; - if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), - S, &SS, std::move(CCC), CTK_ErrorRecovery))) { + if (S && Out) { + SourceLocation TypoLoc = R.getNameLoc(); + assert(!ExplicitTemplateArgs && + "Diagnosing an empty lookup with explicit template args!"); + *Out = CorrectTypoDelayed( + R.getLookupNameInfo(), R.getLookupKind(), S, &SS, std::move(CCC), + [=](const TypoCorrection &TC) { + emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args, + diagnostic, diagnostic_suggest); + }, + nullptr, CTK_ErrorRecovery); + if (*Out) + return true; + } else if (S && (Corrected = + CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, + &SS, std::move(CCC), CTK_ErrorRecovery))) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr; @@ -1950,7 +1998,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, std::unique_ptr<CorrectionCandidateCallback> CCC, - bool IsInlineAsmIdentifier) { + bool IsInlineAsmIdentifier, Token *KeywordReplacement) { assert(!(IsAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); if (SS.isInvalid()) @@ -2062,13 +2110,43 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // If this name wasn't predeclared and if this is not a function // call, diagnose the problem. - auto DefaultValidator = llvm::make_unique<CorrectionCandidateCallback>(); + TypoExpr *TE = nullptr; + auto DefaultValidator = llvm::make_unique<CorrectionCandidateCallback>( + II, SS.isValid() ? SS.getScopeRep() : nullptr); DefaultValidator->IsAddressOfOperand = IsAddressOfOperand; assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) && "Typo correction callback misconfigured"); - if (DiagnoseEmptyLookup(S, SS, R, - CCC ? std::move(CCC) : std::move(DefaultValidator))) - return ExprError(); + if (CCC) { + // Make sure the callback knows what the typo being diagnosed is. + CCC->setTypoName(II); + if (SS.isValid()) + CCC->setTypoNNS(SS.getScopeRep()); + } + if (DiagnoseEmptyLookup( + S, SS, R, CCC ? std::move(CCC) : std::move(DefaultValidator), + nullptr, None, getLangOpts().CPlusPlus ? &TE : nullptr)) { + if (TE && KeywordReplacement) { + auto &State = getTypoExprState(TE); + auto BestTC = State.Consumer->getNextCorrection(); + if (BestTC.isKeyword()) { + auto *II = BestTC.getCorrectionAsIdentifierInfo(); + if (State.DiagHandler) + State.DiagHandler(BestTC); + KeywordReplacement->startToken(); + KeywordReplacement->setKind(II->getTokenID()); + KeywordReplacement->setIdentifierInfo(II); + KeywordReplacement->setLocation(BestTC.getCorrectionRange().getBegin()); + // Clean up the state associated with the TypoExpr, since it has + // now been diagnosed (without a call to CorrectDelayedTyposInExpr). + clearDelayedTypo(TE); + // Signal that a correction to a keyword was performed by returning a + // valid-but-null ExprResult. + return (Expr*)nullptr; + } + State.Consumer->resetCorrectionStream(); + } + return TE ? TE : ExprError(); + } assert(!R.empty() && "DiagnoseEmptyLookup returned false but added no results"); @@ -12450,6 +12528,8 @@ void Sema::UpdateMarkingForLValueToRValue(Expr *E) { } ExprResult Sema::ActOnConstantExpression(ExprResult Res) { + Res = CorrectDelayedTyposInExpr(Res); + if (!Res.isUsable()) return Res; |