iid_iunknown created this revision.
This is a patch proposal for PR34507.
Typo resolution can create new TypoExprs while transforming an expression.
These TypoExprs are not transformed, they are present in the resulting
expression and cause the `DelayedTypos.empty() && "Uncorrected typos!"`
assertion failure in `clang::Sema::~Sema()`. If clang is built without
assertions, these TypoExprs are not reported causing incomplete diagnostics.
The patch checks the transformed expression for new TypoExprs and, if any
found, transforms the expression again until either all TypoExprs are handled
or the result becomes invalid.
Repository:
rL LLVM
https://reviews.llvm.org/D37521
Files:
lib/Sema/SemaExprCXX.cpp
test/Sema/typo-correction-multiple-typos.cpp
Index: test/Sema/typo-correction-multiple-typos.cpp
===================================================================
--- test/Sema/typo-correction-multiple-typos.cpp
+++ test/Sema/typo-correction-multiple-typos.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// This file contains typo correction test which ensures that
+// multiple typos in a single member calls chain are correctly
+// diagnosed.
+
+class X
+{
+public:
+ void foo() const; // expected-note {{'foo' declared here}}
+};
+
+class Y
+{
+public:
+ const X& getX() const { return m_x; } // expected-note {{'getX' declared
here}}
+ int getN() const { return m_n; }
+private:
+ X m_x;
+ int m_n;
+};
+
+class Z
+{
+public:
+ const Y& getY0() const { return m_y0; } // expected-note {{'getY0' declared
here}}
+ const Y& getY1() const { return m_y1; }
+
+private:
+ Y m_y0;
+ Y m_y1;
+};
+
+Z z_obj;
+
+void test()
+{
+ z_obj.getY2(). // expected-error {{no member named 'getY2' in 'Z'; did you
mean 'getY0'}}
+ getM(). // expected-error {{no member named 'getM' in 'Y'; did you
mean 'getX'}}
+ foe(); // expected-error {{no member named 'foe' in 'X'; did you
mean 'foo'}}
+}
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -7362,6 +7362,30 @@
break;
}
+ // The transform is able to produce new TypoExprs while resolving the
typos.
+ // These new TypoExprs are not resolved by the transform, they do not get
+ // into the TypoExprs container and are not reported, so they need to be
+ // handled separately.
+ // If the transform result is valid and contains newly created TypoExprs,
+ // transform the result expression again until no new TypoExprs get created
+ // or the result becomes an invalid expression. Return the longest valid
+ // expression to report as many typos as possible.
+ if (!Res.isInvalid()) {
+ while (true) {
+ unsigned TyposCount = TypoExprs.size();
+ FindTypoExprs(TypoExprs).TraverseStmt(Res.get());
+ if (TypoExprs.size() == TyposCount)
+ // No new TypoExprs created by the transform
+ break;
+ ExprResult TmpRes = TryTransform(Res.get());
+ if (TmpRes.isInvalid())
+ // Further transform prodices an invalid Expr.
+ // Stop with the last valid result.
+ break;
+ Res = TmpRes;
+ }
+ }
+
// Ensure none of the TypoExprs have multiple typo correction candidates
// with the same edit length that pass all the checks and filters.
// TODO: Properly handle various permutations of possible corrections when
Index: test/Sema/typo-correction-multiple-typos.cpp
===================================================================
--- test/Sema/typo-correction-multiple-typos.cpp
+++ test/Sema/typo-correction-multiple-typos.cpp
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// This file contains typo correction test which ensures that
+// multiple typos in a single member calls chain are correctly
+// diagnosed.
+
+class X
+{
+public:
+ void foo() const; // expected-note {{'foo' declared here}}
+};
+
+class Y
+{
+public:
+ const X& getX() const { return m_x; } // expected-note {{'getX' declared here}}
+ int getN() const { return m_n; }
+private:
+ X m_x;
+ int m_n;
+};
+
+class Z
+{
+public:
+ const Y& getY0() const { return m_y0; } // expected-note {{'getY0' declared here}}
+ const Y& getY1() const { return m_y1; }
+
+private:
+ Y m_y0;
+ Y m_y1;
+};
+
+Z z_obj;
+
+void test()
+{
+ z_obj.getY2(). // expected-error {{no member named 'getY2' in 'Z'; did you mean 'getY0'}}
+ getM(). // expected-error {{no member named 'getM' in 'Y'; did you mean 'getX'}}
+ foe(); // expected-error {{no member named 'foe' in 'X'; did you mean 'foo'}}
+}
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -7362,6 +7362,30 @@
break;
}
+ // The transform is able to produce new TypoExprs while resolving the typos.
+ // These new TypoExprs are not resolved by the transform, they do not get
+ // into the TypoExprs container and are not reported, so they need to be
+ // handled separately.
+ // If the transform result is valid and contains newly created TypoExprs,
+ // transform the result expression again until no new TypoExprs get created
+ // or the result becomes an invalid expression. Return the longest valid
+ // expression to report as many typos as possible.
+ if (!Res.isInvalid()) {
+ while (true) {
+ unsigned TyposCount = TypoExprs.size();
+ FindTypoExprs(TypoExprs).TraverseStmt(Res.get());
+ if (TypoExprs.size() == TyposCount)
+ // No new TypoExprs created by the transform
+ break;
+ ExprResult TmpRes = TryTransform(Res.get());
+ if (TmpRes.isInvalid())
+ // Further transform prodices an invalid Expr.
+ // Stop with the last valid result.
+ break;
+ Res = TmpRes;
+ }
+ }
+
// Ensure none of the TypoExprs have multiple typo correction candidates
// with the same edit length that pass all the checks and filters.
// TODO: Properly handle various permutations of possible corrections when
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits