diff --git a/package-lock.json b/package-lock.json index 77c0c691..956c86c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@vshaxe/haxe-language-server", - "version": "2.33.0", + "version": "2.34.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@vshaxe/haxe-language-server", - "version": "2.33.0", + "version": "2.34.1", "hasInstallScript": true, "devDependencies": { - "lix": "^15.12.0", + "lix": "^15.12.4", "terser": "^5.15.0" } }, @@ -96,11 +96,12 @@ "dev": true }, "node_modules/lix": { - "version": "15.12.0", - "resolved": "https://registry.npmjs.org/lix/-/lix-15.12.0.tgz", - "integrity": "sha512-FA36oCl+M+3Of8L4eErXw7tAHGOjqEC4IgEvH6oPDsiYd4yN6XpzZGcbLuIyu4PiztjOrr1TKJnpwi32qb2ddw==", + "version": "15.12.4", + "resolved": "https://registry.npmjs.org/lix/-/lix-15.12.4.tgz", + "integrity": "sha512-xfwGQrXXNba9BM7VcP2u9WvElBYgGJW+1gviaFqJH5OUFPAhwv8TZNk5f+Yew4pyKOmMqshdUYgk9+d3U6P6kw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "haxe": "bin/haxeshim.js", "haxelib": "bin/haxelibshim.js", @@ -215,9 +216,9 @@ "dev": true }, "lix": { - "version": "15.12.0", - "resolved": "https://registry.npmjs.org/lix/-/lix-15.12.0.tgz", - "integrity": "sha512-FA36oCl+M+3Of8L4eErXw7tAHGOjqEC4IgEvH6oPDsiYd4yN6XpzZGcbLuIyu4PiztjOrr1TKJnpwi32qb2ddw==", + "version": "15.12.4", + "resolved": "https://registry.npmjs.org/lix/-/lix-15.12.4.tgz", + "integrity": "sha512-xfwGQrXXNba9BM7VcP2u9WvElBYgGJW+1gviaFqJH5OUFPAhwv8TZNk5f+Yew4pyKOmMqshdUYgk9+d3U6P6kw==", "dev": true }, "source-map": { diff --git a/package.json b/package.json index f90a1ff1..47f6a47f 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "@vshaxe/haxe-language-server", - "version": "2.33.0", + "version": "2.34.1", "devDependencies": { - "lix": "^15.12.0", + "lix": "^15.12.4", "terser": "^5.15.0" }, "scripts": { diff --git a/src/haxeLanguageServer/Configuration.hx b/src/haxeLanguageServer/Configuration.hx index db07acc2..26a25f29 100644 --- a/src/haxeLanguageServer/Configuration.hx +++ b/src/haxeLanguageServer/Configuration.hx @@ -205,7 +205,7 @@ class Configuration { maxCompletionItems: 1000, renameSourceFolders: ["src", "source", "Source", "test", "tests"], disableRefactorCache: false, - disableInlineValue: false, + disableInlineValue: true, inlayHints: { variableTypes: false, parameterNames: false, diff --git a/src/haxeLanguageServer/features/haxe/InlineValueFeature.hx b/src/haxeLanguageServer/features/haxe/InlineValueFeature.hx index a10a97ca..a0ae99a0 100644 --- a/src/haxeLanguageServer/features/haxe/InlineValueFeature.hx +++ b/src/haxeLanguageServer/features/haxe/InlineValueFeature.hx @@ -9,6 +9,11 @@ import jsonrpc.Types.NoData; import languageServerProtocol.Types.InlineValue; import languageServerProtocol.protocol.InlineValue; import refactor.discover.Identifier; +import refactor.discover.IdentifierPos; +import refactor.discover.Type; +import tokentree.utils.TokenTreeCheckUtils; + +using tokentree.TokenTreeAccessHelper; class InlineValueFeature { final context:Context; @@ -26,27 +31,65 @@ class InlineValueFeature { } function onInlineValue(params:InlineValueParams, token:CancellationToken, resolve:Array->Void, reject:ResponseError->Void) { + final onResolve = context.startTimer("textDocument/inlineValue"); if (context.config.user.disableRefactorCache || context.config.user.disableInlineValue) { resolve([]); + onResolve(); return; } var file = refactorCache.fileList.getFile(params.textDocument.uri.toFsPath().toString()); if (file == null) { reject.handler()("file not found"); + onResolve(); return; } var editDoc = new EditDoc(params.textDocument.uri.toFsPath(), new EditList(), context, converter); var localScopedNames:Array = []; + var outOfScope:Array = []; + var functionStartLine:Int = params.context.stoppedLocation.start.line; function matchLocalScoped(identifier:Identifier):Bool { + switch (identifier.name) { + case "this" | "super": + return false; + default: + } return switch (identifier.type) { case ScopedLocal(scopeStart, scopeEnd, scopeType): + var pos:IdentifierPos = { + fileName: identifier.pos.fileName, + start: scopeStart, + end: scopeEnd + }; + var range = editDoc.posToRange(pos); + if (!range.contains(params.context.stoppedLocation)) { + outOfScope.push(identifier); + return false; + } localScopedNames.push(identifier.name); true; - case Access: true; + case Access: + for (scoped in outOfScope) { + switch (scoped.type) { + case ScopedLocal(scopeStart, scopeEnd, scopeType): + if ((scoped.name == identifier.name) || identifier.name.startsWith('${scoped.name}.')) { + if (scopeStart <= identifier.pos.start && scopeEnd >= identifier.pos.end) { + return false; + } + } + default: + } + } + true; + case Method(_): + var functionRange:Range = editDoc.posToRange(identifier.pos); + if (functionRange.start.line <= params.context.stoppedLocation.start.line) { + functionStartLine = functionRange.start.line; + } + false; default: false; } } @@ -54,28 +97,137 @@ class InlineValueFeature { final inlineValueVars:Array = []; for (identifier in identifiers) { var identifierRange = editDoc.posToRange(identifier.pos); + if (identifierRange.start.line < functionStartLine) { + continue; + } if (!params.range.contains(identifierRange)) { continue; } - var needsExpression:Bool = identifier.name.contains("."); - if ((identifier.type == Access) && !localScopedNames.contains(identifier.name)) { - needsExpression = true; + if (params.context.stoppedLocation.end.line < identifierRange.start.line) { + continue; } - - if (needsExpression) { - inlineValueVars.push({ - range: identifierRange, - expression: identifier.name - }); - } else { - inlineValueVars.push({ - range: identifierRange, - variableName: identifier.name, - caseSensitiveLookup: true - }); + if (isSharpCondition(params, identifier)) { + continue; } + if (isTypeParam(params, identifier)) { + continue; + } + if (isLocalFunctionName(params, identifier)) { + continue; + } + var hasDot:Bool = identifier.name.contains("."); + if (!hasDot) { + if (skipIdentifier(identifier)) { + continue; + } + } + inlineValueVars.push({ + range: identifierRange, + expression: identifier.name + }); } resolve(inlineValueVars); + onResolve(); + } + + function isSharpCondition(params:InlineValueParams, identifier:Identifier):Bool { + final doc:Null = context.documents.getHaxe(params.textDocument.uri); + final token = doc?.tokens?.getTokenAtOffset(identifier.pos.start); + + if (token == null) { + return false; + } + var parent = token.parent; + while (parent != null) { + switch (parent.tok) { + case Dot: + case Const(CIdent(_)): + case POpen: + case Unop(OpNot): + case Binop(OpBoolAnd) | Binop(OpBoolOr): + case Sharp("if") | Sharp("elseif"): + return true; + default: + return false; + } + parent = parent.parent; + } + + return false; + } + + function isLocalFunctionName(params:InlineValueParams, identifier:Identifier):Bool { + final doc:Null = context.documents.getHaxe(params.textDocument.uri); + final token = doc?.tokens?.getTokenAtOffset(identifier.pos.start); + + if (token == null) { + return false; + } + switch (token.parent?.tok) { + case Kwd(KwdFunction): + return true; + default: + return false; + } + } + + function isTypeParam(params:InlineValueParams, identifier:Identifier):Bool { + final doc:Null = context.documents.getHaxe(params.textDocument.uri); + final token = doc?.tokens?.getTokenAtOffset(identifier.pos.end); + + if (token == null) { + return false; + } + var parent = token.parent; + while (parent != null) { + switch (parent.tok) { + case Dot: + case DblDot: + case BrOpen: + case Const(CIdent(_)): + case Binop(OpAssign): + case Sharp(_): + return true; + case Binop(OpLt): + return parent.access().firstOf(Binop(OpGt)).exists(); + default: + return false; + } + parent = parent.parent; + } + + return false; + } + + function skipIdentifier(identifier:Identifier):Bool { + if (isTypeUsed(identifier.defineType, identifier.name)) { + return true; + } + var allUses:Array = refactorCache.nameMap.getIdentifiers(identifier.name); + for (use in allUses) { + switch (use.type) { + case EnumField(_): + return true; + default: + } + } + return false; + } + + function isTypeUsed(containerType:Null, name:String):Bool { + if (containerType == null) { + return false; + } + final types:Array = refactorCache.typeList.findTypeName(name); + for (type in types) { + switch (containerType.file.importsModule(type.file.getPackage(), type.file.getMainModulName(), name)) { + case None: + case ImportedWithAlias(_): + case Global | ParentPackage | SamePackage | Imported | StarImported: + return true; + } + } + return false; } }