Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support duplicate static star imports for Groovy #4982

Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import java.util.regex.Pattern;
import java.util.stream.Stream;

import static java.lang.Character.isJavaIdentifierPart;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
Expand Down Expand Up @@ -159,8 +160,51 @@ public G.CompilationUnit visit(SourceUnit unit, ModuleNode ast) throws GroovyPar
for (ImportNode anImport : ast.getStaticImports().values()) {
sortedByPosition.computeIfAbsent(pos(anImport), i -> new ArrayList<>()).add(anImport);
}
for (ImportNode anImport : ast.getStaticStarImports().values()) {
sortedByPosition.computeIfAbsent(pos(anImport), i -> new ArrayList<>()).add(anImport);

// Duplicate imports do work out of the box for import, star-import and static-import.
jevanlingen marked this conversation as resolved.
Show resolved Hide resolved
// For static-star-import, this does work though.
// The groovy compiler does only save the last duplicate import instead of all, so parse all static star imports by hand.
Map<String, ImportNode> staticStarImports = ast.getStaticStarImports();
if (!staticStarImports.isEmpty()) {
// Take source code until last static star import for performance reasons
int lastLineNumber = -1;
for (ImportNode anImport : ast.getStaticStarImports().values()) {
lastLineNumber = Math.max(lastLineNumber, anImport.getLastLineNumber());
}
String importSource = sourceLineNumberOffsets.length <= lastLineNumber ? source : source.substring(0, sourceLineNumberOffsets[lastLineNumber]);
jevanlingen marked this conversation as resolved.
Show resolved Hide resolved

// Create a node for each `import static`
String[] lines = importSource.split("\n");
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
int index = 0;

while (index < line.length()) {
int importIndex = line.indexOf("import", index);
if (importIndex == -1) break;

int maybeStaticIndex = indexOfNextNonWhitespace(importIndex + 6, line);
jevanlingen marked this conversation as resolved.
Show resolved Hide resolved
if (!line.startsWith("static", maybeStaticIndex)) {
index = importIndex + 6;
continue;
}

int packageBegin = indexOfNextNonWhitespace( maybeStaticIndex + 6, line);
int packageEnd = packageBegin;
while (packageEnd < line.length() && (isJavaIdentifierPart(line.charAt(packageEnd)) || line.charAt(packageEnd) == '.')) {
packageEnd++;
}

if (packageEnd < line.length() && line.charAt(packageEnd) == '*') {
ImportNode node = new ImportNode(staticStarImports.get(line.substring(packageBegin, packageEnd - 1)).getType());
node.setLineNumber(i + 1);
node.setColumnNumber(importIndex + 1);
sortedByPosition.computeIfAbsent(pos(node), ii -> new ArrayList<>()).add(node);
}

index = packageEnd;
}
}
}

for (ClassNode aClass : ast.getClasses()) {
Expand Down Expand Up @@ -2672,7 +2716,7 @@ private String name() {
for (; i < source.length(); i++) {
char c = source.charAt(i);
boolean isVarargs = source.length() > (i + 2) && c == '.' && source.charAt(i + 1) == '.' && source.charAt(i + 2) == '.';
if (!(Character.isJavaIdentifierPart(c) || c == '.' || c == '*') || isVarargs) {
if (!(isJavaIdentifierPart(c) || c == '.' || c == '*') || isVarargs) {
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ void classImport() {
);
}

@Test
void multipleImportsOnOneLine() {
rewriteRun(
groovy(
"""
import java.util.List;import java.util.Set
"""
)
);
}

@Test
void starImport() {
rewriteRun(
Expand Down Expand Up @@ -90,4 +101,21 @@ void staticImportAlias() {
)
);
}

@Test
void duplicateImports() {
rewriteRun(
groovy(
"""
import static java.util.Collections.* ; import static java.util.Collections.*
jevanlingen marked this conversation as resolved.
Show resolved Hide resolved
import java.util.Collections.* ; import static java.util.Collections.*
import java.util.Collections.*
import static java.util.Collections.singletonList as listOf
import static java.util.Collections.singletonList as listOf
import static java.util.Collections.singletonList;import static java.util.Collections.*
import java.util.Collections.*
"""
)
);
}
}