(WIP) Properly handled merging Object.d.ts members into current java.lang.Object handling in type resolution & autocomplete

This commit is contained in:
bigguy345 committed 2026-03-06 20:25:12 +02:00
1 parent ef499fd7bd
commit 98885faaa2
4 files changed
+132 -87

No files matched your search

@@ -3,6 +3,7 @@ package noppes.npcs.client.gui.util.script.autocomplete;
import noppes.npcs.client.gui.util.script.interpreter.field.FieldInfo;
import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSFieldInfo;
import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSMethodInfo;
import noppes.npcs.client.gui.util.script.interpreter.js_parser.JSTypeInfo;
import noppes.npcs.client.gui.util.script.interpreter.method.MethodInfo;
import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo;
import noppes.npcs.client.gui.util.script.interpreter.type.synthetic.SyntheticField;
@@ -655,41 +656,32 @@ public class AutocompleteItem implements Comparable<AutocompleteItem> {
* These methods should be deprioritized in autocomplete.
*/
public boolean isInheritedObjectMethod() {
if (kind != Kind.METHOD || !(sourceData instanceof MethodInfo)) {
return false;
}
MethodInfo methodInfo = (MethodInfo) sourceData;
// For Java reflection methods, check the declaring class
if (methodInfo.getJavaMethod() != null) {
if (kind != Kind.METHOD) return false;
if (sourceData instanceof MethodInfo) {
MethodInfo methodInfo = (MethodInfo) sourceData;
java.lang.reflect.Method javaMethod = methodInfo.getJavaMethod();
Class<?> declaringClass = javaMethod.getDeclaringClass();
// If the method is declared in Object, it's an inherited Object method
// unless the containing type is Object itself
if (declaringClass.getName().equals("java.lang.Object")) {
if (javaMethod != null) {
if (!Object.class.equals(javaMethod.getDeclaringClass())) return false;
TypeInfo containingType = methodInfo.getContainingType();
// If we're showing methods for Object itself, don't treat them as "inherited"
return containingType != null && !containingType.getFullName().equals("java.lang.Object");
return containingType == null || !containingType.getFullName().equals("java.lang.Object");
}
} else {
// For script-defined methods, use the original logic
TypeInfo containingType = methodInfo.getContainingType();
// Check if declaring class is Object
if (containingType != null && containingType.getFullName().equals("java.lang.Object")) {
return true;
}
// Check if method overrides from Object (meaning it's overridden, so NOT inherited)
if (methodInfo.isOverride()) {
TypeInfo overridesFrom = methodInfo.getOverridesFrom();
// If it overrides from Object, it means this class overrode it, so it's NOT just inherited
return false;
}
return containingType != null
&& containingType.getFullName().equals("java.lang.Object")
&& !methodInfo.isStatic()
&& !methodInfo.isOverride();
}
if (sourceData instanceof JSMethodInfo) {
JSMethodInfo jsMethod = (JSMethodInfo) sourceData;
JSTypeInfo definingType = jsMethod.getContainingType();
return definingType != null
&& "Object".equals(definingType.getSimpleName())
&& !jsMethod.isStatic()
&& inheritanceDepth > 0;
}
return false;
}
@@ -8,6 +8,9 @@ import noppes.npcs.client.gui.util.script.interpreter.type.TypeChecker;
import noppes.npcs.client.gui.util.script.interpreter.type.TypeInfo;
import noppes.npcs.config.ConfigScript;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
/**
@@ -55,17 +58,51 @@ public class JSAutocompleteProvider extends JavaAutocompleteProvider {
return;
}
// If this is a Java type (has a Java class), delegate to parent's Java handling
// This preserves static/instance context, modifiers, and all Java-specific behavior
boolean isStaticContext = isStaticAccess(receiverExpr, getMemberAccessResolvePosition(context));
Class<?> javaClass = receiverType.getJavaClass();
if (javaClass != null) {
super.addMemberSuggestions(context, items);
Set<String> addedMethods = new HashSet<>();
for (Method method : javaClass.getMethods()) {
if (!Modifier.isPublic(method.getModifiers())) continue;
if (isStaticContext && !Modifier.isStatic(method.getModifiers())) continue;
String sig = method.getName() + "(" + method.getParameterCount() + ")";
if (addedMethods.add(sig)) {
items.add(AutocompleteItem.fromMethod(MethodInfo.fromReflection(method, receiverType), context.methodsOnly));
}
}
if (!receiverType.syntheticMethods.isEmpty()) {
for (MethodInfo method : receiverType.syntheticMethods) {
if (isStaticContext && !method.isStatic()) continue;
items.add(AutocompleteItem.fromMethod(method, context.methodsOnly));
}
} else {
JSTypeInfo jsType = getMergeRegistryType(javaClass);
if (jsType != null) {
addMethodsFromType(jsType, receiverType, items, new HashSet<>(), context.methodsOnly, isStaticContext);
}
}
if (!context.methodsOnly) {
for (Field field : javaClass.getFields()) {
if (!Modifier.isPublic(field.getModifiers())) continue;
if (isStaticContext && !Modifier.isStatic(field.getModifiers())) continue;
items.add(AutocompleteItem.fromField(FieldInfo.fromReflection(field, receiverType)));
}
if (!receiverType.syntheticFields.isEmpty()) {
for (FieldInfo field : receiverType.syntheticFields) {
if (isStaticContext && !field.isStatic()) continue;
items.add(AutocompleteItem.fromField(field));
}
} else {
JSTypeInfo jsType = getMergeRegistryType(javaClass);
if (jsType != null) {
addFieldsFromType(jsType, receiverType, items, new HashSet<>(), isStaticContext);
}
}
}
return;
}
boolean isStaticContext = isStaticAccess(receiverExpr, getMemberAccessResolvePosition(context));
// Add synthetic members (e.g., array built-ins: length, clone)
for (FieldInfo field : receiverType.syntheticFields) {
if (!context.methodsOnly) {
if (isStaticContext && !field.isStatic()) continue;
@@ -77,16 +114,28 @@ public class JSAutocompleteProvider extends JavaAutocompleteProvider {
items.add(AutocompleteItem.fromMethod(method, context.methodsOnly));
}
// For pure JS types, check JSTypeRegistry
JSTypeInfo jsTypeInfo = receiverType.getJSTypeInfo();
if (jsTypeInfo != null) {
// Pass both: jsTypeInfo (current type in hierarchy) and receiverType (context for type params)
addMethodsFromType(jsTypeInfo, receiverType, items, new HashSet<>(), context.methodsOnly, isStaticContext);
if (!context.methodsOnly && ConfigScript.ShowImplementationFieldsInAutocomplete) {
addFieldsFromType(jsTypeInfo, receiverType, items, new HashSet<>(), isStaticContext);
}
if (!isStaticContext) {
JSTypeInfo objJSType = registry.getType("Object");
if (objJSType != null) {
for (JSMethodInfo m : objJSType.getMethods().values()) {
if (!m.isStatic()) {
items.add(AutocompleteItem.fromJSMethod(m, receiverType, 1, context.methodsOnly));
}
}
}
}
}
}
private JSTypeInfo getMergeRegistryType(Class<?> javaClass) {
return document.getTypeResolver().findJSTypeForJavaClass(javaClass);
}
/**
* Add autocomplete suggestions for a synthetic type's methods and fields.
@@ -571,19 +571,19 @@ public class TypeInfo {
for (MethodInfo m : syntheticMethods) if (m.getName().equals(methodName)) return true;
// Check JS type first
if (jsTypeInfo != null) {
return jsTypeInfo.hasMethod(methodName);
if (jsTypeInfo.hasMethod(methodName)) return true;
} else if (javaClass != null) {
try {
for (java.lang.reflect.Method m : javaClass.getMethods()) {
if (m.getName().equals(methodName)) return true;
}
} catch (Exception e) {
// Security or linkage error
}
}
if (javaClass == null) return false;
try {
for (java.lang.reflect.Method m : javaClass.getMethods()) {
if (m.getName().equals(methodName)) {
return true;
}
}
} catch (Exception e) {
// Security or linkage error
}
TypeInfo obj = TypeInfo.object();
if (obj != this) return obj.hasMethod(methodName);
return false;
}
@@ -596,23 +596,19 @@ public class TypeInfo {
if (jsTypeInfo != null) {
List<JSMethodInfo> overloads = jsTypeInfo.getMethodOverloads(methodName);
for (JSMethodInfo m : overloads) {
if (m.getParameterCount() == paramCount) {
return true;
}
if (m.getParameterCount() == paramCount) return true;
}
return false;
}
if (javaClass == null) return false;
try {
for (java.lang.reflect.Method m : javaClass.getMethods()) {
if (m.getName().equals(methodName) && m.getParameterCount() == paramCount) {
return true;
} else if (javaClass != null) {
try {
for (java.lang.reflect.Method m : javaClass.getMethods()) {
if (m.getName().equals(methodName) && m.getParameterCount() == paramCount) return true;
}
} catch (Exception e) {
// Security or linkage error
}
} catch (Exception e) {
// Security or linkage error
}
TypeInfo obj = TypeInfo.object();
if (obj != this) return obj.hasMethod(methodName);
return false;
}
@@ -756,26 +752,20 @@ public class TypeInfo {
*/
public MethodInfo getMethodInfo(String methodName) {
for (MethodInfo m : syntheticMethods) if (m.getName().equals(methodName)) return m;
// Check JS type first
if (jsTypeInfo != null) {
JSMethodInfo jsMethod = jsTypeInfo.getMethod(methodName);
if (jsMethod != null) {
return MethodInfo.fromJSMethod(jsMethod, this);
}
return null;
}
if (javaClass == null) return null;
try {
for (java.lang.reflect.Method m : javaClass.getMethods()) {
if (m.getName().equals(methodName)) {
// Create a synthetic MethodInfo from reflection
return MethodInfo.fromReflection(m, this);
if (jsMethod != null) return MethodInfo.fromJSMethod(jsMethod, this);
} else if (javaClass != null) {
try {
for (java.lang.reflect.Method m : javaClass.getMethods()) {
if (m.getName().equals(methodName)) return MethodInfo.fromReflection(m, this);
}
} catch (Exception e) {
// Security or linkage error
}
} catch (Exception e) {
// Security or linkage error
}
TypeInfo obj = TypeInfo.object();
if (obj != this) return obj.getMethodInfo(methodName);
return null;
}
@@ -785,6 +775,9 @@ public class TypeInfo {
*/
public java.util.List<MethodInfo> getAllMethodOverloads(String methodName) {
java.util.List<MethodInfo> overloads = new java.util.ArrayList<>();
for (MethodInfo m : syntheticMethods) if (m.getName().equals(methodName)) overloads.add(m);
if (!overloads.isEmpty()) return overloads;
// Check JS type first
if (jsTypeInfo != null) {
@@ -792,19 +785,21 @@ public class TypeInfo {
// Type parameter resolution now happens inside fromJSMethod using this TypeInfo
overloads.add(MethodInfo.fromJSMethod(jsMethod, this));
}
return overloads;
}
if (javaClass == null) return overloads;
try {
for (java.lang.reflect.Method m : javaClass.getMethods()) {
if (m.getName().equals(methodName)) {
overloads.add(MethodInfo.fromReflection(m, this));
if (!overloads.isEmpty()) return overloads;
} else if (javaClass != null) {
try {
for (java.lang.reflect.Method m : javaClass.getMethods()) {
if (m.getName().equals(methodName)) {
overloads.add(MethodInfo.fromReflection(m, this));
}
}
} catch (Exception e) {
// Security or linkage error
}
} catch (Exception e) {
// Security or linkage error
if (!overloads.isEmpty()) return overloads;
}
TypeInfo obj = TypeInfo.object();
if (obj != this) return obj.getAllMethodOverloads(methodName);
return overloads;
}
@@ -466,6 +466,15 @@ public class TypeResolver {
}
}
public JSTypeInfo findJSTypeForJavaClass(Class<?> javaClass) {
if (javaClass == null) return null;
String simpleName = javaClass.getSimpleName();
if (getJSJavaMergeBase(simpleName) != null) {
return getJSTypeRegistry().getType(simpleName);
}
return getJSTypeRegistry().getTypeByJavaFqn(javaClass.getName());
}
/**
* For certain core types (e.g., String, Object), we want to merge JS type info from .d.ts with the Java TypeInfo to create an enriched type that has both Java and JS members.
*/