diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/MethodInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/MethodInfo.java
index c8bee1855..9e9ed9039 100644
--- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/MethodInfo.java
+++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/MethodInfo.java
@@ -5,11 +5,20 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* Metadata for a method declaration or method call.
* Tracks method name, parameters, return type, and containing class.
+ *
+ *
This class delegates to helper classes for specific functionality:
+ *
+ * - {@link ControlFlowAnalyzer} - Control flow analysis for missing return detection
+ * - {@link CodeParser} - Code parsing utilities (brace matching, comment removal)
+ * - {@link TypeChecker} - Type compatibility checking
+ *
*/
public final class MethodInfo {
@@ -17,7 +26,9 @@ public final class MethodInfo {
private final TypeInfo returnType;
private final TypeInfo containingType; // The class/interface that owns this method
private final List parameters;
- private final int declarationOffset; // -1 for external methods (calls to library methods)
+ private final int fullDeclarationOffset; // Start of full declaration (including modifiers), -1 for external
+ private final int typeOffset; // Start of return type
+ private final int nameOffset; // Start of method name
private final int bodyStart; // Start of method body (after {)
private final int bodyEnd; // End of method body (before })
private final boolean resolved;
@@ -26,14 +37,16 @@ public final class MethodInfo {
private final String documentation; // Javadoc/comment documentation for this method
private MethodInfo(String name, TypeInfo returnType, TypeInfo containingType,
- List parameters, int declarationOffset,
+ List parameters, int fullDeclarationOffset, int typeOffset, int nameOffset,
int bodyStart, int bodyEnd, boolean resolved, boolean isDeclaration,
int modifiers, String documentation) {
this.name = name;
this.returnType = returnType;
this.containingType = containingType;
this.parameters = parameters != null ? new ArrayList<>(parameters) : new ArrayList<>();
- this.declarationOffset = declarationOffset;
+ this.fullDeclarationOffset = fullDeclarationOffset;
+ this.typeOffset = typeOffset;
+ this.nameOffset = nameOffset;
this.bodyStart = bodyStart;
this.bodyEnd = bodyEnd;
this.resolved = resolved;
@@ -44,25 +57,29 @@ public final class MethodInfo {
// Factory methods
public static MethodInfo declaration(String name, TypeInfo returnType, List params,
- int declOffset, int bodyStart, int bodyEnd) {
- return new MethodInfo(name, returnType, null, params, declOffset, bodyStart, bodyEnd, true, true, 0, null);
+ int fullDeclOffset, int typeOffset, int nameOffset,
+ int bodyStart, int bodyEnd) {
+ return new MethodInfo(name, returnType, null, params, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, 0, null);
}
public static MethodInfo declaration(String name, TypeInfo returnType, List params,
- int declOffset, int bodyStart, int bodyEnd, boolean isStatic) {
+ int fullDeclOffset, int typeOffset, int nameOffset,
+ int bodyStart, int bodyEnd, boolean isStatic) {
int modifiers = isStatic ? Modifier.STATIC : 0;
- return new MethodInfo(name, returnType, null, params, declOffset, bodyStart, bodyEnd, true, true, modifiers, null);
+ return new MethodInfo(name, returnType, null, params, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, modifiers, null);
}
public static MethodInfo declaration(String name, TypeInfo returnType, List params,
- int declOffset, int bodyStart, int bodyEnd, boolean isStatic, String documentation) {
+ int fullDeclOffset, int typeOffset, int nameOffset,
+ int bodyStart, int bodyEnd, boolean isStatic, String documentation) {
int modifiers = isStatic ? Modifier.STATIC : 0;
- return new MethodInfo(name, returnType, null, params, declOffset, bodyStart, bodyEnd, true, true, modifiers, documentation);
+ return new MethodInfo(name, returnType, null, params, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, modifiers, documentation);
}
public static MethodInfo declaration(String name, TypeInfo returnType, List params,
- int declOffset, int bodyStart, int bodyEnd, int modifiers, String documentation) {
- return new MethodInfo(name, returnType, null, params, declOffset, bodyStart, bodyEnd, true, true, modifiers, documentation);
+ int fullDeclOffset, int typeOffset, int nameOffset,
+ int bodyStart, int bodyEnd, int modifiers, String documentation) {
+ return new MethodInfo(name, returnType, null, params, fullDeclOffset, typeOffset, nameOffset, bodyStart, bodyEnd, true, true, modifiers, documentation);
}
public static MethodInfo call(String name, TypeInfo containingType, int paramCount) {
@@ -72,7 +89,7 @@ public final class MethodInfo {
for (int i = 0; i < paramCount; i++) {
params.add(FieldInfo.unresolved("arg" + i, FieldInfo.Scope.PARAMETER));
}
- return new MethodInfo(name, null, containingType, params, -1, -1, -1, resolved, false, 0, null);
+ return new MethodInfo(name, null, containingType, params, -1, -1, -1, -1, -1, resolved, false, 0, null);
}
public static MethodInfo unresolvedCall(String name, int paramCount) {
@@ -80,7 +97,7 @@ public final class MethodInfo {
for (int i = 0; i < paramCount; i++) {
params.add(FieldInfo.unresolved("arg" + i, FieldInfo.Scope.PARAMETER));
}
- return new MethodInfo(name, null, null, params, -1, -1, -1, false, false, 0, null);
+ return new MethodInfo(name, null, null, params, -1, -1, -1, -1, -1, false, false, 0, null);
}
/**
@@ -99,7 +116,7 @@ public final class MethodInfo {
params.add(FieldInfo.reflectionParam("arg" + i, paramType));
}
- return new MethodInfo(name, returnType, containingType, params, -1, -1, -1, true, false, modifiers, null);
+ return new MethodInfo(name, returnType, containingType, params, -1, -1, -1, -1, -1, true, false, modifiers, null);
}
/**
@@ -118,7 +135,7 @@ public final class MethodInfo {
params.add(FieldInfo.reflectionParam("arg" + i, paramType));
}
- return new MethodInfo(name, returnType, containingType, params, -1, -1, -1, true, true, modifiers, null);
+ return new MethodInfo(name, returnType, containingType, params, -1, -1, -1, -1, -1, true, true, modifiers, null);
}
// Getters
@@ -127,7 +144,12 @@ public final class MethodInfo {
public TypeInfo getContainingType() { return containingType; }
public List getParameters() { return Collections.unmodifiableList(parameters); }
public int getParameterCount() { return parameters.size(); }
- public int getDeclarationOffset() { return declarationOffset; }
+ /** @deprecated Use getTypeOffset() or getNameOffset() instead */
+ @Deprecated
+ public int getDeclarationOffset() { return typeOffset; }
+ public int getFullDeclarationOffset() { return fullDeclarationOffset; }
+ public int getTypeOffset() { return typeOffset; }
+ public int getNameOffset() { return nameOffset; }
public int getBodyStart() { return bodyStart; }
public int getBodyEnd() { return bodyEnd; }
public boolean isResolved() { return resolved; }
diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java
index bd0458c13..73874410c 100644
--- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java
+++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java
@@ -455,8 +455,23 @@ public class ScriptDocument {
List params = parseParametersWithPositions(paramList,
bodyStart + 1 + mm.start(3));
+ // Calculate the three offsets
+ int typeOffset = bodyStart + 1 + mm.start(1); // Start of return type
+ int nameOffset = bodyStart + 1 + mm.start(2); // Start of method name
+ int fullDeclOffset = findFullDeclarationStart(mm.start(1), bodyText);
+ if (fullDeclOffset >= 0) {
+ fullDeclOffset += bodyStart + 1;
+ } else {
+ fullDeclOffset = typeOffset;
+ }
+
MethodInfo methodInfo = MethodInfo.declaration(
- methodName, returnType, params, absPos, methodBodyStart, methodBodyEnd, modifiers, documentation);
+ methodName, returnType, params, fullDeclOffset, typeOffset, nameOffset, methodBodyStart, methodBodyEnd, modifiers, documentation);
+
+ // Validate the method (including return type checking)
+ String methodBodyText = text.substring(methodBodyStart + 1, methodBodyEnd);
+ methodInfo.validate(methodBodyText, (expr, pos) -> resolveExpressionType(expr, pos));
+
scriptType.addMethod(methodInfo);
}
@@ -485,12 +500,25 @@ public class ScriptDocument {
// Parse parameters with their actual positions
List params = parseParametersWithPositions(paramList, bodyStart + 1 + cm.start(1));
+ // Calculate the three offsets for constructor
+ // For constructors, type offset and name offset are the same (start of constructor name)
+ int nameOffset = bodyStart + 1 + cm.start();
+ int typeOffset = nameOffset; // No separate type for constructors
+ int fullDeclOffset = findFullDeclarationStart(cm.start(), bodyText);
+ if (fullDeclOffset >= 0) {
+ fullDeclOffset += bodyStart + 1;
+ } else {
+ fullDeclOffset = nameOffset;
+ }
+
// Constructors don't have a return type, but we'll use the containing type as a marker
MethodInfo constructorInfo = MethodInfo.declaration(
typeName,
scriptType, // Return type is the type itself
params,
- absPos,
+ fullDeclOffset,
+ typeOffset,
+ nameOffset,
constructorBodyStart,
constructorBodyEnd,
modifiers,
@@ -547,6 +575,11 @@ public class ScriptDocument {
// Extract modifiers by scanning backwards from match start
int modifiers = extractModifiersBackwards(m.start() - 1, text);
+
+ // Calculate offset positions
+ int typeOffset = m.start(1); // Start of return type
+ int nameOffset = m.start(2); // Start of method name
+ int fullDeclOffset = findFullDeclarationStart(m.start(1), text); // Start including modifiers
// Parse parameters with their actual positions
List params = parseParametersWithPositions(paramList, m.start(3));
@@ -555,12 +588,19 @@ public class ScriptDocument {
methodName,
resolveType(returnType),
params,
- m.start(),
+ fullDeclOffset,
+ typeOffset,
+ nameOffset,
bodyStart,
bodyEnd,
modifiers,
documentation
);
+
+ // Validate the method (return statements, parameters) with type resolution
+ String methodBodyText = bodyEnd > bodyStart + 1 ? text.substring(bodyStart + 1, bodyEnd) : "";
+ methodInfo.validate(methodBodyText, (expr, pos) -> resolveExpressionType(expr, pos));
+
methods.add(methodInfo);
}
@@ -584,6 +624,48 @@ public class ScriptDocument {
}
}
+ /**
+ * Find the start of a full method declaration, including any modifiers before the type.
+ */
+ private int findFullDeclarationStart(int typeStart, String sourceText) {
+ int pos = typeStart - 1;
+
+ // Skip whitespace before type
+ while (pos >= 0 && Character.isWhitespace(sourceText.charAt(pos))) {
+ pos--;
+ }
+
+ // Check for modifiers
+ int earliestPos = typeStart;
+ while (pos >= 0) {
+ // Skip whitespace
+ while (pos >= 0 && Character.isWhitespace(sourceText.charAt(pos))) {
+ pos--;
+ }
+ if (pos < 0) break;
+
+ // Read word backwards
+ int wordEnd = pos + 1;
+ while (pos >= 0 && Character.isJavaIdentifierPart(sourceText.charAt(pos))) {
+ pos--;
+ }
+ int wordStart = pos + 1;
+
+ if (wordStart < wordEnd) {
+ String word = sourceText.substring(wordStart, wordEnd);
+ if (TypeResolver.isModifier(word)) {
+ earliestPos = wordStart;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return earliestPos;
+ }
+
private List parseParametersWithPositions(String paramList, int paramListStart) {
List params = new ArrayList<>();
if (paramList == null || paramList.trim().isEmpty()) {