[CodeCompletion] Migrate PostfixExprParen to solver-based

This commit is contained in:
Alex Hoppen
2023-02-16 13:57:02 +01:00
parent 1e723ddbc2
commit c385fe5e87
12 changed files with 48 additions and 75 deletions

View File

@@ -1507,6 +1507,7 @@ bool CodeCompletionCallbacksImpl::trySolverCompletion(bool MaybeFuncBody) {
Lookup.deliverResults(CurDeclContext, DotLoc, CompletionContext, Consumer);
return true;
}
case CompletionKind::PostfixExprParen:
case CompletionKind::CallArg: {
assert(CodeCompleteTokenExpr);
assert(CurDeclContext);
@@ -1692,6 +1693,7 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
case CompletionKind::AfterPoundExpr:
case CompletionKind::AccessorBeginning:
case CompletionKind::CaseStmtBeginning:
case CompletionKind::PostfixExprParen:
llvm_unreachable("should be already handled");
return;
@@ -1712,45 +1714,6 @@ void CodeCompletionCallbacksImpl::doneParsing(SourceFile *SrcFile) {
break;
}
case CompletionKind::PostfixExprParen: {
Lookup.setHaveLParen(true);
ExprContextInfo ContextInfo(CurDeclContext, CodeCompleteTokenExpr);
if (ShouldCompleteCallPatternAfterParen) {
ExprContextInfo ParentContextInfo(CurDeclContext, ParsedExpr);
Lookup.setExpectedTypes(
ParentContextInfo.getPossibleTypes(),
ParentContextInfo.isImplicitSingleExpressionReturn());
if (!ContextInfo.getPossibleCallees().empty()) {
for (auto &typeAndDecl : ContextInfo.getPossibleCallees())
Lookup.tryFunctionCallCompletions(typeAndDecl.Type, typeAndDecl.Decl,
typeAndDecl.SemanticContext);
} else if (ExprType && ((*ExprType)->is<AnyFunctionType>() ||
(*ExprType)->is<AnyMetatypeType>())) {
Lookup.getValueExprCompletions(*ExprType, ReferencedDecl.getDecl());
}
} else {
// Add argument labels, then fallthrough to get values.
Lookup.addCallArgumentCompletionResults(ContextInfo.getPossibleParams());
}
if (!Lookup.FoundFunctionCalls ||
(Lookup.FoundFunctionCalls &&
Lookup.FoundFunctionsWithoutFirstKeyword)) {
Lookup.setExpectedTypes(ContextInfo.getPossibleTypes(),
ContextInfo.isImplicitSingleExpressionReturn());
Lookup.setHaveLParen(false);
// Add any keywords that can be used in an argument expr position.
addSuperKeyword(CompletionContext.getResultSink(), CurDeclContext);
addExprKeywords(CompletionContext.getResultSink(), CurDeclContext);
DoPostfixExprBeginning();
}
break;
}
case CompletionKind::KeyPathExprObjC: {
if (DotLoc.isValid())
Lookup.setHaveDot(DotLoc);

View File

@@ -3681,15 +3681,22 @@ ParserResult<CustomAttr> Parser::parseCustomAttribute(
ArgumentList *argList = nullptr;
if (Tok.isFollowingLParen() && isCustomAttributeArgument()) {
if (peekToken().is(tok::code_complete)) {
consumeToken(tok::l_paren);
if (CodeCompletionCallbacks) {
auto lParenLoc = consumeToken(tok::l_paren);
auto typeE = new (Context) TypeExpr(type.get());
auto CCE = new (Context) CodeCompletionExpr(Tok.getLoc());
if (CodeCompletionCallbacks) {
CodeCompletionCallbacks->completePostfixExprParen(typeE, CCE);
}
consumeToken(tok::code_complete);
skipUntil(tok::r_paren);
consumeIf(tok::r_paren);
skipUntilDeclStmtRBrace(tok::r_paren);
auto rParenLoc = PreviousLoc;
if (Tok.is(tok::r_paren)) {
rParenLoc = consumeToken(tok::r_paren);
}
argList = ArgumentList::createParsed(
Context, lParenLoc, {Argument::unlabeled(CCE)}, rParenLoc,
/*trailingClosureIdx=*/None);
status.setHasCodeCompletionAndIsError();
} else {
// If we have no local context to parse the initial value into, create

View File

@@ -295,7 +295,7 @@ func resyncParserB14() {}
"\(1) \(#^STRING_INTERP_2?check=STRING_INTERP^#) \(2)"
var stringInterp = "\(#^STRING_INTERP_3?check=STRING_INTERP^#)"
_ = "" + "\(#^STRING_INTERP_4?check=STRING_INTERP^#)" + ""
// STRING_INTERP-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]/IsSystem: ['(']{#(value): T#}[')'][#Void#];
// STRING_INTERP-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]/IsSystem: ['(']{#(value): Any.Type#}[')'][#Void#];
// STRING_INTERP-DAG: Decl[Struct]/CurrModule: FooStruct[#FooStruct#]; name=FooStruct
// STRING_INTERP-DAG: Decl[FreeFunction]/CurrModule/TypeRelation[Invalid]: fooFunc1()[#Void#];
// STRING_INTERP-DAG: Decl[FreeFunction]/CurrModule: optStr()[#String?#];

View File

@@ -221,7 +221,7 @@ class C3 {
// OVERLOAD6-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#(a1): C1#}, {#b1: C2#}[')'][#Void#]; name=:b1:
// OVERLOAD6-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#a2: C2#}, {#b2: C1#}[')'][#Void#]; name=a2:b2:
// OVERLOAD6-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: C1I[#C1#]; name=C1I
// OVERLOAD6-DAG: Decl[InstanceVar]/CurrNominal: C2I[#C2#]; name=C2I
// OVERLOAD6-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: C2I[#C2#]; name=C2I
extension C3 {
func hasError(a1: C1, b1: TypeInvalid) -> Int {}
@@ -234,7 +234,7 @@ extension C3 {
}
}
// HASERROR1-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#a1: C1#}, {#b1: <<error type>>#}[')'][#Int#];
// HASERROR1-DAG: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#a1: C1#}, {#b1: _#}[')'][#Int#];
// HASERROR2-DAG: Decl[InstanceVar]/CurrNominal/TypeRelation[Convertible]: C1I[#C1#];
// HASERROR2-DAG: Decl[InstanceVar]/CurrNominal: C2I[#C2#];
@@ -426,8 +426,8 @@ class Bar {
func curry<T1, T2, R>(_ f: @escaping (T1, T2) -> R) -> (T1) -> (T2) -> R {
return { t1 in { t2 in f(#^NESTED_CLOSURE^#, t2) } }
// FIXME: Should be '/TypeRelation[Invalid]: t2[#T2#]'
// NESTED_CLOSURE: Decl[LocalVar]/Local: t2; name=t2
// NESTED_CLOSURE: Decl[LocalVar]/Local: t1; name=t1
// NESTED_CLOSURE: Decl[LocalVar]/Local: t2[#T2#]; name=t2
// NESTED_CLOSURE: Decl[LocalVar]/Local/TypeRelation[Convertible]: t1[#T1#]; name=t1
}
func trailingClosureLocal(x: Int, fn: (Int) -> Void) {
@@ -554,8 +554,8 @@ func testStaticMemberCall() {
// STATIC_METHOD_AFTERPAREN_1: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1:
let _ = TestStaticMemberCall.create2(#^STATIC_METHOD_AFTERPAREN_2^#)
// STATIC_METHOD_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#(arg1): Int#}[')'][#TestStaticMemberCall#];
// STATIC_METHOD_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#(arg1): Int#}, {#arg2: Int#}, {#arg3: Int#}, {#arg4: Int#}[')'][#TestStaticMemberCall#];
// STATIC_METHOD_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#(arg1): Int#}[')'][#TestStaticMemberCall#];
// STATIC_METHOD_AFTERPAREN_2-DAG: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#(arg1): Int#}, {#arg2: Int#}, {#arg3: Int#}, {#arg4: Int#}[')'][#TestStaticMemberCall#];
// STATIC_METHOD_AFTERPAREN_2-DAG: Decl[Struct]/OtherModule[Swift]/IsSystem/TypeRelation[Convertible]: Int[#Int#];
// STATIC_METHOD_AFTERPAREN_2-DAG: Literal[Integer]/None/TypeRelation[Convertible]: 0[#Int#];
@@ -600,9 +600,8 @@ func testImplicitMember() {
// IMPLICIT_MEMBER_SKIPPED: Pattern/Local/Flair[ArgLabels]: {#arg4: Int#}[#Int#];
let _: TestStaticMemberCall = .createOverloaded(#^IMPLICIT_MEMBER_OVERLOADED^#)
// IMPLICIT_MEMBER_OVERLOADED: Begin completions, 2 items
// IMPLICIT_MEMBER_OVERLOADED: Begin completions, 1 item
// IMPLICIT_MEMBER_OVERLOADED: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#arg1: Int#}[')'][#TestStaticMemberCall#]; name=arg1:
// IMPLICIT_MEMBER_OVERLOADED: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#arg1: String#}[')'][#String#]; name=arg1:
}
func testImplicitMemberInArrayLiteral() {
struct Receiver {
@@ -664,7 +663,7 @@ struct TestHasErrorAutoclosureParam {
func test() {
hasErrorAutoclosureParam(#^PARAM_WITH_ERROR_AUTOCLOSURE^#
// PARAM_WITH_ERROR_AUTOCLOSURE: Begin completions, 1 items
// PARAM_WITH_ERROR_AUTOCLOSURE: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#value: <<error type>>#}[')'][#Void#];
// PARAM_WITH_ERROR_AUTOCLOSURE: Decl[InstanceMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#value: _#}[')'][#Void#];
}
}
@@ -1281,8 +1280,8 @@ extension Rdar89773376 {
func testRdar89773376(arry: [Int]) {
arry.map { Rdar89773376(#^RDAR89773376^#) }
// RDAR89773376: Begin completions, 2 items
// RDAR89773376-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#string: String#}[')'][#Rdar89773376#];
// RDAR89773376-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#intVal: Int#}[')'][#Rdar89773376#];
// RDAR89773376-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#string: String#}[')'][#Rdar89773376#];
// RDAR89773376-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#intVal: Int#}[')'][#Rdar89773376#];
}
// This is an incomplete macro definition but it's sufficient to get the signature for code completion purposes

View File

@@ -316,8 +316,8 @@ func testDependentTypeInClosure() {
// DEPENDENT_IN_CLOSURE_3-DAG: Decl[Constructor]/CurrNominal/TypeRelation[Convertible]: init({#arg: DataType#}, {#fn: () -> Data.Content##() -> Data.Content#})[#DependentTypeInClosure<DataType>#];
let _ = DependentTypeInClosure(#^DEPENDENT_IN_CLOSURE_1^#)
// DEPENDENT_IN_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#(arg): _#}, {#fn: (_.Content) -> Void##(_.Content) -> Void#}[')'][#DependentTypeInClosure<_>#];
// DEPENDENT_IN_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg: _#}, {#fn: () -> _.Content##() -> _.Content#}[')'][#DependentTypeInClosure<_>#];
// DEPENDENT_IN_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#(arg): DataType#}, {#fn: (_) -> Void##(_) -> Void#}[')'][#DependentTypeInClosure<DataType>#];
// DEPENDENT_IN_CLOSURE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg: DataType#}, {#fn: () -> _##() -> _#}[')'][#DependentTypeInClosure<DataType>#];
let _ = DependentTypeInClosure.#^DEPENDENT_IN_CLOSURE_2^#
// DEPENDENT_IN_CLOSURE_2: Begin completions, 4 items
@@ -335,8 +335,8 @@ extension InitWithUnresolved where Self.Data: Comparable {
func testInitWithUnresolved() {
let _ = InitWithUnresolved(#^INIT_WITH_UNRESOLVEDTYPE_1^#
// INIT_WITH_UNRESOLVEDTYPE_1: Begin completions, 2 items
// INIT_WITH_UNRESOLVEDTYPE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg: _#}, {#fn: (_.Content) -> Void##(_.Content) -> Void#}[')'][#InitWithUnresolved<_>#];
// INIT_WITH_UNRESOLVEDTYPE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg2: _#}[')'][#InitWithUnresolved<_>#];
// INIT_WITH_UNRESOLVEDTYPE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg: DataType#}, {#fn: (_) -> Void##(_) -> Void#}[')'][#InitWithUnresolved<DataType>#];
// INIT_WITH_UNRESOLVEDTYPE_1-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#arg2: DataType#}[')'][#InitWithUnresolved<DataType>#];
}
func testIgnoreGenericArgsAfterCompletionToken() {

View File

@@ -156,7 +156,7 @@ func rdar22834017() {
Foo(#^RDAR_22834017^#)
}
// RDAR_22834017: Begin completions, 1 items
// RDAR_22834017: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#a: <<error type>>#}, {#b: <<error type>>#}, {#c: <<error type>>#}[')'][#Foo#];
// RDAR_22834017: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#a: _#}, {#b: _#}, {#c: _#}[')'][#Foo#];
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=RDAR_23173692 | %FileCheck %s -check-prefix=RDAR_23173692
func rdar23173692() {

View File

@@ -29,7 +29,7 @@ func testActor(obj: MyActor) async {
func testClosure(obj: (Int) async -> Void) {
obj(#^CLOSURE_CALL^#)
// CLOSURE_CALL-DAG: Pattern/CurrModule/Flair[ArgLabels]/NotRecommended: ['(']{#Int#}[')'][' async'][#Void#]; name=; diagnostics=error:async function used in a context that does not support concurrency
// CLOSURE_CALL-DAG: Pattern/Local/Flair[ArgLabels]/NotRecommended: ['(']{#Int#}[')'][' async'][#Void#]; name=; diagnostics=error:async function used in a context that does not support concurrency
}
func test() {

View File

@@ -11,7 +11,7 @@ func testInit() {
var state = DragState.inactive
state = .dragging(#^SIGNATURE^#)
// SIGNATURE: Begin completions, 1 item
// SIGNATURE: Pattern/CurrModule/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#translationX: Int#}, {#translationY: Int#}[')'][#DragState#];
// SIGNATURE: Pattern/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#translationX: Int#}, {#translationY: Int#}[')'][#DragState#];
state = .dragging(translationX: 2, #^ARGUMENT^#)
// ARGUMENT: Begin completions, 1 item
@@ -19,7 +19,7 @@ func testInit() {
state = .defaulted(#^DEFAULTED^#)
// DEFAULTED: Begin completions, 1 items
// DEFAULTED: Pattern/CurrModule/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#x: Int#}, {#y: Int#}, {#z: Int#}, {#extra: Int#}[')'][#DragState#];
// DEFAULTED: Pattern/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#x: Int#}, {#y: Int#}, {#z: Int#}, {#extra: Int#}[')'][#DragState#];
state = .defaulted(x: 1, #^DEFAULTEDARG^#)
state = .defaulted(x: "Wrong type", #^ERRORTYPE?check=DEFAULTEDARG^#)

View File

@@ -40,20 +40,20 @@ func testGlobalLookup() {
@TupleBuilder<String> var x2 {
if true {
#^GLOBAL_LOOKUP_IN_IF_BODY?check=GLOBAL_LOOKUP_NO_TYPE_RELATION^#
// GLOBAL_LOOKUP_NO_TYPE_RELATION: Decl[GlobalVar]/CurrModule: MyConstantString[#String#];
#^GLOBAL_LOOKUP_IN_IF_BODY^#
// GLOBAL_LOOKUP_IN_IF_BODY: Decl[GlobalVar]/CurrModule: MyConstantString[#String#];
}
}
@TupleBuilder<String> var x3 {
if {
#^GLOBAL_LOOKUP_IN_IF_BODY_WITHOUT_CONDITION?check=GLOBAL_LOOKUP_NO_TYPE_RELATION^#
#^GLOBAL_LOOKUP_IN_IF_BODY_WITHOUT_CONDITION?check=GLOBAL_LOOKUP_IN_IF_BODY^#
}
}
@TupleBuilder<String> var x4 {
guard else {
#^GLOBAL_LOOKUP_IN_GUARD_BODY_WITHOUT_CONDITION?check=GLOBAL_LOOKUP_NO_TYPE_RELATION^#
#^GLOBAL_LOOKUP_IN_GUARD_BODY_WITHOUT_CONDITION?check=GLOBAL_LOOKUP_IN_IF_BODY^#
}
}
@@ -85,7 +85,7 @@ func testStaticMemberLookup() {
}
@TupleBuilder<String> var x3 {
"hello: \(StringFactory.#^COMPLETE_STATIC_MEMBER_IN_STRING_LITERAL?xfail=rdar106720628^#)"
"hello: \(StringFactory.#^COMPLETE_STATIC_MEMBER_IN_STRING_LITERAL^#)"
// COMPLETE_STATIC_MEMBER_IN_STRING_LITERAL: Begin completions
// COMPLETE_STATIC_MEMBER_IN_STRING_LITERAL: Decl[StaticMethod]/CurrNominal/TypeRelation[Convertible]: makeString({#x: String#})[#String#];
// COMPLETE_STATIC_MEMBER_IN_STRING_LITERAL: End completions
@@ -135,7 +135,7 @@ func testCompleteFunctionArgumentLabels() {
@TupleBuilder<String> var x1 {
StringFactory.makeString(#^FUNCTION_ARGUMENT_LABEL^#)
// FUNCTION_ARGUMENT_LABEL: Begin completions, 1 item
// FUNCTION_ARGUMENT_LABEL: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]: ['(']{#x: String#}[')'][#String#];
// FUNCTION_ARGUMENT_LABEL: Decl[StaticMethod]/CurrNominal/Flair[ArgLabels]/TypeRelation[Convertible]: ['(']{#x: String#}[')'][#String#];
}
}

View File

@@ -70,7 +70,7 @@ class D : C {
// TEST_D_PAREN: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#d: D#}[')'][#D#]; name=d:
// TEST_D_PAREN-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#int: Int#}[')'][#D#]; name=int:
// TEST_D_PAREN-DAG: Decl[Constructor]/Super/Flair[ArgLabels]: ['(']{#c: C#}[')'][#C#]; name=c:
// TEST_D_PAREN-DAG: Decl[Constructor]/Super/Flair[ArgLabels]: ['(']{#c: C#}[')'][#D#]; name=c:
func testA() {
A#^TEST_A^#
@@ -101,5 +101,5 @@ func testR74233797() {
R74233797Derived(#^METATYPE_CONVERSION^#)
// METATYPE_CONVERSION-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#sub: Bool#}[')'][#R74233797Derived#];
// METATYPE_CONVERSION-DAG: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['('][')'][#R74233797Derived#];
// METATYPE_CONVERSION-DAG: Decl[Constructor]/Super/Flair[ArgLabels]: ['(']{#(test): Bool#}[')'][#R74233797Base#];
// METATYPE_CONVERSION-DAG: Decl[Constructor]/Super/Flair[ArgLabels]: ['(']{#(test): Bool#}[')'][#R74233797Derived#];
}

View File

@@ -72,7 +72,7 @@ func testAcceptColorTagged(paramIntVal: Int, paramStringVal: String) {
acceptColorTagged { color in
paramIntVal.tag(#^IN_CLOSURE_COLOR_CONTEXT^#)
// IN_CLOSURE_COLOR_CONTEXT-DAG: Decl[LocalVar]/Local: color; name=color
// IN_CLOSURE_COLOR_CONTEXT-DAG: Decl[LocalVar]/Local: color[#Color#]; name=color
// IN_CLOSURE_COLOR_CONTEXT-DAG: Decl[LocalVar]/Local: taggedValue[#Tagged<Color, Int>#]; name=taggedValue
// IN_CLOSURE_COLOR_CONTEXT-DAG: Decl[LocalVar]/Local: paramIntVal[#Int#]; name=paramIntVal
// IN_CLOSURE_COLOR_CONTEXT-DAG: Decl[LocalVar]/Local: paramStringVal[#String#]; name=paramStringVal

View File

@@ -45,8 +45,10 @@ func testObjDot1() {
// OBJ_DOT_1-DAG: Decl[InstanceMethod]/CurrNominal: method6({#class: Int...#})[#Void#]{{; name=.+$}}
// OBJ_DOT_1-DAG: Decl[InstanceMethod]/CurrNominal: method7({#`inout`: Int...#})[#Void#]{{; name=.+$}}
func testFreeFunc() {
func testFreeFunc1() {
freeFunc1(#^FREE_FUNC_1^#
}
func testFreeFunc2() {
freeFunc2(#^FREE_FUNC_2^#
}
// FREE_FUNC_1: Begin completions, 1 items
@@ -60,8 +62,10 @@ func testInit() {
// INIT_1: Begin completions, 1 items
// INIT_1: Decl[Constructor]/CurrNominal/Flair[ArgLabels]: ['(']{#x: Int...#}[')'][#C#]{{; name=.+$}}
func testMethod() {
func testMethod1() {
obj.method1(#^METHOD_1^#
}
func testMethod2() {
obj.method2(#^METHOD_2^#
}
// METHOD_1: Begin completions, 1 items