Skip to content

Commit 24938cf

Browse files
Expand star imports in ChangePackage and related recipes when they would create ambiguity (#7202)
1 parent 5992f12 commit 24938cf

20 files changed

Lines changed: 1582 additions & 35 deletions

File tree

rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependency.java

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,15 @@
3030
import org.openrewrite.java.search.UsesType;
3131
import org.openrewrite.java.tree.J;
3232
import org.openrewrite.java.tree.JavaSourceFile;
33+
import org.openrewrite.marker.Markup;
34+
import org.openrewrite.maven.MavenDownloadingException;
35+
import org.openrewrite.maven.MavenExecutionContextView;
36+
import org.openrewrite.maven.internal.MavenPomDownloader;
3337
import org.openrewrite.maven.table.MavenMetadataFailures;
34-
import org.openrewrite.maven.tree.GroupArtifact;
38+
import org.openrewrite.maven.tree.*;
39+
import org.openrewrite.maven.utilities.JavaSourceSetUpdater;
3540
import org.openrewrite.semver.Semver;
41+
import org.openrewrite.semver.VersionComparator;
3642

3743
import java.util.*;
3844

@@ -138,6 +144,11 @@ public Validated<Object> validate() {
138144
public static class Scanned {
139145
Map<JavaProject, Boolean> usingType = new HashMap<>();
140146
Map<JavaProject, Set<String>> configurationsByProject = new HashMap<>();
147+
@Nullable
148+
String resolvedVersion;
149+
List<MavenRepository> repositories = new ArrayList<>();
150+
@Nullable
151+
Exception versionResolutionFailure;
141152
}
142153

143154
@Override
@@ -176,7 +187,9 @@ private boolean usesType(SourceFile sourceFile, ExecutionContext ctx) {
176187
sourceFile == hasTestSourceSet.visit(sourceFile, ctx)) {
177188
return tree;
178189
}
179-
sourceFile.getMarkers().findFirst(JavaProject.class).ifPresent(javaProject -> {
190+
Optional<JavaProject> maybeJavaProject = sourceFile.getMarkers().findFirst(JavaProject.class);
191+
if (maybeJavaProject.isPresent()) {
192+
JavaProject javaProject = maybeJavaProject.get();
180193
boolean uses = usesType(sourceFile, ctx);
181194
acc.usingType.compute(javaProject, (jp, usingType) -> Boolean.TRUE.equals(usingType) || uses);
182195

@@ -185,7 +198,25 @@ private boolean usesType(SourceFile sourceFile, ExecutionContext ctx) {
185198
sourceFile.getMarkers().findFirst(JavaSourceSet.class).ifPresent(sourceSet ->
186199
configurations.add("main".equals(sourceSet.getName()) ? "implementation" : sourceSet.getName() + "Implementation"));
187200
}
188-
});
201+
202+
// Resolve version once for JavaSourceSet updates
203+
if (acc.resolvedVersion == null && version != null) {
204+
Optional<GradleProject> maybeGp = sourceFile.getMarkers().findFirst(GradleProject.class);
205+
if (maybeGp.isPresent()) {
206+
try {
207+
DependencyVersionSelector selector = new DependencyVersionSelector(metadataFailures, maybeGp.get(), null);
208+
acc.resolvedVersion = selector.select(
209+
new GroupArtifact(groupId, artifactId), "implementation",
210+
version, versionPattern, ctx);
211+
if (acc.resolvedVersion != null) {
212+
acc.repositories = maybeGp.get().getMavenRepositories();
213+
}
214+
} catch (MavenDownloadingException e) {
215+
acc.versionResolutionFailure = e;
216+
}
217+
}
218+
}
219+
}
189220
return tree;
190221
}
191222
};
@@ -196,7 +227,7 @@ public TreeVisitor<?, ExecutionContext> getVisitor(Scanned acc) {
196227
// Allow when configuration is explicitly provided, when onlyIfUsing is not set (default to "implementation"),
197228
// or when source files were scanned
198229
boolean hasExplicitConfiguration = !StringUtils.isBlank(configuration);
199-
return Preconditions.check(hasExplicitConfiguration || onlyIfUsing == null || !acc.configurationsByProject.isEmpty(),
230+
TreeVisitor<?, ExecutionContext> gradleVisitor = Preconditions.check(hasExplicitConfiguration || onlyIfUsing == null || !acc.configurationsByProject.isEmpty(),
200231
Preconditions.check(new IsBuildGradle<>(true), new JavaIsoVisitor<ExecutionContext>() {
201232

202233
@Override
@@ -280,5 +311,65 @@ private boolean isTopLevel(Cursor cursor) {
280311
}
281312
})
282313
);
314+
315+
if (acc.configurationsByProject.isEmpty() || acc.resolvedVersion == null) {
316+
if (acc.versionResolutionFailure != null) {
317+
Exception failure = acc.versionResolutionFailure;
318+
return new TreeVisitor<Tree, ExecutionContext>() {
319+
@Override
320+
public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) {
321+
return gradleVisitor.isAcceptable(sourceFile, ctx);
322+
}
323+
324+
@Override
325+
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
326+
Tree result = gradleVisitor.visit(tree, ctx);
327+
if (result != tree) {
328+
result = Markup.warn(result, failure);
329+
}
330+
return result;
331+
}
332+
};
333+
}
334+
return gradleVisitor;
335+
}
336+
337+
return new TreeVisitor<Tree, ExecutionContext>() {
338+
@Nullable
339+
private JavaSourceSetUpdater updater;
340+
341+
@Override
342+
public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) {
343+
return gradleVisitor.isAcceptable(sourceFile, ctx) || sourceFile instanceof JavaSourceFile;
344+
}
345+
346+
@Override
347+
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
348+
if (!(tree instanceof SourceFile)) {
349+
return tree;
350+
}
351+
SourceFile sf = (SourceFile) tree;
352+
if (gradleVisitor.isAcceptable(sf, ctx)) {
353+
return gradleVisitor.visit(tree, ctx);
354+
}
355+
if (sf instanceof JavaSourceFile) {
356+
return updateJavaSourceSet(sf, ctx);
357+
}
358+
return tree;
359+
}
360+
361+
private SourceFile updateJavaSourceSet(SourceFile sf, ExecutionContext ctx) {
362+
Optional<JavaProject> maybeJp = sf.getMarkers().findFirst(JavaProject.class);
363+
if (!maybeJp.isPresent() || !acc.configurationsByProject.containsKey(maybeJp.get())) {
364+
return sf;
365+
}
366+
if (updater == null) {
367+
updater = new JavaSourceSetUpdater(ctx);
368+
}
369+
return JavaSourceSet.updateOnSourceFile(sf, sourceSet ->
370+
sourceSet.getGavToTypes().isEmpty() ? sourceSet :
371+
updater.addDependency(sourceSet, groupId, artifactId, acc.resolvedVersion, acc.repositories));
372+
}
373+
};
283374
}
284375
}

rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependency.java

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,16 @@
3030
import org.openrewrite.internal.StringUtils;
3131
import org.openrewrite.java.JavaIsoVisitor;
3232
import org.openrewrite.java.JavaVisitor;
33+
import org.openrewrite.java.marker.JavaProject;
34+
import org.openrewrite.java.marker.JavaSourceSet;
3335
import org.openrewrite.java.tree.J;
3436
import org.openrewrite.java.tree.JavaSourceFile;
3537
import org.openrewrite.kotlin.tree.K;
3638
import org.openrewrite.marker.Markup;
3739
import org.openrewrite.maven.MavenDownloadingException;
3840
import org.openrewrite.maven.tree.*;
3941
import org.openrewrite.maven.table.MavenMetadataFailures;
42+
import org.openrewrite.maven.utilities.JavaSourceSetUpdater;
4043
import org.openrewrite.properties.PropertiesVisitor;
4144
import org.openrewrite.properties.tree.Properties;
4245
import org.openrewrite.semver.DependencyMatcher;
@@ -171,6 +174,8 @@ public static class Accumulator {
171174
Map<String, Object> versionVariableUpdates = new HashMap<>();
172175
Map<String, Set<GroupArtifact>> versionVariableUsages = new HashMap<>();
173176
Set<GroupArtifact> failedResolutions = new HashSet<>();
177+
Map<JavaProject, ResolvedDependency> modulesWithOldDependency = new HashMap<>();
178+
Map<JavaProject, List<MavenRepository>> moduleRepositories = new HashMap<>();
174179
}
175180

176181
@Override
@@ -197,6 +202,21 @@ public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) {
197202
if (gradleProject == null) {
198203
return (J) tree;
199204
}
205+
// Record this module if it has the old dependency
206+
Optional<JavaProject> maybeJp = tree.getMarkers().findFirst(JavaProject.class);
207+
if (maybeJp.isPresent() && !acc.modulesWithOldDependency.containsKey(maybeJp.get())) {
208+
outer:
209+
for (GradleDependencyConfiguration config : gradleProject.getConfigurations()) {
210+
for (ResolvedDependency resolved : config.getDirectResolved()) {
211+
if (StringUtils.matchesGlob(resolved.getGroupId(), oldGroupId) &&
212+
StringUtils.matchesGlob(resolved.getArtifactId(), oldArtifactId)) {
213+
acc.modulesWithOldDependency.put(maybeJp.get(), resolved);
214+
acc.moduleRepositories.put(maybeJp.get(), gradleProject.getMavenRepositories());
215+
break outer;
216+
}
217+
}
218+
}
219+
}
200220
}
201221
return super.visit(tree, ctx);
202222
}
@@ -480,14 +500,23 @@ private GradleProject updateGradleModel(GradleProject gp, ExecutionContext ctx)
480500
});
481501

482502
DependencyMatcher propsMatcher = requireNonNull(DependencyMatcher.build(oldGroupId + ":" + oldArtifactId).getValue());
503+
boolean hasModulesWithOldDep = !acc.modulesWithOldDependency.isEmpty();
483504
return new TreeVisitor<Tree, ExecutionContext>() {
505+
@Nullable
506+
private JavaSourceSetUpdater updater;
507+
private final Map<String, JavaSourceSet> updatedSourceSets = new HashMap<>();
508+
484509
@Override
485510
public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) {
486511
if (sourceFile instanceof Properties.File) {
487512
return sourceFile.getSourcePath().endsWith(GRADLE_PROPERTIES_FILE_NAME);
488513
}
489-
return (sourceFile instanceof G.CompilationUnit || sourceFile instanceof K.CompilationUnit)
490-
&& sourceFile.getMarkers().findFirst(GradleProject.class).isPresent();
514+
if ((sourceFile instanceof G.CompilationUnit || sourceFile instanceof K.CompilationUnit)
515+
&& sourceFile.getMarkers().findFirst(GradleProject.class).isPresent()) {
516+
return true;
517+
}
518+
// Accept Java source files for JavaSourceSet updates
519+
return hasModulesWithOldDep && sourceFile instanceof JavaSourceFile;
491520
}
492521

493522
@Override
@@ -517,8 +546,51 @@ public Properties visitEntry(Properties.Entry entry, ExecutionContext ctx) {
517546
}
518547
return tree;
519548
}
549+
// For Java source files, update JavaSourceSet marker
550+
if (hasModulesWithOldDep && tree instanceof JavaSourceFile) {
551+
return updateJavaSourceSet((SourceFile) tree, ctx);
552+
}
520553
return gradleVisitor.visit(tree, ctx);
521554
}
555+
556+
private SourceFile updateJavaSourceSet(SourceFile sf, ExecutionContext ctx) {
557+
Optional<JavaProject> maybeJp = sf.getMarkers().findFirst(JavaProject.class);
558+
if (!maybeJp.isPresent()) {
559+
return sf;
560+
}
561+
ResolvedDependency oldDep = acc.modulesWithOldDependency.get(maybeJp.get());
562+
if (oldDep == null) {
563+
return sf;
564+
}
565+
if (updater == null) {
566+
updater = new JavaSourceSetUpdater(ctx);
567+
}
568+
JavaProject jp = maybeJp.get();
569+
return JavaSourceSet.updateOnSourceFile(sf, updatedSourceSets, sourceSet -> {
570+
String effectiveNewGroupId = newGroupId != null ? newGroupId : oldDep.getGroupId();
571+
String effectiveNewArtifactId = newArtifactId != null ? newArtifactId : oldDep.getArtifactId();
572+
ResolvedGroupArtifactVersion newGav = new ResolvedGroupArtifactVersion(
573+
oldDep.getGav().getRepository(),
574+
effectiveNewGroupId, effectiveNewArtifactId, oldDep.getVersion(), null);
575+
ResolvedDependency newDep = oldDep
576+
.withGav(newGav)
577+
.withRepository(findRemoteRepository(jp));
578+
return updater.changeDependency(sourceSet, oldDep, newDep);
579+
});
580+
}
581+
582+
private MavenRepository findRemoteRepository(JavaProject jp) {
583+
List<MavenRepository> repos = acc.moduleRepositories.get(jp);
584+
if (repos != null) {
585+
for (MavenRepository repo : repos) {
586+
String uri = repo.getUri();
587+
if (uri != null && (uri.startsWith("http://") || uri.startsWith("https://"))) {
588+
return repo;
589+
}
590+
}
591+
}
592+
return MavenRepository.MAVEN_CENTRAL;
593+
}
522594
};
523595
}
524596

rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveDependency.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.openrewrite.internal.ListUtils;
2727
import org.openrewrite.internal.StringUtils;
2828
import org.openrewrite.java.JavaIsoVisitor;
29+
import org.openrewrite.java.marker.JavaSourceSet;
2930
import org.openrewrite.java.tree.J;
3031
import org.openrewrite.java.tree.JavaSourceFile;
3132
import org.openrewrite.kotlin.tree.K;
@@ -69,7 +70,7 @@ public String getInstanceNameSuffix() {
6970

7071
@Override
7172
public TreeVisitor<?, ExecutionContext> getVisitor() {
72-
return Preconditions.check(new IsBuildGradle<>(), new JavaIsoVisitor<ExecutionContext>() {
73+
TreeVisitor<?, ExecutionContext> gradleVisitor = Preconditions.check(new IsBuildGradle<>(), new JavaIsoVisitor<ExecutionContext>() {
7374
final GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher()
7475
.configuration(configuration)
7576
.groupId(groupId)
@@ -157,5 +158,28 @@ private GradleProject updateGradleModel(GradleProject gp) {
157158
return gp;
158159
}
159160
});
161+
162+
return new TreeVisitor<Tree, ExecutionContext>() {
163+
@Override
164+
public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) {
165+
return gradleVisitor.isAcceptable(sourceFile, ctx) || sourceFile instanceof JavaSourceFile;
166+
}
167+
168+
@Override
169+
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
170+
if (!(tree instanceof SourceFile)) {
171+
return tree;
172+
}
173+
SourceFile sf = (SourceFile) tree;
174+
if (gradleVisitor.isAcceptable(sf, ctx)) {
175+
return gradleVisitor.visit(tree, ctx);
176+
}
177+
if (sf instanceof JavaSourceFile) {
178+
return JavaSourceSet.updateOnSourceFile(sf,
179+
sourceSet -> sourceSet.removeTypesMatching(groupId, artifactId));
180+
}
181+
return tree;
182+
}
183+
};
160184
}
161185
}

0 commit comments

Comments
 (0)