Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Sema][Typo] Fix assertion failure for expressions with multiple typos
Summary: As Typo Resolution can create new TypoExprs while resolving typos, it is necessary to recurse through the expression to search for more typos. This should fix the assertion failure in `clang::Sema::~Sema()`: `DelayedTypos.empty() && "Uncorrected typos!"` Notes: - In case some TypoExprs are created but thrown away, Sema now has a Vector that is used to keep track of newly created typos. - For expressions with multiple typos, we only give suggestions if we are able to resolve all typos in the expression - This patch is similar to D37521 except that it does not eagerly commit to a correction for the first typo in the expression. Instead, it will search for corrections which fix all of the typos in the expression. Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D62648 llvm-svn: 369427
- Loading branch information
1 parent
514f3a1
commit fd4d777
Showing
4 changed files
with
280 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// RUN: %clang_cc1 -fsyntax-only -verify %s | ||
|
||
// Check the following typo correction behavior: | ||
// - multiple typos in a single member call chain are all diagnosed | ||
// - no typos are diagnosed for multiple typos in an expression when not all | ||
// typos can be corrected | ||
|
||
class DeepClass | ||
{ | ||
public: | ||
void trigger() const; // expected-note {{'trigger' declared here}} | ||
}; | ||
|
||
class Y | ||
{ | ||
public: | ||
const DeepClass& getX() const { return m_deepInstance; } // expected-note {{'getX' declared here}} | ||
private: | ||
DeepClass m_deepInstance; | ||
int m_n; | ||
}; | ||
|
||
class Z | ||
{ | ||
public: | ||
const Y& getY0() const { return m_y0; } // expected-note {{'getY0' declared here}} | ||
const Y& getActiveY() const { return m_y0; } | ||
|
||
private: | ||
Y m_y0; | ||
Y m_y1; | ||
}; | ||
|
||
Z z_obj; | ||
|
||
void testMultipleCorrections() | ||
{ | ||
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'}} | ||
triggee(); // expected-error {{no member named 'triggee' in 'DeepClass'; did you mean 'trigger'}} | ||
} | ||
|
||
void testNoCorrections() | ||
{ | ||
z_obj.getY2(). // expected-error {{no member named 'getY2' in 'Z'}} | ||
getM(). | ||
thisDoesntSeemToMakeSense(); | ||
} | ||
|
||
struct C {}; | ||
struct D { int value; }; | ||
struct A { | ||
C get_me_a_C(); | ||
}; | ||
struct B { | ||
D get_me_a_D(); // expected-note {{'get_me_a_D' declared here}} | ||
}; | ||
class Scope { | ||
public: | ||
A make_an_A(); | ||
B make_a_B(); // expected-note {{'make_a_B' declared here}} | ||
}; | ||
|
||
Scope scope_obj; | ||
|
||
int testDiscardedCorrections() { | ||
return scope_obj.make_an_E(). // expected-error {{no member named 'make_an_E' in 'Scope'; did you mean 'make_a_B'}} | ||
get_me_a_Z().value; // expected-error {{no member named 'get_me_a_Z' in 'B'; did you mean 'get_me_a_D'}} | ||
} | ||
|
||
class AmbiguousHelper { | ||
public: | ||
int helpMe(); | ||
int helpBe(); | ||
}; | ||
class Ambiguous { | ||
public: | ||
int calculateA(); | ||
int calculateB(); | ||
|
||
AmbiguousHelper getHelp1(); | ||
AmbiguousHelper getHelp2(); | ||
}; | ||
|
||
Ambiguous ambiguous_obj; | ||
|
||
int testDirectAmbiguousCorrection() { | ||
return ambiguous_obj.calculateZ(); // expected-error {{no member named 'calculateZ' in 'Ambiguous'}} | ||
} | ||
|
||
int testRecursiveAmbiguousCorrection() { | ||
return ambiguous_obj.getHelp3(). // expected-error {{no member named 'getHelp3' in 'Ambiguous'}} | ||
helpCe(); | ||
} | ||
|
||
|
||
class DeepAmbiguityHelper { | ||
public: | ||
DeepAmbiguityHelper& help1(); | ||
DeepAmbiguityHelper& help2(); | ||
|
||
DeepAmbiguityHelper& methodA(); | ||
DeepAmbiguityHelper& somethingMethodB(); | ||
DeepAmbiguityHelper& functionC(); | ||
DeepAmbiguityHelper& deepMethodD(); | ||
DeepAmbiguityHelper& asDeepAsItGets(); | ||
}; | ||
|
||
DeepAmbiguityHelper deep_obj; | ||
|
||
int testDeepAmbiguity() { | ||
deep_obj. | ||
methodB(). // expected-error {{no member named 'methodB' in 'DeepAmbiguityHelper'}} | ||
somethingMethodC(). | ||
functionD(). | ||
deepMethodD(). | ||
help3(). | ||
asDeepASItGet(). | ||
functionE(); | ||
} |