Captured full/type/name offsets of method declarations

This commit is contained in:
bigguy345 committed 2025-12-28 18:53:29 +02:00
1 parent 9aa23ef49d
commit b7333bcf6a
2 files changed
+123 -19

No files matched your search

@@ -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.
*
* <p>This class delegates to helper classes for specific functionality:</p>
* <ul>
* <li>{@link ControlFlowAnalyzer} - Control flow analysis for missing return detection</li>
* <li>{@link CodeParser} - Code parsing utilities (brace matching, comment removal)</li>
* <li>{@link TypeChecker} - Type compatibility checking</li>
* </ul>
*/
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<FieldInfo> 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<FieldInfo> parameters, int declarationOffset,
List<FieldInfo> 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<FieldInfo> 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<FieldInfo> 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<FieldInfo> 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<FieldInfo> 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<FieldInfo> 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; }
@@ -455,8 +455,23 @@ public class ScriptDocument {
List<FieldInfo> 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<FieldInfo> 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<FieldInfo> 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<FieldInfo> parseParametersWithPositions(String paramList, int paramListStart) {
List<FieldInfo> params = new ArrayList<>();
if (paramList == null || paramList.trim().isEmpty()) {