- Set vars assigned with type ClassTypeInfo (e.g.Java.type("")) as static access

- Unified isStaticAccess checkers to TypeResolver.isStaticAccessExpression
This commit is contained in:
bigguy345 committed 2026-01-08 07:05:30 +02:00
1 parent 176a3b6d50
commit bfcdd3c47c
4 files changed
+143 -21

No files matched your search

@@ -343,12 +343,11 @@ public class JavaAutocompleteProvider implements AutocompleteProvider {
/**
* Check if the receiver expression represents static access (class type).
* Similar logic to FieldChainMarker.isStaticContext().
* Returns true if the expression is a TYPE NAME (not a variable).
*/
protected boolean isStaticAccess(String receiverExpr, int position) {
// Try to resolve the receiver expression as a type
TypeInfo typeCheck = document.resolveType(receiverExpr);
return typeCheck != null && typeCheck.isResolved();
// Use unified static access checker
return TypeResolver.isStaticAccessExpression(receiverExpr, position, document);
}
protected UsageTracker getUsageTracker() {
@@ -1,6 +1,7 @@
package noppes.npcs.client.gui.util.script.interpreter;
import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo;
import noppes.npcs.client.gui.util.script.interpreter.type.TypeResolver;
import noppes.npcs.client.gui.util.script.interpreter.type.ScriptTypeInfo;
import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo;
import noppes.npcs.client.gui.util.script.interpreter.field.FieldAccessInfo;
@@ -477,9 +478,9 @@ public class FieldChainMarker {
return false;
String previousSegment = ctx.chain.segments.get(ctx.currentIndex - 1);
// Try to resolve the previous segment as a type
TypeInfo typeCheck = document.resolveType(previousSegment);
return typeCheck != null && typeCheck.isResolved();
int prevPos = ctx.chain.positions.get(ctx.currentIndex - 1)[0];
// Use unified static access checker
return TypeResolver.isStaticAccessExpression(previousSegment, prevPos, document);
}
}
@@ -2789,6 +2789,10 @@ public class ScriptDocument {
* Check if a method call is a static access (Class.method() style).
* Returns true if the immediate receiver before the dot is a class name (uppercase).
*/
/**
* Check if a method call at the given position is static access.
* Walks backward from the method name to analyze the receiver.
*/
private boolean isStaticAccessCall(int methodNameStart) {
// Walk backward to find the dot
int pos = methodNameStart - 1;
@@ -2813,7 +2817,8 @@ public class ScriptDocument {
char c = text.charAt(pos);
if (c == ')' || c == ']') {
// Method call or array - this is instance access
// Method call or array - would need complex expression resolution
// For now, conservatively treat as instance access
return false;
}
@@ -2828,24 +2833,20 @@ public class ScriptDocument {
String ident = text.substring(identStart, identEnd);
// Check if this is a class name (starts with uppercase)
// AND check if there's no dot before it (making it a direct class reference)
// If there's a chain like "obj.SomeClass.method()", we need to check further
// Skip whitespace before the identifier
while (pos >= 0 && Character.isWhitespace(text.charAt(pos)))
pos--;
// If preceded by a dot, this might be part of a longer chain
// In that case, it's not a direct static access
// If preceded by a dot, this is part of a chain - treat as instance for now
if (pos >= 0 && text.charAt(pos) == '.') {
return false;
}
// It's static access if the identifier resolves to a type
// Direct identifier - check if it resolves to a type (static) or variable (instance)
if (ident.isEmpty()) return false;
TypeInfo typeCheck = resolveType(ident);
return typeCheck != null && typeCheck.isResolved();
// Use unified static access checker
return TypeResolver.isStaticAccessExpression(ident, identStart, this);
}
/**
@@ -3486,6 +3487,14 @@ public class ScriptDocument {
if (currentType == null || !currentType.isResolved()) {
return null;
}
// Check if current type is a synthetic type
if (isJavaScript()) {
SyntheticType syntheticType = typeResolver.getSyntheticType(currentType.getSimpleName());
if (syntheticType != null) {
return resolveSyntheticChainSegment(syntheticType, segment);
}
}
if (segment.isMethodCall) {
// Method call - get return type with argument-based overload resolution
@@ -5323,7 +5332,7 @@ public class ScriptDocument {
* Resolve a variable by name at a given position.
* Works for BOTH Java and JavaScript using unified data structures.
*/
FieldInfo resolveVariable(String name, int position) {
public FieldInfo resolveVariable(String name, int position) {
// Find containing method/function
MethodInfo containingMethod = findMethodAtPosition(position);
@@ -668,4 +668,117 @@ public class TypeResolver {
return typeInfo.getTokenType();
}
}
/**
* Check if an expression represents static access (accessing a Class, not an instance).
* This checks if the expression STRING resolves to a TYPE name.
*
* Examples:
* - "String" -> true (it's a class name)
* - "myVar" -> false (it's a variable, even if myVar holds a ClassTypeInfo)
* - "Java" -> true (it's a synthetic type)
*
* Note: This is different from checking if a variable's TYPE is ClassTypeInfo.
* For variables holding ClassTypeInfo (like `var File = Java.type("File")`),
* the receiver type itself should be checked separately.
*
* @param typeInfo The resolved TypeInfo (can be null)
* @param wasResolvedAsType true if this was resolved as a type name (not a variable)
* @return true if this represents static access (direct class reference)
*/
public static boolean isStaticAccess(TypeInfo typeInfo, boolean wasResolvedAsType) {
// If explicitly resolved as a type name, it's static access
if (wasResolvedAsType)
return true;
if (typeInfo == null)
return false;
// If the typeInfo itself is a ClassTypeInfo (e.g., result of Java.type()),
// then accessing members on it should be static
if (typeInfo.isClassReference())
return true;
return false;
}
/**
* Unified static access checker for expressions.
* Determines if an identifier represents static access (type name) or instance access (variable).
*
* This method is used by ScriptDocument, JavaAutocompleteProvider, and FieldChainMarker.
*
* @param identifier The identifier to check (e.g., "String", "myVar", "Java")
* @param position The position in the document for context
* @param document The script document for resolution
* @return true if this represents static access
*/
public static boolean isStaticAccessExpression(String identifier, int position, ScriptDocument document) {
if (identifier == null || identifier.isEmpty() || document == null) {
return false;
}
// First check if it's a variable/field (instance access)
FieldInfo fieldInfo = document.resolveVariable(identifier, position);
if (fieldInfo != null && fieldInfo.isResolved()) {
// It's a variable - check if its type is a ClassTypeInfo
return isStaticAccess(fieldInfo.getTypeInfo(), false);
}
// Not a variable - check if it's a type name
TypeInfo typeCheck = document.resolveExpressionType(identifier,position);
boolean isType = typeCheck != null && typeCheck.isResolved();
return isStaticAccess(typeCheck, isType);
}
/**
* Parse string literal arguments from a method call.
* Used for resolving dynamic return types like Java.type("className").
*
* @param argumentsStr The arguments string (e.g., "\"java.io.File\", 123")
* @return Array of parsed arguments
*/
public static String[] parseStringArguments(String argumentsStr) {
if (argumentsStr == null || argumentsStr.isEmpty()) {
return new String[0];
}
List<String> args = new ArrayList<>();
StringBuilder current = new StringBuilder();
int depth = 0;
boolean inString = false;
char stringChar = 0;
for (int i = 0; i < argumentsStr.length(); i++) {
char c = argumentsStr.charAt(i);
if (inString) {
current.append(c);
if (c == stringChar && (i == 0 || argumentsStr.charAt(i - 1) != '\\')) {
inString = false;
}
} else if (c == '"' || c == '\'') {
current.append(c);
inString = true;
stringChar = c;
} else if (c == '(' || c == '[' || c == '{') {
depth++;
current.append(c);
} else if (c == ')' || c == ']' || c == '}') {
depth--;
current.append(c);
} else if (c == ',' && depth == 0) {
args.add(current.toString().trim());
current = new StringBuilder();
} else {
current.append(c);
}
}
if (current.length() > 0) {
args.add(current.toString().trim());
}
return args.toArray(new String[0]);
}
}