Skip to content

Commit e1fed62

Browse files
authored
fixed inline values only showing values for active function (#137)
* fixed inline values only showing values for active function * added filters for sharp conditions, type names and enum fields * fixed sharp detection for complex sharp conditions * fixed JS debugger not evaluating variable values * fixed type parameters showing up as inline values * updated version number * changed default of disableInlineValue to true
1 parent f17c912 commit e1fed62

File tree

4 files changed

+181
-28
lines changed

4 files changed

+181
-28
lines changed

package-lock.json

+10-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "@vshaxe/haxe-language-server",
3-
"version": "2.33.0",
3+
"version": "2.34.1",
44
"devDependencies": {
5-
"lix": "^15.12.0",
5+
"lix": "^15.12.4",
66
"terser": "^5.15.0"
77
},
88
"scripts": {

src/haxeLanguageServer/Configuration.hx

+1-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ class Configuration {
205205
maxCompletionItems: 1000,
206206
renameSourceFolders: ["src", "source", "Source", "test", "tests"],
207207
disableRefactorCache: false,
208-
disableInlineValue: false,
208+
disableInlineValue: true,
209209
inlayHints: {
210210
variableTypes: false,
211211
parameterNames: false,

src/haxeLanguageServer/features/haxe/InlineValueFeature.hx

+168-16
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ import jsonrpc.Types.NoData;
99
import languageServerProtocol.Types.InlineValue;
1010
import languageServerProtocol.protocol.InlineValue;
1111
import refactor.discover.Identifier;
12+
import refactor.discover.IdentifierPos;
13+
import refactor.discover.Type;
14+
import tokentree.utils.TokenTreeCheckUtils;
15+
16+
using tokentree.TokenTreeAccessHelper;
1217

1318
class InlineValueFeature {
1419
final context:Context;
@@ -26,56 +31,203 @@ class InlineValueFeature {
2631
}
2732

2833
function onInlineValue(params:InlineValueParams, token:CancellationToken, resolve:Array<InlineValue>->Void, reject:ResponseError<NoData>->Void) {
34+
final onResolve = context.startTimer("textDocument/inlineValue");
2935
if (context.config.user.disableRefactorCache || context.config.user.disableInlineValue) {
3036
resolve([]);
37+
onResolve();
3138
return;
3239
}
3340

3441
var file = refactorCache.fileList.getFile(params.textDocument.uri.toFsPath().toString());
3542
if (file == null) {
3643
reject.handler()("file not found");
44+
onResolve();
3745
return;
3846
}
3947

4048
var editDoc = new EditDoc(params.textDocument.uri.toFsPath(), new EditList(), context, converter);
4149

4250
var localScopedNames:Array<String> = [];
51+
var outOfScope:Array<Identifier> = [];
52+
var functionStartLine:Int = params.context.stoppedLocation.start.line;
4353

4454
function matchLocalScoped(identifier:Identifier):Bool {
55+
switch (identifier.name) {
56+
case "this" | "super":
57+
return false;
58+
default:
59+
}
4560
return switch (identifier.type) {
4661
case ScopedLocal(scopeStart, scopeEnd, scopeType):
62+
var pos:IdentifierPos = {
63+
fileName: identifier.pos.fileName,
64+
start: scopeStart,
65+
end: scopeEnd
66+
};
67+
var range = editDoc.posToRange(pos);
68+
if (!range.contains(params.context.stoppedLocation)) {
69+
outOfScope.push(identifier);
70+
return false;
71+
}
4772
localScopedNames.push(identifier.name);
4873
true;
49-
case Access: true;
74+
case Access:
75+
for (scoped in outOfScope) {
76+
switch (scoped.type) {
77+
case ScopedLocal(scopeStart, scopeEnd, scopeType):
78+
if ((scoped.name == identifier.name) || identifier.name.startsWith('${scoped.name}.')) {
79+
if (scopeStart <= identifier.pos.start && scopeEnd >= identifier.pos.end) {
80+
return false;
81+
}
82+
}
83+
default:
84+
}
85+
}
86+
true;
87+
case Method(_):
88+
var functionRange:Range = editDoc.posToRange(identifier.pos);
89+
if (functionRange.start.line <= params.context.stoppedLocation.start.line) {
90+
functionStartLine = functionRange.start.line;
91+
}
92+
false;
5093
default: false;
5194
}
5295
}
5396
final identifiers:Array<Identifier> = file.findAllIdentifiers(matchLocalScoped);
5497
final inlineValueVars:Array<InlineValue> = [];
5598
for (identifier in identifiers) {
5699
var identifierRange = editDoc.posToRange(identifier.pos);
100+
if (identifierRange.start.line < functionStartLine) {
101+
continue;
102+
}
57103
if (!params.range.contains(identifierRange)) {
58104
continue;
59105
}
60-
var needsExpression:Bool = identifier.name.contains(".");
61-
if ((identifier.type == Access) && !localScopedNames.contains(identifier.name)) {
62-
needsExpression = true;
106+
if (params.context.stoppedLocation.end.line < identifierRange.start.line) {
107+
continue;
63108
}
64-
65-
if (needsExpression) {
66-
inlineValueVars.push({
67-
range: identifierRange,
68-
expression: identifier.name
69-
});
70-
} else {
71-
inlineValueVars.push({
72-
range: identifierRange,
73-
variableName: identifier.name,
74-
caseSensitiveLookup: true
75-
});
109+
if (isSharpCondition(params, identifier)) {
110+
continue;
76111
}
112+
if (isTypeParam(params, identifier)) {
113+
continue;
114+
}
115+
if (isLocalFunctionName(params, identifier)) {
116+
continue;
117+
}
118+
var hasDot:Bool = identifier.name.contains(".");
119+
if (!hasDot) {
120+
if (skipIdentifier(identifier)) {
121+
continue;
122+
}
123+
}
124+
inlineValueVars.push({
125+
range: identifierRange,
126+
expression: identifier.name
127+
});
77128
}
78129

79130
resolve(inlineValueVars);
131+
onResolve();
132+
}
133+
134+
function isSharpCondition(params:InlineValueParams, identifier:Identifier):Bool {
135+
final doc:Null<HaxeDocument> = context.documents.getHaxe(params.textDocument.uri);
136+
final token = doc?.tokens?.getTokenAtOffset(identifier.pos.start);
137+
138+
if (token == null) {
139+
return false;
140+
}
141+
var parent = token.parent;
142+
while (parent != null) {
143+
switch (parent.tok) {
144+
case Dot:
145+
case Const(CIdent(_)):
146+
case POpen:
147+
case Unop(OpNot):
148+
case Binop(OpBoolAnd) | Binop(OpBoolOr):
149+
case Sharp("if") | Sharp("elseif"):
150+
return true;
151+
default:
152+
return false;
153+
}
154+
parent = parent.parent;
155+
}
156+
157+
return false;
158+
}
159+
160+
function isLocalFunctionName(params:InlineValueParams, identifier:Identifier):Bool {
161+
final doc:Null<HaxeDocument> = context.documents.getHaxe(params.textDocument.uri);
162+
final token = doc?.tokens?.getTokenAtOffset(identifier.pos.start);
163+
164+
if (token == null) {
165+
return false;
166+
}
167+
switch (token.parent?.tok) {
168+
case Kwd(KwdFunction):
169+
return true;
170+
default:
171+
return false;
172+
}
173+
}
174+
175+
function isTypeParam(params:InlineValueParams, identifier:Identifier):Bool {
176+
final doc:Null<HaxeDocument> = context.documents.getHaxe(params.textDocument.uri);
177+
final token = doc?.tokens?.getTokenAtOffset(identifier.pos.end);
178+
179+
if (token == null) {
180+
return false;
181+
}
182+
var parent = token.parent;
183+
while (parent != null) {
184+
switch (parent.tok) {
185+
case Dot:
186+
case DblDot:
187+
case BrOpen:
188+
case Const(CIdent(_)):
189+
case Binop(OpAssign):
190+
case Sharp(_):
191+
return true;
192+
case Binop(OpLt):
193+
return parent.access().firstOf(Binop(OpGt)).exists();
194+
default:
195+
return false;
196+
}
197+
parent = parent.parent;
198+
}
199+
200+
return false;
201+
}
202+
203+
function skipIdentifier(identifier:Identifier):Bool {
204+
if (isTypeUsed(identifier.defineType, identifier.name)) {
205+
return true;
206+
}
207+
var allUses:Array<Identifier> = refactorCache.nameMap.getIdentifiers(identifier.name);
208+
for (use in allUses) {
209+
switch (use.type) {
210+
case EnumField(_):
211+
return true;
212+
default:
213+
}
214+
}
215+
return false;
216+
}
217+
218+
function isTypeUsed(containerType:Null<Type>, name:String):Bool {
219+
if (containerType == null) {
220+
return false;
221+
}
222+
final types:Array<Type> = refactorCache.typeList.findTypeName(name);
223+
for (type in types) {
224+
switch (containerType.file.importsModule(type.file.getPackage(), type.file.getMainModulName(), name)) {
225+
case None:
226+
case ImportedWithAlias(_):
227+
case Global | ParentPackage | SamePackage | Imported | StarImported:
228+
return true;
229+
}
230+
}
231+
return false;
80232
}
81233
}

0 commit comments

Comments
 (0)