diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 4de2259ebaf3a8..670c0fe80b4e1f 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -6152,8 +6152,12 @@ class AtomicExpr : public Expr { /// TypoExpr - Internal placeholder for expressions where typo correction /// still needs to be performed and/or an error diagnostic emitted. class TypoExpr : public Expr { + // The location for the typo name. + SourceLocation TypoLoc; + public: - TypoExpr(QualType T) : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary) { + TypoExpr(QualType T, SourceLocation TypoLoc) + : Expr(TypoExprClass, T, VK_LValue, OK_Ordinary), TypoLoc(TypoLoc) { assert(T->isDependentType() && "TypoExpr given a non-dependent type"); setDependence(ExprDependence::TypeValueInstantiation | ExprDependence::Error); @@ -6166,8 +6170,8 @@ class TypoExpr : public Expr { return const_child_range(const_child_iterator(), const_child_iterator()); } - SourceLocation getBeginLoc() const LLVM_READONLY { return SourceLocation(); } - SourceLocation getEndLoc() const LLVM_READONLY { return SourceLocation(); } + SourceLocation getBeginLoc() const LLVM_READONLY { return TypoLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return TypoLoc; } static bool classof(const Stmt *T) { return T->getStmtClass() == TypoExprClass; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 2a71d01d6edb14..5f0a03b1c93fa6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3695,7 +3695,7 @@ class Sema final { /// Creates a new TypoExpr AST node. TypoExpr *createDelayedTypo(std::unique_ptr TCC, TypoDiagnosticGenerator TDG, - TypoRecoveryCallback TRC); + TypoRecoveryCallback TRC, SourceLocation TypoLoc); // The set of known/encountered (unique, canonicalized) NamespaceDecls. // diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 9c4e5b4a784820..c22af86d57aa63 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -8307,8 +8307,6 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, if (FullExpr.isInvalid()) { // Typo-correction fails, we rebuild the broken AST with the typos degraded // to RecoveryExpr. - // FIXME: we lose source locations for RecoveryExpr, as TypoExpr doesn't - // track source locations. struct TyposReplace : TreeTransform { TyposReplace(Sema &SemaRef) : TreeTransform(SemaRef) {} ExprResult TransformTypoExpr(TypoExpr *E) { diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index dbbd190caea997..0afb75752c126b 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -5167,9 +5167,9 @@ TypoExpr *Sema::CorrectTypoDelayed( IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3) return nullptr; - ExprEvalContexts.back().NumTypos++; - return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC)); + return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC), + TypoName.getLoc()); } void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { @@ -5481,9 +5481,10 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, TypoExpr *Sema::createDelayedTypo(std::unique_ptr TCC, TypoDiagnosticGenerator TDG, - TypoRecoveryCallback TRC) { + TypoRecoveryCallback TRC, + SourceLocation TypoLoc) { assert(TCC && "createDelayedTypo requires a valid TypoCorrectionConsumer"); - auto TE = new (Context) TypoExpr(Context.DependentTy); + auto TE = new (Context) TypoExpr(Context.DependentTy, TypoLoc); auto &State = DelayedTypos[TE]; State.Consumer = std::move(TCC); State.DiagHandler = std::move(TDG); diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp index 6d271cebc7f91f..e2a71513062874 100644 --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -13,9 +13,9 @@ int invalid_call = some_func(123); void test_invalid_call(int s) { // CHECK: CallExpr {{.*}} '' contains-errors // CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func' - // CHECK-NEXT: |-RecoveryExpr {{.*}} <> - // CHECK-NEXT: `-BinaryOperator {{.*}} <, col:28> - // CHECK-NEXT: |-RecoveryExpr {{.*}} <> + // CHECK-NEXT: |-RecoveryExpr {{.*}} + // CHECK-NEXT: `-BinaryOperator {{.*}} + // CHECK-NEXT: |-RecoveryExpr {{.*}} // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 some_func(undef1, undef2+1);