Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.RecordDeclaration;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

Expand Down Expand Up @@ -77,7 +80,13 @@ public String apply(String rawUnix) throws Exception {
existingImportsBySimple.put(simple, fqn);
}

// 3. Walk the AST to find outermost fully-qualified type nodes
// 3. Collect type names declared in this file (top-level + nested)
Set<String> declaredTypeNames = new LinkedHashSet<>();
cu.findAll(ClassOrInterfaceDeclaration.class).forEach(c -> declaredTypeNames.add(c.getNameAsString()));
cu.findAll(EnumDeclaration.class).forEach(c -> declaredTypeNames.add(c.getNameAsString()));
cu.findAll(RecordDeclaration.class).forEach(c -> declaredTypeNames.add(c.getNameAsString()));

// 4. Walk the AST to find outermost fully-qualified type nodes
Map<String, Set<String>> simpleToFqns = new LinkedHashMap<>();
List<QualifiedTypeRef> qualifiedRefs = new ArrayList<>();

Expand All @@ -87,7 +96,7 @@ public String apply(String rawUnix) throws Exception {
return rawUnix;
}

// 4. Determine which FQNs are safe to shorten
// 5. Determine which FQNs are safe to shorten
Set<String> safeToShorten = new LinkedHashSet<>();
for (Map.Entry<String, Set<String>> entry : simpleToFqns.entrySet()) {
String simple = entry.getKey();
Expand All @@ -100,14 +109,18 @@ public String apply(String rawUnix) throws Exception {
if (existing != null && !existing.equals(fqn)) {
continue;
}
// Skip if simple name clashes with a type declared in this file
if (declaredTypeNames.contains(simple)) {
continue;
}
safeToShorten.add(fqn);
}

if (safeToShorten.isEmpty()) {
return rawUnix;
}

// 5. Convert line/column positions to string offsets and replace
// 6. Convert line/column positions to string offsets and replace
// Build line-start offset table
int[] lineOffsets = buildLineOffsets(rawUnix);

Expand All @@ -134,7 +147,7 @@ public String apply(String rawUnix) throws Exception {
sb.delete(removal[0], removal[1]);
}

// 6. Add missing imports
// 7. Add missing imports
Set<String> newImports = new TreeSet<>();
for (String fqn : safeToShorten) {
if (fqn.startsWith("java.lang.") && fqn.indexOf('.', 10) == -1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,49 @@ void lambdaParameterTypes() throws Exception {
assertTrue(result.contains("import java.util.List;"), "should import List");
}

@Test
void fqnCollisionWithEnclosingClassName() throws Exception {
// dev.jbang.cli.Alias intentionally uses dev.jbang.catalog.Alias as FQN
// because the simple name "Alias" would clash with the enclosing class
String code = String.join("\n",
"package dev.jbang.cli;",
"",
"public class Alias {",
" dev.jbang.catalog.Alias catalogAlias;",
"}",
"");
assertEquals(code, apply(code));
}

@Test
void fqnCollisionWithInnerClassName() throws Exception {
// FQN whose simple name matches an inner class declared in the same file
String code = String.join("\n",
"package com.example;",
"",
"public class Outer {",
" static class Conflict {}",
" com.other.Conflict externalConflict;",
"}",
"");
assertEquals(code, apply(code));
}

@Test
void fqnNoCollisionWithDifferentSimpleName() throws Exception {
// FQN whose simple name does NOT match the enclosing class β€” should still shorten
String before = String.join("\n",
"package dev.jbang.cli;",
"",
"public class Alias {",
" java.util.List<String> items;",
"}",
"");
String result = apply(before);
assertFalse(codeBody(result).contains("java.util.List"), "non-conflicting FQN should be shortened");
assertTrue(result.contains("import java.util.List;"), "should import List");
}

@Test
void multipleAnnotationsWithFqn() throws Exception {
// FQNs used as annotation types should NOT be treated as type references
Expand Down
Loading