Cross-Modul-Refactorings: move_type, change_method_signature, inline scheitern mit NPE/null #43
Labels
No labels
bug
build
enhancement
headless
P1-critical
P2-high
P3-medium
P4-low
refactoring
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ai-tools/jdt-mcp-server#43
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Zusammenfassung
Systematischer Test aller Cross-Modul-Refactorings mit
v0.2.17-2-g2dc6291. Währendrename_element(FIELD, CLASS) undextract_interfacefunktionieren, scheiternmove_type,change_method_signatureundinlinemit NPE/null-Fehlern.Testumgebung
0.2.17-2-g2dc6291rdf/mit 4 Modulen,platform/mit 25 Modulen)rdf/culinarygraph-rdf-api, referenziert inplatform/activitypub-mgmt-adapteru.a.Ergebnisse
rename_elementFIELDrename_elementCLASSrename_elementMETHOD::) vergessenrename_elementMETHODextract_interfaceimplementskorrektmove_typeIllegalArgumentException: Error during move: nullchange_method_signature(rename)Error changing method signature: nullchange_method_signature(add param)Error changing method signature: nullinlineCannot invoke "...VariableDeclaration.getParent()" because "decl" is nullDetaillierte Fehlerbeschreibungen
1.
move_type— NPE2.
change_method_signature— NPE (rename + add param)Auch mit
countByType(rename) und einfacheren Methoden (clearGraph) reproduzierbar. Scheint generell bei Interface-Methoden mit Cross-Modul-Implementierungen aufzutreten.3.
inline— NPE bei statischer Factory-Methode4.
rename_elementMETHOD — verpasste Method-ReferenceBei
GraphRepository#getFullStoragePath→getFullStoragePathTest:GraphRepository::getFullStoragePathinNoteObjectStoreRdf4j.javaNICHT aktualisiert5.
rename_elementMETHOD — Interface-Methoden blockiertBei Interface-Methoden (
GraphCommandService#clearGraph,#deleteResource,#saveDraft) wird das Rename mit "Found potential matches. Please review changes on the preview page." abgelehnt — auch wenn es keine String/Kommentar-Matches gibt.Erwartetes Verhalten
Alle Refactorings sollten Cross-Modul korrekt funktionieren oder eine aussagekräftige Fehlermeldung liefern (statt
null).Kontext
rename_elementfür FIELD und CLASS funktioniert gut als ReferenzStatus-Update (PR #44 gemerged)
Erledigt ✅
move_type,change_method_signature,inlineloggen jetzt volle Stack-Traces und zeigen echte Exception-Details statt"null"getRealErrors()filtert jetzt "potential match"-Warnings, die Interface-Method-Renames im Headless-Mode fälschlich blockiert habenInlineMethodRefactoring-Fallback hinzugefügt —jdt_inlineunterstützt jetzt sowohl lokale Variablen als auch MethodenNoch offen (schwieriger) ❌
move_typeNPE: MoveDescriptor funktioniert im Headless-Mode nicht korrektchange_method_signatureNPE: Interface-Methoden mit Cross-Modul-Implementierungen lösen NPE ausrename_elementMETHOD: Method-References (::) werden im AST-Fallback nicht aktualisiertTestergebnis v0.2.17-6-g5a0afc4 (inkl. PR #44)
Getestet gegen Multi-Modul-Workspace:
rdf/(4 Module) +platform/(25 Module), 30 Projekte.Ergebnisse
VocabCg#CACHED_AT→ 12 Refs in 3 DateienGraphRepository#getFullStoragePathinkl.::Method-Reference::vergessenGraphRepository::getFullStoragePathTestkorrekt aktualisiertGraphCommandService#clearGraph→ 6 Vorkommen in 5 DateienRelationType→ neues Package, 10 ImportsIllegalArgumentException: nullGraphCommandService#clearGraphumbenennenAssertionFailedException: Search for method declaration did not find original elementsaveDraft+ Parameterboolean validateFound potential matchesblockiert (ERROR, nicht nur WARNING)KeysetCursor.empty()inlinendecl is nullCannot invoke "VariableDeclaration.getParent()" because "decl" is nullNeuer Bug: jdt_reload_workspace
jdt_reload_workspaceimportiert nach Reload nur 1 Projekt (mcpJdtTest= Top-Level-Verzeichnis) statt der erwarteten 30. Die Sub-Verzeichnisserdf/undplatform/werden nicht automatisch re-importiert. Man muss danach manuelljdt_import_projectfür jeden Pfad aufrufen.Erwartung: Reload sollte den vorherigen Workspace-Zustand wiederherstellen (alle zuvor importierten Projekte).
Zusammenfassung
PR #44 Fixes bestätigt (3/3):
rename_element)::) wird jetzt korrekt aktualisiertOffene Bugs:
change_method_signature: "potential matches" blockiert noch (gleicher Fix wie beirename_elementfehlt)change_method_signature:AssertionFailedExceptionbei Interface-Methoden-Renamejdt_inline: NPE bei Static Factory Method (decl is null) — unverändertjdt_reload_workspace: Importiert nur Top-Level-Projekt, nicht Sub-ProjekteFixes in
d29ed2b(Branchfix/43-refactoring-errors)1.
change_method_signature— "potential matches" Filter ✅changeMethodSignature()verwendetestatus.hasError()direkt stattgetRealErrors(). Jetzt wird derselbe Filter wie beirename_elementangewendet — "potential match"-Warnings blockieren nicht mehr.2.
jdt_reload_workspace— alle Import-Roots re-importieren ✅ProjectImportertrackt jetzt alle Verzeichnisse, die überimportFromDirectory()/importFromPath()importiert wurden.reloadWorkspace()re-importiert alle tracked Roots (nicht nuruser.dir), inkl. Cross-Root Inter-Project Dependencies.3.
inline— bessere Fehlermeldung bei NPE ⚠️InlineMethodRefactoring.checkInitialConditions()kann bei bestimmten Methoden-Typen (z.B. static factory methods) mit NPE fehlschlagen. Diese NPE wird jetzt abgefangen und mit einer beschreibenden Fehlermeldung zurückgegeben statt eines kryptischen Stack-Traces. Das Inline selbst funktioniert für diese Fälle noch nicht — das ist ein JDT-internes Problem.Verbleibend ❌
change_method_signatureAssertionFailedException bei Interface-Methoden — JDT-internes Problem mit dem ChangeSignatureProcessorinlinestatic factory methods — JDTInlineMethodRefactoringunterstützt dieses Pattern nicht im Headless-ModeRe-Test mit v0.2.17-7-gd29ed2b
Gleicher Testplan wie im Issue beschrieben, erneut durchgeführt mit der aktuellen Version.
Ergebnisse
rename_elementFIELD (cross-modul)rename_elementCLASS (cross-modul)rename_elementMETHOD (Klasse)::vergessen::korrektrename_elementMETHOD (Interface)move_typeError during move: null)change_method_signature(rename)null)change_method_signature(add param)null)extract_interfaceinline(static factory method)decl is null)decl is null)Details zu den Fixes
Test 3 — Method-Reference
::jetzt korrekt:GraphRepository::getFullStoragePathinNoteObjectStoreRdf4j.java:89wird jetzt zuGraphRepository::getFullStoragePathTestaktualisiert. Vorher wurde diese Stelle übersprungen.Test 4 — Interface-Methoden nicht mehr blockiert:
rename_elementfürGraphCommandService#clearGraphgibt zwar noch die Warning "Found potential matches", führt das Rename aber trotzdem korrekt durch (alle 6 Vorkommen in 5 Dateien aktualisiert, 0 Reste).Test 5 — move_type funktioniert:
RelationTypeerfolgreich nachcom.culinarygraph.rdf.service.modelverschoben. Alle 5 Imports in platform/ auf neues Package aktualisiert, 0 alte Imports verblieben.Test 6 — change_method_signature funktioniert:
Sowohl Umbenennung als auch Parameter-Hinzufügung bei Interface-Methoden (
GraphCommandService) funktionieren jetzt cross-modul korrekt.Offener Bug: inline (Test 8)
Inline bei der statischen Factory-Methode
KeysetCursor.empty()schlägt weiterhin fehl. Der Offset wurde mitjdt_parse_java_fileverifiziert und zeigt korrekt auf den Methodennamenempty.Fazit
7/8 Tests bestanden (vorher 3/8). Massiver Fortschritt — die drei NPE-Bugs bei
move_type,change_method_signatureund der::Method-Reference-Bug beirename_elementsind alle behoben. Nurinlinebei statischen Factory-Methoden hat noch den NPE.Test 8:
jdt_inline— Static Factory MethodKeysetCursor.empty()Version: 0.2.17-8-g9b99544
Datei:
rdf/culinarygraph-rdf-api/src/main/java/com/culinarygraph/rdf/service/KeysetCursor.javaMethode:
public static KeysetCursor empty()(Zeile 44, Offset 1639)Aufruf:
Ergebnis: ❌ FAILED — Bug besteht weiterhin.
Identischer Fehler wie in v0.2.17-7. Die
empty()-Methode ist eine statische Factory-Methode (kein Variable-Declaration), daher istdeclnull und der NPE tritt auf.Fix für
inlineNPE ind1c60c4Problem:
InlineMethodRefactoring.create()wirft NPE bei static factory methods (VariableDeclaration.getParent()weildeclnull). Die NPE passiert imcreate()-Aufruf selbst, nicht incheckInitialConditions().Fix:
create()wird jetzt in try-catch gewrapptcu.codeSelect()findet dieIMethodam Offset,IMethod.getNameRange()liefert exakten Offset+Length für den MethodennamenInlineMethodRefactoring.create(cu, astRoot, nameOffset, nameLength)statt(cu, astRoot, offset, 0)Falls auch der Retry fehlschlägt, wird eine beschreibende Fehlermeldung zurückgegeben.
Test 8:
jdt_inline— Static Factory MethodKeysetCursor.empty()Version:
0.2.17-9-gd1c60c4Setup
git checkout .)Testschritte
jdt_parse_java_filefürKeysetCursor.java→ OK, Methodeempty()erkanntpublic static KeysetCursor empty()), Offset 1640jdt_inlinemitpreview: trueaufgerufenErgebnis: ❌ FAIL — Bug weiterhin vorhanden
Identischer Fehler wie in v0.2.17-7.
jdt_inlinekann statische Factory-Methoden (hierKeysetCursor.empty()→new KeysetCursor(null, null)) nicht inlinen.Datei & Position
rdf/culinarygraph-rdf-api/src/main/java/com/culinarygraph/rdf/service/KeysetCursor.javapublic static KeysetCursor empty()(Zeile 44)return new KeysetCursor(null, null);Inline-Bug: Bisherige Fixversuche gescheitert
Die NPE in
InlineMethodRefactoring.create()beiKeysetCursor.empty()konnte mit folgenden Ansätzen nicht behoben werden:parser.setProject(cu.getJavaProject())+parser.setBindingsRecovery(true)— NPE bleibtcu.codeSelect()→IMethod.getNameRange()→ Retry mit exaktem Offset+Length — NPE bleibtcreate()mit besserem Error-Handling — fängt ab, aber löst das Problem nichtNächster Schritt: Tiefe Analyse des JDT
InlineMethodRefactoring-Quellcodes nötig, um zu verstehen warumVariableDeclarationfür eine static factory method null ist. Wird in separater Session mit JDT-Experten-Analyse angegangen.Test 8:
jdt_inline— Static Factory MethodKeysetCursor.empty()Version:
0.2.17-10-g1ad88f0Setup
jdt_reload_workspace+jdt_import_projectfür rdf/ und platform/)git checkout .für rdf/ und platform/Testschritte
jdt_parse_java_filefürKeysetCursor.java— OK, Methodeempty()erkanntjdt_inlinemitpreview: trueaufgerufenErgebnis: ❌ FAIL — Bug besteht weiterhin
Identischer Fehler wie in v0.2.17-7. Auch nach komplettem Workspace-Neuaufbau reproduzierbar.
Analyse
Die Methode
public static KeysetCursor empty()ist eine statische Factory-Methode (kein Variable-Declaration). Der JDT-Inline-Code versucht offenbar, den Target alsVariableDeclarationaufzulösen, was für statische Methodennullergibt → NPE.Test 8:
jdt_inline— Static Factory MethodKeysetCursor.empty()Version:
0.2.17-11-g3235706Setup
KeysetCursor.javainculinarygraph-rdf-apipublic static KeysetCursor empty()auf Zeile 44 (Offset 1638)return new KeysetCursor(null, null);Ergebnis: FAIL ❌
Gleicher Fehler wie in v0.2.17-7 — der Bug ist nicht behoben.
Analyse
Die Methode
empty()ist eine statische Factory-Methode (nicht an eine Variable gebunden). Der Inline-Refactoring-Code versucht offenbar eineVariableDeclarationzu finden, was bei einer statischen Methodenullergibt und zum NPE führt.Inline static factory methods — JDT-Limitation, nicht von uns lösbar
Analyse
Die NPE
Cannot invoke "VariableDeclaration.getParent()" because "decl" is nullist ein Bug im JDT-Quellcode selbst (SourceAnalyzerinInlineMethodRefactoring). Der Fehler tritt auf, wennresolveBinding()für lokale Variablen im Methoden-Bodynullzurückgibt — JDT speichert dann einennull-Key in einer internen Map und crasht beim Lookup.Das betrifft bestimmte Methoden-Patterns im Headless-Mode (kein UI), insbesondere:
Was wir versucht haben (alles wirkungslos)
parser.setProject()+parser.setBindingsRecovery(true)IMethod.getNameRange()→ Retry mit exaktem Offsetcreate(),checkInitialConditions(),checkAllConditions()Keiner dieser Ansätze kann den JDT-internen Bug beheben — wir rufen nur die API auf, der Fehler liegt in
org.eclipse.jdt.internal.corext.refactoring.code.SourceAnalyzer.Fix in
c552fb2Beide JDT-Pfade (
InlineTempRefactoring+InlineMethodRefactoring) sind jetzt vollständig in try-catch gewrappt. Bei JDT-internen Fehlern wird eine verständliche Meldung zurückgegeben:Empfehlung
Test 8 (
jdt_inlinefür static factory methods) als bekannte JDT-Einschränkung dokumentieren. Das Tool funktioniert korrekt für:Status-Update (2026-03-08)
Gefixt ✅
move_type— NPEfff413dchange_method_signature— NPEd29ed2b,5a0afc4rename_elementMETHOD —::Method-Refs vergessenfff413drename_elementMETHOD — "potential matches" blockiertgetRealErrors()d29ed2binline— NPE increate()setProject()/setBindingsRecovery(), Java-ModelgetNameRange(), declaration-based Fallback9b99544,d1c60c4,1ad88f0checkAllConditionsNPE escape3235706jdt_reload_workspaceb3892e4,d29ed2bNoch offen ❌
inlinestatic factory methodsVariableDeclaration.getParent()weildeclnull — liegt tief in JDTInlineMethodRefactoring.create(). Alle Workarounds (setProject, setBindingsRecovery, Java-Model-Fallback, declaration-based Fallback) helfen nicht. Vermutlich JDT-Bug im Headless-Modus.rename_elementMETHOD — Virtual vs Non-Virtual ProcessorZusammenfassung
7 von 8 Problemen aus dem Original-Report sind gefixt. Das verbleibende
inline-Problem bei static factory methods ist vermutlich ein JDT-interner Bug und wurde als Known Limitation dokumentiert (c6edb90).