fix: do not crash on qualified generic types with unresolved arguments in noclasspath mode#6786
Conversation
…s in noclasspath mode
|
@mvanhorn looks good, can u fix the small qodana issue? |
The earlier packageNames.length == off branch already returns for the equal-length case, so once execution reaches this point packageNames != null implies the lengths differ and the packageNames.length != off condition is always true.
|
Done — 42b8c39 drops the redundant |
| //keep it explicit | ||
| return; | ||
| } | ||
| if (packageNames != null) { |
There was a problem hiding this comment.
Is this code only run in no classpath mode?
The previous guard returned early for any non-null packageNames when lengths didn't match, which would have suppressed legitimate errors in full-classpath mode. The structural signature of the no-classpath bug is specifically that JDT folds the declaring type into the package binding's compound name, making packageNames.length *greater than* off. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@mvanhorn I pushed 290b0d8 to your branch to narrow the guard to |
|
Thanks @monperrus — yes, that matches exactly what I observed. In the no-classpath case JDT folds the declaring type into the package compound name, so it ends up longer than the remaining token offset; |
Summary
Building a model in no-classpath mode no longer throws
SpoonException: Unexpected QualifiedNameReference tokenswhen source code uses a qualified nested generic type whose type arguments cannot be resolved (for examplejava.util.AbstractMap.SimpleEntry<A, B>whereAandBcome from a missing dependency).handleImplicitinsrc/main/java/spoon/support/compiler/jdt/JDTTreeBuilderHelper.javanow keeps the package reference explicit and returns when the package tokens cannot be aligned with the JDT binding, instead of falling through to the throw.Why this matters
No-classpath mode exists precisely for analyzing code whose dependencies are absent, and this crash aborts the whole model build on a single unresolvable reference. The root cause is that JDT, lacking the type arguments, treats the declaring type as part of the package, so the Spoon-side package reference and the JDT package binding token arrays disagree in length. That mismatch is expected in this mode and not an internal error, which is what the remaining throw treated it as.
Testing
Added
testQualifiedGenericTypeWithIncompleteClasspathtosrc/test/java/spoon/test/api/NoClasspathTest.javausing the@ModelTestharness with unresolvable imports. It asserts the model builds, the local variable's type resolves tojava.util.AbstractMap$SimpleEntry, and the constructor call keeps its source-form declaring type. The fullNoClasspathTestclass passes (7 tests) with the change.Fixes #4077