From 455f09ac68d07dfe282898ed4821bf2dcffe1815 Mon Sep 17 00:00:00 2001 From: bigguy345 Date: Sat, 27 Dec 2025 18:30:06 +0200 Subject: [PATCH] Captured all external/chained field assignments and their errors for hover info --- .../util/script/interpreter/FieldInfo.java | 22 +++++- .../script/interpreter/ScriptDocument.java | 67 ++++++++++++++++--- .../interpreter/hover/TokenHoverInfo.java | 21 +----- 3 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldInfo.java index 47eb3191a..7031f21fd 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/FieldInfo.java @@ -161,19 +161,35 @@ public final class FieldInfo { /** * Find an assignment that contains the given position. * Returns null if no assignment contains this position. + * Prioritizes LHS matches over RHS matches. */ public AssignmentInfo findAssignmentAtPosition(int position) { // Check declaration assignment first if (declarationAssignment != null && declarationAssignment.containsPosition(position)) { - return declarationAssignment; + // Prioritize LHS match + if (declarationAssignment.containsLhsPosition(position)) { + return declarationAssignment; + } } - // Check other assignments + // Check other assignments for LHS matches first (more specific) for (AssignmentInfo assign : assignments) { - if (assign.containsPosition(position)) { + if (assign.containsLhsPosition(position)) { return assign; } } + + // Then check RHS matches (less specific - might just be a reference in the value) + if (declarationAssignment != null && declarationAssignment.containsRhsPosition(position)) { + return declarationAssignment; + } + + for (AssignmentInfo assign : assignments) { + if (assign.containsRhsPosition(position)) { + return assign; + } + } + return null; } 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 fdd9b2bf5..63ede56dc 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 @@ -78,6 +78,9 @@ public class ScriptDocument { // Field accesses - stores all parsed field access information private final List fieldAccesses = new ArrayList<>(); + + // Assignments to external fields (fields from reflection, not script-defined) + private final List externalFieldAssignments = new ArrayList<>(); // Excluded regions (strings/comments) - positions where other patterns shouldn't match private final List excludedRanges = new ArrayList<>(); @@ -186,6 +189,7 @@ public class ScriptDocument { methodLocals.clear(); scriptTypes.clear(); methodCalls.clear(); + externalFieldAssignments.clear(); // Phase 1: Find excluded regions (strings/comments) findExcludedRanges(); @@ -2785,6 +2789,7 @@ public class ScriptDocument { field.clearAssignments(); } } + externalFieldAssignments.clear(); // Pattern to find assignments: identifier = expression; // But NOT declarations (Type varName = expr) or compound assignments (+=, -=, etc.) @@ -2959,14 +2964,15 @@ public class ScriptDocument { } } - // If we couldn't resolve the target field, we can't attach the assignment - if (targetField == null) { - return; - } - // Resolve the source type (RHS) TypeInfo sourceType = resolveExpressionType(rhs, equalsPos + 1); + // Determine if this is a script-defined field or external field + FieldInfo finalTargetField = targetField; + boolean isScriptField = targetField != null && + (globalFields.containsValue(targetField) || + methodLocals.values().stream().anyMatch(m -> m.containsValue(finalTargetField))); + // Create the assignment info using the new constructor AssignmentInfo info = new AssignmentInfo( targetName, @@ -2979,14 +2985,20 @@ public class ScriptDocument { rhs, receiverType, reflectionField, - targetField.isFinal() + targetField != null ? targetField.isFinal() : false ); // Validate the assignment info.validate(); - // Attach to the FieldInfo - targetField.addAssignment(info); + // Attach to the appropriate location + if (isScriptField && targetField != null) { + // Script-defined field - attach to FieldInfo + targetField.addAssignment(info); + } else { + // External field or unresolved - store separately + externalFieldAssignments.add(info); + } } /** @@ -3368,13 +3380,43 @@ public class ScriptDocument { public List getFieldAccesses() { return Collections.unmodifiableList(fieldAccesses); } + + /** + * Find an assignment at the given position, prioritizing LHS over RHS. + * Searches across all script fields and external field assignments. + * Used by TokenHoverInfo for finding assignment errors. + */ + public AssignmentInfo findAssignmentAtPosition(int position) { + // Check script fields (FieldInfo.findAssignmentAtPosition already handles LHS/RHS priority) + for (FieldInfo field : globalFields.values()) { + AssignmentInfo assign = field.findAssignmentAtPosition(position); + if (assign != null) { + return assign; + } + } + + // Check external field assignments with same LHS-first priority + for (AssignmentInfo assign : externalFieldAssignments) { + if (assign.containsLhsPosition(position)) { + return assign; + } + } + + for (AssignmentInfo assign : externalFieldAssignments) { + if (assign.containsRhsPosition(position)) { + return assign; + } + } + + return null; + } public Map getGlobalFields() { return Collections.unmodifiableMap(globalFields); } /** - * Get all errored assignments across all fields (global and local). + * Get all errored assignments across all fields (global, local, and external). * Used by ScriptLine to draw error underlines. */ public List getAllErroredAssignments() { @@ -3392,6 +3434,13 @@ public class ScriptDocument { } } + // Check external field assignments + for (AssignmentInfo assign : externalFieldAssignments) { + if (assign.hasError()) { + errored.add(assign); + } + } + return errored; } diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java index 05c3344fe..a55386641 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/hover/TokenHoverInfo.java @@ -212,7 +212,7 @@ public class TokenHoverInfo { /** * Find an assignment that contains this token's position. - * Searches through all FieldInfo's assignments in the document. + * Searches through all assignments (script fields and external fields). */ private AssignmentInfo findAssignmentContainingPosition(Token token) { ScriptLine line = token.getParentLine(); @@ -223,23 +223,8 @@ public class TokenHoverInfo { ScriptDocument doc = line.getParent(); int tokenStart = token.getGlobalStart(); - // Search global fields - for (FieldInfo field : doc.getGlobalFields().values()) { - AssignmentInfo assign = field.findAssignmentAtPosition(tokenStart); - if (assign != null) { - return assign; - } - } - - // Search method locals (need access to method locals map) - // For now, use the getAllErroredAssignments approach and filter by position - for (AssignmentInfo assign : doc.getAllErroredAssignments()) { - if (assign.containsPosition(tokenStart)) { - return assign; - } - } - - return null; + // Use ScriptDocument's method which handles all prioritization + return doc.findAssignmentAtPosition(tokenStart); } /**