mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 20:07:32 +00:00
Added error "method signature already defined in this scope"
This commit is contained in:
1 parent
6d20f5f52c
commit
e2a5d254a9
5 files changed
+251
-1
No files matched your search
@@ -30,6 +30,7 @@ public final class MethodInfo {
|
||||
MISSING_RETURN, // Non-void method missing return statement
|
||||
RETURN_TYPE_MISMATCH, // Return statement type doesn't match method return type
|
||||
VOID_METHOD_RETURNS_VALUE, // Void method returns a value
|
||||
DUPLICATE_METHOD, // Method with same signature already defined in scope
|
||||
DUPLICATE_PARAMETER, // Two parameters have the same name
|
||||
PARAMETER_UNDEFINED // Parameter type cannot be resolved
|
||||
}
|
||||
@@ -191,6 +192,16 @@ public final class MethodInfo {
|
||||
return position >= bodyStart && position < bodyEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the end of the method declaration (closing paren position).
|
||||
* This is used for error highlighting of duplicate methods.
|
||||
*/
|
||||
public int getDeclarationEnd() {
|
||||
// The declaration ends just before the opening brace
|
||||
// We find the closing paren by searching backwards from bodyStart
|
||||
return bodyStart > 0 ? bodyStart - 1 : nameOffset + name.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this method has a parameter with the given name.
|
||||
*/
|
||||
@@ -215,6 +226,22 @@ public final class MethodInfo {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get method signature for duplicate detection.
|
||||
* Signature = name + parameter types (ignoring parameter names).
|
||||
*/
|
||||
public MethodSignature cachedSignature;
|
||||
|
||||
public MethodSignature getSignature() {
|
||||
if (cachedSignature == null) {
|
||||
List<TypeInfo> paramTypes = new ArrayList<>();
|
||||
for (FieldInfo param : parameters)
|
||||
paramTypes.add(param.getDeclaredType());
|
||||
cachedSignature = new MethodSignature(name, paramTypes);
|
||||
}
|
||||
return cachedSignature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate TokenType for highlighting this method.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package noppes.npcs.client.gui.util.script.interpreter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a method signature for robust comparison.
|
||||
* Compares method name and parameter types as structured data, not as strings.
|
||||
*/
|
||||
public final class MethodSignature {
|
||||
private final String methodName;
|
||||
private final List<TypeInfo> parameterTypes;
|
||||
|
||||
public MethodSignature(String methodName, List<TypeInfo> parameterTypes) {
|
||||
this.methodName = methodName;
|
||||
this.parameterTypes = new ArrayList<>(parameterTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!(obj instanceof MethodSignature))
|
||||
return false;
|
||||
|
||||
MethodSignature other = (MethodSignature) obj;
|
||||
|
||||
// Compare method names
|
||||
if (!this.methodName.equals(other.methodName))
|
||||
return false;
|
||||
|
||||
// Compare parameter count
|
||||
if (this.parameterTypes.size() != other.parameterTypes.size())
|
||||
return false;
|
||||
|
||||
// Compare each parameter type
|
||||
for (int i = 0; i < this.parameterTypes.size(); i++) {
|
||||
TypeInfo thisType = this.parameterTypes.get(i);
|
||||
TypeInfo otherType = other.parameterTypes.get(i);
|
||||
|
||||
// Both null = equal
|
||||
if (thisType == null && otherType == null)
|
||||
continue;
|
||||
|
||||
// One null, one not = not equal
|
||||
if (thisType == null || otherType == null)
|
||||
return false;
|
||||
|
||||
// Compare full type names
|
||||
if (!thisType.getFullName().equals(otherType.getFullName()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = methodName.hashCode();
|
||||
for (TypeInfo paramType : parameterTypes) {
|
||||
result = 31 * result + (paramType != null ? paramType.getFullName().hashCode() : 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(methodName);
|
||||
sb.append("(");
|
||||
for (int i = 0; i < parameterTypes.size(); i++) {
|
||||
if (i > 0)
|
||||
sb.append(", ");
|
||||
TypeInfo type = parameterTypes.get(i);
|
||||
sb.append(type != null ? type.getFullName() : "?");
|
||||
}
|
||||
sb.append(")");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package noppes.npcs.client.gui.util.script.interpreter;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import noppes.npcs.client.ClientProxy;
|
||||
|
||||
import java.util.*;
|
||||
@@ -604,6 +603,9 @@ public class ScriptDocument {
|
||||
methods.add(methodInfo);
|
||||
}
|
||||
|
||||
// Check for duplicate method declarations
|
||||
checkDuplicateMethods();
|
||||
|
||||
// Also parse JS-style functions
|
||||
Matcher funcM = FUNC_PARAMS_PATTERN.matcher(text);
|
||||
while (funcM.find()) {
|
||||
@@ -666,6 +668,97 @@ public class ScriptDocument {
|
||||
return earliestPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for duplicate method declarations with same signature in same scope.
|
||||
*/
|
||||
private void checkDuplicateMethods() {
|
||||
// Group methods by scope depth
|
||||
Map<Integer, List<MethodInfo>> methodsByScope = new HashMap<>();
|
||||
|
||||
for (MethodInfo method : methods) {
|
||||
int scopeDepth = calculateScopeDepth(method.getFullDeclarationOffset());
|
||||
methodsByScope.computeIfAbsent(scopeDepth, k -> new ArrayList<>()).add(method);
|
||||
}
|
||||
|
||||
// Check each scope for duplicates
|
||||
for (List<MethodInfo> scopeMethods : methodsByScope.values()) {
|
||||
Map<MethodSignature, List<MethodInfo>> signatureMap = new HashMap<>();
|
||||
|
||||
for (MethodInfo method : scopeMethods) {
|
||||
MethodSignature signature = method.getSignature();
|
||||
signatureMap.computeIfAbsent(signature, k -> new ArrayList<>()).add(method);
|
||||
}
|
||||
|
||||
// Mark all methods with duplicate signatures
|
||||
for (Map.Entry<MethodSignature, List<MethodInfo>> entry : signatureMap.entrySet()) {
|
||||
List<MethodInfo> duplicates = entry.getValue();
|
||||
if (duplicates.size() > 1) {
|
||||
for (MethodInfo duplicate : duplicates) {
|
||||
duplicate.setError(
|
||||
MethodInfo.ErrorType.DUPLICATE_METHOD,
|
||||
duplicate.getSignature() + " is already defined in this scope"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the scope depth of a position (0 = top level, 1 = in class, etc.).
|
||||
*/
|
||||
private int calculateScopeDepth(int position) {
|
||||
int depth = 0;
|
||||
int braceDepth = 0;
|
||||
boolean inString = false;
|
||||
boolean inComment = false;
|
||||
boolean inLineComment = false;
|
||||
|
||||
for (int i = 0; i < position && i < text.length(); i++) {
|
||||
char c = text.charAt(i);
|
||||
char next = (i + 1 < text.length()) ? text.charAt(i + 1) : 0;
|
||||
|
||||
// Handle strings
|
||||
if (c == '"' && !inComment && !inLineComment) {
|
||||
inString = !inString;
|
||||
continue;
|
||||
}
|
||||
if (inString) continue;
|
||||
|
||||
// Handle comments
|
||||
if (!inComment && !inLineComment && c == '/' && next == '/') {
|
||||
inLineComment = true;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!inComment && !inLineComment && c == '/' && next == '*') {
|
||||
inComment = true;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (inComment && c == '*' && next == '/') {
|
||||
inComment = false;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (inLineComment && c == '\n') {
|
||||
inLineComment = false;
|
||||
continue;
|
||||
}
|
||||
if (inComment || inLineComment) continue;
|
||||
|
||||
// Track braces
|
||||
if (c == '{') {
|
||||
braceDepth++;
|
||||
depth = Math.max(depth, braceDepth);
|
||||
} else if (c == '}') {
|
||||
braceDepth--;
|
||||
}
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
private List<FieldInfo> parseParametersWithPositions(String paramList, int paramListStart) {
|
||||
List<FieldInfo> params = new ArrayList<>();
|
||||
if (paramList == null || paramList.trim().isEmpty()) {
|
||||
|
||||
@@ -522,6 +522,47 @@ public class ScriptLine {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle duplicate method error (underline from full declaration start to closing paren)
|
||||
if (method.getErrorType() == MethodInfo.ErrorType.DUPLICATE_METHOD) {
|
||||
int declStart = method.getFullDeclarationOffset();
|
||||
int declEnd = method.getDeclarationEnd();
|
||||
|
||||
// Skip if declaration doesn't intersect this line
|
||||
if (declEnd < lineStart || declStart > lineEnd)
|
||||
continue;
|
||||
|
||||
// Clip to line boundaries
|
||||
int clipStart = Math.max(declStart, lineStart);
|
||||
int clipEnd = Math.min(declEnd, lineEnd);
|
||||
|
||||
if (clipStart >= clipEnd)
|
||||
continue;
|
||||
|
||||
// Convert to line-local coordinates
|
||||
int lineLocalStart = clipStart - lineStart;
|
||||
int lineLocalEnd = clipEnd - lineStart;
|
||||
|
||||
// Bounds check
|
||||
if (lineLocalStart < 0 || lineLocalStart >= lineText.length())
|
||||
continue;
|
||||
|
||||
// Compute pixel position
|
||||
String beforeDecl = lineText.substring(0, lineLocalStart);
|
||||
int beforeWidth = ClientProxy.Font.width(beforeDecl);
|
||||
|
||||
int declWidth;
|
||||
if (lineLocalEnd > lineText.length()) {
|
||||
declWidth = ClientProxy.Font.width(lineText.substring(lineLocalStart));
|
||||
} else {
|
||||
String declTextOnLine = lineText.substring(lineLocalStart, lineLocalEnd);
|
||||
declWidth = ClientProxy.Font.width(declTextOnLine);
|
||||
}
|
||||
|
||||
if (declWidth > 0) {
|
||||
drawCurlyUnderline(lineStartX + beforeWidth, baselineY, declWidth, 0xFF5555);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle parameter errors (underline specific parameters)
|
||||
if (method.hasParameterErrors()) {
|
||||
for (MethodInfo.ParameterError paramError : method.getParameterErrors()) {
|
||||
|
||||
+10
@@ -221,6 +221,16 @@ public class TokenHoverInfo {
|
||||
}
|
||||
}
|
||||
|
||||
// If hovering over duplicate method declaration, show the error
|
||||
if (methodDecl.getErrorType() == MethodInfo.ErrorType.DUPLICATE_METHOD) {
|
||||
int declStart = methodDecl.getFullDeclarationOffset();
|
||||
int declEnd = methodDecl.getDeclarationEnd();
|
||||
|
||||
if (tokenStart >= declStart && tokenEnd <= declEnd) {
|
||||
errors.add(methodDecl.getErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// If hovering over a parameter with an error, show that error
|
||||
if (methodDecl.hasParameterErrors()) {
|
||||
for (MethodInfo.ParameterError paramError : methodDecl.getParameterErrors()) {
|
||||
|
||||
Reference in new issue
Block a user