mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 20:07:32 +00:00
Code optimization (for erorring static access of non static members)
This commit is contained in:
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
|
||||
|
||||
+6
-20
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user