Initial implementation of a code-completion interface in Clang. In
essence, code completion is triggered by a magic "code completion"
token produced by the lexer [*], which the parser recognizes at
certain points in the grammar. The parser then calls into the Action
object with the appropriate CodeCompletionXXX action.
Sema implements the CodeCompletionXXX callbacks by performing minimal
translation, then forwarding them to a CodeCompletionConsumer
subclass, which uses the results of semantic analysis to provide
code-completion results. At present, only a single, "printing" code
completion consumer is available, for regression testing and
debugging. However, the design is meant to permit other
code-completion consumers.
This initial commit contains two code-completion actions: one for
member access, e.g., "x." or "p->", and one for
nested-name-specifiers, e.g., "std::". More code-completion actions
will follow, along with improved gathering of code-completion results
for the various contexts.
[*] In the current -code-completion-dump testing/debugging mode, the
file is truncated at the completion point and EOF is translated into
"code completion".
llvm-svn: 82166
2009-09-18 05:32:03 +08:00
|
|
|
struct Base1 {
|
|
|
|
int member1;
|
|
|
|
float member2;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Base2 {
|
|
|
|
int member1;
|
|
|
|
double member3;
|
|
|
|
void memfun1(int);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Base3 : Base1, Base2 {
|
|
|
|
void memfun1(float);
|
2009-12-12 02:44:16 +08:00
|
|
|
void memfun1(double) const;
|
Initial implementation of a code-completion interface in Clang. In
essence, code completion is triggered by a magic "code completion"
token produced by the lexer [*], which the parser recognizes at
certain points in the grammar. The parser then calls into the Action
object with the appropriate CodeCompletionXXX action.
Sema implements the CodeCompletionXXX callbacks by performing minimal
translation, then forwarding them to a CodeCompletionConsumer
subclass, which uses the results of semantic analysis to provide
code-completion results. At present, only a single, "printing" code
completion consumer is available, for regression testing and
debugging. However, the design is meant to permit other
code-completion consumers.
This initial commit contains two code-completion actions: one for
member access, e.g., "x." or "p->", and one for
nested-name-specifiers, e.g., "std::". More code-completion actions
will follow, along with improved gathering of code-completion results
for the various contexts.
[*] In the current -code-completion-dump testing/debugging mode, the
file is truncated at the completion point and EOF is translated into
"code completion".
llvm-svn: 82166
2009-09-18 05:32:03 +08:00
|
|
|
void memfun2(int);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Derived : Base3 {
|
2018-01-23 04:44:47 +08:00
|
|
|
template <typename T> Derived(T);
|
|
|
|
Derived(int);
|
Initial implementation of a code-completion interface in Clang. In
essence, code completion is triggered by a magic "code completion"
token produced by the lexer [*], which the parser recognizes at
certain points in the grammar. The parser then calls into the Action
object with the appropriate CodeCompletionXXX action.
Sema implements the CodeCompletionXXX callbacks by performing minimal
translation, then forwarding them to a CodeCompletionConsumer
subclass, which uses the results of semantic analysis to provide
code-completion results. At present, only a single, "printing" code
completion consumer is available, for regression testing and
debugging. However, the design is meant to permit other
code-completion consumers.
This initial commit contains two code-completion actions: one for
member access, e.g., "x." or "p->", and one for
nested-name-specifiers, e.g., "std::". More code-completion actions
will follow, along with improved gathering of code-completion results
for the various contexts.
[*] In the current -code-completion-dump testing/debugging mode, the
file is truncated at the completion point and EOF is translated into
"code completion".
llvm-svn: 82166
2009-09-18 05:32:03 +08:00
|
|
|
int member4;
|
|
|
|
int memfun3(int);
|
|
|
|
};
|
|
|
|
|
|
|
|
class Proxy {
|
|
|
|
public:
|
|
|
|
Derived *operator->() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
void test(const Proxy &p) {
|
2009-09-23 05:11:38 +08:00
|
|
|
p->
|
2017-01-15 14:11:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct Test1 {
|
|
|
|
Base1 b;
|
|
|
|
|
|
|
|
static void sfunc() {
|
|
|
|
b. // expected-error {{invalid use of member 'b' in static member function}}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-03-28 15:22:21 +08:00
|
|
|
struct Foo {
|
|
|
|
void foo() const;
|
|
|
|
static void foo(bool);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Bar {
|
|
|
|
void foo(bool param) {
|
|
|
|
Foo::foo( );// unresolved member expression with an implicit base
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-01-23 04:44:47 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:31:6 %s -o - | FileCheck -check-prefix=CHECK-CC1 --implicit-check-not="Derived : Derived(" %s
|
2018-10-24 20:57:27 +08:00
|
|
|
// CHECK-CC1: Base1 (InBase) : Base1::
|
|
|
|
// CHECK-CC1: member1 (InBase) : [#int#][#Base1::#]member1
|
|
|
|
// CHECK-CC1: member1 (InBase) : [#int#][#Base2::#]member1
|
|
|
|
// CHECK-CC1: member2 (InBase) : [#float#][#Base1::#]member2
|
|
|
|
// CHECK-CC1: member3 (InBase)
|
2010-01-14 07:24:38 +08:00
|
|
|
// CHECK-CC1: member4
|
2018-10-24 20:57:27 +08:00
|
|
|
// CHECK-CC1: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#float#>)
|
|
|
|
// CHECK-CC1: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#double#>)[# const#]
|
|
|
|
// CHECK-CC1: memfun1 (Hidden,InBase) : [#void#]Base2::memfun1(<#int#>)
|
|
|
|
// CHECK-CC1: memfun2 (InBase) : [#void#][#Base3::#]memfun2(<#int#>)
|
2010-01-14 07:24:38 +08:00
|
|
|
// CHECK-CC1: memfun3 : [#int#]memfun3(<#int#>)
|
2017-01-15 14:11:04 +08:00
|
|
|
|
|
|
|
// Make sure this doesn't crash
|
2018-01-23 04:44:47 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:38:7 %s -verify
|
2017-03-28 15:22:21 +08:00
|
|
|
|
|
|
|
// Make sure this also doesn't crash
|
2018-01-23 04:44:47 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:49:14 %s
|
2017-05-11 21:48:57 +08:00
|
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
class BaseTemplate {
|
|
|
|
public:
|
|
|
|
T baseTemplateFunction();
|
|
|
|
|
|
|
|
T baseTemplateField;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T, typename S>
|
|
|
|
class TemplateClass: public Base1 , public BaseTemplate<T> {
|
|
|
|
public:
|
|
|
|
T function() { }
|
|
|
|
T field;
|
|
|
|
|
|
|
|
void overload1(const T &);
|
|
|
|
void overload1(const S &);
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T, typename S>
|
|
|
|
void completeDependentMembers(TemplateClass<T, S> &object,
|
|
|
|
TemplateClass<int, S> *object2) {
|
|
|
|
object.field;
|
|
|
|
object2->field;
|
2018-10-24 20:57:27 +08:00
|
|
|
// CHECK-CC2: baseTemplateField (InBase) : [#T#][#BaseTemplate<T>::#]baseTemplateField
|
|
|
|
// CHECK-CC2: baseTemplateFunction (InBase) : [#T#][#BaseTemplate<T>::#]baseTemplateFunction()
|
2017-05-11 21:48:57 +08:00
|
|
|
// CHECK-CC2: field : [#T#]field
|
|
|
|
// CHECK-CC2: function : [#T#]function()
|
2018-10-24 20:57:27 +08:00
|
|
|
// CHECK-CC2: member1 (InBase) : [#int#][#Base1::#]member1
|
|
|
|
// CHECK-CC2: member2 (InBase) : [#float#][#Base1::#]member2
|
2017-05-11 21:48:57 +08:00
|
|
|
// CHECK-CC2: overload1 : [#void#]overload1(<#const T &#>)
|
|
|
|
// CHECK-CC2: overload1 : [#void#]overload1(<#const S &#>)
|
|
|
|
|
2018-01-23 04:44:47 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:94:10 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:95:12 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
|
2017-05-11 21:48:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void completeDependentSpecializedMembers(TemplateClass<int, double> &object,
|
|
|
|
TemplateClass<int, double> *object2) {
|
|
|
|
object.field;
|
|
|
|
object2->field;
|
2018-10-24 20:57:27 +08:00
|
|
|
// CHECK-CC3: baseTemplateField (InBase) : [#int#][#BaseTemplate<int>::#]baseTemplateField
|
|
|
|
// CHECK-CC3: baseTemplateFunction (InBase) : [#int#][#BaseTemplate<int>::#]baseTemplateFunction()
|
2017-05-11 21:48:57 +08:00
|
|
|
// CHECK-CC3: field : [#int#]field
|
|
|
|
// CHECK-CC3: function : [#int#]function()
|
2018-10-24 20:57:27 +08:00
|
|
|
// CHECK-CC3: member1 (InBase) : [#int#][#Base1::#]member1
|
|
|
|
// CHECK-CC3: member2 (InBase) : [#float#][#Base1::#]member2
|
2017-05-11 21:48:57 +08:00
|
|
|
// CHECK-CC3: overload1 : [#void#]overload1(<#const int &#>)
|
|
|
|
// CHECK-CC3: overload1 : [#void#]overload1(<#const double &#>)
|
|
|
|
|
2018-01-23 04:44:47 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:112:10 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:113:12 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
|
2017-05-11 21:48:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class Template {
|
|
|
|
public:
|
|
|
|
BaseTemplate<int> o1;
|
|
|
|
BaseTemplate<T> o2;
|
|
|
|
|
|
|
|
void function() {
|
|
|
|
o1.baseTemplateField;
|
|
|
|
// CHECK-CC4: BaseTemplate : BaseTemplate::
|
|
|
|
// CHECK-CC4: baseTemplateField : [#int#]baseTemplateField
|
|
|
|
// CHECK-CC4: baseTemplateFunction : [#int#]baseTemplateFunction()
|
2018-01-23 04:44:47 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:134:8 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
|
2017-05-11 21:48:57 +08:00
|
|
|
o2.baseTemplateField;
|
|
|
|
// CHECK-CC5: BaseTemplate : BaseTemplate::
|
|
|
|
// CHECK-CC5: baseTemplateField : [#T#]baseTemplateField
|
|
|
|
// CHECK-CC5: baseTemplateFunction : [#T#]baseTemplateFunction()
|
2018-01-23 04:44:47 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:139:8 %s -o - | FileCheck -check-prefix=CHECK-CC5 %s
|
2017-05-11 21:48:57 +08:00
|
|
|
this->o1;
|
|
|
|
// CHECK-CC6: [#void#]function()
|
|
|
|
// CHECK-CC6: o1 : [#BaseTemplate<int>#]o1
|
|
|
|
// CHECK-CC6: o2 : [#BaseTemplate<T>#]o2
|
2018-01-23 04:44:47 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:144:11 %s -o - | FileCheck -check-prefix=CHECK-CC6 %s
|
2017-05-11 21:48:57 +08:00
|
|
|
}
|
2017-06-16 05:40:54 +08:00
|
|
|
|
|
|
|
static void staticFn(T &obj);
|
|
|
|
|
|
|
|
struct Nested { };
|
2017-05-11 21:48:57 +08:00
|
|
|
};
|
2017-06-16 05:40:54 +08:00
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void dependentColonColonCompletion() {
|
|
|
|
Template<T>::staticFn();
|
|
|
|
// CHECK-CC7: function : [#void#]function()
|
|
|
|
// CHECK-CC7: Nested : Nested
|
|
|
|
// CHECK-CC7: o1 : [#BaseTemplate<int>#]o1
|
|
|
|
// CHECK-CC7: o2 : [#BaseTemplate<T>#]o2
|
|
|
|
// CHECK-CC7: staticFn : [#void#]staticFn(<#T &obj#>)
|
|
|
|
// CHECK-CC7: Template : Template
|
2018-01-23 04:44:47 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:158:16 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
|
2017-06-16 05:40:54 +08:00
|
|
|
typename Template<T>::Nested m;
|
2018-01-23 04:44:47 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:166:25 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
|
2017-06-16 05:40:54 +08:00
|
|
|
}
|
2018-05-25 20:56:26 +08:00
|
|
|
|
|
|
|
class Proxy2 {
|
|
|
|
public:
|
|
|
|
Derived *operator->() const;
|
|
|
|
int member5;
|
|
|
|
};
|
|
|
|
|
|
|
|
void test2(const Proxy2 &p) {
|
|
|
|
p->
|
|
|
|
}
|
|
|
|
|
|
|
|
void test3(const Proxy2 &p) {
|
|
|
|
p.
|
|
|
|
}
|
|
|
|
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:177:6 %s -o - | FileCheck -check-prefix=CHECK-CC8 --implicit-check-not="Derived : Derived(" %s
|
2018-10-24 20:57:27 +08:00
|
|
|
// CHECK-CC8: Base1 (InBase) : Base1::
|
|
|
|
// CHECK-CC8: member1 (InBase) : [#int#][#Base1::#]member1
|
|
|
|
// CHECK-CC8: member1 (InBase) : [#int#][#Base2::#]member1
|
|
|
|
// CHECK-CC8: member2 (InBase) : [#float#][#Base1::#]member2
|
|
|
|
// CHECK-CC8: member3 (InBase) : [#double#][#Base2::#]member3
|
2018-05-25 20:56:26 +08:00
|
|
|
// CHECK-CC8: member4 : [#int#]member4
|
|
|
|
// CHECK-CC8: member5 : [#int#]member5 (requires fix-it: {177:4-177:6} to ".")
|
2018-10-24 20:57:27 +08:00
|
|
|
// CHECK-CC8: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#float#>)
|
|
|
|
// CHECK-CC8: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#double#>)[# const#]
|
|
|
|
// CHECK-CC8: memfun1 (Hidden,InBase) : [#void#]Base2::memfun1(<#int#>)
|
|
|
|
// CHECK-CC8: memfun2 (InBase) : [#void#][#Base3::#]memfun2(<#int#>)
|
2018-05-25 20:56:26 +08:00
|
|
|
// CHECK-CC8: memfun3 : [#int#]memfun3(<#int#>)
|
|
|
|
// CHECK-CC8: operator-> : [#Derived *#]operator->()[# const#] (requires fix-it: {177:4-177:6} to ".")
|
|
|
|
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-with-fixits -code-completion-at=%s:181:6 %s -o - | FileCheck -check-prefix=CHECK-CC9 --implicit-check-not="Derived : Derived(" %s
|
2018-10-24 20:57:27 +08:00
|
|
|
// CHECK-CC9: Base1 (InBase) : Base1::
|
|
|
|
// CHECK-CC9: member1 (InBase) : [#int#][#Base1::#]member1 (requires fix-it: {181:4-181:5} to "->")
|
|
|
|
// CHECK-CC9: member1 (InBase) : [#int#][#Base2::#]member1 (requires fix-it: {181:4-181:5} to "->")
|
|
|
|
// CHECK-CC9: member2 (InBase) : [#float#][#Base1::#]member2 (requires fix-it: {181:4-181:5} to "->")
|
|
|
|
// CHECK-CC9: member3 (InBase) : [#double#][#Base2::#]member3 (requires fix-it: {181:4-181:5} to "->")
|
2018-05-25 20:56:26 +08:00
|
|
|
// CHECK-CC9: member4 : [#int#]member4 (requires fix-it: {181:4-181:5} to "->")
|
|
|
|
// CHECK-CC9: member5 : [#int#]member5
|
2018-10-24 20:57:27 +08:00
|
|
|
// CHECK-CC9: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#float#>) (requires fix-it: {181:4-181:5} to "->")
|
|
|
|
// CHECK-CC9: memfun1 (InBase) : [#void#][#Base3::#]memfun1(<#double#>)[# const#] (requires fix-it: {181:4-181:5} to "->")
|
|
|
|
// CHECK-CC9: memfun1 (Hidden,InBase) : [#void#]Base2::memfun1(<#int#>) (requires fix-it: {181:4-181:5} to "->")
|
|
|
|
// CHECK-CC9: memfun2 (InBase) : [#void#][#Base3::#]memfun2(<#int#>) (requires fix-it: {181:4-181:5} to "->")
|
2018-05-25 20:56:26 +08:00
|
|
|
// CHECK-CC9: memfun3 : [#int#]memfun3(<#int#>) (requires fix-it: {181:4-181:5} to "->")
|
|
|
|
// CHECK-CC9: operator-> : [#Derived *#]operator->()[# const#]
|
2019-06-10 23:17:52 +08:00
|
|
|
|
|
|
|
// These overload sets differ only by return type and this-qualifiers.
|
|
|
|
// So for any given callsite, only one is available.
|
|
|
|
struct Overloads {
|
|
|
|
double ConstOverload(char);
|
|
|
|
int ConstOverload(char) const;
|
|
|
|
|
|
|
|
int RefOverload(char) &;
|
|
|
|
double RefOverload(char) const&;
|
|
|
|
char RefOverload(char) &&;
|
|
|
|
};
|
|
|
|
void testLValue(Overloads& Ref) {
|
|
|
|
Ref.
|
|
|
|
}
|
|
|
|
void testConstLValue(const Overloads& ConstRef) {
|
|
|
|
ConstRef.
|
|
|
|
}
|
|
|
|
void testRValue() {
|
|
|
|
Overloads().
|
|
|
|
}
|
|
|
|
void testXValue(Overloads& X) {
|
|
|
|
static_cast<Overloads&&>(X).
|
|
|
|
}
|
|
|
|
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:225:7 %s -o - | FileCheck -check-prefix=CHECK-LVALUE %s \
|
|
|
|
// RUN: --implicit-check-not="[#int#]ConstOverload(" \
|
|
|
|
// RUN: --implicit-check-not="[#double#]RefOverload(" \
|
|
|
|
// RUN: --implicit-check-not="[#char#]RefOverload("
|
|
|
|
// CHECK-LVALUE-DAG: [#double#]ConstOverload(
|
|
|
|
// CHECK-LVALUE-DAG: [#int#]RefOverload(
|
|
|
|
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:228:12 %s -o - | FileCheck -check-prefix=CHECK-CONSTLVALUE %s \
|
|
|
|
// RUN: --implicit-check-not="[#double#]ConstOverload(" \
|
|
|
|
// RUN: --implicit-check-not="[#int#]RefOverload(" \
|
|
|
|
// RUN: --implicit-check-not="[#char#]RefOverload("
|
|
|
|
// CHECK-CONSTLVALUE: [#int#]ConstOverload(
|
|
|
|
// CHECK-CONSTLVALUE: [#double#]RefOverload(
|
|
|
|
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:231:15 %s -o - | FileCheck -check-prefix=CHECK-PRVALUE %s \
|
|
|
|
// RUN: --implicit-check-not="[#int#]ConstOverload(" \
|
|
|
|
// RUN: --implicit-check-not="[#int#]RefOverload(" \
|
|
|
|
// RUN: --implicit-check-not="[#double#]RefOverload("
|
|
|
|
// CHECK-PRVALUE: [#double#]ConstOverload(
|
|
|
|
// CHECK-PRVALUE: [#char#]RefOverload(
|
|
|
|
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:234:31 %s -o - | FileCheck -check-prefix=CHECK-XVALUE %s \
|
|
|
|
// RUN: --implicit-check-not="[#int#]ConstOverload(" \
|
|
|
|
// RUN: --implicit-check-not="[#int#]RefOverload(" \
|
|
|
|
// RUN: --implicit-check-not="[#double#]RefOverload("
|
|
|
|
// CHECK-XVALUE: [#double#]ConstOverload(
|
|
|
|
// CHECK-XVALUE: [#char#]RefOverload(
|
|
|
|
|
|
|
|
void testOverloadOperator() {
|
|
|
|
struct S {
|
|
|
|
char operator=(int) const;
|
|
|
|
int operator=(int);
|
|
|
|
} s;
|
|
|
|
return s.
|
|
|
|
}
|
|
|
|
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:270:12 %s -o - | FileCheck -check-prefix=CHECK-OPER %s \
|
|
|
|
// RUN: --implicit-check-not="[#char#]operator=("
|
|
|
|
// CHECK-OPER: [#int#]operator=(
|
|
|
|
|
[AST] Preserve the type in RecoveryExprs for broken function calls.
RecoveryExprs are modeled as dependent type to prevent bogus diagnostics
and crashes in clang.
This patch allows to preseve the type for broken calls when the
RecoveryEprs have a known type, e.g. a broken non-overloaded call, a
overloaded call when the all candidates have the same return type, so
that more features (code completion still work on "take2args(x).^") still
work.
However, adding the type is risky, which may result in more clang code being
affected leading to new crashes and hurt diagnostic, and it requires large
effort to minimize the affect (update all sites in clang to handle errorDepend
case), so we add a new flag (off by default) to allow us to develop/test
them incrementally.
This patch also has some trivial fixes to suppress diagnostics (to prevent regressions).
Tested:
all existing tests are passed (when both "-frecovery-ast", "-frecovery-ast-type" flags are flipped on);
Reviewed By: sammccall
Subscribers: rsmith, arphaman, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D79160
2020-05-08 22:13:17 +08:00
|
|
|
struct S { int member; };
|
|
|
|
S overloaded(int);
|
|
|
|
S overloaded(double);
|
|
|
|
void foo() {
|
|
|
|
// No overload matches, but we have recovery-expr with the correct type.
|
|
|
|
overloaded().
|
|
|
|
}
|
|
|
|
// RUN: not %clang_cc1 -fsyntax-only -frecovery-ast -frecovery-ast-type -code-completion-at=%s:281:16 %s -o - | FileCheck -check-prefix=CHECK-RECOVERY %s
|
|
|
|
// CHECK-RECOVERY: [#int#]member
|