summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKadir Cetinkaya <kadircet@google.com>2021-02-03 12:45:46 +0100
committerKadir Cetinkaya <kadircet@google.com>2021-02-23 11:12:08 +0100
commit99df95fd910becbcf89dd6f17f1e259353a72d27 (patch)
tree469dcaac9b8a8b29c350880d486b34cf6e644051
parenta92ceea91116e7b95d23eff634507fa2cff86ef2 (diff)
downloadllvm-99df95fd910becbcf89dd6f17f1e259353a72d27.tar.gz
[clang][CodeComplete] Fix crash on ParenListExprs
Fixes https://github.com/clangd/clangd/issues/676. Differential Revision: https://reviews.llvm.org/D95935
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp18
-rw-r--r--clang/test/CodeCompletion/function-overloads.cpp6
-rw-r--r--clang/test/CodeCompletion/member-access.c7
-rw-r--r--clang/unittests/Sema/CodeCompleteTest.cpp1
4 files changed, 30 insertions, 2 deletions
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index c2785fd60fc2..40ea0f5d24b3 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -5168,6 +5168,15 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
if (!Base || !CodeCompleter)
return;
+ // Peel off the ParenListExpr by chosing the last one, as they don't have a
+ // predefined type.
+ if (auto *PLE = llvm::dyn_cast<ParenListExpr>(Base))
+ Base = PLE->getExpr(PLE->getNumExprs() - 1);
+ if (OtherOpBase) {
+ if (auto *PLE = llvm::dyn_cast<ParenListExpr>(OtherOpBase))
+ OtherOpBase = PLE->getExpr(PLE->getNumExprs() - 1);
+ }
+
ExprResult ConvertedBase = PerformMemberExprBaseConversion(Base, IsArrow);
if (ConvertedBase.isInvalid())
return;
@@ -5597,12 +5606,17 @@ ProduceSignatureHelp(Sema &SemaRef, Scope *S,
QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn,
ArrayRef<Expr *> Args,
SourceLocation OpenParLoc) {
- if (!CodeCompleter)
+ if (!CodeCompleter || !Fn)
return QualType();
+ // If we have a ParenListExpr for LHS, peel it off by chosing the last expr.
+ // As ParenListExprs don't have a predefined type.
+ if (auto *PLE = llvm::dyn_cast<ParenListExpr>(Fn))
+ Fn = PLE->getExpr(PLE->getNumExprs() - 1);
+
// FIXME: Provide support for variadic template functions.
// Ignore type-dependent call expressions entirely.
- if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args))
+ if (Fn->isTypeDependent() || anyNullArguments(Args))
return QualType();
// In presence of dependent args we surface all possible signatures using the
// non-dependent args in the prefix. Afterwards we do a post filtering to make
diff --git a/clang/test/CodeCompletion/function-overloads.cpp b/clang/test/CodeCompletion/function-overloads.cpp
index 11c864c28107..7b8ccef1d580 100644
--- a/clang/test/CodeCompletion/function-overloads.cpp
+++ b/clang/test/CodeCompletion/function-overloads.cpp
@@ -21,6 +21,8 @@ namespace NS {
void test_adl() {
NS::X x;
g(x, x);
+ (void)(f)(1, 2, 3);
+ (void)(test, test, test, f)(1, 2, 3);
}
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
@@ -31,6 +33,10 @@ void test_adl() {
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:10:21 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:23:7 %s -o - | \
// RUN: FileCheck -check-prefix=CHECK-CC5 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:24:13 %s -o - | \
+// RUN: FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:25:31 %s -o - | \
+// RUN: FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: OVERLOAD: [#int#]f(<#float x#>, float y)
// CHECK-CC1: OVERLOAD: [#int#]f(<#int i#>)
// CHECK-CC1-NOT, CHECK-CC2-NOT: OVERLOAD: A(
diff --git a/clang/test/CodeCompletion/member-access.c b/clang/test/CodeCompletion/member-access.c
index 72afbf2ff947..545349f71731 100644
--- a/clang/test/CodeCompletion/member-access.c
+++ b/clang/test/CodeCompletion/member-access.c
@@ -29,3 +29,10 @@ void test3(struct Point2 *p) {
// RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:24:5 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: x (requires fix-it: {24:4-24:5} to "->")
+
+void test4(struct Point *p) {
+ (int)(p)->x;
+ (int)(0,1,2,3,4,p)->x;
+}
+// RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:34:13 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:35:23 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
diff --git a/clang/unittests/Sema/CodeCompleteTest.cpp b/clang/unittests/Sema/CodeCompleteTest.cpp
index d8b303d77bb9..dae0793658c5 100644
--- a/clang/unittests/Sema/CodeCompleteTest.cpp
+++ b/clang/unittests/Sema/CodeCompleteTest.cpp
@@ -488,6 +488,7 @@ TEST(PreferredTypeTest, NoCrashOnInvalidTypes) {
auto y = new decltype(&1)(^);
// GNU decimal type extension is not supported in clang.
auto z = new _Decimal128(^);
+ void foo() { (void)(foo)(^); }
)cpp";
EXPECT_THAT(collectPreferredTypes(Code), Each("NULL TYPE"));
}