diff options
author | David Goldman <davg@google.com> | 2020-07-17 15:06:28 -0400 |
---|---|---|
committer | David Goldman <davg@google.com> | 2020-07-24 17:02:06 -0400 |
commit | 3c1fca803bc14617b67ba2125e1b4b77190e9f86 (patch) | |
tree | 0749145f0ab74d00d1f4800eede227fd5d9dfd8e | |
parent | 833f8c958601bb640ba6a25d627c1dc58dad14d2 (diff) | |
download | llvm-3c1fca803bc14617b67ba2125e1b4b77190e9f86.zip llvm-3c1fca803bc14617b67ba2125e1b4b77190e9f86.tar.gz llvm-3c1fca803bc14617b67ba2125e1b4b77190e9f86.tar.bz2 |
Fix issue in typo handling which could lead clang to hang
Summary:
We need to detect when certain TypoExprs are not being transformed
due to invalid trees, otherwise we risk endlessly trying to fix it.
Reviewers: rsmith
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D84067
(cherry picked from commit dde98c82c0ad02410229e7e5c9efcbb0ab42a995)
-rw-r--r-- | clang/include/clang/Sema/SemaInternal.h | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 25 | ||||
-rw-r--r-- | clang/test/Sema/typo-correction-no-hang.cpp | 40 | ||||
-rw-r--r-- | clang/test/Sema/typo-correction-recursive.cpp | 12 |
4 files changed, 73 insertions, 9 deletions
diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h index cdaf7b7..842eec0 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -168,6 +168,11 @@ public: return TC; } + /// In the case of deeply invalid expressions, `getNextCorrection()` will + /// never be called since the transform never makes progress. If we don't + /// detect this we risk trying to correct typos forever. + bool hasMadeAnyCorrectionProgress() const { return CurrentTCIndex != 0; } + /// Reset the consumer's position in the stream of viable corrections /// (i.e. getNextCorrection() will return each of the previously returned /// corrections in order before returning any new corrections). diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index d885920..77bd1ab 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -7977,19 +7977,26 @@ class TransformTypos : public TreeTransform<TransformTypos> { } } - /// If corrections for the first TypoExpr have been exhausted for a - /// given combination of the other TypoExprs, retry those corrections against - /// the next combination of substitutions for the other TypoExprs by advancing - /// to the next potential correction of the second TypoExpr. For the second - /// and subsequent TypoExprs, if its stream of corrections has been exhausted, - /// the stream is reset and the next TypoExpr's stream is advanced by one (a - /// TypoExpr's correction stream is advanced by removing the TypoExpr from the - /// TransformCache). Returns true if there is still any untried combinations - /// of corrections. + /// Try to advance the typo correction state of the first unfinished TypoExpr. + /// We allow advancement of the correction stream by removing it from the + /// TransformCache which allows `TransformTypoExpr` to advance during the + /// next transformation attempt. + /// + /// Any substitution attempts for the previous TypoExprs (which must have been + /// finished) will need to be retried since it's possible that they will now + /// be invalid given the latest advancement. + /// + /// We need to be sure that we're making progress - it's possible that the + /// tree is so malformed that the transform never makes it to the + /// `TransformTypoExpr`. + /// + /// Returns true if there are any untried correction combinations. bool CheckAndAdvanceTypoExprCorrectionStreams() { for (auto TE : TypoExprs) { auto &State = SemaRef.getTypoExprState(TE); TransformCache.erase(TE); + if (!State.Consumer->hasMadeAnyCorrectionProgress()) + return false; if (!State.Consumer->finished()) return true; State.Consumer->resetCorrectionStream(); diff --git a/clang/test/Sema/typo-correction-no-hang.cpp b/clang/test/Sema/typo-correction-no-hang.cpp new file mode 100644 index 0000000..3c59164 --- /dev/null +++ b/clang/test/Sema/typo-correction-no-hang.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// From `test/Sema/typo-correction.c` but for C++ since the behavior varies +// between the two languages. +struct rdar38642201 { + int fieldName; +}; + +void rdar38642201_callee(int x, int y); +void rdar38642201_caller() { + struct rdar38642201 structVar; + rdar38642201_callee( + structVar1.fieldName1.member1, //expected-error{{use of undeclared identifier 'structVar1'}} + structVar2.fieldName2.member2); //expected-error{{use of undeclared identifier 'structVar2'}} +} + +// Similar reproducer. +class A { +public: + int minut() const = delete; + int hour() const = delete; + + int longit() const; //expected-note{{'longit' declared here}} + int latit() const; +}; + +class B { +public: + A depar() const { return A(); } +}; + +int Foo(const B &b) { + return b.deparT().hours() * 60 + //expected-error{{no member named 'deparT' in 'B'}} + b.deparT().minutes(); //expected-error{{no member named 'deparT' in 'B'}} +} + +int Bar(const B &b) { + return b.depar().longitude() + //expected-error{{no member named 'longitude' in 'A'; did you mean 'longit'?}} + b.depar().latitude(); //expected-error{{no member named 'latitude' in 'A'}} +} diff --git a/clang/test/Sema/typo-correction-recursive.cpp b/clang/test/Sema/typo-correction-recursive.cpp index 48bd3b8..b39beb5 100644 --- a/clang/test/Sema/typo-correction-recursive.cpp +++ b/clang/test/Sema/typo-correction-recursive.cpp @@ -118,3 +118,15 @@ int testDeepAmbiguity() { asDeepASItGet(). functionE(); } + +struct Dog { + int age; //expected-note{{'age' declared here}} + int size; //expected-note{{'size' declared here}} +}; + +int from_dog_years(int DogYears, int DogSize); +int get_dog_years() { + struct Dog doggo; + return from_dog_years(doggo.agee, //expected-error{{no member named 'agee' in 'Dog'; did you mean 'age'}} + doggo.sizee); //expected-error{{no member named 'sizee' in 'Dog'; did you mean 'size'}} +} |