Code optimization (for erorring static access of non static members)

This commit is contained in:
bigguy345 committed 2025-12-30 18:51:22 +02:00
1 parent bd0044a2aa
commit 5899186445
3 files changed
+38 -113

No files matched your search

@@ -3496,9 +3496,7 @@ public class ScriptDocument {
currentType = null; // We'll use globalFields for the next segment
} else if (Character.isUpperCase(firstSegment.charAt(0))) {
// Static field access like SomeClass.field
TypeInfo classType = resolveType(firstSegment);
// Class names are always in static context (can only access static members)
currentType = (classType != null) ? classType.asStaticContext() : null;
currentType = resolveType(firstSegment);
} else {
// Variable or field access
if (firstIsPrecededByDot) {
@@ -3507,8 +3505,7 @@ public class ScriptDocument {
TypeInfo receiverType = resolveReceiverChain(chainStart);
if (receiverType != null && receiverType.hasField(firstSegment)) {
FieldInfo varInfo = receiverType.getFieldInfo(firstSegment);
// Field values are always instances, even if field itself is static
currentType = (varInfo != null) ? varInfo.getTypeInfo().asInstanceContext() : null;
currentType = (varInfo != null) ? varInfo.getTypeInfo() : null;
} else {
currentType = null; // Can't resolve
}
@@ -3516,8 +3513,7 @@ public class ScriptDocument {
// This is a variable starting the chain
FieldInfo varInfo = resolveVariable(firstSegment, chainStart);
if (varInfo != null) {
// Variables are always instances
currentType = varInfo.getTypeInfo().asInstanceContext();
currentType = varInfo.getTypeInfo();
} else {
currentType = null;
}
@@ -3549,8 +3545,7 @@ public class ScriptDocument {
FieldAccessInfo accessInfo = createFieldAccessInfo(segment, segPos[0], segPos[1], receiverType, fieldInfo, isLastSegment, isStaticAccessSeg);
marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.GLOBAL_FIELD, accessInfo));
// Field values are always instances
currentType = (fieldInfo != null) ? fieldInfo.getTypeInfo().asInstanceContext() : null;
currentType = (fieldInfo != null) ? fieldInfo.getTypeInfo() : null;
} else {
marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.UNDEFINED_VAR));
currentType = null;
@@ -3560,52 +3555,33 @@ public class ScriptDocument {
if (globalFields.containsKey(segment)) {
FieldInfo fieldInfo = globalFields.get(segment);
marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.GLOBAL_FIELD, fieldInfo));
// Field values are always instances
currentType = fieldInfo.getTypeInfo().asInstanceContext();
currentType = fieldInfo.getTypeInfo();
} else {
marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.UNDEFINED_VAR));
currentType = null;
}
} else if (currentType != null && currentType.isResolved()) {
// Check if this type has this field
// First check if field exists at all (ignoring static context)
FieldInfo fieldInfo = null;
boolean fieldExists = false;
boolean isStaticAccessError = false;
if (currentType.hasField(segment)) {
FieldInfo fieldInfo = currentType.getFieldInfo(segment);
// Check if field exists by temporarily using instance context
TypeInfo instanceContext = currentType.asInstanceContext();
if (instanceContext.hasField(segment)) {
fieldExists = true;
// Now check if accessible in actual context
if (currentType.hasField(segment)) {
fieldInfo = currentType.getFieldInfo(segment);
// If accessing from a class name (isStaticAccessSeg) and field is not static, that's an error
if (isStaticAccessSeg && fieldInfo != null && !fieldInfo.isStatic()) {
// Mark as error - trying to access non-static field from static context
TokenErrorMessage errorMsg = TokenErrorMessage
.from("Cannot access non-static field '" + segment + "' from static context '" + currentType.getSimpleName() + "'")
.clearOtherErrors();
marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.UNDEFINED_VAR, errorMsg));
currentType = null; // Can't continue resolving
} else {
// Field exists but not accessible in static context
isStaticAccessError = true;
fieldInfo = instanceContext.getFieldInfo(segment);
// Valid access
FieldAccessInfo accessInfo = createFieldAccessInfo(segment, segPos[0], segPos[1],
currentType, fieldInfo, isLastSegment, isStaticAccessSeg);
marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.GLOBAL_FIELD, accessInfo));
// Update currentType for next segment
currentType = (fieldInfo != null && fieldInfo.getTypeInfo() != null) ? fieldInfo.getTypeInfo() : null;
}
}
if (fieldInfo != null && !isStaticAccessError) {
// Check if this is the last segment and if it's in an assignment context
// Create and mark FieldAccessInfo for this segment (last or intermediate)
FieldAccessInfo accessInfo = createFieldAccessInfo(segment, segPos[0], segPos[1], currentType, fieldInfo, isLastSegment, isStaticAccessSeg);
marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.GLOBAL_FIELD, accessInfo));
// Update currentType for next segment - field values are always instances
currentType = (fieldInfo != null) ? fieldInfo.getTypeInfo().asInstanceContext() : null;
/*TODO THIS ELSE OVERRIDES FOR CHAINED METHOD CALLS LIKE "Minecraft.getMinecraft()"
Do we resolve this by increasing METHOD_CALL PRIORITY or how exactly?
Think of the best fitting solution that doesnt regress other parts of the whole framework.
*/
} else if (isStaticAccessError && fieldInfo != null) {
// Mark as error - trying to access non-static field from static context
TokenErrorMessage errorMsg = TokenErrorMessage.from(
"Cannot access non-static field '" + segment + "' from static context '" + currentType.getSimpleName() + "'").clearOtherErrors();
marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.UNDEFINED_VAR, errorMsg));
currentType = null; // Can't continue resolving
} else {
marks.add(new ScriptLine.Mark(segPos[0], segPos[1], TokenType.UNDEFINED_VAR));
currentType = null; // Can't continue resolving
@@ -34,8 +34,8 @@ public class ScriptTypeInfo extends TypeInfo {
private ScriptTypeInfo outerClass;
private ScriptTypeInfo(String simpleName, String fullName, Kind kind,
int declarationOffset, int bodyStart, int bodyEnd, int modifiers, boolean staticContext) {
super(simpleName, fullName, "", kind, null, true, null, staticContext, true);
int declarationOffset, int bodyStart, int bodyEnd, int modifiers) {
super(simpleName, fullName, "", kind, null, true, null, true);
this.scriptClassName = simpleName;
this.declarationOffset = declarationOffset;
this.bodyStart = bodyStart;
@@ -46,13 +46,13 @@ public class ScriptTypeInfo extends TypeInfo {
// Factory method
public static ScriptTypeInfo create(String simpleName, Kind kind,
int declarationOffset, int bodyStart, int bodyEnd, int modifiers) {
return new ScriptTypeInfo(simpleName, simpleName, kind, declarationOffset, bodyStart, bodyEnd, modifiers, false);
return new ScriptTypeInfo(simpleName, simpleName, kind, declarationOffset, bodyStart, bodyEnd, modifiers);
}
public static ScriptTypeInfo createInner(String simpleName, Kind kind, ScriptTypeInfo outer,
int declarationOffset, int bodyStart, int bodyEnd, int modifiers) {
String fullName = outer.getFullName() + "$" + simpleName;
ScriptTypeInfo inner = new ScriptTypeInfo(simpleName, fullName, kind, declarationOffset, bodyStart, bodyEnd, modifiers, false);
ScriptTypeInfo inner = new ScriptTypeInfo(simpleName, fullName, kind, declarationOffset, bodyStart, bodyEnd, modifiers);
inner.outerClass = outer;
outer.innerClasses.add(inner);
return inner;
@@ -82,26 +82,12 @@ public class ScriptTypeInfo extends TypeInfo {
@Override
public boolean hasField(String fieldName) {
FieldInfo field = fields.get(fieldName);
if (field == null) return false;
// In static context, only static fields are accessible
if (isStaticContext() && !field.isStatic()) {
return false;
}
return true;
return fields.containsKey(fieldName);
}
@Override
public FieldInfo getFieldInfo(String fieldName) {
FieldInfo field = fields.get(fieldName);
if (field == null) return null;
// In static context, only static fields are accessible
if (isStaticContext() && !field.isStatic()) {
return null; // Non-static field not accessible from static context
}
return field;
return fields.get(fieldName);
}
public Map<String, FieldInfo> getFields() {
@@ -27,10 +27,9 @@ public class TypeInfo {
private final Class<?> javaClass; // The actual resolved Java class (null if unresolved)
private final boolean resolved; // Whether this type was successfully resolved
private final TypeInfo enclosingType; // For inner classes, the outer type (null if top-level)
private final boolean staticContext; // true if this is a class reference (can only access static members), false if instance
private TypeInfo(String simpleName, String fullName, String packageName,
Kind kind, Class<?> javaClass, boolean resolved, TypeInfo enclosingType, boolean staticContext) {
Kind kind, Class<?> javaClass, boolean resolved, TypeInfo enclosingType) {
this.simpleName = simpleName;
this.fullName = fullName;
this.packageName = packageName;
@@ -38,13 +37,12 @@ public class TypeInfo {
this.javaClass = javaClass;
this.resolved = resolved;
this.enclosingType = enclosingType;
this.staticContext = staticContext;
}
// Protected constructor for subclasses (like ScriptTypeInfo)
protected TypeInfo(String simpleName, String fullName, String packageName,
Kind kind, Class<?> javaClass, boolean resolved, TypeInfo enclosingType,
boolean staticContext, @SuppressWarnings("unused") boolean subclass) {
@SuppressWarnings("unused") boolean subclass) {
this.simpleName = simpleName;
this.fullName = fullName;
this.packageName = packageName;
@@ -52,24 +50,23 @@ public class TypeInfo {
this.javaClass = javaClass;
this.resolved = resolved;
this.enclosingType = enclosingType;
this.staticContext = staticContext;
}
// Factory methods
public static TypeInfo resolved(String simpleName, String fullName, String packageName,
Kind kind, Class<?> javaClass) {
return new TypeInfo(simpleName, fullName, packageName, kind, javaClass, true, null, false);
return new TypeInfo(simpleName, fullName, packageName, kind, javaClass, true, null);
}
public static TypeInfo resolvedInner(String simpleName, String fullName, String packageName,
Kind kind, Class<?> javaClass, TypeInfo enclosing) {
return new TypeInfo(simpleName, fullName, packageName, kind, javaClass, true, enclosing, false);
return new TypeInfo(simpleName, fullName, packageName, kind, javaClass, true, enclosing);
}
public static TypeInfo unresolved(String simpleName, String fullPath) {
int lastDot = fullPath.lastIndexOf('.');
String pkg = lastDot > 0 ? fullPath.substring(0, lastDot) : "";
return new TypeInfo(simpleName, fullPath, pkg, Kind.UNKNOWN, null, false, null, false);
return new TypeInfo(simpleName, fullPath, pkg, Kind.UNKNOWN, null, false, null);
}
public static TypeInfo fromClass(Class<?> clazz) {
@@ -102,7 +99,7 @@ public class TypeInfo {
enclosing = fromClass(clazz.getEnclosingClass());
}
return new TypeInfo(simpleName, fullName, packageName, kind, clazz, true, enclosing, false);
return new TypeInfo(simpleName, fullName, packageName, kind, clazz, true, enclosing);
}
/**
@@ -121,7 +118,7 @@ public class TypeInfo {
case "double": primitiveClass = double.class; break;
case "void": primitiveClass = void.class; break;
}
return new TypeInfo(typeName, typeName, "", Kind.CLASS, primitiveClass, true, null, false);
return new TypeInfo(typeName, typeName, "", Kind.CLASS, primitiveClass, true, null);
}
// Getters
@@ -133,25 +130,6 @@ public class TypeInfo {
public boolean isResolved() { return resolved; }
public TypeInfo getEnclosingType() { return enclosingType; }
public boolean isInnerClass() { return enclosingType != null; }
public boolean isStaticContext() { return staticContext; }
/**
* Create a new TypeInfo with static context (for class references).
* Used when referencing a class name directly, which can only access static members.
*/
public TypeInfo asStaticContext() {
if (staticContext) return this;
return new TypeInfo(simpleName, fullName, packageName, kind, javaClass, resolved, enclosingType, true);
}
/**
* Create a new TypeInfo with instance context (for object instances).
* Used when referencing an instance of a class, which can access both static and instance members.
*/
public TypeInfo asInstanceContext() {
if (!staticContext) return this;
return new TypeInfo(simpleName, fullName, packageName, kind, javaClass, resolved, enclosingType, false);
}
/**
* Get the appropriate TokenType for highlighting this type.
@@ -259,19 +237,13 @@ public class TypeInfo {
}
/**
* Check if this type has a field with the given name that is accessible in the current context.
* In static context (class reference), only static fields are accessible.
* In instance context, both static and instance fields are accessible.
* Check if this type has a field with the given name.
*/
public boolean hasField(String fieldName) {
if (javaClass == null) return false;
try {
for (java.lang.reflect.Field f : javaClass.getFields()) {
if (f.getName().equals(fieldName)) {
// In static context, only static fields are accessible
if (staticContext && !java.lang.reflect.Modifier.isStatic(f.getModifiers())) {
return false;
}
return true;
}
}
@@ -469,9 +441,7 @@ public class TypeInfo {
}
/**
* Get FieldInfo for a field by name. Returns null if not found or not accessible.
* In static context (class reference), only static fields are accessible.
* In instance context, both static and instance fields are accessible.
* Get FieldInfo for a field by name. Returns null if not found.
* Creates a synthetic FieldInfo based on reflection data.
*/
public FieldInfo getFieldInfo(String fieldName) {
@@ -479,15 +449,8 @@ public class TypeInfo {
try {
for (java.lang.reflect.Field f : javaClass.getFields()) {
if (f.getName().equals(fieldName)) {
// In static context, only static fields are accessible
if (staticContext && !java.lang.reflect.Modifier.isStatic(f.getModifiers())) {
return null; // Non-static field not accessible from static context
}
// Create a synthetic FieldInfo from reflection
// Always return instance context for the field's type (field values are instances)
FieldInfo fieldInfo = FieldInfo.fromReflection(f, this);
// The field's type should be in instance context since we're accessing a value
return fieldInfo;
return FieldInfo.fromReflection(f, this);
}
}
} catch (Exception e) {