diff --git a/server/src/e2e/tolk/testcases/completion/methods.test b/server/src/e2e/tolk/testcases/completion/methods.test index 5f46711d..84552438 100644 --- a/server/src/e2e/tolk/testcases/completion/methods.test +++ b/server/src/e2e/tolk/testcases/completion/methods.test @@ -35,3 +35,33 @@ fun foo(someParameter: int) { 1 bad() of Foo 1 bar() of Foo 1 baz() of Foo + +======================================================================== +Static methods completion for generic struct +======================================================================== +struct Second {} +fun Second.new(): Second {} +fun Second.new(): Second {} + +fun main() { + val first = First.; +} +------------------------------------------------------------------------ +No completion items + +======================================================================== +Static methods completion for generic struct 2 +======================================================================== +struct Second {} +fun Second.new(): Second {} +fun Second.new(): Second {} + +fun main() { + val first = Second.; +} +------------------------------------------------------------------------ +1 fromCell(packedCell: cell, options: UnpackOptions = {}): T of T +1 fromSlice(rawSlice: slice, options: UnpackOptions = {}): T of T +1 getDeclaredPackPrefix(): int of T +1 getDeclaredPackPrefixLen(): int of T +1 new(): Second of Second diff --git a/server/src/languages/tolk/psi/Reference.ts b/server/src/languages/tolk/psi/Reference.ts index 5a23cd1c..9bf1b39c 100644 --- a/server/src/languages/tolk/psi/Reference.ts +++ b/server/src/languages/tolk/psi/Reference.ts @@ -291,13 +291,19 @@ export class Reference { if (resolved) { // static methods like Foo.bar(); if (resolved instanceof Struct || resolved instanceof TypeAlias) { - return this.processStaticMethods(resolved, proc, state) + return this.processStaticMethods(resolved.name(), proc, state) } } const qualifierType = inference?.typeOf(qualifier.node)?.unwrapOption() if (!qualifierType) return true + if (qualifier.node.type === "generic_instantiation") { + // Foo.bar() + const baseType = qualifierType.unwrapInstantiation() + return this.processStaticMethods(baseType.name(), proc, state) + } + if (!this.processType(qualifier, qualifierType, proc, state)) return false // last resort, trying to find methods of T? @@ -306,7 +312,7 @@ export class Reference { } private processStaticMethods( - resolved: NamedNode | null, + typeName: string, proc: ScopeProcessor, state: ResolveState, ): boolean { @@ -315,10 +321,19 @@ export class Reference { new (class implements ScopeProcessor { public execute(node: InstanceMethod | StaticMethod, state: ResolveState): boolean { if (node instanceof InstanceMethod) return true - const receiverType = node.receiverTypeString() - if (receiverType === resolved?.name() || receiverType === "T") { + const receiverTypeString = node.receiverTypeString() + if (receiverTypeString === typeName || receiverTypeString === "T") { return proc.execute(node, state) } + + const receiverType = node.receiverTypeNode() + if (receiverType?.type === "type_instantiatedTs") { + const innerName = receiverType.childForFieldName("name")?.text + if (innerName === typeName) { + return proc.execute(node, state) + } + } + return true } })(),