From b373d9f50c9852b347b1d46e2043bc773866975c Mon Sep 17 00:00:00 2001 From: Kyle Scully Date: Tue, 3 Dec 2024 15:58:30 -0800 Subject: [PATCH 001/179] refactor: update OWASP suppression date bounds (#4739) Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.xml.security.UpdateOwaspSuppressionDate?organizationId=T3BlblJld3JpdGU%3D#defaults=W3sidmFsdWUiOlsiQ1ZFLTIwMTctMTI2MjYiLCJDVkUtMjAxOS0xNTA1MiIsIkNWRS0yMDIzLTM1OTQ3ICIsIkNWRS0yMDIxLTI5NDI4IiwiQ1ZFLTIwMjAtMTE5NzkiLCJDVkUtMjAyMS0zMjc1MSIsIkNWRS0yMDIzLTQ1MTYxIiwiQ1ZFLTIwMjMtNDUxNjMiLCJDVkUtMjAyMy01OTY0ICIsIkNWRS0yMDE5LTExNDAyIiwiQ1ZFLTIwMTktMTE0MDMiLCJDVkUtMjAyMS00MTU4OSIsIkNWRS0yMDIzLTQ5MjM4IiwiQ1ZFLTIwMjItMjUzNjQiLCJDVkUtMjAyMi0xNDcxIiwiQ1ZFLTIwMTgtMTI1OCJdLCJuYW1lIjoiY3ZlTGlzdCJ9XQ== Co-authored-by: Moderne --- suppressions.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/suppressions.xml b/suppressions.xml index 0376a3d984e..adba34b3922 100644 --- a/suppressions.xml +++ b/suppressions.xml @@ -9,7 +9,7 @@ ^pkg:maven/com\.squareup\.okio/okio@.*$ CVE-2023-3635 - + CVE-2023-45163 CVE-2023-5964 - + @@ -39,4 +39,4 @@ ^pkg:maven/org\.glassfish/javax\.json@.*$ CVE-2023-7272 - \ No newline at end of file + From 9936a7a70a4792aa73e7f2d1f1378c05b3507123 Mon Sep 17 00:00:00 2001 From: Shannon Pamperl Date: Tue, 3 Dec 2024 21:27:48 -0600 Subject: [PATCH 002/179] Enrich GradleDependency.Matcher to match on cases where a ResolvedDependency is unavailable --- .../openrewrite/gradle/ChangeDependency.java | 96 +++++++++- .../gradle/ChangeDependencyArtifactId.java | 164 ++++++++++------- .../gradle/ChangeDependencyClassifier.java | 160 +++++++++++++++-- .../gradle/ChangeDependencyConfiguration.java | 77 ++++++-- .../gradle/ChangeDependencyExtension.java | 81 ++++++--- .../gradle/ChangeDependencyGroupId.java | 164 ++++++++++------- .../gradle/DependencyUseMapNotation.java | 5 +- .../gradle/DependencyUseStringNotation.java | 5 +- .../openrewrite/gradle/RemoveDependency.java | 168 ++++++------------ .../gradle/UpgradeDependencyVersion.java | 12 +- .../gradle/trait/GradleDependency.java | 100 ++++++++--- 11 files changed, 688 insertions(+), 344 deletions(-) diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependency.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependency.java index 0ff50885dee..9312fa96c3b 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependency.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependency.java @@ -180,14 +180,16 @@ public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionCon public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation m = super.visitMethodInvocation(method, ctx); - GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); + GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher() + .groupId(oldGroupId) + .artifactId(oldArtifactId); if (!gradleDependencyMatcher.get(getCursor()).isPresent()) { return m; } List depArgs = m.getArguments(); - if (depArgs.get(0) instanceof J.Literal || depArgs.get(0) instanceof G.GString || depArgs.get(0) instanceof G.MapEntry) { + if (depArgs.get(0) instanceof J.Literal || depArgs.get(0) instanceof G.GString || depArgs.get(0) instanceof G.MapEntry || depArgs.get(0) instanceof G.MapLiteral) { m = updateDependency(m, ctx); } else if (depArgs.get(0) instanceof J.MethodInvocation && (((J.MethodInvocation) depArgs.get(0)).getSimpleName().equals("platform") || @@ -204,7 +206,7 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m, ExecutionConte String gav = (String) ((J.Literal) depArgs.get(0)).getValue(); if (gav != null) { Dependency original = DependencyStringNotationConverter.parse(gav); - if (original != null && depMatcher.matches(original.getGroupId(), original.getArtifactId())) { + if (original != null) { Dependency updated = original; if (!StringUtils.isBlank(newGroupId) && !updated.getGroupId().equals(newGroupId)) { updated = updated.withGroupId(newGroupId); @@ -238,7 +240,7 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m, ExecutionConte J.Literal literal = (J.Literal) strings.get(0); Dependency original = DependencyStringNotationConverter.parse((String) requireNonNull(literal.getValue())); - if (original != null && depMatcher.matches(original.getGroupId(), original.getArtifactId())) { + if (original != null) { Dependency updated = original; if (!StringUtils.isBlank(newGroupId) && !updated.getGroupId().equals(newGroupId)) { updated = updated.withGroupId(newGroupId); @@ -352,6 +354,92 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m, ExecutionConte return arg; })); } + } else if (m.getArguments().get(0) instanceof G.MapLiteral) { + G.MapLiteral map = (G.MapLiteral) depArgs.get(0); + G.MapEntry groupEntry = null; + G.MapEntry artifactEntry = null; + G.MapEntry versionEntry = null; + String groupId = null; + String artifactId = null; + String version = null; + + for (G.MapEntry arg : map.getElements()) { + if (!(arg.getKey() instanceof J.Literal) || !(arg.getValue() instanceof J.Literal)) { + continue; + } + J.Literal key = (J.Literal) arg.getKey(); + J.Literal value = (J.Literal) arg.getValue(); + if (!(key.getValue() instanceof String) || !(value.getValue() instanceof String)) { + continue; + } + String keyValue = (String) key.getValue(); + String valueValue = (String) value.getValue(); + switch (keyValue) { + case "group": + groupEntry = arg; + groupId = valueValue; + break; + case "name": + artifactEntry = arg; + artifactId = valueValue; + break; + case "version": + versionEntry = arg; + version = valueValue; + break; + } + } + if (groupId == null || artifactId == null) { + return m; + } + if (!depMatcher.matches(groupId, artifactId)) { + return m; + } + String updatedGroupId = groupId; + if (!StringUtils.isBlank(newGroupId) && !updatedGroupId.equals(newGroupId)) { + updatedGroupId = newGroupId; + } + String updatedArtifactId = artifactId; + if (!StringUtils.isBlank(newArtifactId) && !updatedArtifactId.equals(newArtifactId)) { + updatedArtifactId = newArtifactId; + } + String updatedVersion = version; + if (!StringUtils.isBlank(newVersion) && (!StringUtils.isBlank(version) || Boolean.TRUE.equals(overrideManagedVersion))) { + String resolvedVersion; + try { + resolvedVersion = new DependencyVersionSelector(null, gradleProject, null) + .select(new GroupArtifact(updatedGroupId, updatedArtifactId), m.getSimpleName(), newVersion, versionPattern, ctx); + } catch (MavenDownloadingException e) { + return e.warn(m); + } + if (resolvedVersion != null && !resolvedVersion.equals(updatedVersion)) { + updatedVersion = resolvedVersion; + } + } + + if (!updatedGroupId.equals(groupId) || !updatedArtifactId.equals(artifactId) || updatedVersion != null && !updatedVersion.equals(version)) { + G.MapEntry finalGroup = groupEntry; + String finalGroupIdValue = updatedGroupId; + G.MapEntry finalArtifact = artifactEntry; + String finalArtifactIdValue = updatedArtifactId; + G.MapEntry finalVersion = versionEntry; + String finalVersionValue = updatedVersion; + m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> { + G.MapLiteral mapLiteral = (G.MapLiteral) arg; + return mapLiteral.withElements(ListUtils.map(mapLiteral.getElements(), e -> { + if (e == finalGroup) { + return finalGroup.withValue(ChangeStringLiteral.withStringValue((J.Literal) finalGroup.getValue(), finalGroupIdValue)); + } + if (e == finalArtifact) { + return finalArtifact.withValue(ChangeStringLiteral.withStringValue((J.Literal) finalArtifact.getValue(), finalArtifactIdValue)); + } + if (e == finalVersion) { + return finalVersion.withValue(ChangeStringLiteral.withStringValue((J.Literal) finalVersion.getValue(), finalVersionValue)); + } + return e; + })); + })); + } } return m; diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyArtifactId.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyArtifactId.java index ba98f950ca9..02e028fd305 100755 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyArtifactId.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyArtifactId.java @@ -25,21 +25,18 @@ import org.openrewrite.gradle.util.ChangeStringLiteral; import org.openrewrite.gradle.util.Dependency; import org.openrewrite.gradle.util.DependencyStringNotationConverter; -import org.openrewrite.groovy.GroovyVisitor; +import org.openrewrite.groovy.GroovyIsoVisitor; import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.ListUtils; import org.openrewrite.internal.StringUtils; -import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; -import org.openrewrite.maven.tree.GroupArtifact; -import org.openrewrite.maven.tree.ResolvedDependency; import org.openrewrite.semver.DependencyMatcher; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Optional; import static java.util.Objects.requireNonNull; @@ -90,38 +87,42 @@ public Validated validate() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new IsBuildGradle<>(), new GroovyVisitor() { + return Preconditions.check(new IsBuildGradle<>(), new GroovyIsoVisitor() { final DependencyMatcher depMatcher = requireNonNull(DependencyMatcher.build(groupId + ":" + artifactId).getValue()); - final MethodMatcher dependencyDsl = new MethodMatcher("DependencyHandlerSpec *(..)"); - final Map updatedDependencies = new HashMap<>(); + GradleProject gradleProject; @Override - public G visitCompilationUnit(G.CompilationUnit compilationUnit, ExecutionContext ctx) { - G.CompilationUnit cu = (G.CompilationUnit) super.visitCompilationUnit(compilationUnit, ctx); - if(cu != compilationUnit) { - cu = cu.withMarkers(cu.getMarkers().withMarkers(ListUtils.map(cu.getMarkers().getMarkers(), m -> { - if (m instanceof GradleProject) { - return updateModel((GradleProject) m, updatedDependencies); - } - return m; - }))); + public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionContext ctx) { + Optional maybeGp = cu.getMarkers().findFirst(GradleProject.class); + if (!maybeGp.isPresent()) { + return cu; + } + + gradleProject = maybeGp.get(); + + G.CompilationUnit g = super.visitCompilationUnit(cu, ctx); + if (g != cu) { + g = g.withMarkers(g.getMarkers().setByType(updateGradleModel(gradleProject))); } - return cu; + return g; } @Override - public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); - GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); + GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher() + .configuration(configuration) + .groupId(groupId) + .artifactId(artifactId); - if (!((gradleDependencyMatcher.get(getCursor()).isPresent() || dependencyDsl.matches(m)) && (StringUtils.isBlank(configuration) || m.getSimpleName().equals(configuration)))) { + if (!gradleDependencyMatcher.get(getCursor()).isPresent()) { return m; } List depArgs = m.getArguments(); - if (depArgs.get(0) instanceof J.Literal || depArgs.get(0) instanceof G.GString || depArgs.get(0) instanceof G.MapEntry) { + if (depArgs.get(0) instanceof J.Literal || depArgs.get(0) instanceof G.GString || depArgs.get(0) instanceof G.MapEntry || depArgs.get(0) instanceof G.MapLiteral) { m = updateDependency(m); } else if (depArgs.get(0) instanceof J.MethodInvocation && (((J.MethodInvocation) depArgs.get(0)).getSimpleName().equals("platform") || @@ -138,11 +139,8 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m) { String gav = (String) ((J.Literal) depArgs.get(0)).getValue(); if (gav != null) { Dependency dependency = DependencyStringNotationConverter.parse(gav); - if (dependency != null && !newArtifactId.equals(dependency.getArtifactId()) && - ((dependency.getVersion() == null && depMatcher.matches(dependency.getGroupId(), dependency.getArtifactId())) || - (dependency.getVersion() != null && depMatcher.matches(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion())))) { + if (dependency != null && !newArtifactId.equals(dependency.getArtifactId())) { Dependency newDependency = dependency.withArtifactId(newArtifactId); - updatedDependencies.put(dependency.getGav().asGroupArtifact(), newDependency.getGav().asGroupArtifact()); m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> ChangeStringLiteral.withStringValue((J.Literal) arg, newDependency.toStringNotation()))); } } @@ -151,10 +149,8 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m) { if (strings.size() >= 2 && strings.get(0) instanceof J.Literal) { Dependency dependency = DependencyStringNotationConverter.parse((String) requireNonNull(((J.Literal) strings.get(0)).getValue())); - if (dependency != null && !newArtifactId.equals(dependency.getArtifactId()) && - depMatcher.matches(dependency.getGroupId(), dependency.getArtifactId())) { + if (dependency != null && !newArtifactId.equals(dependency.getArtifactId())) { Dependency newDependency = dependency.withArtifactId(newArtifactId); - updatedDependencies.put(dependency.getGav().asGroupArtifact(), newDependency.getGav().asGroupArtifact()); String replacement = newDependency.toStringNotation(); m = m.withArguments(ListUtils.mapFirst(depArgs, arg -> { G.GString gString = (G.GString) arg; @@ -166,7 +162,6 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m) { G.MapEntry artifactEntry = null; String groupId = null; String artifactId = null; - String version = null; String versionStringDelimiter = "'"; for (Expression e : depArgs) { @@ -192,13 +187,9 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m) { } artifactEntry = arg; artifactId = valueValue; - } else if ("version".equals(keyValue)) { - version = valueValue; } } - if (groupId == null || artifactId == null || - (version == null && !depMatcher.matches(groupId, artifactId)) || - (version != null && !depMatcher.matches(groupId, artifactId, version))) { + if (groupId == null || artifactId == null) { return m; } String delimiter = versionStringDelimiter; @@ -211,35 +202,86 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m) { } return arg; })); + } else if (depArgs.get(0) instanceof G.MapLiteral) { + G.MapLiteral map = (G.MapLiteral) depArgs.get(0); + G.MapEntry artifactEntry = null; + String groupId = null; + String artifactId = null; + + String versionStringDelimiter = "'"; + for (G.MapEntry arg : map.getElements()) { + if (!(arg.getKey() instanceof J.Literal) || !(arg.getValue() instanceof J.Literal)) { + continue; + } + J.Literal key = (J.Literal) arg.getKey(); + J.Literal value = (J.Literal) arg.getValue(); + if (!(key.getValue() instanceof String) || !(value.getValue() instanceof String)) { + continue; + } + String keyValue = (String) key.getValue(); + String valueValue = (String) value.getValue(); + if ("group".equals(keyValue)) { + groupId = valueValue; + } else if ("name".equals(keyValue) && !newArtifactId.equals(valueValue)) { + if (value.getValueSource() != null) { + versionStringDelimiter = value.getValueSource().substring(0, value.getValueSource().indexOf(valueValue)); + } + artifactEntry = arg; + artifactId = valueValue; + } + } + if (groupId == null || artifactId == null) { + return m; + } + String delimiter = versionStringDelimiter; + G.MapEntry finalArtifact = artifactEntry; + m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> { + G.MapLiteral mapLiteral = (G.MapLiteral) arg; + return mapLiteral.withElements(ListUtils.map(mapLiteral.getElements(), e -> { + if (e == finalArtifact) { + return finalArtifact.withValue(((J.Literal) finalArtifact.getValue()) + .withValue(newArtifactId) + .withValueSource(delimiter + newArtifactId + delimiter)); + } + return e; + })); + })); } return m; } - }); - } - private GradleProject updateModel(GradleProject gp, Map updatedDependencies) { - Map nameToConfigurations = gp.getNameToConfiguration(); - Map updatedNameToConfigurations = new HashMap<>(); - for (Map.Entry nameToConfiguration : nameToConfigurations.entrySet()) { - String configurationName = nameToConfiguration.getKey(); - GradleDependencyConfiguration configuration = nameToConfiguration.getValue(); - - List newRequested = configuration.getRequested() - .stream() - .map(requested -> requested.withGav(requested.getGav() - .withGroupArtifact(updatedDependencies.getOrDefault(requested.getGav().asGroupArtifact(), requested.getGav().asGroupArtifact())))) - .collect(Collectors.toList()); - - List newResolved = configuration.getResolved().stream() - .map(resolved -> - resolved.withGav(resolved.getGav() - .withGroupArtifact(updatedDependencies.getOrDefault(resolved.getGav().asGroupArtifact(), resolved.getGav().asGroupArtifact())))) - .collect(Collectors.toList()); - - updatedNameToConfigurations.put(configurationName, configuration.withRequested(newRequested).withDirectResolved(newResolved)); - } - - return gp.withNameToConfiguration(updatedNameToConfigurations); + private GradleProject updateGradleModel(GradleProject gp) { + Map nameToConfiguration = gp.getNameToConfiguration(); + Map newNameToConfiguration = new HashMap<>(nameToConfiguration.size()); + boolean anyChanged = false; + for (GradleDependencyConfiguration gdc : nameToConfiguration.values()) { + if (!StringUtils.isBlank(configuration) && configuration.equals(gdc.getName())) { + newNameToConfiguration.put(gdc.getName(), gdc); + continue; + } + + GradleDependencyConfiguration newGdc = gdc; + newGdc = newGdc.withRequested(ListUtils.map(gdc.getRequested(), requested -> { + if (depMatcher.matches(requested.getGroupId(), requested.getArtifactId())) { + return requested.withGav(requested.getGav().withArtifactId(newArtifactId)); + } + return requested; + })); + newGdc = newGdc.withDirectResolved(ListUtils.map(gdc.getDirectResolved(), resolved -> { + if (depMatcher.matches(resolved.getGroupId(), resolved.getArtifactId())) { + return resolved.withGav(resolved.getGav().withArtifactId(newArtifactId)); + } + return resolved; + })); + anyChanged |= newGdc != gdc; + newNameToConfiguration.put(newGdc.getName(), newGdc); + } + if (anyChanged) { + gp = gp.withNameToConfiguration(newNameToConfiguration); + } + return gp; + } + }); } } diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyClassifier.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyClassifier.java index c11f7ccd68d..fcc162cea02 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyClassifier.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyClassifier.java @@ -19,21 +19,21 @@ import lombok.Value; import org.jspecify.annotations.Nullable; import org.openrewrite.*; +import org.openrewrite.gradle.marker.GradleDependencyConfiguration; +import org.openrewrite.gradle.marker.GradleProject; import org.openrewrite.gradle.trait.GradleDependency; import org.openrewrite.gradle.util.ChangeStringLiteral; import org.openrewrite.gradle.util.Dependency; import org.openrewrite.gradle.util.DependencyStringNotationConverter; -import org.openrewrite.groovy.GroovyVisitor; +import org.openrewrite.groovy.GroovyIsoVisitor; import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.ListUtils; import org.openrewrite.internal.StringUtils; -import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; import org.openrewrite.semver.DependencyMatcher; -import java.util.List; -import java.util.Objects; +import java.util.*; import static java.util.Objects.requireNonNull; @@ -86,16 +86,36 @@ public Validated validate() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new IsBuildGradle<>(), new GroovyVisitor() { + return Preconditions.check(new IsBuildGradle<>(), new GroovyIsoVisitor() { final DependencyMatcher depMatcher = requireNonNull(DependencyMatcher.build(groupId + ":" + artifactId).getValue()); - final MethodMatcher dependencyDsl = new MethodMatcher("DependencyHandlerSpec *(..)"); + + GradleProject gradleProject; + + @Override + public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionContext ctx) { + Optional maybeGp = cu.getMarkers().findFirst(GradleProject.class); + if (!maybeGp.isPresent()) { + return cu; + } + + gradleProject = maybeGp.get(); + + G.CompilationUnit g = super.visitCompilationUnit(cu, ctx); + if (g != cu) { + g = g.withMarkers(g.getMarkers().setByType(updateGradleModel(gradleProject))); + } + return g; + } @Override - public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); - GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); + GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher() + .configuration(configuration) + .groupId(groupId) + .artifactId(artifactId); - if (!((gradleDependencyMatcher.get(getCursor()).isPresent() || dependencyDsl.matches(m)) && (StringUtils.isBlank(configuration) || m.getSimpleName().equals(configuration)))) { + if (!gradleDependencyMatcher.get(getCursor()).isPresent()) { return m; } @@ -104,8 +124,7 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) String gav = (String) ((J.Literal) depArgs.get(0)).getValue(); if (gav != null) { Dependency dependency = DependencyStringNotationConverter.parse(gav); - if (dependency != null && dependency.getVersion() != null && !Objects.equals(newClassifier, dependency.getClassifier()) && - depMatcher.matches(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion())) { + if (dependency != null && dependency.getVersion() != null && !Objects.equals(newClassifier, dependency.getClassifier())) { Dependency newDependency = dependency.withClassifier(newClassifier); m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> ChangeStringLiteral.withStringValue((J.Literal) arg, newDependency.toStringNotation()))); } @@ -157,10 +176,7 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) } index++; } - if (groupId == null || artifactId == null || - (version == null && !depMatcher.matches(groupId, artifactId)) || - (version != null && !depMatcher.matches(groupId, artifactId, version)) || - Objects.equals(newClassifier, classifier)) { + if (groupId == null || artifactId == null || Objects.equals(newClassifier, classifier)) { return m; } @@ -187,12 +203,122 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) })); } } + } else if (depArgs.get(0) instanceof G.MapLiteral) { + G.MapLiteral map = (G.MapLiteral) depArgs.get(0); + G.MapEntry classifierEntry = null; + String groupId = null; + String artifactId = null; + String classifier = null; + String groupDelimiter = "'"; + G.MapEntry mapEntry = null; + String classifierStringDelimiter = null; + int index = 0; + for (Expression e : depArgs) { + if (!(e instanceof G.MapEntry)) { + continue; + } + G.MapEntry arg = (G.MapEntry) e; + if (!(arg.getKey() instanceof J.Literal) || !(arg.getValue() instanceof J.Literal)) { + continue; + } + J.Literal key = (J.Literal) arg.getKey(); + J.Literal value = (J.Literal) arg.getValue(); + if (!(key.getValue() instanceof String) || !(value.getValue() instanceof String)) { + continue; + } + String keyValue = (String) key.getValue(); + String valueValue = (String) value.getValue(); + if ("group".equals(keyValue)) { + groupId = valueValue; + if (value.getValueSource() != null) { + groupDelimiter = value.getValueSource().substring(0, value.getValueSource().indexOf(valueValue)); + } + } else if ("name".equals(keyValue)) { + if (index > 0 && mapEntry == null) { + mapEntry = arg; + } + artifactId = valueValue; + } else if ("classifier".equals(keyValue)) { + if (value.getValueSource() != null) { + classifierStringDelimiter = value.getValueSource().substring(0, value.getValueSource().indexOf(valueValue)); + } + classifierEntry = arg; + classifier = valueValue; + } + index++; + } + if (groupId == null || artifactId == null || Objects.equals(newClassifier, classifier)) { + return m; + } + + if (classifier == null) { + String delimiter = groupDelimiter; + G.MapEntry finalMapEntry = mapEntry; + J.Literal keyLiteral = new J.Literal(Tree.randomId(), mapEntry == null ? Space.EMPTY : mapEntry.getKey().getPrefix(), Markers.EMPTY, "classifier", "classifier", null, JavaType.Primitive.String); + J.Literal valueLiteral = new J.Literal(Tree.randomId(), mapEntry == null ? Space.EMPTY : mapEntry.getValue().getPrefix(), Markers.EMPTY, newClassifier, delimiter + newClassifier + delimiter, null, JavaType.Primitive.String); + m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> { + G.MapLiteral mapLiteral = (G.MapLiteral) arg; + return mapLiteral.withElements(ListUtils.concat(mapLiteral.getElements(), new G.MapEntry(Tree.randomId(), finalMapEntry == null ? Space.EMPTY : finalMapEntry.getPrefix(), Markers.EMPTY, JRightPadded.build(keyLiteral), valueLiteral, null))); + })); + } else { + G.MapEntry finalClassifier = classifierEntry; + if (newClassifier == null) { + m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> { + G.MapLiteral mapLiteral = (G.MapLiteral) arg; + return mapLiteral.withElements(ListUtils.map(mapLiteral.getElements(), e -> e == finalClassifier ? null : e)); + })); + } else { + String delimiter = classifierStringDelimiter; // `classifierStringDelimiter` cannot be null + m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> { + G.MapLiteral mapLiteral = (G.MapLiteral) arg; + return mapLiteral.withElements(ListUtils.map(mapLiteral.getElements(), e -> { + if (e == finalClassifier) { + return finalClassifier.withValue(((J.Literal) finalClassifier.getValue()) + .withValue(newClassifier) + .withValueSource(delimiter + newClassifier + delimiter)); + } + return e; + })); + })); + } + } } return m; } + + private GradleProject updateGradleModel(GradleProject gp) { + Map nameToConfiguration = gp.getNameToConfiguration(); + Map newNameToConfiguration = new HashMap<>(nameToConfiguration.size()); + boolean anyChanged = false; + for (GradleDependencyConfiguration gdc : nameToConfiguration.values()) { + if (!StringUtils.isBlank(configuration) && !configuration.equals(gdc.getName())) { + newNameToConfiguration.put(gdc.getName(), gdc); + continue; + } + + GradleDependencyConfiguration newGdc = gdc; + newGdc = newGdc.withRequested(ListUtils.map(gdc.getRequested(), requested -> { + if (depMatcher.matches(requested.getGroupId(), requested.getArtifactId()) && !Objects.equals(requested.getClassifier(), newClassifier)) { + return requested.withClassifier(newClassifier); + } + return requested; + })); + newGdc = newGdc.withDirectResolved(ListUtils.map(gdc.getDirectResolved(), resolved -> { + if (depMatcher.matches(resolved.getGroupId(), resolved.getArtifactId()) && !Objects.equals(resolved.getClassifier(), newClassifier)) { + return resolved.withClassifier(newClassifier); + } + return resolved; + })); + anyChanged |= newGdc != gdc; + newNameToConfiguration.put(newGdc.getName(), newGdc); + } + if (anyChanged) { + gp = gp.withNameToConfiguration(newNameToConfiguration); + } + return gp; + } }); } - } diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyConfiguration.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyConfiguration.java index dd2e0275e5c..ad6747d3a41 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyConfiguration.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyConfiguration.java @@ -22,9 +22,8 @@ import org.openrewrite.gradle.trait.GradleDependency; import org.openrewrite.gradle.util.Dependency; import org.openrewrite.gradle.util.DependencyStringNotationConverter; -import org.openrewrite.groovy.GroovyVisitor; +import org.openrewrite.groovy.GroovyIsoVisitor; import org.openrewrite.groovy.tree.G; -import org.openrewrite.internal.StringUtils; import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; @@ -86,16 +85,18 @@ public Duration getEstimatedEffortPerOccurrence() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new IsBuildGradle<>(), new GroovyVisitor() { + return Preconditions.check(new IsBuildGradle<>(), new GroovyIsoVisitor() { + // Still need to be able to change the configuration for project dependencies which are not yet supported by the `GradleDependency.Matcher` final MethodMatcher dependencyDsl = new MethodMatcher("DependencyHandlerSpec *(..)"); @Override - public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); - GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); + GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher() + .configuration(configuration); - if (!((gradleDependencyMatcher.get(getCursor()).isPresent() || dependencyDsl.matches(m)) && (StringUtils.isBlank(configuration) || m.getSimpleName().equals(configuration)))) { + if (!(gradleDependencyMatcher.get(getCursor()).isPresent() || dependencyDsl.matches(m))) { return m; } @@ -127,19 +128,65 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) if (dependency == null || !dependencyMatcher.matches(dependency.getGroupId(), dependency.getArtifactId())) { return m; } - } else if (args.get(0) instanceof G.MapEntry && args.size() >= 2) { - Expression groupValue = ((G.MapEntry) args.get(0)).getValue(); - Expression artifactValue = ((G.MapEntry) args.get(1)).getValue(); - if (!(groupValue instanceof J.Literal) || !(artifactValue instanceof J.Literal)) { + } else if (args.get(0) instanceof G.MapEntry) { + if (args.size() < 2) { return m; } - J.Literal groupLiteral = (J.Literal) groupValue; - J.Literal artifactLiteral = (J.Literal) artifactValue; - if (!(groupLiteral.getValue() instanceof String) || !(artifactLiteral.getValue() instanceof String)) { + + String groupId = null; + String artifactId = null; + for (Expression e : args) { + if (!(e instanceof G.MapEntry)) { + continue; + } + G.MapEntry arg = (G.MapEntry) e; + if (!(arg.getKey() instanceof J.Literal) || !(arg.getValue() instanceof J.Literal)) { + continue; + } + J.Literal key = (J.Literal) arg.getKey(); + J.Literal value = (J.Literal) arg.getValue(); + if (!(key.getValue() instanceof String) || !(value.getValue() instanceof String)) { + continue; + } + String keyValue = (String) key.getValue(); + String valueValue = (String) value.getValue(); + if ("group".equals(keyValue)) { + groupId = valueValue; + } else if ("name".equals(keyValue)) { + artifactId = valueValue; + } + } + + if (artifactId == null || !dependencyMatcher.matches(groupId, artifactId)) { return m; } + } else if (args.get(0) instanceof G.MapLiteral) { + if (args.size() < 2) { + return m; + } + + G.MapLiteral map = (G.MapLiteral) args.get(0); + String groupId = null; + String artifactId = null; + for (G.MapEntry arg : map.getElements()) { + if (!(arg.getKey() instanceof J.Literal) || !(arg.getValue() instanceof J.Literal)) { + continue; + } + J.Literal key = (J.Literal) arg.getKey(); + J.Literal value = (J.Literal) arg.getValue(); + if (!(key.getValue() instanceof String) || !(value.getValue() instanceof String)) { + continue; + } + String keyValue = (String) key.getValue(); + String valueValue = (String) value.getValue(); + if ("group".equals(keyValue)) { + groupId = valueValue; + } else if ("name".equals(keyValue)) { + artifactId = valueValue; + } + } - if (!dependencyMatcher.matches((String) groupLiteral.getValue(), (String) artifactLiteral.getValue())) { + if (artifactId == null || !dependencyMatcher.matches(groupId, artifactId)) { return m; } } else if (args.get(0) instanceof J.MethodInvocation) { diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyExtension.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyExtension.java index a6a617f627b..dc103c00f75 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyExtension.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyExtension.java @@ -23,19 +23,15 @@ import org.openrewrite.gradle.util.ChangeStringLiteral; import org.openrewrite.gradle.util.Dependency; import org.openrewrite.gradle.util.DependencyStringNotationConverter; -import org.openrewrite.groovy.GroovyVisitor; +import org.openrewrite.groovy.GroovyIsoVisitor; import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.ListUtils; -import org.openrewrite.internal.StringUtils; -import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.semver.DependencyMatcher; import java.util.List; -import static java.util.Objects.requireNonNull; - @Value @EqualsAndHashCode(callSuper = false) public class ChangeDependencyExtension extends Recipe { @@ -83,17 +79,17 @@ public Validated validate() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new IsBuildGradle<>(), new GroovyVisitor() { - final DependencyMatcher depMatcher = requireNonNull(DependencyMatcher.build(groupId + ":" + artifactId).getValue()); - final MethodMatcher dependencyDsl = new MethodMatcher("DependencyHandlerSpec *(..)"); - + return Preconditions.check(new IsBuildGradle<>(), new GroovyIsoVisitor() { @Override - public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); - GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); + GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher() + .configuration(configuration) + .groupId(groupId) + .artifactId(artifactId); - if (!((gradleDependencyMatcher.get(getCursor()).isPresent() || dependencyDsl.matches(m)) && (StringUtils.isBlank(configuration) || m.getSimpleName().equals(configuration)))) { + if (!gradleDependencyMatcher.get(getCursor()).isPresent()) { return m; } @@ -102,9 +98,7 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) String gav = (String) ((J.Literal) depArgs.get(0)).getValue(); if (gav != null) { Dependency dependency = DependencyStringNotationConverter.parse(gav); - if (dependency != null && !newExtension.equals(dependency.getExt()) && - ((dependency.getVersion() == null && depMatcher.matches(dependency.getGroupId(), dependency.getArtifactId())) || - (dependency.getVersion() != null && depMatcher.matches(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion())))) { + if (dependency != null && !newExtension.equals(dependency.getExt())) { Dependency newDependency = dependency.withExt(newExtension); m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> ChangeStringLiteral.withStringValue((J.Literal) arg, newDependency.toStringNotation()))); } @@ -113,7 +107,6 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) G.MapEntry extensionEntry = null; String groupId = null; String artifactId = null; - String version = null; String extension = null; String extensionStringDelimiter = "'"; @@ -136,8 +129,6 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) groupId = valueValue; } else if ("name".equals(keyValue)) { artifactId = valueValue; - } else if ("version".equals(keyValue)) { - version = valueValue; } else if ("ext".equals(keyValue) && !newExtension.equals(valueValue)) { if (value.getValueSource() != null) { extensionStringDelimiter = value.getValueSource().substring(0, value.getValueSource().indexOf(valueValue)); @@ -146,10 +137,7 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) extension = valueValue; } } - if (groupId == null || artifactId == null || - (version == null && !depMatcher.matches(groupId, artifactId)) || - (version != null && !depMatcher.matches(groupId, artifactId, version)) || - extension == null) { + if (groupId == null || artifactId == null || extension == null) { return m; } String delimiter = extensionStringDelimiter; @@ -162,6 +150,53 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) } return arg; })); + } else if (depArgs.get(0) instanceof G.MapLiteral) { + G.MapLiteral map = (G.MapLiteral) depArgs.get(0); + G.MapEntry extensionEntry = null; + String groupId = null; + String artifactId = null; + String extension = null; + + String extensionStringDelimiter = "'"; + for (G.MapEntry arg : map.getElements()) { + if (!(arg.getKey() instanceof J.Literal) || !(arg.getValue() instanceof J.Literal)) { + continue; + } + J.Literal key = (J.Literal) arg.getKey(); + J.Literal value = (J.Literal) arg.getValue(); + if (!(key.getValue() instanceof String) || !(value.getValue() instanceof String)) { + continue; + } + String keyValue = (String) key.getValue(); + String valueValue = (String) value.getValue(); + if ("group".equals(keyValue)) { + groupId = valueValue; + } else if ("name".equals(keyValue)) { + artifactId = valueValue; + } else if ("ext".equals(keyValue) && !newExtension.equals(valueValue)) { + if (value.getValueSource() != null) { + extensionStringDelimiter = value.getValueSource().substring(0, value.getValueSource().indexOf(valueValue)); + } + extensionEntry = arg; + extension = valueValue; + } + } + if (groupId == null || artifactId == null || extension == null) { + return m; + } + String delimiter = extensionStringDelimiter; + G.MapEntry finalExtension = extensionEntry; + m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> { + G.MapLiteral mapLiteral = (G.MapLiteral) arg; + return mapLiteral.withElements(ListUtils.map(mapLiteral.getElements(), e -> { + if (e == finalExtension) { + return finalExtension.withValue(((J.Literal) finalExtension.getValue()) + .withValue(newExtension) + .withValueSource(delimiter + newExtension + delimiter)); + } + return e; + })); + })); } return m; diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyGroupId.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyGroupId.java index 550b71f1492..ade503f67d1 100755 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyGroupId.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyGroupId.java @@ -25,21 +25,18 @@ import org.openrewrite.gradle.util.ChangeStringLiteral; import org.openrewrite.gradle.util.Dependency; import org.openrewrite.gradle.util.DependencyStringNotationConverter; -import org.openrewrite.groovy.GroovyVisitor; +import org.openrewrite.groovy.GroovyIsoVisitor; import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.ListUtils; import org.openrewrite.internal.StringUtils; -import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; -import org.openrewrite.maven.tree.GroupArtifact; -import org.openrewrite.maven.tree.ResolvedDependency; import org.openrewrite.semver.DependencyMatcher; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import java.util.Optional; import static java.util.Objects.requireNonNull; @@ -90,38 +87,42 @@ public Validated validate() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new IsBuildGradle<>(), new GroovyVisitor() { + return Preconditions.check(new IsBuildGradle<>(), new GroovyIsoVisitor() { final DependencyMatcher depMatcher = requireNonNull(DependencyMatcher.build(groupId + ":" + artifactId).getValue()); - final MethodMatcher dependencyDsl = new MethodMatcher("DependencyHandlerSpec *(..)"); - final Map updatedDependencies = new HashMap<>(); + GradleProject gradleProject; @Override - public G visitCompilationUnit(G.CompilationUnit compilationUnit, ExecutionContext ctx) { - G.CompilationUnit cu = (G.CompilationUnit) super.visitCompilationUnit(compilationUnit, ctx); - if(cu != compilationUnit) { - cu = cu.withMarkers(cu.getMarkers().withMarkers(ListUtils.map(cu.getMarkers().getMarkers(), m -> { - if (m instanceof GradleProject) { - return updateModel((GradleProject) m, updatedDependencies); - } - return m; - }))); + public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionContext ctx) { + Optional maybeGp = cu.getMarkers().findFirst(GradleProject.class); + if (!maybeGp.isPresent()) { + return cu; + } + + gradleProject = maybeGp.get(); + + G.CompilationUnit g = super.visitCompilationUnit(cu, ctx); + if (g != cu) { + g = g.withMarkers(g.getMarkers().setByType(updateGradleModel(gradleProject))); } - return cu; + return g; } @Override - public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); - GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); + GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher() + .configuration(configuration) + .groupId(groupId) + .artifactId(artifactId); - if (!((gradleDependencyMatcher.get(getCursor()).isPresent() || dependencyDsl.matches(m)) && (StringUtils.isBlank(configuration) || m.getSimpleName().equals(configuration)))) { + if (!gradleDependencyMatcher.get(getCursor()).isPresent()) { return m; } List depArgs = m.getArguments(); - if (depArgs.get(0) instanceof J.Literal || depArgs.get(0) instanceof G.GString || depArgs.get(0) instanceof G.MapEntry) { + if (depArgs.get(0) instanceof J.Literal || depArgs.get(0) instanceof G.GString || depArgs.get(0) instanceof G.MapEntry || depArgs.get(0) instanceof G.MapLiteral) { m = updateDependency(m); } else if (depArgs.get(0) instanceof J.MethodInvocation && (((J.MethodInvocation) depArgs.get(0)).getSimpleName().equals("platform") || @@ -138,11 +139,8 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m) { String gav = (String) ((J.Literal) depArgs.get(0)).getValue(); if (gav != null) { Dependency dependency = DependencyStringNotationConverter.parse(gav); - if (dependency != null && !newGroupId.equals(dependency.getGroupId()) && - ((dependency.getVersion() == null && depMatcher.matches(dependency.getGroupId(), dependency.getArtifactId())) || - (dependency.getVersion() != null && depMatcher.matches(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion())))) { + if (dependency != null && !newGroupId.equals(dependency.getGroupId())) { Dependency newDependency = dependency.withGroupId(newGroupId); - updatedDependencies.put(dependency.getGav().asGroupArtifact(), newDependency.getGav().asGroupArtifact()); m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> ChangeStringLiteral.withStringValue((J.Literal) arg, newDependency.toStringNotation()))); } } @@ -151,10 +149,8 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m) { if (strings.size() >= 2 && strings.get(0) instanceof J.Literal) { Dependency dependency = DependencyStringNotationConverter.parse((String) requireNonNull(((J.Literal) strings.get(0)).getValue())); - if (dependency != null && !newGroupId.equals(dependency.getGroupId()) && - depMatcher.matches(dependency.getGroupId(), dependency.getArtifactId())) { + if (dependency != null && !newGroupId.equals(dependency.getGroupId())) { Dependency newDependency = dependency.withGroupId(newGroupId); - updatedDependencies.put(dependency.getGav().asGroupArtifact(), newDependency.getGav().asGroupArtifact()); String replacement = newDependency.toStringNotation(); m = m.withArguments(ListUtils.mapFirst(depArgs, arg -> { G.GString gString = (G.GString) arg; @@ -166,7 +162,6 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m) { G.MapEntry groupEntry = null; String groupId = null; String artifactId = null; - String version = null; String versionStringDelimiter = "'"; for (Expression e : depArgs) { @@ -192,13 +187,9 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m) { groupId = valueValue; } else if ("name".equals(keyValue)) { artifactId = valueValue; - } else if ("version".equals(keyValue)) { - version = valueValue; } } - if (groupId == null || artifactId == null || - (version == null && !depMatcher.matches(groupId, artifactId)) || - (version != null && !depMatcher.matches(groupId, artifactId, version))) { + if (groupId == null || artifactId == null) { return m; } String delimiter = versionStringDelimiter; @@ -211,35 +202,86 @@ private J.MethodInvocation updateDependency(J.MethodInvocation m) { } return arg; })); + } else if (depArgs.get(0) instanceof G.MapLiteral) { + G.MapLiteral map = (G.MapLiteral) depArgs.get(0); + G.MapEntry groupEntry = null; + String groupId = null; + String artifactId = null; + + String versionStringDelimiter = "'"; + for (G.MapEntry arg : map.getElements()) { + if (!(arg.getKey() instanceof J.Literal) || !(arg.getValue() instanceof J.Literal)) { + continue; + } + J.Literal key = (J.Literal) arg.getKey(); + J.Literal value = (J.Literal) arg.getValue(); + if (!(key.getValue() instanceof String) || !(value.getValue() instanceof String)) { + continue; + } + String keyValue = (String) key.getValue(); + String valueValue = (String) value.getValue(); + if ("group".equals(keyValue) && !newGroupId.equals(valueValue)) { + if (value.getValueSource() != null) { + versionStringDelimiter = value.getValueSource().substring(0, value.getValueSource().indexOf(valueValue)); + } + groupEntry = arg; + groupId = valueValue; + } else if ("name".equals(keyValue)) { + artifactId = valueValue; + } + } + if (groupId == null || artifactId == null) { + return m; + } + String delimiter = versionStringDelimiter; + G.MapEntry finalGroup = groupEntry; + m = m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> { + G.MapLiteral mapLiteral = (G.MapLiteral) arg; + return mapLiteral.withElements(ListUtils.map(mapLiteral.getElements(), e -> { + if (e == finalGroup) { + return finalGroup.withValue(((J.Literal) finalGroup.getValue()) + .withValue(newGroupId) + .withValueSource(delimiter + newGroupId + delimiter)); + } + return e; + })); + })); } return m; } - }); - } - private GradleProject updateModel(GradleProject gp, Map updatedDependencies) { - Map nameToConfigurations = gp.getNameToConfiguration(); - Map updatedNameToConfigurations = new HashMap<>(); - for (Map.Entry nameToConfiguration : nameToConfigurations.entrySet()) { - String configurationName = nameToConfiguration.getKey(); - GradleDependencyConfiguration configuration = nameToConfiguration.getValue(); - - List newRequested = configuration.getRequested() - .stream() - .map(requested -> requested.withGav(requested.getGav() - .withGroupArtifact(updatedDependencies.getOrDefault(requested.getGav().asGroupArtifact(), requested.getGav().asGroupArtifact())))) - .collect(Collectors.toList()); - - List newResolved = configuration.getResolved().stream() - .map(resolved -> - resolved.withGav(resolved.getGav() - .withGroupArtifact(updatedDependencies.getOrDefault(resolved.getGav().asGroupArtifact(), resolved.getGav().asGroupArtifact())))) - .collect(Collectors.toList()); - - updatedNameToConfigurations.put(configurationName, configuration.withRequested(newRequested).withDirectResolved(newResolved)); - } - - return gp.withNameToConfiguration(updatedNameToConfigurations); + private GradleProject updateGradleModel(GradleProject gp) { + Map nameToConfiguration = gp.getNameToConfiguration(); + Map newNameToConfiguration = new HashMap<>(nameToConfiguration.size()); + boolean anyChanged = false; + for (GradleDependencyConfiguration gdc : nameToConfiguration.values()) { + if (!StringUtils.isBlank(configuration) && configuration.equals(gdc.getName())) { + newNameToConfiguration.put(gdc.getName(), gdc); + continue; + } + + GradleDependencyConfiguration newGdc = gdc; + newGdc = newGdc.withRequested(ListUtils.map(gdc.getRequested(), requested -> { + if (depMatcher.matches(requested.getGroupId(), requested.getArtifactId())) { + return requested.withGav(requested.getGav().withGroupId(newGroupId)); + } + return requested; + })); + newGdc = newGdc.withDirectResolved(ListUtils.map(gdc.getDirectResolved(), resolved -> { + if (depMatcher.matches(resolved.getGroupId(), resolved.getArtifactId())) { + return resolved.withGav(resolved.getGav().withGroupId(newGroupId)); + } + return resolved; + })); + anyChanged |= newGdc != gdc; + newNameToConfiguration.put(newGdc.getName(), newGdc); + } + if (anyChanged) { + gp = gp.withNameToConfiguration(newNameToConfiguration); + } + return gp; + } + }); } } diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/DependencyUseMapNotation.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/DependencyUseMapNotation.java index 984523ff5d8..301fb375987 100755 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/DependencyUseMapNotation.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/DependencyUseMapNotation.java @@ -25,7 +25,6 @@ import org.openrewrite.groovy.GroovyVisitor; import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.ListUtils; -import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; @@ -53,15 +52,13 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { return Preconditions.check(new IsBuildGradle<>(), new GroovyVisitor() { - final MethodMatcher dependencyDsl = new MethodMatcher("DependencyHandlerSpec *(..)"); - @Override public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); - if (!(gradleDependencyMatcher.get(getCursor()).isPresent() || dependencyDsl.matches(m))) { + if (!gradleDependencyMatcher.get(getCursor()).isPresent()) { return m; } m = forBasicString(m); diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/DependencyUseStringNotation.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/DependencyUseStringNotation.java index b3c17260f90..17f8b300a05 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/DependencyUseStringNotation.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/DependencyUseStringNotation.java @@ -23,7 +23,6 @@ import org.openrewrite.gradle.trait.GradleDependency; import org.openrewrite.groovy.GroovyVisitor; import org.openrewrite.groovy.tree.G; -import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; @@ -50,15 +49,13 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { return Preconditions.check(new IsBuildGradle<>(), new GroovyVisitor() { - final MethodMatcher dependencyDsl = new MethodMatcher("DependencyHandlerSpec *(..)"); - @Override public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); - if (!(gradleDependencyMatcher.get(getCursor()).isPresent() || dependencyDsl.matches(m))) { + if (!gradleDependencyMatcher.get(getCursor()).isPresent()) { return m; } diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveDependency.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveDependency.java index f38e853fbe6..b05ac29701b 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveDependency.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveDependency.java @@ -15,7 +15,6 @@ */ package org.openrewrite.gradle; -import io.micrometer.core.instrument.util.StringUtils; import lombok.EqualsAndHashCode; import lombok.Value; import org.jspecify.annotations.Nullable; @@ -23,17 +22,14 @@ import org.openrewrite.gradle.marker.GradleDependencyConfiguration; import org.openrewrite.gradle.marker.GradleProject; import org.openrewrite.gradle.trait.GradleDependency; -import org.openrewrite.gradle.util.Dependency; -import org.openrewrite.gradle.util.DependencyStringNotationConverter; -import org.openrewrite.groovy.GroovyVisitor; +import org.openrewrite.groovy.GroovyIsoVisitor; import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.ListUtils; -import org.openrewrite.java.MethodMatcher; -import org.openrewrite.java.tree.Expression; +import org.openrewrite.internal.StringUtils; import org.openrewrite.java.tree.J; import org.openrewrite.semver.DependencyMatcher; -import java.util.List; +import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -77,55 +73,35 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return Preconditions.check(new IsBuildGradle<>(), new GroovyVisitor() { - final MethodMatcher dependencyDsl = new MethodMatcher("DependencyHandlerSpec *(..)"); - final DependencyMatcher dependencyMatcher = requireNonNull(DependencyMatcher.build(groupId + ":" + artifactId).getValue()); + return Preconditions.check(new IsBuildGradle<>(), new GroovyIsoVisitor() { + final GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher() + .configuration(configuration) + .groupId(groupId) + .artifactId(artifactId); + final DependencyMatcher depMatcher = requireNonNull(DependencyMatcher.build(groupId + ":" + artifactId).getValue()); + + GradleProject gradleProject; @Override - public J visitCompilationUnit(G.CompilationUnit cu, ExecutionContext ctx) { - G.CompilationUnit g = (G.CompilationUnit) super.visitCompilationUnit(cu, ctx); - if (g == cu) { + public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionContext ctx) { + Optional maybeGp = cu.getMarkers().findFirst(GradleProject.class); + if (!maybeGp.isPresent()) { return cu; } - Optional maybeGp = g.getMarkers().findFirst(GradleProject.class); - if (!maybeGp.isPresent()) { - // Allow modification of freestanding scripts which do not carry a GradleProject marker - return g; - } + gradleProject = maybeGp.get(); - GradleProject gp = maybeGp.get(); - Map nameToConfiguration = gp.getNameToConfiguration(); - boolean anyChanged = false; - for (GradleDependencyConfiguration gdc : nameToConfiguration.values()) { - GradleDependencyConfiguration newGdc = gdc.withRequested(ListUtils.map(gdc.getRequested(), requested -> { - if (requested.getGroupId() != null && dependencyMatcher.matches(requested.getGroupId(), requested.getArtifactId())) { - return null; - } - return requested; - })); - newGdc = newGdc.withDirectResolved(ListUtils.map(newGdc.getDirectResolved(), resolved -> { - if (dependencyMatcher.matches(resolved.getGroupId(), resolved.getArtifactId())) { - return null; - } - return resolved; - })); - nameToConfiguration.put(newGdc.getName(), newGdc); - anyChanged |= newGdc != gdc; - } - - if (!anyChanged) { - // instance was changed, but no marker update is needed - return g; + G.CompilationUnit g = super.visitCompilationUnit(cu, ctx); + if (g != cu) { + g = g.withMarkers(g.getMarkers().setByType(updateGradleModel(gradleProject))); } - - return g.withMarkers(g.getMarkers().setByType(gp.withNameToConfiguration(nameToConfiguration))); + return g; } @Override - public @Nullable J visitReturn(J.Return return_, ExecutionContext ctx) { - boolean dependencyInvocation = return_.getExpression() instanceof J.MethodInvocation && dependencyDsl.matches((J.MethodInvocation) return_.getExpression()); - J.Return r = (J.Return) super.visitReturn(return_, ctx); + public J.@Nullable Return visitReturn(J.Return return_, ExecutionContext ctx) { + boolean dependencyInvocation = return_.getExpression() instanceof J.MethodInvocation && gradleDependencyMatcher.get(return_.getExpression(), getCursor()).isPresent(); + J.Return r = super.visitReturn(return_, ctx); if (dependencyInvocation && r.getExpression() == null) { //noinspection DataFlowIssue return null; @@ -134,86 +110,46 @@ public J visitCompilationUnit(G.CompilationUnit cu, ExecutionContext ctx) { } @Override - public @Nullable J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); - - GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); - - if ((gradleDependencyMatcher.get(getCursor()).isPresent() || dependencyDsl.matches(m)) && (StringUtils.isEmpty(configuration) || configuration.equals(m.getSimpleName()))) { - Expression firstArgument = m.getArguments().get(0); - if (firstArgument instanceof J.Literal || firstArgument instanceof G.GString || firstArgument instanceof G.MapEntry) { - //noinspection DataFlowIssue - return maybeRemoveDependency(m); - } else if (firstArgument instanceof J.MethodInvocation && - (((J.MethodInvocation) firstArgument).getSimpleName().equals("platform") || - ((J.MethodInvocation) firstArgument).getSimpleName().equals("enforcedPlatform"))) { - J after = maybeRemoveDependency((J.MethodInvocation) firstArgument); - if (after == null) { - //noinspection DataFlowIssue - return null; - } - } + public J.@Nullable MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); + + if (gradleDependencyMatcher.get(getCursor()).isPresent()) { + return null; } return m; } - private @Nullable J maybeRemoveDependency(J.MethodInvocation m) { - if (m.getArguments().get(0) instanceof G.GString) { - G.GString gString = (G.GString) m.getArguments().get(0); - List strings = gString.getStrings(); - if (strings.size() != 2 || !(strings.get(0) instanceof J.Literal) || !(strings.get(1) instanceof G.GString.Value)) { - return m; - } - J.Literal groupArtifact = (J.Literal) strings.get(0); - if (!(groupArtifact.getValue() instanceof String)) { - return m; - } - Dependency dependency = DependencyStringNotationConverter.parse((String) groupArtifact.getValue()); - if (dependency != null && dependencyMatcher.matches(dependency.getGroupId(), dependency.getArtifactId())) { - return null; - } - } else if (m.getArguments().get(0) instanceof J.Literal) { - Object value = ((J.Literal) m.getArguments().get(0)).getValue(); - if(!(value instanceof String)) { - return null; - } - Dependency dependency = DependencyStringNotationConverter.parse((String) value); - if (dependency != null && dependencyMatcher.matches(dependency.getGroupId(), dependency.getArtifactId())) { - return null; + private GradleProject updateGradleModel(GradleProject gp) { + Map nameToConfiguration = gp.getNameToConfiguration(); + Map newNameToConfiguration = new HashMap<>(nameToConfiguration.size()); + boolean anyChanged = false; + for (GradleDependencyConfiguration gdc : nameToConfiguration.values()) { + if (!StringUtils.isBlank(configuration) && configuration.equals(gdc.getName())) { + newNameToConfiguration.put(gdc.getName(), gdc); + continue; } - } else if (m.getArguments().get(0) instanceof G.MapEntry) { - String groupId = null; - String artifactId = null; - for (Expression e : m.getArguments()) { - if (!(e instanceof G.MapEntry)) { - continue; - } - G.MapEntry arg = (G.MapEntry) e; - if (!(arg.getKey() instanceof J.Literal) || !(arg.getValue() instanceof J.Literal)) { - continue; - } - J.Literal key = (J.Literal) arg.getKey(); - J.Literal value = (J.Literal) arg.getValue(); - if (!(key.getValue() instanceof String) || !(value.getValue() instanceof String)) { - continue; + GradleDependencyConfiguration newGdc = gdc; + newGdc = newGdc.withRequested(ListUtils.map(gdc.getRequested(), requested -> { + if (depMatcher.matches(requested.getGroupId(), requested.getArtifactId())) { + return null; } - String keyValue = (String) key.getValue(); - String valueValue = (String) value.getValue(); - if ("group".equals(keyValue)) { - groupId = valueValue; - } else if ("name".equals(keyValue)) { - artifactId = valueValue; + return requested; + })); + newGdc = newGdc.withDirectResolved(ListUtils.map(gdc.getDirectResolved(), resolved -> { + if (depMatcher.matches(resolved.getGroupId(), resolved.getArtifactId())) { + return null; } - } - - if (groupId != null && artifactId != null && dependencyMatcher.matches(groupId, artifactId)) { - return null; - } + return resolved; + })); + anyChanged |= newGdc != gdc; + newNameToConfiguration.put(newGdc.getName(), newGdc); } - - return m; + if (anyChanged) { + gp = gp.withNameToConfiguration(newNameToConfiguration); + } + return gp; } }); } diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpgradeDependencyVersion.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpgradeDependencyVersion.java index d008c4ae3f1..d8c32b7cd84 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpgradeDependencyVersion.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/UpgradeDependencyVersion.java @@ -32,7 +32,6 @@ import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.ListUtils; import org.openrewrite.internal.StringUtils; -import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaSourceFile; @@ -140,8 +139,6 @@ public DependencyVersionState getInitialValue(ExecutionContext ctx) { return new DependencyVersionState(); } - private static final MethodMatcher DEPENDENCY_DSL_MATCHER = new MethodMatcher("DependencyHandlerSpec *(..)"); - @Override public TreeVisitor getScanner(DependencyVersionState acc) { @@ -163,7 +160,7 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); - if (gradleDependencyMatcher.get(getCursor()).isPresent() || DEPENDENCY_DSL_MATCHER.matches(m)) { + if (gradleDependencyMatcher.get(getCursor()).isPresent()) { if (m.getArguments().get(0) instanceof G.MapEntry) { String groupId = null; String artifactId = null; @@ -374,15 +371,10 @@ public J postVisit(J tree, ExecutionContext ctx) { @Override public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - if ("constraints".equals(method.getSimpleName()) || "project".equals(method.getSimpleName())) { - // don't mess with anything inside a constraints block, leave that to UpgradeTransitiveDependency version recipe - // `project` dependencies should also be skipped - return method; - } J.MethodInvocation m = (J.MethodInvocation) super.visitMethodInvocation(method, ctx); GradleDependency.Matcher gradleDependencyMatcher = new GradleDependency.Matcher(); - if (gradleDependencyMatcher.get(getCursor()).isPresent() || DEPENDENCY_DSL_MATCHER.matches(m)) { + if (gradleDependencyMatcher.get(getCursor()).isPresent()) { List depArgs = m.getArguments(); if (depArgs.get(0) instanceof J.Literal || depArgs.get(0) instanceof G.GString || depArgs.get(0) instanceof G.MapEntry) { m = updateDependency(m, ctx); diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradleDependency.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradleDependency.java index 1f20c8e92e2..e4a806cdd25 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradleDependency.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/trait/GradleDependency.java @@ -24,10 +24,13 @@ import org.openrewrite.gradle.util.DependencyStringNotationConverter; import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.StringUtils; +import org.openrewrite.java.MethodMatcher; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.J; import org.openrewrite.maven.tree.Dependency; +import org.openrewrite.maven.tree.GroupArtifactVersion; import org.openrewrite.maven.tree.ResolvedDependency; +import org.openrewrite.maven.tree.ResolvedGroupArtifactVersion; import org.openrewrite.trait.Trait; import java.util.List; @@ -43,6 +46,8 @@ public class GradleDependency implements Trait { ResolvedDependency resolvedDependency; public static class Matcher extends GradleTraitMatcher { + private static final MethodMatcher DEPENDENCY_DSL_MATCHER = new MethodMatcher("DependencyHandlerSpec *(..)"); + @Nullable protected String configuration; @@ -77,13 +82,14 @@ public Matcher artifactId(@Nullable String artifactId) { return null; } - GradleProject gradleProject = getGradleProject(cursor); - if (gradleProject == null) { + if (withinDependencyConstraintsBlock(cursor)) { + // A dependency constraint is different from an actual dependency return null; } + GradleProject gradleProject = getGradleProject(cursor); GradleDependencyConfiguration gdc = getConfiguration(gradleProject, methodInvocation); - if (gdc == null) { + if (gdc == null && !(DEPENDENCY_DSL_MATCHER.matches(methodInvocation) && !"project".equals(methodInvocation.getSimpleName()))) { return null; } @@ -95,49 +101,77 @@ public Matcher artifactId(@Nullable String artifactId) { Expression argument = methodInvocation.getArguments().get(0); if (argument instanceof J.Literal || argument instanceof G.GString || argument instanceof G.MapEntry || argument instanceof G.MapLiteral) { dependency = parseDependency(methodInvocation.getArguments()); - } else if (argument instanceof J.MethodInvocation && - (((J.MethodInvocation) argument).getSimpleName().equals("platform") || - ((J.MethodInvocation) argument).getSimpleName().equals("enforcedPlatform"))) { - dependency = parseDependency(((J.MethodInvocation) argument).getArguments()); + } else if (argument instanceof J.MethodInvocation) { + if (((J.MethodInvocation) argument).getSimpleName().equals("platform") || + ((J.MethodInvocation) argument).getSimpleName().equals("enforcedPlatform")) { + dependency = parseDependency(((J.MethodInvocation) argument).getArguments()); + } else if (((J.MethodInvocation) argument).getSimpleName().equals("project")) { + // project dependencies are not yet supported + return null; + } } if (dependency == null) { return null; } - if (gdc.isCanBeResolved()) { - for (ResolvedDependency resolvedDependency : gdc.getResolved()) { - if ((groupId == null || matchesGlob(resolvedDependency.getGroupId(), groupId)) && - (artifactId == null || matchesGlob(resolvedDependency.getArtifactId(), artifactId))) { - Dependency req = resolvedDependency.getRequested(); - if ((req.getGroupId() == null || req.getGroupId().equals(dependency.getGroupId())) && - req.getArtifactId().equals(dependency.getArtifactId())) { - return new GradleDependency(cursor, resolvedDependency); + if (gdc != null) { + if (gdc.isCanBeResolved()) { + for (ResolvedDependency resolvedDependency : gdc.getResolved()) { + if ((groupId == null || matchesGlob(resolvedDependency.getGroupId(), groupId)) && + (artifactId == null || matchesGlob(resolvedDependency.getArtifactId(), artifactId))) { + Dependency req = resolvedDependency.getRequested(); + if ((req.getGroupId() == null || req.getGroupId().equals(dependency.getGroupId())) && + req.getArtifactId().equals(dependency.getArtifactId())) { + return new GradleDependency(cursor, resolvedDependency); + } } } - } - } else { - for (GradleDependencyConfiguration transitiveConfiguration : gradleProject.configurationsExtendingFrom(gdc, true)) { - if (transitiveConfiguration.isCanBeResolved()) { - for (ResolvedDependency resolvedDependency : transitiveConfiguration.getResolved()) { - if ((groupId == null || matchesGlob(resolvedDependency.getGroupId(), groupId)) && - (artifactId == null || matchesGlob(resolvedDependency.getArtifactId(), artifactId))) { - Dependency req = resolvedDependency.getRequested(); - if ((req.getGroupId() == null || req.getGroupId().equals(dependency.getGroupId())) && - req.getArtifactId().equals(dependency.getArtifactId())) { - return new GradleDependency(cursor, resolvedDependency); + } else { + for (GradleDependencyConfiguration transitiveConfiguration : gradleProject.configurationsExtendingFrom(gdc, true)) { + if (transitiveConfiguration.isCanBeResolved()) { + for (ResolvedDependency resolvedDependency : transitiveConfiguration.getResolved()) { + if ((groupId == null || matchesGlob(resolvedDependency.getGroupId(), groupId)) && + (artifactId == null || matchesGlob(resolvedDependency.getArtifactId(), artifactId))) { + Dependency req = resolvedDependency.getRequested(); + if ((req.getGroupId() == null || req.getGroupId().equals(dependency.getGroupId())) && + req.getArtifactId().equals(dependency.getArtifactId())) { + return new GradleDependency(cursor, resolvedDependency); + } } } } } } } + + if ((groupId == null || matchesGlob(dependency.getGroupId(), groupId)) && + (artifactId == null || matchesGlob(dependency.getArtifactId(), artifactId))) { + // Couldn't find the actual resolved dependency, return a virtualized one instead + ResolvedDependency resolvedDependency = ResolvedDependency.builder() + .depth(-1) + .gav(new ResolvedGroupArtifactVersion(null, dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() != null ? dependency.getVersion() : "", null)) + .classifier(dependency.getClassifier()) + .type(dependency.getExt()) + .requested(Dependency.builder() + .scope(methodInvocation.getSimpleName()) + .type(dependency.getExt()) + .gav(new GroupArtifactVersion(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion())) + .classifier(dependency.getClassifier()) + .build()) + .build(); + return new GradleDependency(cursor, resolvedDependency); + } } return null; } - private static @Nullable GradleDependencyConfiguration getConfiguration(GradleProject gradleProject, J.MethodInvocation methodInvocation) { + private static @Nullable GradleDependencyConfiguration getConfiguration(@Nullable GradleProject gradleProject, J.MethodInvocation methodInvocation) { + if (gradleProject == null) { + return null; + } + String methodName = methodInvocation.getSimpleName(); if (methodName.equals("classpath")) { return gradleProject.getBuildscript().getConfiguration(methodName); @@ -146,12 +180,12 @@ public Matcher artifactId(@Nullable String artifactId) { } } - private boolean withinDependenciesBlock(Cursor cursor) { + private boolean withinBlock(Cursor cursor, String name) { Cursor parentCursor = cursor.getParent(); while (parentCursor != null) { if (parentCursor.getValue() instanceof J.MethodInvocation) { J.MethodInvocation m = parentCursor.getValue(); - if (m.getSimpleName().equals("dependencies")) { + if (m.getSimpleName().equals(name)) { return true; } } @@ -161,6 +195,14 @@ private boolean withinDependenciesBlock(Cursor cursor) { return false; } + private boolean withinDependenciesBlock(Cursor cursor) { + return withinBlock(cursor, "dependencies"); + } + + private boolean withinDependencyConstraintsBlock(Cursor cursor) { + return withinBlock(cursor, "constraints") && withinDependenciesBlock(cursor); + } + private org.openrewrite.gradle.util.@Nullable Dependency parseDependency(List arguments) { Expression argument = arguments.get(0); if (argument instanceof J.Literal) { From cd4a37fcbf4ea33229cac6c868991ee2e0ef711e Mon Sep 17 00:00:00 2001 From: Laurens Westerlaken Date: Wed, 4 Dec 2024 10:44:32 +0100 Subject: [PATCH 003/179] Fix `JavaNamingService` license header year --- .../java/org/openrewrite/java/service/JavaNamingService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/service/JavaNamingService.java b/rewrite-java/src/main/java/org/openrewrite/java/service/JavaNamingService.java index 5f2e84e9c04..f424ce8d9de 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/service/JavaNamingService.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/service/JavaNamingService.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 the original author or authors. + * Copyright 2024 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From f9d71bc0b29404da5ac0cff2455b733de57a2433 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 4 Dec 2024 11:37:58 +0100 Subject: [PATCH 004/179] Fix multiline example in CreateYamlFile Fixes https://github.com/openrewrite/rewrite-docs/pull/328 --- .../src/main/java/org/openrewrite/yaml/CreateYamlFile.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/CreateYamlFile.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/CreateYamlFile.java index 157cb2f7db3..adbcf45ecd0 100644 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/CreateYamlFile.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/CreateYamlFile.java @@ -46,7 +46,10 @@ public class CreateYamlFile extends ScanningRecipe { @Language("yml") @Option(displayName = "File contents", description = "Multiline text content for the file.", - example = "a:\nproperty: value\nanother:\nproperty: value", + example = "a:\n" + + " property: value\n" + + "another:\n" + + " property: value", required = false) @Nullable String fileContents; From c30f37dc7d6db5c7877e50de52394bde248f9264 Mon Sep 17 00:00:00 2001 From: Laurens Westerlaken Date: Wed, 4 Dec 2024 16:49:12 +0100 Subject: [PATCH 005/179] Fix gradle/groovy parser issue with gradle 6 (#4742) --- .../main/java/org/openrewrite/groovy/GroovyParserVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 47b65310df4..60a995e7acc 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -1374,7 +1374,7 @@ public void visitConstantExpression(ConstantExpression expression) { public void visitConstructorCallExpression(ConstructorCallExpression ctor) { queue.add(insideParentheses(ctor, fmt -> { cursor += 3; // skip "new" - TypeTree clazz = visitTypeTree(ctor.getType(), ctor.getMetaDataMap().containsKey(StaticTypesMarker.INFERRED_TYPE)); + TypeTree clazz = visitTypeTree(ctor.getType(), ctor.getNodeMetaData().containsKey(StaticTypesMarker.INFERRED_TYPE)); JContainer args = visit(ctor.getArguments()); J.Block body = null; if (ctor.isUsingAnonymousInnerClass() && ctor.getType() instanceof InnerClassNode) { From efc38e3371b1713245ba4f3848e32e38541f896e Mon Sep 17 00:00:00 2001 From: Laurens Westerlaken Date: Wed, 4 Dec 2024 20:33:57 +0100 Subject: [PATCH 006/179] Take J.Case statements into account in JavaTemplate (#4744) --- .../internal/template/BlockStatementTemplateGenerator.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java index 3be2c6e2b0b..e6e13c0aff8 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java @@ -463,16 +463,17 @@ private void contextTemplate(Cursor cursor, J prior, StringBuilder before, Strin // If prior is a type parameter, wrap in __M__.anyT() // For anything else, ignore the invocation J.MethodInvocation m = (J.MethodInvocation) j; + J firstEnclosing = cursor.getParentOrThrow().firstEnclosing(J.class); if (m.getArguments().stream().anyMatch(arg -> referToSameElement(prior, arg))) { before.insert(0, "__M__.any("); - if (cursor.getParentOrThrow().firstEnclosing(J.class) instanceof J.Block) { + if (firstEnclosing instanceof J.Block || firstEnclosing instanceof J.Case) { after.append(");"); } else { after.append(")"); } } else if (m.getTypeParameters() != null && m.getTypeParameters().stream().anyMatch(tp -> referToSameElement(prior, tp))) { before.insert(0, "__M__.anyT<"); - if (cursor.getParentOrThrow().firstEnclosing(J.class) instanceof J.Block) { + if (firstEnclosing instanceof J.Block || firstEnclosing instanceof J.Case) { after.append(">();"); } else { after.append(">()"); @@ -481,7 +482,7 @@ private void contextTemplate(Cursor cursor, J prior, StringBuilder before, Strin List comments = new ArrayList<>(1); comments.add(new TextComment(true, STOP_COMMENT, "", Markers.EMPTY)); after.append(".").append(m.withSelect(null).withComments(comments).printTrimmed(cursor.getParentOrThrow())); - if (cursor.getParentOrThrow().firstEnclosing(J.class) instanceof J.Block) { + if (firstEnclosing instanceof J.Block || firstEnclosing instanceof J.Case) { after.append(";"); } } From 334b9e2d691c53f4cb9d2bc021518738f93650e5 Mon Sep 17 00:00:00 2001 From: Eason Lin Date: Tue, 3 Dec 2024 14:54:37 -0800 Subject: [PATCH 007/179] preserve annotation values when parsing compiled classes --- .../isolated/ReloadableJava11TypeMapping.java | 5 +- .../isolated/ReloadableJava17TypeMapping.java | 5 +- .../isolated/ReloadableJava21TypeMapping.java | 5 +- .../openrewrite/java/Java21ParserTest.java | 49 ++++++++++++ .../java/ReloadableJava8TypeMapping.java | 5 +- .../org/openrewrite/java/tree/JavaType.java | 79 +++++++++++++++++++ 6 files changed, 144 insertions(+), 4 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java index d0b90bea744..5130b863ac9 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java @@ -697,7 +697,10 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (retention != null && retention.value() == RetentionPolicy.SOURCE) { continue; } - annotations.add(annotType); + List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + annotations.add(annotation); } } return annotations; diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java index 7d5ad9da3f6..183270befd0 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java @@ -705,7 +705,10 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (retention != null && retention.value() == RetentionPolicy.SOURCE) { continue; } - annotations.add(annotType); + List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + annotations.add(annotation); } } return annotations; diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index 10d9b202c6f..930adb2396c 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -716,7 +716,10 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (retention != null && retention.value() == RetentionPolicy.SOURCE) { continue; } - annotations.add(annotType); + List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + annotations.add(annotation); } } return annotations; diff --git a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java index d5255503810..c6ea02f4e80 100644 --- a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java +++ b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java @@ -17,11 +17,18 @@ import org.junit.jupiter.api.Test; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.SourceFile; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; import org.openrewrite.test.RewriteTest; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; class Java21ParserTest implements RewriteTest { @@ -30,4 +37,46 @@ void shouldLoadResourceFromClasspath() throws IOException { Files.deleteIfExists(Paths.get(System.getProperty("user.home"), ".rewrite", "classpath", "jackson-annotations-2.17.1.jar")); rewriteRun(spec -> spec.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "jackson-annotations"))); } + + @Test + void testPreserveAnnotationsFromClasspath() throws IOException { + JavaParser p = JavaParser.fromJavaVersion().build(); + /** + * Using these annotations in core library for testing this feature: + * + * @Deprecated(since="1.2", forRemoval=true) + * public final void stop() + * + * @CallerSensitive + * public ClassLoader getContextClassLoader() { + */ + List sourceFiles = p.parse( + """ + class Test { + public void test() { + Thread.currentThread().stop(); + Thread.currentThread().getContextClassLoader(); + } + } + """ + ).toList(); + J.CompilationUnit cu = (J.CompilationUnit) sourceFiles.get(0); + + J.MethodDeclaration md = (J.MethodDeclaration) cu.getClasses().get(0).getBody().getStatements().get(0); + J.MethodInvocation mi = (J.MethodInvocation) md.getBody().getStatements().get(0); + JavaType.Annotation annotation = (JavaType.Annotation) mi.getMethodType().getAnnotations().get(0); + + // Thread.currentThread().stop(); + assertEquals("java.lang.Deprecated" ,annotation.type.getFullyQualifiedName()); + assertEquals("since", annotation.values.get(0).getMethod().getName()); + assertEquals("1.2", annotation.values.get(0).getValue()); + assertEquals("forRemoval", annotation.values.get(1).getMethod().getName()); + assertEquals("true", annotation.values.get(1).getValue()); + + // Thread.currentThread().getContextClassLoader(); + mi = (J.MethodInvocation) md.getBody().getStatements().get(1); + annotation = (JavaType.Annotation) mi.getMethodType().getAnnotations().get(0); + assertEquals("jdk.internal.reflect.CallerSensitive" ,annotation.type.getFullyQualifiedName()); + assertTrue(annotation.values.isEmpty()); + } } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java index 988b0920206..f1543c4a7c2 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java @@ -698,7 +698,10 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (retention != null && retention.value() == RetentionPolicy.SOURCE) { continue; } - annotations.add(annotType); + List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + annotations.add(annotation); } } return annotations; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index 112861469e8..b31befd2939 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.annotation.*; import lombok.AccessLevel; +import lombok.Data; import lombok.Getter; import lombok.With; import lombok.experimental.FieldDefaults; @@ -26,6 +27,7 @@ import org.openrewrite.internal.ListUtils; import org.openrewrite.java.internal.DefaultJavaTypeSignatureBuilder; +import java.lang.invoke.MethodType; import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; @@ -626,6 +628,83 @@ public static ShallowClass build(String fullyQualifiedName) { } } + @Data + class AnnotationValue { + private final Method method; + private final String value; + } + + class Annotation extends FullyQualified { + + public final List values; + public final FullyQualified type; + + public Annotation(FullyQualified type, List values) { + this.type = type; + this.values = values; + } + + @Override + public String getFullyQualifiedName() { + return type.getFullyQualifiedName(); + } + + @Override + public FullyQualified withFullyQualifiedName(String fullyQualifiedName) { + return null; + } + + @Override + public List getAnnotations() { + return type.getAnnotations(); + } + + @Override + public boolean hasFlags(Flag... test) { + return type.hasFlags(); + } + + @Override + public Set getFlags() { + return type.getFlags(); + } + + @Override + public List getInterfaces() { + return type.getInterfaces(); + } + + @Override + public Kind getKind() { + return type.getKind(); + } + + @Override + public List getMembers() { + return type.getMembers(); + } + + @Override + public List getMethods() { + return type.getMethods(); + } + + @Override + public List getTypeParameters() { + return type.getTypeParameters(); + } + + @Override + public @Nullable FullyQualified getOwningClass() { + return type.getOwningClass(); + } + + @Override + public @Nullable FullyQualified getSupertype() { + return type.getSupertype(); + } + } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) class Parameterized extends FullyQualified { @Getter From 8998388dcbc1195bb036fc68766edeeae3b01096 Mon Sep 17 00:00:00 2001 From: Eason Lin Date: Wed, 4 Dec 2024 13:38:59 -0800 Subject: [PATCH 008/179] use Collectors.toList() instead for compatiability and consistency --- .../openrewrite/java/isolated/ReloadableJava11TypeMapping.java | 2 +- .../openrewrite/java/isolated/ReloadableJava17TypeMapping.java | 2 +- .../openrewrite/java/isolated/ReloadableJava21TypeMapping.java | 2 +- .../java/org/openrewrite/java/ReloadableJava8TypeMapping.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java index 5130b863ac9..d8ee83901a8 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java @@ -698,7 +698,7 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { continue; } List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList()); JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); annotations.add(annotation); } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java index 183270befd0..4793fc212c5 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java @@ -706,7 +706,7 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { continue; } List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList());; JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); annotations.add(annotation); } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index 930adb2396c..645d4d1a62f 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -717,7 +717,7 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { continue; } List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList());;; JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); annotations.add(annotation); } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java index f1543c4a7c2..0195f08af26 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java @@ -699,7 +699,7 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { continue; } List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList()); JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); annotations.add(annotation); } From f9737d5a22ec5478134a1b7833cfb22a1e2664cf Mon Sep 17 00:00:00 2001 From: Eason Lin Date: Wed, 4 Dec 2024 14:58:10 -0800 Subject: [PATCH 009/179] Remove extra semi-colons Co-authored-by: Tim te Beek --- .../openrewrite/java/isolated/ReloadableJava17TypeMapping.java | 2 +- .../openrewrite/java/isolated/ReloadableJava21TypeMapping.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java index 4793fc212c5..f251137a6bf 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java @@ -706,7 +706,7 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { continue; } List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList());; + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList()); JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); annotations.add(annotation); } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index 645d4d1a62f..2b1bcc3d4f1 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -717,7 +717,7 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { continue; } List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList());;; + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList()); JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); annotations.add(annotation); } From 65303377ca57b28cd0709f068df67889ab7bee53 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Thu, 5 Dec 2024 08:34:22 +0100 Subject: [PATCH 010/179] Added a few missing `@Nullable` annotations to `JavaType` --- .../org/openrewrite/java/tree/JavaType.java | 95 ++++++++++--------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index 112861469e8..2fa596187f4 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -15,7 +15,10 @@ */ package org.openrewrite.java.tree; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import lombok.AccessLevel; import lombok.Getter; import lombok.With; @@ -102,7 +105,7 @@ public MultiCatch(@Nullable List throwableTypes) { this.throwableTypes = arrayOrNullIfEmpty(throwableTypes, EMPTY_JAVA_TYPE_ARRAY); } - MultiCatch(JavaType @Nullable[] throwableTypes) { + MultiCatch(JavaType @Nullable [] throwableTypes) { this.throwableTypes = nullIfEmpty(throwableTypes); } @@ -110,7 +113,7 @@ public MultiCatch(@Nullable List throwableTypes) { MultiCatch() { } - private JavaType[] throwableTypes; + private JavaType @Nullable [] throwableTypes; public List getThrowableTypes() { if (throwableTypes == null) { @@ -143,7 +146,7 @@ public Intersection(@Nullable List bounds) { this.bounds = arrayOrNullIfEmpty(bounds, EMPTY_JAVA_TYPE_ARRAY); } - Intersection(JavaType @Nullable[] throwableTypes) { + Intersection(JavaType @Nullable [] throwableTypes) { this.bounds = nullIfEmpty(throwableTypes); } @@ -151,7 +154,7 @@ public Intersection(@Nullable List bounds) { Intersection() { } - private JavaType[] bounds; + private JavaType @Nullable [] bounds; public List getBounds() { if (bounds == null) { @@ -320,16 +323,16 @@ public String getPackageName() { public boolean isAssignableTo(String fullyQualifiedName) { return TypeUtils.fullyQualifiedNamesAreEqual(getFullyQualifiedName(), fullyQualifiedName) || - getInterfaces().stream().anyMatch(anInterface -> anInterface.isAssignableTo(fullyQualifiedName)) || - (getSupertype() != null && getSupertype().isAssignableTo(fullyQualifiedName)); + getInterfaces().stream().anyMatch(anInterface -> anInterface.isAssignableTo(fullyQualifiedName)) || + (getSupertype() != null && getSupertype().isAssignableTo(fullyQualifiedName)); } public boolean isAssignableFrom(@Nullable JavaType type) { if (type instanceof FullyQualified) { FullyQualified clazz = (FullyQualified) type; return TypeUtils.fullyQualifiedNamesAreEqual(getFullyQualifiedName(), clazz.getFullyQualifiedName()) || - isAssignableFrom(clazz.getSupertype()) || - clazz.getInterfaces().stream().anyMatch(this::isAssignableFrom); + isAssignableFrom(clazz.getSupertype()) || + clazz.getInterfaces().stream().anyMatch(this::isAssignableFrom); } else if (type instanceof GenericTypeVariable) { GenericTypeVariable generic = (GenericTypeVariable) type; for (JavaType bound : generic.getBounds()) { @@ -372,7 +375,7 @@ class Class extends FullyQualified { Kind kind; @NonFinal - JavaType @Nullable[] typeParameters; + JavaType @Nullable [] typeParameters; @With @Nullable @@ -386,7 +389,7 @@ class Class extends FullyQualified { @NonFinal - FullyQualified @Nullable[] annotations; + FullyQualified @Nullable [] annotations; public Class(@Nullable Integer managedReference, long flagsBitMap, String fullyQualifiedName, Kind kind, @Nullable List typeParameters, @Nullable FullyQualified supertype, @Nullable FullyQualified owningClass, @@ -408,9 +411,9 @@ public Class(@Nullable Integer managedReference, long flagsBitMap, String fullyQ } Class(@Nullable Integer managedReference, long flagsBitMap, String fullyQualifiedName, - Kind kind, JavaType @Nullable[] typeParameters, @Nullable FullyQualified supertype, @Nullable FullyQualified owningClass, - FullyQualified @Nullable[] annotations, FullyQualified @Nullable[] interfaces, - Variable @Nullable[] members, Method @Nullable[] methods) { + Kind kind, JavaType @Nullable [] typeParameters, @Nullable FullyQualified supertype, @Nullable FullyQualified owningClass, + FullyQualified @Nullable [] annotations, FullyQualified @Nullable [] interfaces, + Variable @Nullable [] members, Method @Nullable [] methods) { this.managedReference = managedReference; this.flagsBitMap = flagsBitMap & Flag.VALID_CLASS_FLAGS; this.fullyQualifiedName = fullyQualifiedName; @@ -445,7 +448,7 @@ public Class withAnnotations(@Nullable List annotations) { @NonFinal - FullyQualified @Nullable[] interfaces; + FullyQualified @Nullable [] interfaces; @Override public List getInterfaces() { @@ -463,7 +466,7 @@ public Class withInterfaces(@Nullable List interfaces) { @NonFinal - Variable @Nullable[] members; + Variable @Nullable [] members; @Override public List getMembers() { @@ -481,7 +484,7 @@ public Class withMembers(@Nullable List members) { @NonFinal - Method @Nullable[] methods; + Method @Nullable [] methods; @Override public List getMethods() { @@ -554,9 +557,9 @@ public Class unsafeSet(@Nullable List typeParameters, @Nullable FullyQ return this; } - public Class unsafeSet(JavaType @Nullable[] typeParameters, @Nullable FullyQualified supertype, @Nullable FullyQualified owningClass, - FullyQualified @Nullable[] annotations, FullyQualified @Nullable[] interfaces, - Variable @Nullable[] members, Method @Nullable[] methods) { + public Class unsafeSet(JavaType @Nullable [] typeParameters, @Nullable FullyQualified supertype, @Nullable FullyQualified owningClass, + FullyQualified @Nullable [] annotations, FullyQualified @Nullable [] interfaces, + Variable @Nullable [] members, Method @Nullable [] methods) { //noinspection DuplicatedCode this.typeParameters = ListUtils.nullIfEmpty(typeParameters); this.supertype = supertype; @@ -574,7 +577,7 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Class aClass = (Class) o; return TypeUtils.fullyQualifiedNamesAreEqual(fullyQualifiedName, aClass.fullyQualifiedName) && - (typeParameters == null && aClass.typeParameters == null || typeParameters != null && Arrays.equals(typeParameters, aClass.typeParameters)); + (typeParameters == null && aClass.typeParameters == null || typeParameters != null && Arrays.equals(typeParameters, aClass.typeParameters)); } @Override @@ -639,7 +642,7 @@ class Parameterized extends FullyQualified { FullyQualified type; @NonFinal - JavaType @Nullable[] typeParameters; + JavaType @Nullable [] typeParameters; public Parameterized(@Nullable Integer managedReference, @Nullable FullyQualified type, @Nullable List typeParameters) { @@ -651,7 +654,7 @@ public Parameterized(@Nullable Integer managedReference, @Nullable FullyQualifie } Parameterized(@Nullable Integer managedReference, @Nullable FullyQualified type, - JavaType @Nullable[] typeParameters) { + JavaType @Nullable [] typeParameters) { this.managedReference = managedReference; this.type = unknownIfNull(type); this.typeParameters = nullIfEmpty(typeParameters); @@ -691,7 +694,7 @@ public Parameterized unsafeSet(@Nullable FullyQualified type, @Nullable List bounds) { this( @@ -802,7 +805,7 @@ public GenericTypeVariable(@Nullable Integer managedReference, String name, Vari ); } - GenericTypeVariable(@Nullable Integer managedReference, String name, Variance variance, JavaType @Nullable[] bounds) { + GenericTypeVariable(@Nullable Integer managedReference, String name, Variance variance, JavaType @Nullable [] bounds) { this.managedReference = managedReference; this.name = name; this.variance = variance; @@ -838,7 +841,7 @@ public GenericTypeVariable unsafeSet(String name, Variance variance, @Nullable L return this; } - public GenericTypeVariable unsafeSet(String name, Variance variance, JavaType @Nullable[] bounds) { + public GenericTypeVariable unsafeSet(String name, Variance variance, JavaType @Nullable [] bounds) { this.name = name; this.variance = variance; this.bounds = ListUtils.nullIfEmpty(bounds); @@ -851,7 +854,7 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; GenericTypeVariable that = (GenericTypeVariable) o; return name.equals(that.name) && variance == that.variance && - (variance == Variance.INVARIANT && bounds == null && that.bounds == null || bounds != null && Arrays.equals(bounds, that.bounds)); + (variance == Variance.INVARIANT && bounds == null && that.bounds == null || bounds != null && Arrays.equals(bounds, that.bounds)); } @Override @@ -879,9 +882,9 @@ class Array implements JavaType { @NonFinal - FullyQualified @Nullable[] annotations; + FullyQualified @Nullable [] annotations; - public Array(@Nullable Integer managedReference, @Nullable JavaType elemType, FullyQualified @Nullable[] annotations) { + public Array(@Nullable Integer managedReference, @Nullable JavaType elemType, FullyQualified @Nullable [] annotations) { this.managedReference = managedReference; this.elemType = unknownIfNull(elemType); this.annotations = ListUtils.nullIfEmpty(annotations); @@ -913,7 +916,7 @@ public Array unsafeSetManagedReference(Integer id) { return this; } - public Array unsafeSet(JavaType elemType, FullyQualified @Nullable[] annotations) { + public Array unsafeSet(JavaType elemType, FullyQualified @Nullable [] annotations) { this.elemType = unknownIfNull(elemType); this.annotations = ListUtils.nullIfEmpty(annotations); return this; @@ -1099,16 +1102,16 @@ class Method implements JavaType { @NonFinal - String @Nullable[] parameterNames; + String @Nullable [] parameterNames; @NonFinal - JavaType @Nullable[] parameterTypes; + JavaType @Nullable [] parameterTypes; @NonFinal - FullyQualified @Nullable[] thrownExceptions; + FullyQualified @Nullable [] thrownExceptions; @NonFinal - FullyQualified @Nullable[] annotations; + FullyQualified @Nullable [] annotations; @Incubating(since = "7.34.0") @Nullable @@ -1142,9 +1145,9 @@ public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable Fu } public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable FullyQualified declaringType, String name, - @Nullable JavaType returnType, String @Nullable[] parameterNames, - JavaType @Nullable[] parameterTypes, FullyQualified @Nullable[] thrownExceptions, - FullyQualified @Nullable[] annotations, @Nullable List defaultValue) { + @Nullable JavaType returnType, String @Nullable [] parameterNames, + JavaType @Nullable [] parameterTypes, FullyQualified @Nullable [] thrownExceptions, + FullyQualified @Nullable [] annotations, @Nullable List defaultValue) { this.managedReference = managedReference; this.flagsBitMap = flagsBitMap & Flag.VALID_FLAGS; this.declaringType = unknownIfNull(declaringType); @@ -1182,9 +1185,9 @@ public Method unsafeSet(@Nullable FullyQualified declaringType, public Method unsafeSet(@Nullable FullyQualified declaringType, @Nullable JavaType returnType, - JavaType @Nullable[] parameterTypes, - FullyQualified @Nullable[] thrownExceptions, - FullyQualified @Nullable[] annotations) { + JavaType @Nullable [] parameterTypes, + FullyQualified @Nullable [] thrownExceptions, + FullyQualified @Nullable [] annotations) { this.declaringType = unknownIfNull(declaringType); this.returnType = unknownIfNull(returnType); this.parameterTypes = ListUtils.nullIfEmpty(parameterTypes); @@ -1355,9 +1358,9 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Method method = (Method) o; return Objects.equals(declaringType, method.declaringType) && - name.equals(method.name) && - Objects.equals(returnType, method.returnType) && - Arrays.equals(parameterTypes, method.parameterTypes); + name.equals(method.name) && + Objects.equals(returnType, method.returnType) && + Arrays.equals(parameterTypes, method.parameterTypes); } @Override @@ -1393,7 +1396,7 @@ class Variable implements JavaType { JavaType type; @NonFinal - FullyQualified @Nullable[] annotations; + FullyQualified @Nullable [] annotations; public Variable(@Nullable Integer managedReference, long flagsBitMap, String name, @Nullable JavaType owner, @Nullable JavaType type, @Nullable List annotations) { @@ -1408,7 +1411,7 @@ public Variable(@Nullable Integer managedReference, long flagsBitMap, String nam } Variable(@Nullable Integer managedReference, long flagsBitMap, String name, @Nullable JavaType owner, - @Nullable JavaType type, FullyQualified @Nullable[] annotations) { + @Nullable JavaType type, FullyQualified @Nullable [] annotations) { this.managedReference = managedReference; this.flagsBitMap = flagsBitMap & Flag.VALID_FLAGS; this.name = name; From fcd9bcbc9d02075239536008bc839e76187a163a Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Thu, 5 Dec 2024 09:02:33 +0100 Subject: [PATCH 011/179] Store actual annotation values --- .../isolated/ReloadableJava21TypeMapping.java | 48 ++++++++++++------- .../openrewrite/java/Java21ParserTest.java | 2 +- .../org/openrewrite/java/tree/JavaType.java | 8 ++-- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index 2b1bcc3d4f1..dc5610a956b 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -18,6 +18,7 @@ import com.sun.source.tree.Tree; import com.sun.tools.javac.code.*; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.Pair; import lombok.RequiredArgsConstructor; import org.jspecify.annotations.Nullable; import org.openrewrite.java.JavaTypeMapping; @@ -28,8 +29,6 @@ import javax.lang.model.type.NullType; import javax.lang.model.type.TypeMirror; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -47,7 +46,7 @@ class ReloadableJava21TypeMapping implements JavaTypeMapping { public JavaType type(com.sun.tools.javac.code.@Nullable Type type) { if (type == null || type instanceof Type.ErrorType || type instanceof Type.PackageType || type instanceof Type.UnknownType || - type instanceof NullType) { + type instanceof NullType) { return JavaType.Class.Unknown.getInstance(); } @@ -423,7 +422,7 @@ public JavaType.Primitive primitive(TypeTag tag) { } private JavaType.@Nullable Variable variableType(@Nullable Symbol symbol, - JavaType.@Nullable FullyQualified owner) { + JavaType.@Nullable FullyQualified owner) { if (!(symbol instanceof Symbol.VarSymbol)) { return null; } @@ -593,15 +592,15 @@ public JavaType.Primitive primitive(TypeTag tag) { } } List defaultValues = null; - if(methodSymbol.getDefaultValue() != null) { - if(methodSymbol.getDefaultValue() instanceof Attribute.Array) { + if (methodSymbol.getDefaultValue() != null) { + if (methodSymbol.getDefaultValue() instanceof Attribute.Array) { defaultValues = ((Attribute.Array) methodSymbol.getDefaultValue()).getValue().stream() .map(attr -> attr.getValue().toString()) .collect(Collectors.toList()); } else { try { defaultValues = Collections.singletonList(methodSymbol.getDefaultValue().getValue().toString()); - } catch(UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { // not all Attribute implementations define `getValue()` } } @@ -703,25 +702,42 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { } } - private @Nullable List listAnnotations(Symbol symb) { + private @Nullable List listAnnotations(Symbol sym) { List annotations = null; - if (!symb.getDeclarationAttributes().isEmpty()) { - annotations = new ArrayList<>(symb.getDeclarationAttributes().size()); - for (Attribute.Compound a : symb.getDeclarationAttributes()) { + if (!sym.getDeclarationAttributes().isEmpty()) { + annotations = new ArrayList<>(sym.getDeclarationAttributes().size()); + for (Attribute.Compound a : sym.getDeclarationAttributes()) { JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(a.type)); if (annotType == null) { continue; } - Retention retention = a.getAnnotationType().asElement().getAnnotation(Retention.class); - if (retention != null && retention.value() == RetentionPolicy.SOURCE) { - continue; + List annotationValues = new ArrayList<>(); + for (Pair attr : a.values) { + JavaType.AnnotationValue annotationValue = new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), annotationValue(attr.snd.getValue())); + annotationValues.add(annotationValue); } - List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList()); JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); annotations.add(annotation); } } return annotations; } + + private @Nullable Object annotationValue(Object value) { + if (value instanceof Symbol.VarSymbol) { + return variableType((Symbol.VarSymbol) value); + } else if (value instanceof Attribute.Enum) { + return variableType(((Attribute.Enum) value).value); + } else if (value instanceof List) { + return ((List) value).stream().map(this::annotationValue).toList(); + } else if (value instanceof String) { + return value; + } else if (value instanceof Boolean) { + return value; + } else if (value instanceof Integer) { + return value; + } + return value; + } } diff --git a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java index c6ea02f4e80..759ea8e854b 100644 --- a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java +++ b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java @@ -71,7 +71,7 @@ public void test() { assertEquals("since", annotation.values.get(0).getMethod().getName()); assertEquals("1.2", annotation.values.get(0).getValue()); assertEquals("forRemoval", annotation.values.get(1).getMethod().getName()); - assertEquals("true", annotation.values.get(1).getValue()); + assertEquals(Boolean.TRUE, annotation.values.get(1).getValue()); // Thread.currentThread().getContextClassLoader(); mi = (J.MethodInvocation) md.getBody().getStatements().get(1); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index b31befd2939..f6d79dcedaf 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -15,7 +15,10 @@ */ package org.openrewrite.java.tree; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; import lombok.AccessLevel; import lombok.Data; import lombok.Getter; @@ -27,7 +30,6 @@ import org.openrewrite.internal.ListUtils; import org.openrewrite.java.internal.DefaultJavaTypeSignatureBuilder; -import java.lang.invoke.MethodType; import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; @@ -631,7 +633,7 @@ public static ShallowClass build(String fullyQualifiedName) { @Data class AnnotationValue { private final Method method; - private final String value; + private final @Nullable Object value; } class Annotation extends FullyQualified { From 228585e0205f2fb00aab4ebdfef011b8a00916c6 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Thu, 5 Dec 2024 09:49:54 +0100 Subject: [PATCH 012/179] Map some more annotation attribute value types --- .../isolated/ReloadableJava17TypeMapping.java | 83 ++++++++++++++----- .../isolated/ReloadableJava21TypeMapping.java | 51 ++++++++---- .../openrewrite/java/Java21ParserTest.java | 10 +-- .../openrewrite/java/JavaTypeMappingTest.java | 13 ++- .../org/openrewrite/java/tree/JavaType.java | 9 +- 5 files changed, 119 insertions(+), 47 deletions(-) diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java index f251137a6bf..411d4e5fd35 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java @@ -18,6 +18,7 @@ import com.sun.source.tree.Tree; import com.sun.tools.javac.code.*; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.Pair; import lombok.RequiredArgsConstructor; import org.jspecify.annotations.Nullable; import org.openrewrite.java.JavaTypeMapping; @@ -28,8 +29,6 @@ import javax.lang.model.type.NullType; import javax.lang.model.type.TypeMirror; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -47,7 +46,7 @@ class ReloadableJava17TypeMapping implements JavaTypeMapping { public JavaType type(com.sun.tools.javac.code.@Nullable Type type) { if (type == null || type instanceof Type.ErrorType || type instanceof Type.PackageType || type instanceof Type.UnknownType || - type instanceof NullType) { + type instanceof NullType) { return JavaType.Class.Unknown.getInstance(); } @@ -272,8 +271,8 @@ private JavaType.FullyQualified classType(Type.ClassType classType, String signa if (sym.members_field != null) { for (Symbol elem : sym.members_field.getSymbols()) { if (elem instanceof Symbol.VarSymbol && - (elem.flags_field & (Flags.SYNTHETIC | Flags.BRIDGE | Flags.HYPOTHETICAL | - Flags.GENERATEDCONSTR | Flags.ANONCONSTR)) == 0) { + (elem.flags_field & (Flags.SYNTHETIC | Flags.BRIDGE | Flags.HYPOTHETICAL | + Flags.GENERATEDCONSTR | Flags.ANONCONSTR)) == 0) { if (fqn.equals("java.lang.String") && elem.name.toString().equals("serialPersistentFields")) { // there is a "serialPersistentFields" member within the String class which is used in normal Java // serialization to customize how the String field is serialized. This field is tripping up Jackson @@ -286,7 +285,7 @@ private JavaType.FullyQualified classType(Type.ClassType classType, String signa } fields.add(variableType(elem, clazz)); } else if (elem instanceof Symbol.MethodSymbol && - (elem.flags_field & (Flags.SYNTHETIC | Flags.BRIDGE | Flags.HYPOTHETICAL | Flags.ANONCONSTR)) == 0) { + (elem.flags_field & (Flags.SYNTHETIC | Flags.BRIDGE | Flags.HYPOTHETICAL | Flags.ANONCONSTR)) == 0) { if (methods == null) { methods = new ArrayList<>(); } @@ -590,7 +589,7 @@ public JavaType.Primitive primitive(TypeTag tag) { } else { try { defaultValues = Collections.singletonList(methodSymbol.getDefaultValue().getValue().toString()); - } catch(UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { // not all Attribute implementations define `getValue()` } } @@ -692,25 +691,65 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { } } - private @Nullable List listAnnotations(Symbol symb) { + private @Nullable List listAnnotations(Symbol sym) { List annotations = null; - if (!symb.getDeclarationAttributes().isEmpty()) { - annotations = new ArrayList<>(symb.getDeclarationAttributes().size()); - for (Attribute.Compound a : symb.getDeclarationAttributes()) { - JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(a.type)); - if (annotType == null) { - continue; - } - Retention retention = a.getAnnotationType().asElement().getAnnotation(Retention.class); - if (retention != null && retention.value() == RetentionPolicy.SOURCE) { - continue; - } - List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList()); - JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + if (!sym.getDeclarationAttributes().isEmpty()) { + annotations = new ArrayList<>(sym.getDeclarationAttributes().size()); + for (Attribute.Compound a : sym.getDeclarationAttributes()) { + JavaType.Annotation annotation = annotationValue(a); + if (annotation == null) continue; annotations.add(annotation); } } return annotations; } + + private JavaType.@Nullable Annotation annotationValue(Attribute.Compound compound) { + JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(compound.type)); + if (annotType == null) { + return null; + } + List annotationValues = new ArrayList<>(); + for (Pair attr : compound.values) { + JavaType.AnnotationValue annotationValue = new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), annotationAttributeValue(attr.snd.getValue())); + annotationValues.add(annotationValue); + } + return new JavaType.Annotation(annotType, annotationValues); + } + + private @Nullable Object annotationAttributeValue(Object value) { + if (value instanceof Symbol.VarSymbol) { + return variableType((Symbol.VarSymbol) value); + } else if (value instanceof Type.ClassType) { + return type((Type.ClassType) value); + } else if (value instanceof Attribute.Array) { + List<@Nullable Object> list = new ArrayList<>(); + for (Attribute attribute : ((Attribute.Array) value).values) { + list.add(annotationAttributeValue(attribute)); + } + return list; + } else if (value instanceof Attribute.Class) { + return type(((Attribute.Class) value).classType); + } else if (value instanceof Attribute.Compound) { + return annotationValue((Attribute.Compound) value); + } else if (value instanceof Attribute.Constant) { + return annotationAttributeValue(((Attribute.Constant) value).value); + } else if (value instanceof Attribute.Enum) { + return annotationAttributeValue(((Attribute.Enum) value).value); + } else if (value instanceof List) { + List<@Nullable Object> list = new ArrayList<>(); + for (Object o : ((List) value)) { + list.add(annotationAttributeValue(o)); + } + return list; + } else if (value instanceof String) { + return value; + } else if (value instanceof Boolean) { + return value; + } else if (value instanceof Integer) { + return value; + } + return value; + } } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index dc5610a956b..51f3232487d 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -707,30 +707,53 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (!sym.getDeclarationAttributes().isEmpty()) { annotations = new ArrayList<>(sym.getDeclarationAttributes().size()); for (Attribute.Compound a : sym.getDeclarationAttributes()) { - JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(a.type)); - if (annotType == null) { - continue; - } - List annotationValues = new ArrayList<>(); - for (Pair attr : a.values) { - JavaType.AnnotationValue annotationValue = new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), annotationValue(attr.snd.getValue())); - annotationValues.add(annotationValue); - } - JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + JavaType.Annotation annotation = annotationValue(a); + if (annotation == null) continue; annotations.add(annotation); } } return annotations; } - private @Nullable Object annotationValue(Object value) { + private JavaType.@Nullable Annotation annotationValue(Attribute.Compound compound) { + JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(compound.type)); + if (annotType == null) { + return null; + } + List annotationValues = new ArrayList<>(); + for (Pair attr : compound.values) { + JavaType.AnnotationValue annotationValue = new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), annotationAttributeValue(attr.snd.getValue())); + annotationValues.add(annotationValue); + } + return new JavaType.Annotation(annotType, annotationValues); + } + + private @Nullable Object annotationAttributeValue(Object value) { if (value instanceof Symbol.VarSymbol) { return variableType((Symbol.VarSymbol) value); + } else if (value instanceof Type.ClassType) { + return type((Type.ClassType) value); + } else if (value instanceof Attribute.Array) { + List<@Nullable Object> list = new ArrayList<>(); + for (Attribute attribute : ((Attribute.Array) value).values) { + list.add(annotationAttributeValue(attribute)); + } + return list; + } else if (value instanceof Attribute.Class) { + return type(((Attribute.Class) value).classType); + } else if (value instanceof Attribute.Compound) { + return annotationValue((Attribute.Compound) value); + } else if (value instanceof Attribute.Constant) { + return annotationAttributeValue(((Attribute.Constant) value).value); } else if (value instanceof Attribute.Enum) { - return variableType(((Attribute.Enum) value).value); + return annotationAttributeValue(((Attribute.Enum) value).value); } else if (value instanceof List) { - return ((List) value).stream().map(this::annotationValue).toList(); + List<@Nullable Object> list = new ArrayList<>(); + for (Object o : ((List) value)) { + list.add(annotationAttributeValue(o)); + } + return list; } else if (value instanceof String) { return value; } else if (value instanceof Boolean) { diff --git a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java index 759ea8e854b..c1132c9ddba 100644 --- a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java +++ b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java @@ -68,15 +68,15 @@ public void test() { // Thread.currentThread().stop(); assertEquals("java.lang.Deprecated" ,annotation.type.getFullyQualifiedName()); - assertEquals("since", annotation.values.get(0).getMethod().getName()); - assertEquals("1.2", annotation.values.get(0).getValue()); - assertEquals("forRemoval", annotation.values.get(1).getMethod().getName()); - assertEquals(Boolean.TRUE, annotation.values.get(1).getValue()); + assertEquals("since", annotation.getValues().get(0).getMethod().getName()); + assertEquals("1.2", annotation.getValues().get(0).getValue()); + assertEquals("forRemoval", annotation.getValues().get(1).getMethod().getName()); + assertEquals(Boolean.TRUE, annotation.getValues().get(1).getValue()); // Thread.currentThread().getContextClassLoader(); mi = (J.MethodInvocation) md.getBody().getStatements().get(1); annotation = (JavaType.Annotation) mi.getMethodType().getAnnotations().get(0); assertEquals("jdk.internal.reflect.CallerSensitive" ,annotation.type.getFullyQualifiedName()); - assertTrue(annotation.values.isEmpty()); + assertTrue(annotation.getValues().isEmpty()); } } diff --git a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java index 591d897bfc3..a79267516d6 100644 --- a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java +++ b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java @@ -223,12 +223,17 @@ default void enumTypeB() { @Test default void ignoreSourceRetentionAnnotations() { JavaType.Parameterized goat = goatType(); - assertThat(goat.getAnnotations().size()).isEqualTo(1); - assertThat(goat.getAnnotations().get(0).getClassName()).isEqualTo("AnnotationWithRuntimeRetention"); + assertThat(goat.getAnnotations().size()).isEqualTo(2); + assertThat(goat.getAnnotations()).satisfiesExactlyInAnyOrder( + a -> assertThat(a.getClassName()).isEqualTo("AnnotationWithRuntimeRetention"), + a -> assertThat(a.getClassName()).isEqualTo("AnnotationWithSourceRetention") + ); JavaType.Method clazzMethod = methodType("clazz"); - assertThat(clazzMethod.getAnnotations().size()).isEqualTo(1); - assertThat(clazzMethod.getAnnotations().get(0).getClassName()).isEqualTo("AnnotationWithRuntimeRetention"); + assertThat(clazzMethod.getAnnotations()).satisfiesExactlyInAnyOrder( + a -> assertThat(a.getClassName()).isEqualTo("AnnotationWithRuntimeRetention"), + a -> assertThat(a.getClassName()).isEqualTo("AnnotationWithSourceRetention") + ); } @Issue("https://github.com/openrewrite/rewrite/issues/1367") diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index f6d79dcedaf..6f279172767 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -49,6 +49,7 @@ public interface JavaType { Method[] EMPTY_METHOD_ARRAY = new Method[0]; String[] EMPTY_STRING_ARRAY = new String[0]; JavaType[] EMPTY_JAVA_TYPE_ARRAY = new JavaType[0]; + AnnotationValue[] EMPTY_ANNOTATION_VALUE_ARRAY = new AnnotationValue[0]; // TODO: To be removed with OpenRewrite 9 default @Nullable Integer getManagedReference() { @@ -638,12 +639,16 @@ class AnnotationValue { class Annotation extends FullyQualified { - public final List values; + public final AnnotationValue @Nullable [] values; public final FullyQualified type; public Annotation(FullyQualified type, List values) { this.type = type; - this.values = values; + this.values = ListUtils.arrayOrNullIfEmpty(values, EMPTY_ANNOTATION_VALUE_ARRAY); + } + + public List getValues() { + return values == null ? emptyList() : Arrays.asList(values); } @Override From 0749964c10c75626c48997c57c94a71f1ba54e48 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Thu, 5 Dec 2024 10:08:22 +0100 Subject: [PATCH 013/179] Include source retention annotations for Java 1.8 and Java 11 --- .../java/isolated/ReloadableJava11TypeMapping.java | 6 ------ .../org/openrewrite/java/ReloadableJava8TypeMapping.java | 6 ------ 2 files changed, 12 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java index d8ee83901a8..93bf4a8b988 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java @@ -28,8 +28,6 @@ import javax.lang.model.type.NullType; import javax.lang.model.type.TypeMirror; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -693,10 +691,6 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (annotType == null) { continue; } - Retention retention = a.getAnnotationType().asElement().getAnnotation(Retention.class); - if (retention != null && retention.value() == RetentionPolicy.SOURCE) { - continue; - } List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList()); JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java index 0195f08af26..5cbb1690d95 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java @@ -27,8 +27,6 @@ import javax.lang.model.type.NullType; import javax.lang.model.type.TypeMirror; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -694,10 +692,6 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (annotType == null) { continue; } - Retention retention = a.getAnnotationType().asElement().getAnnotation(Retention.class); - if (retention != null && retention.value() == RetentionPolicy.SOURCE) { - continue; - } List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList()); JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); From a551727667dffa84de4d428a9f17409b732519ae Mon Sep 17 00:00:00 2001 From: Laurens Westerlaken Date: Thu, 5 Dec 2024 12:05:42 +0100 Subject: [PATCH 014/179] A `J.Case`, like `J.Block` is a scope that ends statements with a semicolon (#4749) --- .../java/internal/template/BlockStatementTemplateGenerator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java index e6e13c0aff8..e39d37b01ea 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java @@ -562,6 +562,8 @@ private void contextTemplate(Cursor cursor, J prior, StringBuilder before, Strin before.insert(0, ev.getName()); } else if (j instanceof J.EnumValueSet) { after.append(";"); + } else if (j instanceof J.Case) { + after.append(";"); } contextTemplate(next(cursor), j, before, after, insertionPoint, REPLACEMENT); } From 72793ae979620bd699ddc6e34904d6162550db8d Mon Sep 17 00:00:00 2001 From: SiBorea <108953913+SiBorea@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:46:11 +0800 Subject: [PATCH 015/179] Fix AddImport match variable's name (#4747) * Fix AddImport match variable's name * Apply formatter * Run a single test * Simplify if/else --------- Co-authored-by: Tim te Beek --- .../org/openrewrite/java/AddImportTest.java | 291 ++++++++++-------- .../java/org/openrewrite/java/AddImport.java | 26 +- 2 files changed, 183 insertions(+), 134 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java index e5b6c404e5f..d82981f8863 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java @@ -37,9 +37,7 @@ import static java.util.Collections.emptySet; import static java.util.Collections.singletonList; -import static org.openrewrite.java.Assertions.addTypesToSourceSet; -import static org.openrewrite.java.Assertions.java; -import static org.openrewrite.java.Assertions.srcMainJava; +import static org.openrewrite.java.Assertions.*; import static org.openrewrite.test.RewriteTest.toRecipe; @SuppressWarnings("rawtypes") @@ -113,7 +111,7 @@ void dontDuplicateImports() { """ import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus.Series; - + class A {} """ ) @@ -139,7 +137,7 @@ class A {} import org.junit.jupiter.api.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - + class A {} """ ) @@ -155,16 +153,16 @@ void dontDuplicateImports3() { """ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; - + import java.util.List; class A {} """, """ import static org.junit.jupiter.api.Assertions.*; - + import java.util.List; - + class A {} """ ) @@ -178,7 +176,7 @@ void dontImportYourself() { java( """ package com.myorg; - + class A { } """ @@ -241,7 +239,7 @@ void dontImportFromSamePackage() { java( """ package com.myorg; - + class B { } """ @@ -249,7 +247,7 @@ class B { java( """ package com.myorg; - + class A { } """ @@ -309,7 +307,7 @@ void addNamedImport() { java("class A {}", """ import java.util.List; - + class A {} """ ) @@ -323,7 +321,7 @@ void doNotAddImportIfNotReferenced() { java( """ package a; - + class A {} """ ) @@ -337,22 +335,22 @@ void addImportInsertsNewMiddleBlock() { java( """ package a; - + import com.sun.naming.*; - + import static java.util.Collections.*; - + class A {} """, """ package a; - + import com.sun.naming.*; - + import java.util.List; - + import static java.util.Collections.*; - + class A {} """ ) @@ -366,14 +364,14 @@ void addFirstImport() { java( """ package a; - + class A {} """, """ package a; - + import java.util.List; - + class A {} """ ) @@ -385,22 +383,22 @@ class A {} void addImportIfReferenced() { rewriteRun( spec -> spec.recipe(toRecipe(() -> - new JavaIsoVisitor<>() { - @Override - public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { - J.ClassDeclaration c = super.visitClassDeclaration(classDecl, ctx); - maybeAddImport("java.math.BigDecimal"); - maybeAddImport("java.math.RoundingMode"); - return JavaTemplate.builder("BigDecimal d = BigDecimal.valueOf(1).setScale(1, RoundingMode.HALF_EVEN);") - .imports("java.math.BigDecimal", "java.math.RoundingMode") - .build() - .apply( - updateCursor(c), - c.getBody().getCoordinates().lastStatement() - ); - } - } - ).withMaxCycles(1)), + new JavaIsoVisitor<>() { + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { + J.ClassDeclaration c = super.visitClassDeclaration(classDecl, ctx); + maybeAddImport("java.math.BigDecimal"); + maybeAddImport("java.math.RoundingMode"); + return JavaTemplate.builder("BigDecimal d = BigDecimal.valueOf(1).setScale(1, RoundingMode.HALF_EVEN);") + .imports("java.math.BigDecimal", "java.math.RoundingMode") + .build() + .apply( + updateCursor(c), + c.getBody().getCoordinates().lastStatement() + ); + } + } + ).withMaxCycles(1)), java( """ package a; @@ -410,10 +408,10 @@ class A { """, """ package a; - + import java.math.BigDecimal; import java.math.RoundingMode; - + class A { BigDecimal d = BigDecimal.valueOf(1).setScale(1, RoundingMode.HALF_EVEN); } @@ -429,7 +427,7 @@ void doNotAddWildcardImportIfNotReferenced() { java( """ package a; - + class A {} """ ) @@ -443,7 +441,7 @@ void lastImportWhenFirstClassDeclarationHasJavadoc() { java( """ import java.util.List; - + /** * My type */ @@ -451,9 +449,9 @@ class A {} """, """ import java.util.List; - + import static java.util.Collections.*; - + /** * My type */ @@ -474,9 +472,9 @@ class A {} """, """ package a; - + import java.util.List; - + class A {} """ ) @@ -516,18 +514,18 @@ public class B {} java( """ package a; - + import c.C0; import c.c.C1; import c.c.c.C2; - + class A {} """, String.format(""" package a; - + %s - + class A {} """, expectedImports.stream().map(i -> "import " + i + ";").collect(Collectors.joining("\n")) @@ -549,7 +547,7 @@ void doNotAddImportIfAlreadyExists() { java( """ package a; - + import java.util.List; class A {} """ @@ -564,7 +562,7 @@ void doNotAddImportIfCoveredByStarImport() { java( """ package a; - + import java.util.*; class A {} """ @@ -595,17 +593,17 @@ void addNamedImportIfStarStaticImportExists() { java( """ package a; - + import static java.util.List.*; class A {} """, """ package a; - + import java.util.List; - + import static java.util.List.*; - + class A {} """ ) @@ -623,9 +621,9 @@ class A {} """, """ import java.util.*; - + import static java.util.Collections.emptyList; - + class A {} """ ) @@ -640,7 +638,7 @@ void addStaticImportForUnreferencedField() { java( """ package mycompany; - + public class Type { public static String FIELD; } @@ -650,7 +648,7 @@ public class Type { "class A {}", """ import static mycompany.Type.FIELD; - + class A {} """ ) @@ -683,17 +681,17 @@ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Ex java( """ public class A { - + } """, """ import java.time.temporal.ChronoUnit; - + import static java.time.temporal.ChronoUnit.MILLIS; - + public class A { ChronoUnit unit = MILLIS; - + } """ ) @@ -708,9 +706,9 @@ void dontAddImportToStaticFieldWithNamespaceConflict() { java( """ package a; - + import java.time.temporal.ChronoUnit; - + class A { static final int MILLIS = 1; ChronoUnit unit = ChronoUnit.MILLIS; @@ -727,7 +725,7 @@ void dontAddStaticWildcardImportIfNotReferenced() { java( """ package a; - + class A {} """ ) @@ -749,9 +747,9 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu java( """ package a; - + import java.util.List; - + class A { public A() { List list = java.util.Collections.emptyList(); @@ -760,11 +758,11 @@ public A() { """, """ package a; - + import java.util.List; - + import static java.util.Collections.emptyList; - + class A { public A() { List list = emptyList(); @@ -775,6 +773,49 @@ public A() { ); } + @Test + void addNamedStaticImportWhenReferenced2() { + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new JavaIsoVisitor<>() { + @Override + public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext executionContext) { + method = super.visitMethodDeclaration(method, executionContext); + method = JavaTemplate.builder("List list = new ArrayList<>();") + .imports("java.util.ArrayList", "java.util.List") + .staticImports("java.util.Calendar.Builder") + .build() + .apply(getCursor(), method.getBody().getCoordinates().firstStatement()); + maybeAddImport("java.util.ArrayList"); + maybeAddImport("java.util.List"); + maybeAddImport("java.util.Calendar", "Builder"); + return method; + } + }).withMaxCycles(1)), + java( + """ + import static java.util.Calendar.Builder; + + class A { + public A() { + } + } + """, + """ + import java.util.ArrayList; + import java.util.List; + + import static java.util.Calendar.Builder; + + class A { + public A() { + List list = new ArrayList<>(); + } + } + """ + ) + ); + } + @Test void doNotAddNamedStaticImportIfNotReferenced() { rewriteRun( @@ -782,7 +823,7 @@ void doNotAddNamedStaticImportIfNotReferenced() { java( """ package a; - + class A {} """ ) @@ -807,9 +848,9 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu java( """ package a; - + import java.util.List; - + class A { public A() { List list = java.util.Collections.emptyList(); @@ -818,11 +859,11 @@ public A() { """, """ package a; - + import java.util.List; - + import static java.util.Collections.*; - + class A { public A() { List list = emptyList(); @@ -883,14 +924,14 @@ public class C { """ import foo.B; import foo.C; - + import java.util.Collections; import java.util.List; import java.util.HashSet; import java.util.HashMap; import java.util.Map; import java.util.Set; - + class A { B b = new B(); C c = new C(); @@ -903,7 +944,7 @@ class A { """ import foo.B; import foo.C; - + import java.util.*; class A { @@ -928,15 +969,15 @@ void addImportWhenDuplicatesExist() { """ import javax.ws.rs.Path; import javax.ws.rs.Path; - + class A {} """, """ import org.springframework.http.MediaType; - + import javax.ws.rs.Path; import javax.ws.rs.Path; - + class A {} """ ) @@ -952,15 +993,15 @@ void unorderedImportsWithNewBlock() { """ import org.foo.B; import org.foo.A; - + class A {} """, """ import org.foo.B; import org.foo.A; - + import java.time.Duration; - + class A {} """ ) @@ -981,7 +1022,7 @@ void doNotFoldNormalImportWithNamespaceConflict() { import java.util.Collections; import java.util.Map; import java.util.Set; - + @SuppressWarnings("ALL") class Test { List list; @@ -994,7 +1035,7 @@ class Test { import java.util.List; import java.util.Map; import java.util.Set; - + @SuppressWarnings("ALL") class Test { List list; @@ -1136,7 +1177,7 @@ void noImportLayout() { """, """ import java.util.List; - + import static java.util.Collections.*; """ ) @@ -1154,9 +1195,9 @@ class A {} """.replace("\n", "\r\n"), """ package a; - + import java.util.List; - + class A {} """.replace("\n", "\r\n") ) @@ -1170,17 +1211,17 @@ void crlfNewLinesWithPreviousImports() { java( """ package a; - + import java.util.Set; - + class A {} """.replace("\n", "\r\n"), """ package a; - + import java.util.List; import java.util.Set; - + class A {} """.replace("\n", "\r\n") ) @@ -1194,13 +1235,13 @@ void crlfNewLinesWithPreviousImportsNoPackage() { java( """ import java.util.Set; - + class A {} """.replace("\n", "\r\n"), """ import java.util.List; import java.util.Set; - + class A {} """.replace("\n", "\r\n") ) @@ -1214,13 +1255,13 @@ void crlfNewLinesWithPreviousImportsNoClass() { java( """ package a; - + import java.util.Arrays; import java.util.Set; """.replace("\n", "\r\n"), """ package a; - + import java.util.Arrays; import java.util.List; import java.util.Set; @@ -1269,10 +1310,10 @@ void crlfNewLinesInComments() { * limitations under the License. */ """.replace("\n", "\r\n") + - """ - import java.util.Arrays; - import java.util.Set; - """, + """ + import java.util.Arrays; + import java.util.Set; + """, """ /* * Copyright 2023 the original author or authors. @@ -1305,31 +1346,31 @@ void crlfNewLinesInJavadoc() { """ import java.util.Arrays; import java.util.Set; - + """ + - """ - /** - * Copyright 2023 the original author or authors. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * https://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - """.replace("\n", "\r\n") + - "class Foo {}", + """ + /** + * Copyright 2023 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + """.replace("\n", "\r\n") + + "class Foo {}", """ import java.util.Arrays; import java.util.List; import java.util.Set; - + /** * Copyright 2023 the original author or authors. *

diff --git a/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java b/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java index 3feff736d1c..9aecd66f89f 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java @@ -107,7 +107,7 @@ public AddImport(@Nullable String packageName, String typeName, @Nullable String // No need to add imports if the class to import is in java.lang, or if the classes are within the same package if (("java.lang".equals(packageName) && StringUtils.isBlank(member)) || (cu.getPackageDeclaration() != null && - packageName.equals(cu.getPackageDeclaration().getExpression().printTrimmed(getCursor())))) { + packageName.equals(cu.getPackageDeclaration().getExpression().printTrimmed(getCursor())))) { return cu; } @@ -119,10 +119,10 @@ public AddImport(@Nullable String packageName, String typeName, @Nullable String String ending = i.getQualid().getSimpleName(); if (member == null) { return !i.isStatic() && i.getPackageName().equals(packageName) && - (ending.equals(typeName) || "*".equals(ending)); + (ending.equals(typeName) || "*".equals(ending)); } return i.isStatic() && i.getTypeName().equals(fullyQualifiedName) && - (ending.equals(member) || "*".equals(ending)); + (ending.equals(member) || "*".equals(ending)); })) { return cu; } @@ -133,7 +133,7 @@ public AddImport(@Nullable String packageName, String typeName, @Nullable String new JLeftPadded<>(member == null ? Space.EMPTY : Space.SINGLE_SPACE, member != null, Markers.EMPTY), TypeTree.build(fullyQualifiedName + - (member == null ? "" : "." + member)).withPrefix(Space.SINGLE_SPACE), + (member == null ? "" : "." + member)).withPrefix(Space.SINGLE_SPACE), null); List> imports = new ArrayList<>(cu.getPadding().getImports()); @@ -214,7 +214,7 @@ private boolean hasReference(JavaSourceFile compilationUnit) { //Non-static imports, we just look for field accesses. for (NameTree t : FindTypes.find(compilationUnit, fullyQualifiedName)) { if ((!(t instanceof J.FieldAccess) || !((J.FieldAccess) t).isFullyQualifiedClassReference(fullyQualifiedName)) && - isTypeReference(t)) { + isTypeReference(t)) { return true; } } @@ -226,7 +226,7 @@ private boolean hasReference(JavaSourceFile compilationUnit) { if (invocation instanceof J.MethodInvocation) { J.MethodInvocation mi = (J.MethodInvocation) invocation; if (mi.getSelect() == null && - ("*".equals(member) || mi.getName().getSimpleName().equals(member))) { + ("*".equals(member) || mi.getName().getSimpleName().equals(member))) { return true; } } @@ -239,11 +239,18 @@ private boolean hasReference(JavaSourceFile compilationUnit) { } private class FindStaticFieldAccess extends JavaIsoVisitor> { + private boolean checkIsOfClassType(@Nullable JavaType type, String fullyQualifiedName) { + if (isOfClassType(type, fullyQualifiedName)) { + return true; + } + return type instanceof JavaType.Class && isOfClassType(((JavaType.Class) type).getOwningClass(), fullyQualifiedName); + } + @Override public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, AtomicReference found) { // If the type isn't used there's no need to proceed further for (JavaType.Variable varType : cu.getTypesInUse().getVariables()) { - if (varType.getName().equals(member) && isOfClassType(varType.getType(), fullyQualifiedName)) { + if (checkIsOfClassType(varType.getType(), fullyQualifiedName)) { return super.visitCompilationUnit(cu, found); } } @@ -253,8 +260,9 @@ public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, AtomicRefere @Override public J.Identifier visitIdentifier(J.Identifier identifier, AtomicReference found) { assert getCursor().getParent() != null; - if (identifier.getSimpleName().equals(member) && isOfClassType(identifier.getType(), fullyQualifiedName) && - !(getCursor().getParent().firstEnclosingOrThrow(J.class) instanceof J.FieldAccess)) { + if (identifier.getSimpleName().equals(member) && + checkIsOfClassType(identifier.getType(), fullyQualifiedName) && + !(getCursor().getParent().firstEnclosingOrThrow(J.class) instanceof J.FieldAccess)) { found.set(true); } return identifier; From 20de532a6e994b2c2cd0fdaf703284ab17bfb831 Mon Sep 17 00:00:00 2001 From: ashakirin <2254222+ashakirin@users.noreply.github.com> Date: Thu, 5 Dec 2024 13:13:22 +0100 Subject: [PATCH 016/179] feat: Added option to comment out property in yaml (#4741) * feat: Added option to comment out property in yaml Refs: #4740 * Update rewrite-yaml/src/main/java/org/openrewrite/yaml/CommentOutProperty.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update rewrite-yaml/src/main/java/org/openrewrite/yaml/CommentOutProperty.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Handle nullable Boolean correctly for usage from rewrite.yml * Drop unused default * Prevent double negation * Adopt `else if` --------- Co-authored-by: Andrei Shakirin Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tim te Beek --- .../openrewrite/yaml/CommentOutProperty.java | 70 +++++-- .../yaml/CommentOutPropertyTest.java | 192 ++++++++++++++++-- 2 files changed, 231 insertions(+), 31 deletions(-) diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/CommentOutProperty.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/CommentOutProperty.java index 83d5563bc10..8d94aa04c3b 100644 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/CommentOutProperty.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/CommentOutProperty.java @@ -17,7 +17,11 @@ import lombok.EqualsAndHashCode; import lombok.Value; -import org.openrewrite.*; +import org.jspecify.annotations.Nullable; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; import org.openrewrite.yaml.tree.Yaml; import java.util.ArrayDeque; @@ -40,6 +44,12 @@ public class CommentOutProperty extends Recipe { example = "The `foo` property is deprecated, please migrate") String commentText; + @Option(example = "true", displayName = "Comment out property", + description = "If false, property wouldn't be commented out, only comment will be added. By default, set to true", + required = false) + @Nullable + Boolean commentOutProperty; + @Override public String getDisplayName() { return "Comment out property"; @@ -61,6 +71,7 @@ public TreeVisitor getVisitor() { private boolean nextDocNeedsNewline; private String comment = ""; private String indentation = ""; + private boolean isBlockCommentExists; @Override public Yaml.Document visitDocument(Yaml.Document document, ExecutionContext ctx) { @@ -72,7 +83,7 @@ public Yaml.Document visitDocument(Yaml.Document document, ExecutionContext ctx) } // Add any leftover comment to the end of document - if (!comment.isEmpty()) { + if (!comment.isEmpty() && !Boolean.FALSE.equals(commentOutProperty)) { String newPrefix = String.format("%s# %s%s%s", indentation, commentText, @@ -89,7 +100,9 @@ public Yaml.Document visitDocument(Yaml.Document document, ExecutionContext ctx) public Yaml.Sequence.Entry visitSequenceEntry(Yaml.Sequence.Entry entry, ExecutionContext ctx) { indentation = entry.getPrefix(); - if (!comment.isEmpty()) { + if (Boolean.FALSE.equals(commentOutProperty)) { + return addBockCommentIfNecessary(entry, ctx); + } else if (!comment.isEmpty()) { // add comment and return String newPrefix = entry.getPrefix() + "# " + commentText + comment + entry.getPrefix(); comment = ""; @@ -103,20 +116,13 @@ public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry entry, ExecutionC String lastIndentation = indentation; indentation = entry.getPrefix(); - if (!comment.isEmpty()) { + if (!comment.isEmpty() && !Boolean.FALSE.equals(commentOutProperty)) { String newPrefix = entry.getPrefix() + "# " + commentText + comment + entry.getPrefix(); comment = ""; return entry.withPrefix(newPrefix); } - Deque propertyEntries = getCursor().getPathAsStream() - .filter(Yaml.Mapping.Entry.class::isInstance) - .map(Yaml.Mapping.Entry.class::cast) - .collect(Collectors.toCollection(ArrayDeque::new)); - - String prop = stream(spliteratorUnknownSize(propertyEntries.descendingIterator(), 0), false) - .map(e2 -> e2.getKey().getValue()) - .collect(Collectors.joining(".")); + String prop = calculateCurrentKeyPath(); if (prop.equals(propertyKey)) { String prefix = entry.getPrefix(); @@ -128,12 +134,50 @@ public Yaml.Mapping.Entry visitMappingEntry(Yaml.Mapping.Entry entry, ExecutionC comment = lastIndentation + "#" + entry.print(getCursor().getParentTreeCursor()); } - doAfterVisit(new DeleteProperty(propertyKey, null, null, null).getVisitor()); + if (Boolean.FALSE.equals(commentOutProperty)) { + if (!entry.getPrefix().contains(commentText) && !isBlockCommentExists) { + return entry.withPrefix(entry.getPrefix() + "# " + commentText + (entry.getPrefix().contains("\n") ? entry.getPrefix() : "\n" + entry.getPrefix())); + } + } else { + doAfterVisit(new DeleteProperty(propertyKey, null, null, null).getVisitor()); + } return entry; } return super.visitMappingEntry(entry, ctx); } + + private Yaml.Sequence.Entry addBockCommentIfNecessary(Yaml.Sequence.Entry entry, ExecutionContext ctx) { + boolean propertyExistsInSequence = isPropertyExistsInSequence(entry); + if (propertyExistsInSequence) { + isBlockCommentExists = true; + if (!entry.getPrefix().contains(commentText)) { + return entry.withPrefix(entry.getPrefix() + "# " + commentText + (entry.getPrefix().contains("\n") ? entry.getPrefix() : "\n" + entry.getPrefix())); + } + } + return super.visitSequenceEntry(entry, ctx); + } + + private boolean isPropertyExistsInSequence(Yaml.Sequence.Entry entry) { + if (!(entry.getBlock() instanceof Yaml.Mapping)) { + return false; + } + Yaml.Mapping mapping = (Yaml.Mapping) entry.getBlock(); + String prop = calculateCurrentKeyPath(); + return mapping.getEntries().stream() + .anyMatch(e -> propertyKey.equals(prop + "." + e.getKey().getValue())); + } + + private String calculateCurrentKeyPath() { + Deque propertyEntries = getCursor().getPathAsStream() + .filter(Yaml.Mapping.Entry.class::isInstance) + .map(Yaml.Mapping.Entry.class::cast) + .collect(Collectors.toCollection(ArrayDeque::new)); + + return stream(spliteratorUnknownSize(propertyEntries.descendingIterator(), 0), false) + .map(e2 -> e2.getKey().getValue()) + .collect(Collectors.joining(".")); + } }; } } diff --git a/rewrite-yaml/src/test/java/org/openrewrite/yaml/CommentOutPropertyTest.java b/rewrite-yaml/src/test/java/org/openrewrite/yaml/CommentOutPropertyTest.java index 57334b24734..9f5d7dcf239 100644 --- a/rewrite-yaml/src/test/java/org/openrewrite/yaml/CommentOutPropertyTest.java +++ b/rewrite-yaml/src/test/java/org/openrewrite/yaml/CommentOutPropertyTest.java @@ -17,24 +17,17 @@ import org.junit.jupiter.api.Test; import org.openrewrite.DocumentExample; -import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; import static org.openrewrite.yaml.Assertions.yaml; class CommentOutPropertyTest implements RewriteTest { - @Override - public void defaults(RecipeSpec spec) { - spec.recipe(new CommentOutProperty("management.metrics.binders.files.enabled", "some comments")); - } - @DocumentExample("comment out a map entry") @Test void regular() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence.propertyA", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence.propertyA", "Some comments", null)), yaml( """ foo: @@ -63,8 +56,7 @@ void regular() { @Test void commentSequence() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence", "Some comments", null)), yaml( """ foo: @@ -92,8 +84,7 @@ void commentSequence() { @Test void commentSingleProperty() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("with.java-version", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", null)), yaml( """ with: @@ -115,8 +106,7 @@ void commentSingleProperty() { @Test void commentLastPropertyWithIndent() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("with.java-version", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", null)), yaml( """ with: @@ -136,8 +126,7 @@ void commentLastPropertyWithIndent() { @Test void commentLastPropertyOfFirstDocument() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("with.java-version", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", null)), yaml( """ with: @@ -159,8 +148,7 @@ void commentLastPropertyOfFirstDocument() { @Test void commentLastProperty() { rewriteRun( - spec -> spec.recipe(new CommentOutProperty("test", - "Some comments")), + spec -> spec.recipe(new CommentOutProperty("test", "Some comments", null)), yaml( """ test: foo @@ -172,4 +160,172 @@ void commentLastProperty() { ) ); } + + @DocumentExample("comment out a map entry") + @Test + void sequenceKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence.propertyA", + "Some comments", false)), + yaml( + """ + foo: + bar: + sequence: + - name: name + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """, + """ + foo: + bar: + sequence: + - name: name + # Some comments + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """ + ) + ); + } + + @DocumentExample("comment out a map entry") + @Test + void sequenceFirstKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence.name", "Some comments", false)), + yaml( + """ + foo: + bar: + sequence: + - name: name + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """, + """ + foo: + bar: + sequence: + # Some comments + - name: name + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """ + ) + ); + } + + @DocumentExample("comment out entire sequence") + @Test + void commentSequenceKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("foo.bar.sequence", "Some comments", false)), + yaml( + """ + foo: + bar: + sequence: + - name: name + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """, + """ + foo: + bar: + # Some comments + sequence: + - name: name + - propertyA: fieldA + - propertyB: fieldB + scalar: value + """ + ) + ); + } + + @Test + void commentSinglePropertyKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", false)), + yaml( + """ + with: + java-cache: 'maven' + java-version: 11 + test: 'bar' + """, + """ + with: + java-cache: 'maven' + # Some comments + java-version: 11 + test: 'bar' + """ + ) + ); + } + + @Test + void commentLastPropertyWithIndentKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", false)), + yaml( + """ + with: + java-cache: 'maven' + java-version: 11 + """, + """ + with: + java-cache: 'maven' + # Some comments + java-version: 11 + """ + ) + ); + } + + @Test + void commentLastPropertyOfFirstDocumentKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("with.java-version", "Some comments", false)), + yaml( + """ + with: + java-cache: 'maven' + java-version: 11 + --- + """, + """ + with: + java-cache: 'maven' + # Some comments + java-version: 11 + --- + """ + ) + ); + } + + @Test + void commentLastPropertyKeepProperty() { + rewriteRun( + spec -> spec.recipe(new CommentOutProperty("test", "Some comments", false)), + yaml( + """ + test: foo + """, + """ + # Some comments + test: foo + """ + ) + ); + } } From 45f228ab15599ab292cb94019acea95a7fa1723e Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Thu, 5 Dec 2024 14:25:33 -0500 Subject: [PATCH 017/179] Fix #4705 Groovy parser does not correctly handle redundant "def" preceding declaration type --- .../groovy/GroovyParserVisitor.java | 39 +++++++++-- .../org/openrewrite/groovy/GroovyPrinter.java | 64 +++++++++++++++++++ .../groovy/marker/RedundantDef.java | 34 ++++++++++ .../groovy/tree/MethodDeclarationTest.java | 11 ++-- .../groovy/tree/VariableDeclarationsTest.java | 15 ++++- 5 files changed, 152 insertions(+), 11 deletions(-) create mode 100644 rewrite-groovy/src/main/java/org/openrewrite/groovy/marker/RedundantDef.java diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 60a995e7acc..c84f0c37856 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -110,6 +110,35 @@ private static boolean isOlderThanGroovy3() { return olderThanGroovy3; } + /** + * Groovy methods can be declared with "def" AND a return type + * In these cases the "def" is semantically meaningless but needs to be preserved for source code accuracy + * If there is both a def and a return type, this method returns a RedundantDef object and advances the cursor + * position past the "def" keyword, leaving the return type to be parsed as normal. + * In any other situation an empty Optional is returned and the cursor is not advanced. + */ + private Optional maybeRedundantDef(ClassNode type, String name) { + int saveCursor = cursor; + Space defPrefix = whitespace(); + if(source.startsWith("def", cursor)) { + skip("def"); + // The def is redundant only when it is followed by the method's return type + // I hope no one puts an annotation between "def" and the return type + int cursorBeforeReturnType = cursor; + int lengthOfTypePrefix = indexOfNextNonWhitespace(cursorBeforeReturnType, source) - cursorBeforeReturnType; + // Differentiate between the next token being the method/variable name and it being the return type + if (!source.startsWith(name, cursorBeforeReturnType + lengthOfTypePrefix)) { + TypeTree returnType = visitTypeTree(type); + if (source.startsWith(returnType.toString(), cursorBeforeReturnType + lengthOfTypePrefix)) { + cursor = cursorBeforeReturnType; + return Optional.of(new RedundantDef(randomId(), defPrefix)); + } + } + } + cursor = saveCursor; + return Optional.empty(); + } + public G.CompilationUnit visit(SourceUnit unit, ModuleNode ast) throws GroovyParsingException { NavigableMap> sortedByPosition = new TreeMap<>(); for (org.codehaus.groovy.ast.stmt.Statement s : ast.getStatementBlock().getStatements()) { @@ -510,7 +539,7 @@ public void visitMethod(MethodNode method) { .collect(Collectors.toList()); List modifiers = visitModifiers(method.getModifiers()); - + Optional redundantDef = maybeRedundantDef(method.getReturnType(), method.getName()); TypeTree returnType = visitTypeTree(method.getReturnType()); // Method name might be in quotes @@ -589,7 +618,8 @@ null, emptyList(), bodyVisitor.visit(method.getCode()); queue.add(new J.MethodDeclaration( - randomId(), fmt, Markers.EMPTY, + randomId(), fmt, + redundantDef.map(Markers.EMPTY::add).orElse(Markers.EMPTY), annotations, modifiers, null, @@ -1411,12 +1441,13 @@ public void visitNotExpression(NotExpression expression) { @Override public void visitDeclarationExpression(DeclarationExpression expression) { + Optional redundantDef = maybeRedundantDef(expression.getVariableExpression().getType(), expression.getVariableExpression().getName()); TypeTree typeExpr = visitVariableExpressionType(expression.getVariableExpression()); J.VariableDeclarations.NamedVariable namedVariable; if (expression.isMultipleAssignmentDeclaration()) { // def (a, b) = [1, 2] - throw new UnsupportedOperationException("FIXME"); + throw new UnsupportedOperationException("Parsing multiple assignment (e.g.: def (a, b) = [1, 2]) is not implemented"); } else { J.Identifier name = visit(expression.getVariableExpression()); namedVariable = new J.VariableDeclarations.NamedVariable( @@ -1439,7 +1470,7 @@ public void visitDeclarationExpression(DeclarationExpression expression) { J.VariableDeclarations variableDeclarations = new J.VariableDeclarations( randomId(), EMPTY, - Markers.EMPTY, + redundantDef.map(Markers.EMPTY::add).orElse(Markers.EMPTY), emptyList(), emptyList(), typeExpr, diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java index 223036f95c2..e0d462843cb 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java @@ -25,6 +25,7 @@ import org.openrewrite.groovy.tree.GRightPadded; import org.openrewrite.groovy.tree.GSpace; import org.openrewrite.java.JavaPrinter; +import org.openrewrite.java.marker.CompactConstructor; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Marker; import org.openrewrite.marker.Markers; @@ -258,6 +259,36 @@ public J visitTypeCast(J.TypeCast t, PrintOutputCapture

p) { return t; } + + @Override + public J visitVariableDeclarations(J.VariableDeclarations multiVariable, PrintOutputCapture

p) { + beforeSyntax(multiVariable, Space.Location.VARIABLE_DECLARATIONS_PREFIX, p); + visitSpace(Space.EMPTY, Space.Location.ANNOTATIONS, p); + visit(multiVariable.getLeadingAnnotations(), p); + for (J.Modifier m : multiVariable.getModifiers()) { + visitModifier(m, p); + } + multiVariable.getMarkers().findFirst(RedundantDef.class).ifPresent(def -> { + visitSpace(def.getPrefix(), Space.Location.LANGUAGE_EXTENSION, p); + p.append("def"); + }); + visit(multiVariable.getTypeExpression(), p); + // For backwards compatibility. + for (JLeftPadded dim : multiVariable.getDimensionsBeforeName()) { + visitSpace(dim.getBefore(), Space.Location.DIMENSION_PREFIX, p); + p.append('['); + visitSpace(dim.getElement(), Space.Location.DIMENSION, p); + p.append(']'); + } + if (multiVariable.getVarargs() != null) { + visitSpace(multiVariable.getVarargs(), Space.Location.VARARGS, p); + p.append("..."); + } + visitRightPadded(multiVariable.getPadding().getVariables(), JRightPadded.Location.NAMED_VARIABLE, ",", p); + afterSyntax(multiVariable, p); + return multiVariable; + } + @Override public J visitLambda(J.Lambda lambda, PrintOutputCapture

p) { beforeSyntax(lambda, Space.Location.LAMBDA_PREFIX, p); @@ -327,6 +358,39 @@ public J visitForEachLoop(J.ForEachLoop forEachLoop, PrintOutputCapture

p) { afterSyntax(forEachLoop, p); return forEachLoop; } + @Override + public J visitMethodDeclaration(J.MethodDeclaration method, PrintOutputCapture

p) { + beforeSyntax(method, Space.Location.METHOD_DECLARATION_PREFIX, p); + visitSpace(Space.EMPTY, Space.Location.ANNOTATIONS, p); + visit(method.getLeadingAnnotations(), p); + for (J.Modifier m : method.getModifiers()) { + visitModifier(m, p); + } + J.TypeParameters typeParameters = method.getAnnotations().getTypeParameters(); + if (typeParameters != null) { + visit(typeParameters.getAnnotations(), p); + visitSpace(typeParameters.getPrefix(), Space.Location.TYPE_PARAMETERS, p); + visitMarkers(typeParameters.getMarkers(), p); + p.append('<'); + visitRightPadded(typeParameters.getPadding().getTypeParameters(), JRightPadded.Location.TYPE_PARAMETER, ",", p); + p.append('>'); + } + method.getMarkers().findFirst(RedundantDef.class).ifPresent(def -> { + visitSpace(def.getPrefix(), Space.Location.LANGUAGE_EXTENSION, p); + p.append("def"); + }); + visit(method.getReturnTypeExpression(), p); + visit(method.getAnnotations().getName().getAnnotations(), p); + visit(method.getName(), p); + if (!method.getMarkers().findFirst(CompactConstructor.class).isPresent()) { + visitContainer("(", method.getPadding().getParameters(), JContainer.Location.METHOD_DECLARATION_PARAMETERS, ",", ")", p); + } + visitContainer("throws", method.getPadding().getThrows(), JContainer.Location.THROWS, ",", null, p); + visit(method.getBody(), p); + visitLeftPadded("default", method.getPadding().getDefaultValue(), JLeftPadded.Location.METHOD_DECLARATION_DEFAULT_VALUE, p); + afterSyntax(method, p); + return method; + } @Override public J visitMethodInvocation(J.MethodInvocation method, PrintOutputCapture

p) { diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/marker/RedundantDef.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/marker/RedundantDef.java new file mode 100644 index 00000000000..34157a68d97 --- /dev/null +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/marker/RedundantDef.java @@ -0,0 +1,34 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.groovy.marker; + +import lombok.Value; +import lombok.With; +import org.openrewrite.java.tree.Space; +import org.openrewrite.marker.Marker; + +import java.util.UUID; + +/** + * In Groovy methods can be declared with a return type and also a redundant 'def' keyword. + * This captures the extra def keyword. + */ +@Value +@With +public class RedundantDef implements Marker { + UUID id; + Space prefix; +} diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java index 1963ef2db08..ff2bf380095 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java @@ -15,7 +15,6 @@ */ package org.openrewrite.groovy.tree; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openrewrite.Issue; import org.openrewrite.java.JavaIsoVisitor; @@ -182,16 +181,16 @@ void escapedMethodNameWithSpacesTest() { } @Issue("https://github.com/openrewrite/rewrite/issues/4705") - @Disabled @Test void functionWithDefAndExplicitReturnType() { rewriteRun( groovy( - """ - class A { - def int one() { 1 } - } """ + class A { + def /*int*/ int one() { 1 } + def /*Object*/ Object two() { 2 } + } + """ ) ); } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java index 3915c6c39f8..9a2efcf03bd 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java @@ -32,7 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.openrewrite.groovy.Assertions.groovy; -@SuppressWarnings({"GroovyUnusedAssignment", "DataFlowIssue"}) +@SuppressWarnings({"GroovyUnusedAssignment", "DataFlowIssue", "GrUnnecessaryDefModifier"}) class VariableDeclarationsTest implements RewriteTest { @Test @@ -203,4 +203,17 @@ class A { ) ); } + + @Issue("https://github.com/openrewrite/rewrite/issues/4705") + @Test + void defAndExplicitReturnType() { + rewriteRun( + groovy( + """ + def /*int*/ int one = 1 + def /*Object*/ Object two = 2 + """ + ) + ); + } } From 7013518939404119722f36bbf390e50343826aac Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Fri, 6 Dec 2024 10:26:26 +0100 Subject: [PATCH 018/179] Support variable expressions in parenthesis (#4751) --- .../groovy/GroovyParserVisitor.java | 216 ++++++++---------- .../openrewrite/groovy/tree/BinaryTest.java | 22 +- .../org/openrewrite/groovy/tree/CastTest.java | 25 ++ .../groovy/tree/MethodInvocationTest.java | 46 ++++ .../openrewrite/groovy/tree/RangeTest.java | 15 ++ .../openrewrite/groovy/tree/TernaryTest.java | 4 +- .../java/org/openrewrite/java/tree/Space.java | 8 +- 7 files changed, 204 insertions(+), 132 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index c84f0c37856..b710c0c78cc 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -36,7 +36,9 @@ import org.openrewrite.internal.ListUtils; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.ImplicitReturn; +import org.openrewrite.java.marker.OmitParentheses; import org.openrewrite.java.marker.Semicolon; +import org.openrewrite.java.marker.TrailingComma; import org.openrewrite.java.tree.*; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.Statement; @@ -247,16 +249,7 @@ private class RewriteGroovyClassVisitor extends ClassCodeVisitorSupport { @Override public void visitClass(ClassNode clazz) { Space fmt = whitespace(); - List leadingAnnotations; - if (clazz.getAnnotations().isEmpty()) { - leadingAnnotations = emptyList(); - } else { - leadingAnnotations = new ArrayList<>(clazz.getAnnotations().size()); - for (AnnotationNode annotation : clazz.getAnnotations()) { - visitAnnotation(annotation); - leadingAnnotations.add(pollQueue()); - } - } + List leadingAnnotations = visitAndGetAnnotations(clazz); List modifiers = visitModifiers(clazz.getModifiers()); Space kindPrefix = whitespace(); @@ -344,13 +337,13 @@ J.Block visitClassBlock(ClassNode clazz) { } } for (org.codehaus.groovy.ast.stmt.Statement objectInitializer : clazz.getObjectInitializerStatements()) { - if(!(objectInitializer instanceof BlockStatement)) { + if (!(objectInitializer instanceof BlockStatement)) { continue; } // A class initializer BlockStatement will be wrapped in an otherwise empty BlockStatement with the same source positions // No idea why, except speculation that it is for consistency with static intiializers, but we can skip the wrapper and just visit its contents BlockStatement s = (BlockStatement) objectInitializer; - if(s.getStatements().size() == 1 && pos(s).equals(pos(s.getStatements().get(0)))) { + if (s.getStatements().size() == 1 && pos(s).equals(pos(s.getStatements().get(0)))) { s = (BlockStatement) s.getStatements().get(0); } sortedByPosition.computeIfAbsent(pos(s), i -> new ArrayList<>()) @@ -441,13 +434,7 @@ private void visitEnumField(@SuppressWarnings("unused") FieldNode fieldNode) { private void visitVariableField(FieldNode field) { RewriteGroovyVisitor visitor = new RewriteGroovyVisitor(field, this); - List annotations = field.getAnnotations().stream() - .map(a -> { - visitAnnotation(a); - return (J.Annotation) pollQueue(); - }) - .collect(Collectors.toList()); - + List annotations = visitAndGetAnnotations(field); List modifiers = visitModifiers(field.getModifiers()); TypeTree typeExpr = visitTypeTree(field.getOriginType()); @@ -531,13 +518,7 @@ argName, padLeft(sourceBefore("="), bodyVisitor.visit(arg.getValue())), public void visitMethod(MethodNode method) { Space fmt = whitespace(); - List annotations = method.getAnnotations().stream() - .map(a -> { - visitAnnotation(a); - return (J.Annotation) pollQueue(); - }) - .collect(Collectors.toList()); - + List annotations = visitAndGetAnnotations(method); List modifiers = visitModifiers(method.getModifiers()); Optional redundantDef = maybeRedundantDef(method.getReturnType(), method.getName()); TypeTree returnType = visitTypeTree(method.getReturnType()); @@ -568,12 +549,7 @@ public void visitMethod(MethodNode method) { for (int i = 0; i < unparsedParams.length; i++) { Parameter param = unparsedParams[i]; - List paramAnnotations = param.getAnnotations().stream() - .map(a -> { - visitAnnotation(a); - return (J.Annotation) pollQueue(); - }) - .collect(Collectors.toList()); + List paramAnnotations = visitAndGetAnnotations(param); TypeTree paramType; if (param.isDynamicTyped()) { @@ -634,50 +610,39 @@ null, emptyList(), } @Override - public void visitConstructor(ConstructorNode ctor) { + public void visitConstructor(ConstructorNode constructor) { Space fmt = whitespace(); - List annotations = ctor.getAnnotations().stream() - .map(a -> { - visitAnnotation(a); - return (J.Annotation) pollQueue(); - }) - .collect(Collectors.toList()); - - List modifiers = visitModifiers(ctor.getModifiers()); + List annotations = visitAndGetAnnotations(constructor); + List modifiers = visitModifiers(constructor.getModifiers()); // Constructor name might be in quotes Space namePrefix = whitespace(); - String ctorName; - if (source.startsWith(ctor.getDeclaringClass().getName(), cursor)) { - ctorName = ctor.getDeclaringClass().getName(); + String constructorName; + if (source.startsWith(constructor.getDeclaringClass().getName(), cursor)) { + constructorName = constructor.getDeclaringClass().getName(); } else { char openingQuote = source.charAt(cursor); - ctorName = openingQuote + ctor.getName() + openingQuote; + constructorName = openingQuote + constructor.getName() + openingQuote; } - cursor += ctorName.length(); + cursor += constructorName.length(); J.Identifier name = new J.Identifier(randomId(), namePrefix, Markers.EMPTY, emptyList(), - ctorName, + constructorName, null, null); - RewriteGroovyVisitor bodyVisitor = new RewriteGroovyVisitor(ctor, this); + RewriteGroovyVisitor bodyVisitor = new RewriteGroovyVisitor(constructor, this); // Parameter has no visit implementation, so we've got to do this by hand Space beforeParen = sourceBefore("("); - List> params = new ArrayList<>(ctor.getParameters().length); - Parameter[] unparsedParams = ctor.getParameters(); + List> params = new ArrayList<>(constructor.getParameters().length); + Parameter[] unparsedParams = constructor.getParameters(); for (int i = 0; i < unparsedParams.length; i++) { Parameter param = unparsedParams[i]; - List paramAnnotations = param.getAnnotations().stream() - .map(a -> { - visitAnnotation(a); - return (J.Annotation) pollQueue(); - }) - .collect(Collectors.toList()); + List paramAnnotations = visitAndGetAnnotations(param); TypeTree paramType; if (param.isDynamicTyped()) { @@ -712,14 +677,14 @@ null, emptyList(), params.add(JRightPadded.build(new J.Empty(randomId(), sourceBefore(")"), Markers.EMPTY))); } - JContainer throws_ = ctor.getExceptions().length == 0 ? null : JContainer.build( + JContainer throws_ = constructor.getExceptions().length == 0 ? null : JContainer.build( sourceBefore("throws"), - bodyVisitor.visitRightPadded(ctor.getExceptions(), null), + bodyVisitor.visitRightPadded(constructor.getExceptions(), null), Markers.EMPTY ); - J.Block body = ctor.getCode() == null ? null : - bodyVisitor.visit(ctor.getCode()); + J.Block body = constructor.getCode() == null ? null : + bodyVisitor.visit(constructor.getCode()); queue.add(new J.MethodDeclaration( randomId(), fmt, Markers.EMPTY, @@ -732,10 +697,23 @@ null, emptyList(), throws_, body, null, - typeMapping.methodType(ctor) + typeMapping.methodType(constructor) )); } + public List visitAndGetAnnotations(AnnotatedNode node) { + if (node.getAnnotations().isEmpty()) { + return emptyList(); + } + + List paramAnnotations = new ArrayList<>(node.getAnnotations().size()); + for (AnnotationNode annotationNode : node.getAnnotations()) { + visitAnnotation(annotationNode); + paramAnnotations.add(pollQueue()); + } + return paramAnnotations; + } + @SuppressWarnings({"ConstantConditions", "unchecked"}) private T pollQueue() { return (T) queue.poll(); @@ -763,14 +741,14 @@ private List> visitRightPadded(ASTNode[] nodes, @Nullable St List> ts = new ArrayList<>(nodes.length); for (int i = 0; i < nodes.length; i++) { ASTNode node = nodes[i]; - @SuppressWarnings("unchecked") JRightPadded converted = JRightPadded.build( - node instanceof ClassNode ? (T) visitTypeTree((ClassNode) node) : visit(node)); + @SuppressWarnings("unchecked") + JRightPadded converted = JRightPadded.build(node instanceof ClassNode ? (T) visitTypeTree((ClassNode) node) : visit(node)); if (i == nodes.length - 1) { converted = converted.withAfter(whitespace()); if (',' == source.charAt(cursor)) { // In Groovy trailing "," are allowed cursor += 1; - converted = converted.withMarkers(Markers.EMPTY.add(new org.openrewrite.java.marker.TrailingComma(randomId(), whitespace()))); + converted = converted.withMarkers(Markers.EMPTY.add(new TrailingComma(randomId(), whitespace()))); } ts.add(converted); if (afterLast != null && source.startsWith(afterLast, cursor)) { @@ -827,11 +805,11 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { int saveCursor = cursor; Space beforeOpenParen = whitespace(); - org.openrewrite.java.marker.OmitParentheses omitParentheses = null; + OmitParentheses omitParentheses = null; if (source.charAt(cursor) == '(') { cursor++; } else { - omitParentheses = new org.openrewrite.java.marker.OmitParentheses(randomId()); + omitParentheses = new OmitParentheses(randomId()); beforeOpenParen = EMPTY; cursor = saveCursor; } @@ -861,9 +839,8 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { // If it is wrapped in "[]" then this isn't a named arguments situation, and we should not lift the parameters out of the enclosing MapExpression saveCursor = cursor; whitespace(); - boolean isOpeningBracketPresent = '[' == source.charAt(cursor); cursor = saveCursor; - if (!isOpeningBracketPresent) { + if ('[' != source.charAt(cursor)) { // Bring named parameters out of their containing MapExpression so that they can be parsed correctly MapExpression namedArgExpressions = (MapExpression) unparsedArgs.get(0); unparsedArgs = @@ -894,7 +871,7 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { after = whitespace(); if (source.charAt(cursor) == ')') { // the next argument will have an OmitParentheses marker - omitParentheses = new org.openrewrite.java.marker.OmitParentheses(randomId()); + omitParentheses = new OmitParentheses(randomId()); } cursor++; } @@ -1102,7 +1079,7 @@ public void visitBlockStatement(BlockStatement block) { J expr = visit(statement); if (i == blockStatements.size() - 1 && (expr instanceof Expression)) { if (parent instanceof ClosureExpression || (parent instanceof MethodNode && - !JavaType.Primitive.Void.equals(typeMapping.type(((MethodNode) parent).getReturnType())))) { + !JavaType.Primitive.Void.equals(typeMapping.type(((MethodNode) parent).getReturnType())))) { expr = new J.Return(randomId(), expr.getPrefix(), Markers.EMPTY, expr.withPrefix(EMPTY)); expr = expr.withMarkers(expr.getMarkers().add(new ImplicitReturn(randomId()))); @@ -1688,7 +1665,6 @@ public void visitMapExpression(MapExpression map) { @Override public void visitMethodCallExpression(MethodCallExpression call) { queue.add(insideParentheses(call, fmt -> { - ImplicitDot implicitDot = null; JRightPadded select = null; if (!call.isImplicitThis()) { @@ -1763,30 +1739,14 @@ public void visitMethodCallExpression(MethodCallExpression call) { } } } - // handle the obscure case where there are empty parens ahead of a closure - if (args.getExpressions().size() == 1 && args.getExpressions().get(0) instanceof ClosureExpression) { - int saveCursor = cursor; - Space argPrefix = whitespace(); - if (source.charAt(cursor) == '(') { - cursor += 1; - Space infix = whitespace(); - if (source.charAt(cursor) == ')') { - cursor += 1; - markers = markers.add(new EmptyArgumentListPrecedesArgument(randomId(), argPrefix, infix)); - } else { - cursor = saveCursor; - } - } else { - cursor = saveCursor; - } - } + markers = handlesCaseWhereEmptyParensAheadOfClosure(args, markers); } JContainer args = visit(call.getArguments()); MethodNode methodNode = (MethodNode) call.getNodeMetaData().get(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET); JavaType.Method methodType = null; if (methodNode == null && call.getObjectExpression() instanceof VariableExpression && - ((VariableExpression) call.getObjectExpression()).getAccessedVariable() != null) { + ((VariableExpression) call.getObjectExpression()).getAccessedVariable() != null) { // Groovy doesn't know what kind of object this method is being invoked on // But if this invocation is inside a Closure we may have already enriched its parameters with types from the static type checker // Use any such type information to attempt to find a matching method @@ -1867,23 +1827,7 @@ public void visitStaticMethodCallExpression(StaticMethodCallExpression call) { } } } - // handle the obscure case where there are empty parens ahead of a closure - if (args.getExpressions().size() == 1 && args.getExpressions().get(0) instanceof ClosureExpression) { - int saveCursor = cursor; - Space prefix = whitespace(); - if (source.charAt(cursor) == '(') { - cursor += 1; - Space infix = whitespace(); - if (source.charAt(cursor) == ')') { - cursor += 1; - markers = markers.add(new EmptyArgumentListPrecedesArgument(randomId(), prefix, infix)); - } else { - cursor = saveCursor; - } - } else { - cursor = saveCursor; - } - } + markers = handlesCaseWhereEmptyParensAheadOfClosure(args, markers); } JContainer args = visit(call.getArguments()); @@ -2014,11 +1958,11 @@ public void visitTupleExpression(TupleExpression tuple) { int saveCursor = cursor; Space beforeOpenParen = whitespace(); - org.openrewrite.java.marker.OmitParentheses omitParentheses = null; + OmitParentheses omitParentheses = null; if (source.charAt(cursor) == '(') { cursor++; } else { - omitParentheses = new org.openrewrite.java.marker.OmitParentheses(randomId()); + omitParentheses = new OmitParentheses(randomId()); beforeOpenParen = EMPTY; cursor = saveCursor; } @@ -2042,7 +1986,7 @@ public void visitTupleExpression(TupleExpression tuple) { after = whitespace(); if (source.charAt(cursor) == ')') { // the next argument will have an OmitParentheses marker - omitParentheses = new org.openrewrite.java.marker.OmitParentheses(randomId()); + omitParentheses = new OmitParentheses(randomId()); } cursor++; } @@ -2078,7 +2022,6 @@ public void visitTryCatchFinally(TryCatchStatement node) { //noinspection ConstantConditions queue.add(new J.Try(randomId(), prefix, Markers.EMPTY, resources, body, catches, finally_)); - } @Override @@ -2167,19 +2110,21 @@ public TypeTree visitVariableExpressionType(VariableExpression expression) { @Override public void visitVariableExpression(VariableExpression expression) { - JavaType type; - if (expression.isDynamicTyped() && expression.getAccessedVariable() != null && expression.getAccessedVariable().getType() != expression.getOriginType()) { - type = typeMapping.type(staticType(expression.getAccessedVariable())); - } else { - type = typeMapping.type(staticType((org.codehaus.groovy.ast.expr.Expression) expression)); - } - queue.add(new J.Identifier(randomId(), - sourceBefore(expression.getName()), - Markers.EMPTY, - emptyList(), - expression.getName(), - type, null) - ); + queue.add(insideParentheses(expression, fmt -> { + JavaType type; + if (expression.isDynamicTyped() && expression.getAccessedVariable() != null && expression.getAccessedVariable().getType() != expression.getOriginType()) { + type = typeMapping.type(staticType(expression.getAccessedVariable())); + } else { + type = typeMapping.type(staticType((org.codehaus.groovy.ast.expr.Expression) expression)); + } + + return new J.Identifier(randomId(), + fmt.withWhitespace(fmt.getWhitespace() + sourceBefore(expression.getName()).getWhitespace()), + Markers.EMPTY, + emptyList(), + expression.getName(), + type, null); + })); } @Override @@ -2231,6 +2176,27 @@ private T pollQueue() { } } + // handle the obscure case where there are empty parens ahead of a closure + private Markers handlesCaseWhereEmptyParensAheadOfClosure(ArgumentListExpression args, Markers markers) { + if (args.getExpressions().size() == 1 && args.getExpressions().get(0) instanceof ClosureExpression) { + int saveCursor = cursor; + Space argPrefix = whitespace(); + if (source.charAt(cursor) == '(') { + cursor += 1; + Space infix = whitespace(); + if (source.charAt(cursor) == ')') { + cursor += 1; + markers = markers.add(new EmptyArgumentListPrecedesArgument(randomId(), argPrefix, infix)); + } else { + cursor = saveCursor; + } + } else { + cursor = saveCursor; + } + } + return markers; + } + private JRightPadded convertTopLevelStatement(SourceUnit unit, ASTNode node) { if (node instanceof ClassNode) { ClassNode classNode = (ClassNode) node; @@ -2459,6 +2425,10 @@ private TypeTree mapDimensions(TypeTree baseType, ClassNode classNode) { return baseType; } + /** + * Get all characters of the source file between the cursor and the given delimiter. + * The cursor will be moved past the delimiter. + */ private Space sourceBefore(String untilDelim) { int delimIndex = positionOfNext(untilDelim); if (delimIndex < 0) { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java index 2d2675bfe72..13239c0fc76 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java @@ -34,7 +34,9 @@ void insideParentheses() { // NOT inside parentheses, but verifies the parser's // test for "inside parentheses" condition - groovy("(1) + 1") + groovy("(1) + 1"), + // And combine the two cases + groovy("((1) + 1)") ); } @@ -62,6 +64,19 @@ void in() { ); } + @Test + void withVariable() { + rewriteRun( + groovy( + """ + def foo(int a) { + 60 + a + } + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/1531") @Test void regexFindOperator() { @@ -201,17 +216,12 @@ void stringMultipliedInParentheses() { ); } - @Disabled @Issue("https://github.com/openrewrite/rewrite/issues/4703") @Test void extraParensAroundInfixOperator() { rewriteRun( groovy( """ - def foo(Map map) { - ((map.containsKey("foo")) - && ((map.get("foo")).equals("bar"))) - } def timestamp(int hours, int minutes, int seconds) { (hours) * 60 * 60 + (minutes * 60) + seconds } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java index e5fc6a0cb95..5cf82ae85be 100755 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java @@ -16,6 +16,7 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -79,6 +80,18 @@ void groovyCastAndInvokeMethod() { ); } + @Test + @ExpectedToFail("Parentheses with method invocation is not yet supported") + void groovyCastAndInvokeMethodWithParentheses() { + rewriteRun( + groovy( + """ + (((((( "" as String ))))).toString()) + """ + ) + ); + } + @Test void javaCastAndInvokeMethod() { rewriteRun( @@ -89,4 +102,16 @@ void javaCastAndInvokeMethod() { ) ); } + + @ExpectedToFail("Parentheses with method invocation is not yet supported") + @Test + void javaCastAndInvokeMethodWithParentheses() { + rewriteRun( + groovy( + """ + (((((( (String) "" )).toString())))) + """ + ) + ); + } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java index e22c1e08d46..cd5ea56bed3 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java @@ -16,6 +16,7 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -45,6 +46,22 @@ void gradle() { ); } + @ExpectedToFail("Parentheses with method invocation is not yet supported") + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4615") + void gradleWithParentheses() { + rewriteRun( + groovy( + """ + plugins { + id 'java-library' + } + def version = (rootProject.jobName.startsWith('a')) ? "latest.release" : "3.0" + """ + ) + ); + } + @Test void emptyArgsWithParens() { rewriteRun( @@ -262,4 +279,33 @@ static void main(String[] args) { ) ); } + + @ExpectedToFail("Parentheses with method invocation is not yet supported") + @Issue("https://github.com/openrewrite/rewrite/issues/4703") + @Test + void insideParentheses() { + rewriteRun( + groovy( + """ + static def foo(Map map) { + ((map.containsKey("foo")) + && ((map.get("foo")).equals("bar"))) + } + """ + ) + ); + } + + @ExpectedToFail("Parentheses with method invocation is not yet supported") + @Issue("https://github.com/openrewrite/rewrite/issues/4703") + @Test + void insideParenthesesWithoutNewLineAndEscapedMethodName() { + rewriteRun( + groovy( + """ + static def foo(Map someMap) {((((((someMap.get("(bar")))) ).'equals' "baz" ) ) } + """ + ) + ); + } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java index bdea313eb33..ac839e34d88 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java @@ -16,6 +16,7 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.test.RewriteTest; import static org.openrewrite.groovy.Assertions.groovy; @@ -46,4 +47,18 @@ void parenthesized() { ) ); } + + @ExpectedToFail("Parentheses with method invocation is not yet supported") + @Test + void parenthesizedAndInvokeMethodWithParentheses() { + rewriteRun( + groovy( + """ + (((( 8..19 ))).each { majorVersion -> + if (majorVersion == 9) return + }) + """ + ) + ); + } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/TernaryTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/TernaryTest.java index 09ef3f92b64..bb6bfb5fb4a 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/TernaryTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/TernaryTest.java @@ -31,7 +31,9 @@ void insideParentheses() { // NOT inside parentheses, but verifies the parser's // test for "inside parentheses" condition - groovy("(true) ? 1 : 2") + groovy("(true) ? 1 : 2"), + // And combine the two cases + groovy("((true) ? 1 : 2)") ); } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java index 129a0eee381..834fb6b6800 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java @@ -286,13 +286,17 @@ public String toString() { printedWs.append(spaces[(i - lastNewline) % 10]); } else if (c == '\t') { printedWs.append(tabs[(i - lastNewline) % 10]); + } else { + // should never happen (probably a bug in the parser) + printedWs.append(c); } } } + String whitespaces = printedWs.toString(); return "Space(" + - "comments=<" + (comments.size() == 1 ? "1 comment" : comments.size() + " comments") + - ">, whitespace='" + printedWs + "')"; + "comments=<" + (comments.size() == 1 ? "1 comment" : comments.size() + " comments") + ">, " + + "whitespace=" + (whitespaces.isEmpty() ? "" : "'" + whitespaces + "'") + ")"; } public enum Location { From e571da7baba822d1fc66dc8269a96379eb0c1097 Mon Sep 17 00:00:00 2001 From: amishra-u <119983081+amishra-u@users.noreply.github.com> Date: Fri, 6 Dec 2024 03:09:12 -0800 Subject: [PATCH 019/179] Update get classpath by artifact name to support bazel (#4750) * Update get classpath by artifact name to support bazel * Remove string concatenation and add `else` for clarity --------- Co-authored-by: Tim te Beek --- .../org/openrewrite/java/JavaParserTest.java | 20 +++++++ .../java/org/openrewrite/java/JavaParser.java | 54 ++++++++++++------- 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java index 03c6a38ee89..ccfe243aec1 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java @@ -29,8 +29,10 @@ import org.openrewrite.test.RewriteTest; import java.io.IOException; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; import java.util.stream.Stream; @@ -214,4 +216,22 @@ class A { ) ); } + + @Test + void filterArtifacts() { + List classpath = List.of( + URI.create("file:/.m2/repository/com/google/guava/guava-24.1.1/com_google_guava_guava-24.1.1.jar"), + URI.create("file:/.m2/repository/org/threeten/threeten-extra-1.5.0/org_threeten_threeten_extra-1.5.0.jar"), + URI.create("file:/.m2/repository/com/amazonaws/aws-java-sdk-s3-1.11.546/com_amazonaws_aws_java_sdk_s3-1.11.546.jar"), + URI.create("file:/.m2/repository/org/openrewrite/rewrite-java/8.41.1/rewrite-java-8.41.1.jar") + ); + assertThat(JavaParser.filterArtifacts("threeten-extra", classpath)) + .containsOnly(Paths.get("/.m2/repository/org/threeten/threeten-extra-1.5.0/org_threeten_threeten_extra-1.5.0.jar")); + assertThat(JavaParser.filterArtifacts("guava", classpath)) + .containsOnly(Paths.get("/.m2/repository/com/google/guava/guava-24.1.1/com_google_guava_guava-24.1.1.jar")); + assertThat(JavaParser.filterArtifacts("aws-java-sdk-s3", classpath)) + .containsOnly(Paths.get("/.m2/repository/com/amazonaws/aws-java-sdk-s3-1.11.546/com_amazonaws_aws_java_sdk_s3-1.11.546.jar")); + assertThat(JavaParser.filterArtifacts("rewrite-java", classpath)) + .containsOnly(Paths.get("/.m2/repository/org/openrewrite/rewrite-java/8.41.1/rewrite-java-8.41.1.jar")); + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaParser.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaParser.java index 98913cb04a7..066da57e0fb 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaParser.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaParser.java @@ -74,26 +74,11 @@ static List dependenciesFromClasspath(String... artifactNames) { List artifacts = new ArrayList<>(artifactNames.length); List missingArtifactNames = new ArrayList<>(artifactNames.length); for (String artifactName : artifactNames) { - Pattern jarPattern = Pattern.compile(artifactName + "(?:" + "-.*?" + ")?" + "\\.jar$"); - // In a multi-project IDE classpath, some classpath entries aren't jars - Pattern explodedPattern = Pattern.compile("/" + artifactName + "/"); - boolean lacking = true; - for (URI cpEntry : runtimeClasspath) { - if (!"file".equals(cpEntry.getScheme())) { - // exclude any `jar` entries which could result from `Bundle-ClassPath` in `MANIFEST.MF` - continue; - } - String cpEntryString = cpEntry.toString(); - Path path = Paths.get(cpEntry); - if (jarPattern.matcher(cpEntryString).find() || - explodedPattern.matcher(cpEntryString).find() && path.toFile().isDirectory()) { - artifacts.add(path); - lacking = false; - // Do not break because jarPattern matches "foo-bar-1.0.jar" and "foo-1.0.jar" to "foo" - } - } - if (lacking) { + List matchedArtifacts = filterArtifacts(artifactName, runtimeClasspath); + if (matchedArtifacts.isEmpty()) { missingArtifactNames.add(artifactName); + } else { + artifacts.addAll(matchedArtifacts); } } @@ -107,6 +92,37 @@ static List dependenciesFromClasspath(String... artifactNames) { return artifacts; } + /** + * Filters the classpath entries to find paths that match the given artifact name. + * + * @param artifactName The artifact name to search for. + * @param runtimeClasspath The list of classpath URIs to search within. + * @return List of Paths that match the artifact name. + */ + // VisibleForTesting + static List filterArtifacts(String artifactName, List runtimeClasspath) { + List artifacts = new ArrayList<>(); + // Bazel automatically replaces '-' with '_' when generating jar files. + String normalizedArtifactName = artifactName.replace('-', '_'); + Pattern jarPattern = Pattern.compile(String.format("(%s|%s)(?:-.*?)?\\.jar$", artifactName, normalizedArtifactName)); + // In a multi-project IDE classpath, some classpath entries aren't jars + Pattern explodedPattern = Pattern.compile("/" + artifactName + "/"); + for (URI cpEntry : runtimeClasspath) { + if (!"file".equals(cpEntry.getScheme())) { + // exclude any `jar` entries which could result from `Bundle-ClassPath` in `MANIFEST.MF` + continue; + } + String cpEntryString = cpEntry.toString(); + Path path = Paths.get(cpEntry); + if (jarPattern.matcher(cpEntryString).find() || + explodedPattern.matcher(cpEntryString).find() && path.toFile().isDirectory()) { + artifacts.add(path); + // Do not break because jarPattern matches "foo-bar-1.0.jar" and "foo-1.0.jar" to "foo" + } + } + return artifacts; + } + static List dependenciesFromResources(ExecutionContext ctx, String... artifactNamesWithVersions) { if (artifactNamesWithVersions.length == 0) { return Collections.emptyList(); From 4c0f0cab953dcfff64b4bad022b1caab55b91816 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Fri, 6 Dec 2024 12:19:47 +0100 Subject: [PATCH 020/179] IncrementProjectVersion should only update matching old version --- .../maven/IncrementProjectVersion.java | 8 ++-- .../maven/IncrementProjectVersionTest.java | 42 +++++++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/IncrementProjectVersion.java b/rewrite-maven/src/main/java/org/openrewrite/maven/IncrementProjectVersion.java index 780127619be..b1513956dfa 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/IncrementProjectVersion.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/IncrementProjectVersion.java @@ -165,12 +165,14 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { return t; } String newVersion = acc.get(new GroupArtifact( - t.getChildValue("groupId").orElse(null), t.getChildValue("artifactId").orElse(null))); - if (newVersion == null || newVersion.equals(t.getChildValue("version").orElse(null))) { + t.getChildValue("groupId").orElse(null), + t.getChildValue("artifactId").orElse(null))); + String oldVersion = t.getChildValue("version").orElse(null); + if (newVersion == null || newVersion.equals(oldVersion)) { return t; } t = t.withMarkers(t.getMarkers().add(new AlreadyIncremented(randomId()))); - return (Xml.Tag) new ChangeTagValue("version", null, newVersion).getVisitor() + return (Xml.Tag) new ChangeTagValue("version", oldVersion, newVersion).getVisitor() .visitNonNull(t, ctx); } }; diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/IncrementProjectVersionTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/IncrementProjectVersionTest.java index 9e68f1f8cea..4198418ee22 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/IncrementProjectVersionTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/IncrementProjectVersionTest.java @@ -35,18 +35,54 @@ public void defaults(RecipeSpec spec) { void changeProjectVersion() { rewriteRun( pomXml( - """ + """ + + org.openrewrite + rewrite-maven + 8.40.1-SNAPSHOT + + """, + """ org.openrewrite rewrite-maven - 8.40.1-SNAPSHOT + 8.41.0-SNAPSHOT - """, + """ + ) + ); + } + + @Test + void changeProjectVersionShouldNotUpdateDependencyVersion() { + rewriteRun( + pomXml( + """ + + org.openrewrite + rewrite-maven + 8.40.1-SNAPSHOT + + + com.google.guava + guava + 29.0-jre + + + + """, """ org.openrewrite rewrite-maven 8.41.0-SNAPSHOT + + + com.google.guava + guava + 29.0-jre + + """ ) From 4e723d8c7327d8fc3f41eefe5dae38cacd57ddd4 Mon Sep 17 00:00:00 2001 From: anthochristen <34420055+anthochristen@users.noreply.github.com> Date: Fri, 6 Dec 2024 18:14:39 +0530 Subject: [PATCH 021/179] Add RegExp support to ChangeTagValue recipe (#4733) * Add ability to change value using RegExp * Add regex login in separate visitor * Fix formatting * Limit new public API by using a nested dedicated `RegexReplaceVisitor` * Add test for missed case * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: Antho Durairaj Co-authored-by: Tim te Beek Co-authored-by: Tim te Beek Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../maven/IncrementProjectVersion.java | 4 +- .../org/openrewrite/xml/ChangeTagValue.java | 83 ++++- .../openrewrite/xml/ChangeTagValueTest.java | 314 ++++++++++++++++++ .../xml/ChangeTagValueVisitorTest.java | 20 ++ 4 files changed, 409 insertions(+), 12 deletions(-) create mode 100755 rewrite-xml/src/test/java/org/openrewrite/xml/ChangeTagValueTest.java diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/IncrementProjectVersion.java b/rewrite-maven/src/main/java/org/openrewrite/maven/IncrementProjectVersion.java index b1513956dfa..af1691941b7 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/IncrementProjectVersion.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/IncrementProjectVersion.java @@ -172,8 +172,8 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { return t; } t = t.withMarkers(t.getMarkers().add(new AlreadyIncremented(randomId()))); - return (Xml.Tag) new ChangeTagValue("version", oldVersion, newVersion).getVisitor() - .visitNonNull(t, ctx); + return (Xml.Tag) new ChangeTagValue("version", oldVersion, newVersion, null) + .getVisitor().visitNonNull(t, ctx); } }; } diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/ChangeTagValue.java b/rewrite-xml/src/main/java/org/openrewrite/xml/ChangeTagValue.java index 0773c33abba..254fb705ed7 100644 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/ChangeTagValue.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/ChangeTagValue.java @@ -18,12 +18,16 @@ import lombok.EqualsAndHashCode; import lombok.Value; import org.jspecify.annotations.Nullable; -import org.openrewrite.ExecutionContext; -import org.openrewrite.Option; -import org.openrewrite.Recipe; -import org.openrewrite.TreeVisitor; +import org.openrewrite.*; +import org.openrewrite.marker.AlreadyReplaced; +import org.openrewrite.marker.Markers; import org.openrewrite.xml.tree.Xml; +import java.util.regex.Pattern; + +import static java.util.Collections.singletonList; +import static org.openrewrite.Tree.randomId; + @Value @EqualsAndHashCode(callSuper = false) public class ChangeTagValue extends Recipe { @@ -34,17 +38,24 @@ public class ChangeTagValue extends Recipe { String elementName; @Option(displayName = "Old value", - description = "The old value of the tag.", + description = "The old value of the tag. Interpreted as pattern if regex is enabled.", required = false, example = "user") @Nullable String oldValue; @Option(displayName = "New value", - description = "The new value for the tag.", + description = "The new value for the tag. Supports capture groups when regex is enabled. " + + "If literal $,\\ characters are needed in newValue, with regex true, then it should be escaped.", example = "user") String newValue; + @Option(displayName = "Regex", + description = "Default false. If true, `oldValue` will be interpreted as a [Regular Expression](https://en.wikipedia.org/wiki/Regular_expression), and capture group contents will be available in `newValue`.", + required = false) + @Nullable + Boolean regex; + @Override public String getDisplayName() { return "Change XML tag value"; @@ -52,7 +63,15 @@ public String getDisplayName() { @Override public String getDescription() { - return "Alters the value of XML tags matching the provided expression."; + return "Alters the value of XML tags matching the provided expression. " + + "When regex is enabled the replacement happens only for text nodes provided the pattern matches."; + } + + @Override + public Validated validate(ExecutionContext ctx) { + //noinspection ConstantValue + return super.validate(ctx).and(Validated.test("regex", "Regex usage requires an `oldValue`", regex, + value -> value == null || oldValue != null && !oldValue.equals(newValue))); } @Override @@ -63,9 +82,9 @@ public TreeVisitor getVisitor() { @Override public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) { if (xPathMatcher.matches(getCursor())) { - // if either no oldValue is supplied OR oldValue equals the value of this tag - // then change the value to the newValue supplied - if (oldValue == null || oldValue.equals(tag.getValue().orElse(null))) { + if (Boolean.TRUE.equals(regex) && oldValue != null) { + doAfterVisit(new RegexReplaceVisitor<>(tag, oldValue, newValue)); + } else if (oldValue == null || oldValue.equals(tag.getValue().orElse(null))) { doAfterVisit(new ChangeTagValueVisitor<>(tag, newValue)); } } @@ -73,4 +92,48 @@ public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) { } }; } + + /** + * This visitor finds and replaces text within a specified XML tag. + * It supports both literal and regular expression replacements. + * Use {@link ChangeTagValueVisitor} if you only wish change the value, irrespective of current data. + * + * @param

+ */ + @Value + @EqualsAndHashCode(callSuper = false) + static class RegexReplaceVisitor

extends XmlVisitor

{ + + Xml.Tag scope; + String oldValue; + String newValue; + + @Override + public Xml visitTag(Xml.Tag tag, P p) { + Xml.Tag t = (Xml.Tag) super.visitTag(tag, p); + if (scope.isScope(t) && + t.getContent() != null && + t.getContent().size() == 1 && + t.getContent().get(0) instanceof Xml.CharData) { + return updateUsingRegex(t, (Xml.CharData) t.getContent().get(0)); + } + return t; + } + + private Xml.Tag updateUsingRegex(Xml.Tag t, Xml.CharData content) { + String text = content.getText(); + if (Pattern.compile(oldValue).matcher(text).find()) { + Markers oldMarkers = content.getMarkers(); + if (oldMarkers + .findAll(AlreadyReplaced.class) + .stream() + .noneMatch(m -> m.getFind().equals(oldValue) && newValue.equals(m.getReplace()))) { + return t.withContent(singletonList(content + .withText(text.replaceAll(oldValue, newValue)) + .withMarkers(oldMarkers.add(new AlreadyReplaced(randomId(), oldValue, newValue))))); + } + } + return t; + } + } } diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/ChangeTagValueTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/ChangeTagValueTest.java new file mode 100755 index 00000000000..aaa97e84ae6 --- /dev/null +++ b/rewrite-xml/src/test/java/org/openrewrite/xml/ChangeTagValueTest.java @@ -0,0 +1,314 @@ +/* + * Copyright 2020 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.xml; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.ExecutionContext; +import org.openrewrite.test.RewriteTest; +import org.openrewrite.xml.tree.Xml; + +import static java.util.Objects.requireNonNull; +import static org.openrewrite.test.RewriteTest.toRecipe; +import static org.openrewrite.xml.Assertions.xml; + +class ChangeTagValueTest implements RewriteTest { + + @DocumentExample + @Test + void rewriteEmptyTagValue() { + rewriteRun( + spec -> spec.recipe( + new ChangeTagValue("/dependency/version", + null, "2.0", null)), + xml( + """ + + + + """, + """ + + 2.0 + + """) + ); + } + + @Test + void matchExistingTagValue() { + rewriteRun( + spec -> spec.recipe( + new ChangeTagValue("/dependency/version", + "1.0", "2.0", null)), + xml( + """ + + 1.0 + + """, + """ + + 2.0 + + """) + ); + } + + @Test + void noMatchExistingTagValue() { + rewriteRun( + spec -> spec.recipe( + new ChangeTagValue("/dependency/version", + "1.0", "2.0", null)), + xml( + """ + + 3.0 + + """) + ); + } + + @Test + void rewriteTagValueSubstring() { + rewriteRun( + spec -> spec.recipe( + new ChangeTagValue("/dependency/version", + "SNAPSHOT", "RELEASE", true) + ), + xml( + """ + + com.company.project + artifact + 1.2.3-SNAPSHOT + + """, + """ + + com.company.project + artifact + 1.2.3-RELEASE + + """ + ) + ); + } + + + @Test + void appendTagValue() { + rewriteRun( + spec -> spec.recipe( + new ChangeTagValue("/dependency/version", + "$", "-RELEASE", true) + ), + xml( + """ + + com.company.project + artifact + 1.2.3 + + """, + """ + + com.company.project + artifact + 1.2.3-RELEASE + + """ + ) + ); + } + + + @Test + void replaceWithCapturingGroups() { + rewriteRun( + spec -> spec.recipe( + new ChangeTagValue("/dependency/version", + "(\\d).(\\d).(\\d)", "$1.$3.4", true) + ), + xml( + """ + + com.company.project + artifact + 1.2.3 + + """, + """ + + com.company.project + artifact + 1.3.4 + + """ + ) + ); + } + + @Test + void replacedExactlyOnce() { + rewriteRun( + spec -> spec.recipe(new ChangeTagValue( + "/tag", + "(aaa)", + "$1-aaa", + true)), + xml( + "aaa", + "aaa-aaa" + ) + ); + } + + @Nested + class FindAndReplaceTagTextVisitorTest { + + @Test + void findAndReplace() { + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new XmlVisitor<>() { + @Override + public Xml visitDocument(Xml.Document x, ExecutionContext ctx) { + doAfterVisit(new ChangeTagValue.RegexReplaceVisitor<>( + (Xml.Tag) requireNonNull(x.getRoot().getContent()).get(0), + "2.0", + "3.0") + ); + return super.visitDocument(x, ctx); + } + })), + xml( + """ + + + 2.0 + + + """, + """ + + + 3.0 + + + """ + ) + ); + } + + @Test + void changeContentSubstring() { + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new XmlVisitor<>() { + @Override + public Xml visitDocument(Xml.Document x, ExecutionContext ctx) { + doAfterVisit(new ChangeTagValue.RegexReplaceVisitor<>( + requireNonNull(x.getRoot()), + "SNAPSHOT", + "RELEASE") + ); + return super.visitDocument(x, ctx); + } + })), + xml( + "1.2.3-SNAPSHOT", + "1.2.3-RELEASE" + ) + ); + } + + @Test + void doNothingIfPatternDoesNotMatch() { + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new XmlVisitor<>() { + @Override + public Xml visitDocument(Xml.Document x, ExecutionContext ctx) { + doAfterVisit(new ChangeTagValue.RegexReplaceVisitor<>( + (Xml.Tag) requireNonNull(x.getRoot().getContent()).get(0), + "7.0", + "8.0") + ); + return super.visitDocument(x, ctx); + } + })), + xml( + """ + + + + + + + """ + ) + ); + } + + @Test + void doNothingForNonTextNotFound() { + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new XmlVisitor<>() { + @Override + public Xml visitDocument(Xml.Document x, ExecutionContext ctx) { + doAfterVisit(new ChangeTagValue.RegexReplaceVisitor<>( + (Xml.Tag) requireNonNull(x.getRoot().getContent()).get(0), + "7.0", + "8.0") + ); + return super.visitDocument(x, ctx); + } + })), + xml( + """ + + 2.0 + + """ + ) + ); + } + + @Test + void skipsChildIfNotText() { + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new XmlVisitor<>() { + @Override + public Xml visitDocument(Xml.Document x, ExecutionContext ctx) { + doAfterVisit(new ChangeTagValue.RegexReplaceVisitor<>( + (Xml.Tag) requireNonNull(x.getRoot().getContent()).get(0), + "invalid", + "2.0") + ); + return super.visitDocument(x, ctx); + } + })), + xml( + """ + + + + """ + ) + ); + } + } +} diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/ChangeTagValueVisitorTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/ChangeTagValueVisitorTest.java index 8d844e515bc..808c19e7eb2 100755 --- a/rewrite-xml/src/test/java/org/openrewrite/xml/ChangeTagValueVisitorTest.java +++ b/rewrite-xml/src/test/java/org/openrewrite/xml/ChangeTagValueVisitorTest.java @@ -53,6 +53,26 @@ public Xml visitDocument(Xml.Document x, ExecutionContext ctx) { ); } + @Test + void noChangeIfAlreadyPresent() { + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new XmlVisitor<>() { + @Override + public Xml visitDocument(Xml.Document x, ExecutionContext ctx) { + doAfterVisit(new ChangeTagValueVisitor<>((Xml.Tag) requireNonNull(x.getRoot().getContent()).get(0), "2.0")); + return super.visitDocument(x, ctx); + } + })), + xml( + """ + + 2.0 + + """ + ) + ); + } + @Test void preserveOriginalFormatting() { rewriteRun( From 14a077615075480faa2a2d111a855dbc4290937d Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Thu, 5 Dec 2024 10:08:22 +0100 Subject: [PATCH 022/179] Include source retention annotations for Java 1.8 and Java 11 --- .../openrewrite/java/JavaTypeMappingTest.java | 1 - .../JavaReflectionTypeMappingTest.java | 19 ++++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java index a79267516d6..3dc8d562eef 100644 --- a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java +++ b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java @@ -223,7 +223,6 @@ default void enumTypeB() { @Test default void ignoreSourceRetentionAnnotations() { JavaType.Parameterized goat = goatType(); - assertThat(goat.getAnnotations().size()).isEqualTo(2); assertThat(goat.getAnnotations()).satisfiesExactlyInAnyOrder( a -> assertThat(a.getClassName()).isEqualTo("AnnotationWithRuntimeRetention"), a -> assertThat(a.getClassName()).isEqualTo("AnnotationWithSourceRetention") diff --git a/rewrite-java/src/test/java/org/openrewrite/java/internal/JavaReflectionTypeMappingTest.java b/rewrite-java/src/test/java/org/openrewrite/java/internal/JavaReflectionTypeMappingTest.java index e858ccbceef..6c2e192fac9 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/internal/JavaReflectionTypeMappingTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/internal/JavaReflectionTypeMappingTest.java @@ -22,9 +22,11 @@ import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.TypeUtils; +import static org.assertj.core.api.Assertions.assertThat; + @SuppressWarnings("ConstantConditions") class JavaReflectionTypeMappingTest implements JavaTypeMappingTest { - JavaReflectionTypeMapping typeMapping = new JavaReflectionTypeMapping(new JavaTypeCache()); + JavaReflectionTypeMapping typeMapping = new JavaReflectionTypeMapping(new AdaptiveRadixJavaTypeCache()); JavaType.Parameterized goat = TypeUtils.asParameterized(typeMapping.type(JavaTypeGoat.class)); @Override @@ -56,4 +58,19 @@ public void enumTypeA() { @Override public void enumTypeB() { } + + @Test + @Override + public void ignoreSourceRetentionAnnotations() { + JavaType.Parameterized goat = goatType(); + assertThat(goat.getAnnotations()).satisfiesExactlyInAnyOrder( + a -> assertThat(a.getClassName()).isEqualTo("AnnotationWithRuntimeRetention") + ); + + JavaType.Method clazzMethod = methodType("clazz"); + assertThat(clazzMethod.getAnnotations()).satisfiesExactlyInAnyOrder( + a -> assertThat(a.getClassName()).isEqualTo("AnnotationWithRuntimeRetention") + ); + } + } From 104f7053f2c89358ec036441e2be507c34edd4aa Mon Sep 17 00:00:00 2001 From: Niels de Bruin Date: Fri, 6 Dec 2024 14:46:00 +0100 Subject: [PATCH 023/179] Add initial support for java references for yaml (#4698) * Add initial support for java references for yaml scalars * Add incubation annotation * Add extra test * Add rename support in YamlReference * Add NullMarked Package info * Restrict to application files and rename provider * Fix paths in tests * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Knut Wannheden * Minimize diff between Yaml and Properties type references --------- Co-authored-by: Tim te Beek Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Knut Wannheden --- .../openrewrite/java/ChangePackageTest.java | 69 ++++++++---- .../org/openrewrite/java/ChangeTypeTest.java | 25 +++++ .../org/openrewrite/java/TypeMatcher.java | 1 - .../properties/trait/PropertiesReference.java | 18 ++- .../openrewrite/yaml/trait/YamlReference.java | 105 ++++++++++++++++++ .../openrewrite/yaml/trait/package-info.java | 21 ++++ .../java/org/openrewrite/yaml/tree/Yaml.java | 28 ++++- .../org.openrewrite.trait.Reference$Provider | 1 + .../yaml/trait/YamlReferenceTest.java | 96 ++++++++++++++++ 9 files changed, 329 insertions(+), 35 deletions(-) create mode 100644 rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java create mode 100644 rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/package-info.java create mode 100644 rewrite-yaml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider create mode 100644 rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/ChangePackageTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/ChangePackageTest.java index 39ca3ed049e..5419f7c5be6 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/ChangePackageTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/ChangePackageTest.java @@ -32,6 +32,7 @@ import static org.openrewrite.java.Assertions.java; import static org.openrewrite.properties.Assertions.properties; import static org.openrewrite.xml.Assertions.xml; +import static org.openrewrite.yaml.Assertions.yaml; @SuppressWarnings("ConstantConditions") class ChangePackageTest implements RewriteTest { @@ -430,11 +431,11 @@ class A { } """, """ - import org.openrewrite.test.other.Test; - class A { - Test test = null; - } - """, + import org.openrewrite.test.other.Test; + class A { + Test test = null; + } + """, spec -> spec.afterRecipe(cu -> { assertThat(cu.findType("org.openrewrite.other.Test")).isEmpty(); assertThat(cu.findType("org.openrewrite.test.other.Test")).isNotEmpty(); @@ -488,11 +489,11 @@ class A { } """, """ - import org.openrewrite.test.other.Test; - class A { - Test test = null; - } - """, + import org.openrewrite.test.other.Test; + class A { + Test test = null; + } + """, spec -> spec.afterRecipe(cu -> { assertThat(cu.findType("org.openrewrite.other.Test")).isEmpty(); assertThat(cu.findType("org.openrewrite.test.other.Test")).isNotEmpty(); @@ -546,11 +547,11 @@ class A { } """, """ - import org.openrewrite.test.other.Test; - class A { - Test test = null; - } - """, + import org.openrewrite.test.other.Test; + class A { + Test test = null; + } + """, spec -> spec.afterRecipe(cu -> { assertThat(cu.findType("org.openrewrite.other.Test")).isEmpty(); assertThat(cu.findType("org.openrewrite.test.other.Test")).isNotEmpty(); @@ -705,7 +706,7 @@ void method() {} void annotationArgument() { rewriteRun( java( - """ + """ package org.openrewrite; public class Argument {} """, @@ -757,7 +758,7 @@ void method() {} void annotationArgumentNamed() { rewriteRun( java( - """ + """ package org.openrewrite; public class Argument {} """, @@ -807,7 +808,7 @@ void method() {} void annotationArgumentFullyQualified() { rewriteRun( java( - """ + """ package org.openrewrite; public class Argument {} """, @@ -855,7 +856,7 @@ void method() {} void annotationArgumentNamedFullyQualified() { rewriteRun( java( - """ + """ package org.openrewrite; public class Argument {} """, @@ -1439,7 +1440,7 @@ void staticImport() { java( """ import static org.openrewrite.Test.stat; - + public class B { public void test() { stat(); @@ -1448,7 +1449,7 @@ public void test() { """, """ import static org.openrewrite.test.Test.stat; - + public class B { public void test() { stat(); @@ -1724,7 +1725,6 @@ void changePackageInSpringXml() { """ ) ); - } @Test @@ -1741,7 +1741,30 @@ void changeTypeInPropertiesFile() { a.property=java.cool.String b.property=java.cool.test.String c.property=String - """, spec -> spec.path("application.properties")) + """, + spec -> spec.path("application.properties")) + ); + } + + @Test + void changePackageInYaml() { + rewriteRun( + spec -> spec.recipe(new ChangePackage("java.lang", "java.cool", true)), + yaml( + """ + root: + a: java.lang.String + b: java.lang.test.String + c: String + """, + """ + root: + a: java.cool.String + b: java.cool.test.String + c: String + """, + spec -> spec.path("application.yaml") + ) ); } } diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java index 487e56e4a8e..ad20be88dc7 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java @@ -31,6 +31,7 @@ import static org.openrewrite.java.Assertions.java; import static org.openrewrite.properties.Assertions.properties; import static org.openrewrite.xml.Assertions.xml; +import static org.openrewrite.yaml.Assertions.yaml; @SuppressWarnings("ConstantConditions") class ChangeTypeTest implements RewriteTest { @@ -2079,4 +2080,28 @@ void changeTypeInPropertiesFile() { """, spec -> spec.path("application.properties")) ); } + + @Test + void changeTypeInYaml() { + rewriteRun( + spec -> spec.recipe(new ChangeType("java.lang.String", "java.lang.Integer", true)), + yaml( + """ + root: + a: java.lang.String + b: java.lang.StringBuilder + c: java.lang.test.String + d: String + """, + """ + root: + a: java.lang.Integer + b: java.lang.StringBuilder + c: java.lang.test.String + d: String + """, + spec -> spec.path("application.yaml") + ) + ); + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java b/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java index 1cf2f2ff53f..1a1b5aa6f40 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java @@ -119,5 +119,4 @@ public boolean matchesReference(Reference reference) { public Reference.Renamer createRenamer(String newName) { return reference -> newName; } - } diff --git a/rewrite-properties/src/main/java/org/openrewrite/properties/trait/PropertiesReference.java b/rewrite-properties/src/main/java/org/openrewrite/properties/trait/PropertiesReference.java index 038aafccfd6..2d5fd55846a 100644 --- a/rewrite-properties/src/main/java/org/openrewrite/properties/trait/PropertiesReference.java +++ b/rewrite-properties/src/main/java/org/openrewrite/properties/trait/PropertiesReference.java @@ -53,9 +53,6 @@ public boolean supportsRename() { return true; } - /** - * {@inheritDoc} - */ @Override public Tree rename(Renamer renamer, Cursor cursor, ExecutionContext ctx) { Tree tree = cursor.getValue(); @@ -67,7 +64,7 @@ public Tree rename(Renamer renamer, Cursor cursor, ExecutionContext ctx) { return tree; } - public static class Matcher extends SimpleTraitMatcher { + private static class Matcher extends SimpleTraitMatcher { private static final Predicate javaFullyQualifiedTypeMatcher = Pattern.compile( "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*(?:\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*").asPredicate(); @@ -75,7 +72,7 @@ public static class Matcher extends SimpleTraitMatcher { protected @Nullable PropertiesReference test(Cursor cursor) { Object value = cursor.getValue(); if (value instanceof Properties.Entry && - javaFullyQualifiedTypeMatcher.test(((Properties.Entry) value).getValue().getText())) { + javaFullyQualifiedTypeMatcher.test(((Properties.Entry) value).getValue().getText())) { return new PropertiesReference(cursor, determineKind(((Properties.Entry) value).getValue().getText())); } return null; @@ -88,8 +85,14 @@ private Kind determineKind(String value) { @SuppressWarnings("unused") public static class Provider implements Reference.Provider { + private static final Predicate applicationPropertiesMatcher = Pattern.compile("^application(-\\w+)?\\.properties$").asPredicate(); + @Override + public boolean isAcceptable(SourceFile sourceFile) { + return sourceFile instanceof Properties.File && applicationPropertiesMatcher.test(sourceFile.getSourcePath().getFileName().toString()); + } + @Override public Set getReferences(SourceFile sourceFile) { Set references = new HashSet<>(); @@ -99,10 +102,5 @@ public Set getReferences(SourceFile sourceFile) { }).visit(sourceFile, 0); return references; } - - @Override - public boolean isAcceptable(SourceFile sourceFile) { - return sourceFile instanceof Properties.File && applicationPropertiesMatcher.test(sourceFile.getSourcePath().getFileName().toString()); - } } } diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java new file mode 100644 index 00000000000..23705fdae96 --- /dev/null +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java @@ -0,0 +1,105 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.yaml.trait; + +import lombok.Value; +import org.jspecify.annotations.Nullable; +import org.openrewrite.Cursor; +import org.openrewrite.ExecutionContext; +import org.openrewrite.SourceFile; +import org.openrewrite.Tree; +import org.openrewrite.trait.Reference; +import org.openrewrite.trait.SimpleTraitMatcher; +import org.openrewrite.yaml.tree.Yaml; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +@Value +public class YamlReference implements Reference { + Cursor cursor; + Kind kind; + + @Override + public Kind getKind() { + return kind; + } + + @Override + public String getValue() { + if (getTree() instanceof Yaml.Scalar) { + return ((Yaml.Scalar) getTree()).getValue(); + } + throw new IllegalArgumentException("getTree() must be an Yaml.Scalar: " + getTree().getClass()); + } + + @Override + public boolean supportsRename() { + return true; + } + + @Override + public Tree rename(Renamer renamer, Cursor cursor, ExecutionContext ctx) { + Tree tree = cursor.getValue(); + if (tree instanceof Yaml.Scalar) { + return ((Yaml.Scalar) tree).withValue(renamer.rename(this)); + } + throw new IllegalArgumentException("cursor.getValue() must be an Yaml.Scalar but is: " + tree.getClass()); + } + + private static class Matcher extends SimpleTraitMatcher { + private static final Predicate javaFullyQualifiedTypePattern = Pattern.compile( + "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*(?:\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*") + .asPredicate(); + + @Override + protected @Nullable YamlReference test(Cursor cursor) { + Object value = cursor.getValue(); + if (value instanceof Yaml.Scalar && + javaFullyQualifiedTypePattern.test(((Yaml.Scalar) value).getValue())) { + return new YamlReference(cursor, determineKind(((Yaml.Scalar) value).getValue())); + } + return null; + } + + private Kind determineKind(String value) { + return Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Kind.TYPE : Kind.PACKAGE; + } + } + + @SuppressWarnings("unused") + public static class Provider implements Reference.Provider { + + private static final Predicate applicationPropertiesMatcher = Pattern.compile("^application(-\\w+)?\\.(yaml|yml)$").asPredicate(); + + @Override + public boolean isAcceptable(SourceFile sourceFile) { + return sourceFile instanceof Yaml.Documents && applicationPropertiesMatcher.test(sourceFile.getSourcePath().getFileName().toString()); + } + + @Override + public Set getReferences(SourceFile sourceFile) { + Set references = new HashSet<>(); + new Matcher().asVisitor(reference -> { + references.add(reference); + return reference.getTree(); + }).visit(sourceFile, 0); + return references; + } + } +} diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/package-info.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/package-info.java new file mode 100644 index 00000000000..b2cf0ce8763 --- /dev/null +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +@NonNullFields +package org.openrewrite.yaml.trait; + +import org.jspecify.annotations.NullMarked; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/tree/Yaml.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/tree/Yaml.java index 5245d9ab397..4639bfbf40b 100755 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/tree/Yaml.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/tree/Yaml.java @@ -17,12 +17,15 @@ import lombok.*; import lombok.experimental.FieldDefaults; +import lombok.experimental.NonFinal; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.marker.Markers; import org.openrewrite.yaml.YamlVisitor; import org.openrewrite.yaml.internal.YamlPrinter; +import java.beans.Transient; +import java.lang.ref.SoftReference; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Path; @@ -60,8 +63,10 @@ default

boolean isAcceptable(TreeVisitor v, P p) { @Value @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) @With - class Documents implements Yaml, SourceFile { + class Documents implements Yaml, SourceFileWithReferences { @EqualsAndHashCode.Include UUID id; @@ -125,6 +130,27 @@ public Documents withPrefix(String prefix) { public

TreeVisitor> printer(Cursor cursor) { return new YamlPrinter<>(); } + + @Nullable + @NonFinal + transient SoftReference references; + + @Transient + @Override + public References getReferences() { + References cache; + if (this.references == null) { + cache = References.build(this); + this.references = new SoftReference<>(cache); + } else { + cache = this.references.get(); + if (cache == null || cache.getSourceFile() != this) { + cache = References.build(this); + this.references = new SoftReference<>(cache); + } + } + return cache; + } } @Value diff --git a/rewrite-yaml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider b/rewrite-yaml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider new file mode 100644 index 00000000000..dd857df5564 --- /dev/null +++ b/rewrite-yaml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider @@ -0,0 +1 @@ +org.openrewrite.yaml.trait.YamlReference$Provider \ No newline at end of file diff --git a/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java b/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java new file mode 100644 index 00000000000..a9bd71b35f4 --- /dev/null +++ b/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java @@ -0,0 +1,96 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.yaml.trait; + +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.openrewrite.test.RewriteTest; +import org.openrewrite.trait.Reference; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.openrewrite.yaml.Assertions.yaml; + +class YamlReferenceTest implements RewriteTest { + @Language("yml") + private static final String YAML = """ + root: + a: java.lang.String + b: java.lang + c: String + recipelist: + - org.openrewrite.java.DoSomething: + option: 'org.foo.Bar' + """; + + + @ParameterizedTest + @CsvSource({ + "application.yaml", + "application.yml", + "application-test.yaml", + "application-test.yml", + "/foo/bar/application-test.yaml", + "/foo/bar/application-test.yml", + }) + void findJavaReferencesInYamlProperties(String filename) { + rewriteRun( + yaml( + YAML, + spec -> spec.path(filename).afterRecipe(doc -> { + assertThat(doc.getReferences().getReferences()).satisfiesExactlyInAnyOrder( + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); + assertThat(ref.getValue()).isEqualTo("java.lang.String"); + }, + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.PACKAGE); + assertThat(ref.getValue()).isEqualTo("java.lang"); + }, + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); + assertThat(ref.getValue()).isEqualTo("org.openrewrite.java.DoSomething"); + }, + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); + assertThat(ref.getValue()).isEqualTo("org.foo.Bar"); + }); + })) + ); + } + + @ParameterizedTest + @CsvSource({ + "application-.yaml", + "application-.yml", + "application.test.yaml", + "application.test.yml", + "other-application.yaml", + "other-application.yml", + "other.yaml", + "other.yml", + "/foo/bar/other.yaml", + "/foo/bar/other.yml" + }) + void noReferencesInMismatchedFilenames(String filename) { + rewriteRun( + yaml( + YAML, + spec -> spec.path(filename).afterRecipe(doc -> assertThat(doc.getReferences().getReferences()).isEmpty()) + ) + ); + } +} From 16df13a793ab49e575759b66e18e6511b2f82ffa Mon Sep 17 00:00:00 2001 From: Steven Van Ingelgem Date: Sun, 8 Dec 2024 13:09:03 +0100 Subject: [PATCH 024/179] Adding master password decrypting (#4753) * Adding master password decrypting * Remove redundant nonnull * Reorder methods to read top down and use ListUtils * Start off with a minimize public API * Moving the decryption routing inside MavenSettings so it's always executed. * Added tests * Adding newline * Remove unused and failing ChangeParentPom2Test.java * Move decryption to MavenSecuritySettings * Polish MavenSettingsSecurityTest * Implement relocation --------- Co-authored-by: Tim te Beek --- .../maven/MavenSecuritySettings.java | 214 +++++++++++++ .../org/openrewrite/maven/MavenSettings.java | 50 ++- .../maven/MavenSecuritySettingsTest.java | 297 ++++++++++++++++++ 3 files changed, 558 insertions(+), 3 deletions(-) create mode 100644 rewrite-maven/src/main/java/org/openrewrite/maven/MavenSecuritySettings.java create mode 100644 rewrite-maven/src/test/java/org/openrewrite/maven/MavenSecuritySettingsTest.java diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/MavenSecuritySettings.java b/rewrite-maven/src/main/java/org/openrewrite/maven/MavenSecuritySettings.java new file mode 100644 index 00000000000..f5006c9c612 --- /dev/null +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/MavenSecuritySettings.java @@ -0,0 +1,214 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.maven; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Parser; +import org.openrewrite.internal.PropertyPlaceholderHelper; +import org.openrewrite.maven.internal.MavenXmlMapper; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Base64; +import java.util.Optional; +import java.util.function.UnaryOperator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.util.Collections.emptyList; + +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@ToString(onlyExplicitlyIncluded = true) +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@Data +@AllArgsConstructor +@JacksonXmlRootElement(localName = "settingsSecurity") +public class MavenSecuritySettings { + + @Nullable + String master; + + @Nullable + String relocation; + + private static @Nullable MavenSecuritySettings parse(Parser.Input source, ExecutionContext ctx) { + try { + return new Interpolator().interpolate( + MavenXmlMapper.readMapper().readValue(source.getSource(ctx), MavenSecuritySettings.class)); + } catch (IOException e) { + ctx.getOnError().accept(new IOException("Failed to parse " + source.getPath(), e)); + return null; + } + } + + private static @Nullable MavenSecuritySettings parse(Path settingsPath, ExecutionContext ctx) { + return parse(new Parser.Input(settingsPath, () -> { + try { + return Files.newInputStream(settingsPath); + } catch (IOException e) { + ctx.getOnError().accept(new IOException("Failed to read settings-security.xml at " + settingsPath, e)); + return null; + } + }), ctx); + } + + public static @Nullable MavenSecuritySettings readMavenSecuritySettingsFromDisk(ExecutionContext ctx) { + Optional userSettings = Optional.of(userSecuritySettingsPath()) + .filter(MavenSecuritySettings::exists) + .map(path -> parse(path, ctx)); + MavenSecuritySettings installSettings = findMavenHomeSettings().map(path -> parse(path, ctx)).orElse(null); + MavenSecuritySettings mergedSettings = userSettings + .map(mavenSecuritySettings -> mavenSecuritySettings.merge(installSettings)) + .orElse(installSettings); + if (mergedSettings != null && mergedSettings.relocation != null) { + return mergedSettings.merge(parse(Paths.get(mergedSettings.relocation), ctx)); + } + return mergedSettings; + } + + private static Path userSecuritySettingsPath() { + return Paths.get(System.getProperty("user.home")).resolve(".m2/settings-security.xml"); + } + + private static Optional findMavenHomeSettings() { + for (String envVariable : Arrays.asList("MVN_HOME", "M2_HOME", "MAVEN_HOME")) { + for (String s : Optional.ofNullable(System.getenv(envVariable)).map(Arrays::asList).orElse(emptyList())) { + Path resolve = Paths.get(s).resolve("conf/settings-security.xml"); + if (exists(resolve)) { + return Optional.of(resolve); + } + } + } + return Optional.empty(); + } + + private static boolean exists(Path path) { + try { + return path.toFile().exists(); + } catch (SecurityException e) { + return false; + } + } + + private MavenSecuritySettings merge(@Nullable MavenSecuritySettings installSettings) { + return installSettings == null ? this : new MavenSecuritySettings( + master == null ? installSettings.master : master, + relocation == null ? installSettings.relocation : relocation + ); + } + + /** + * Resolve all properties EXCEPT in the profiles section, which can be affected by + * the POM using the settings. + */ + private static class Interpolator { + private static final PropertyPlaceholderHelper propertyPlaceholders = new PropertyPlaceholderHelper( + "${", "}", null); + + private static final UnaryOperator propertyResolver = key -> { + String property = System.getProperty(key); + if (property != null) { + return property; + } + if (key.startsWith("env.")) { + return System.getenv().get(key.substring(4)); + } + return System.getenv().get(key); + }; + + public MavenSecuritySettings interpolate(MavenSecuritySettings mavenSecuritySettings) { + return new MavenSecuritySettings( + interpolate(mavenSecuritySettings.master), + interpolate(mavenSecuritySettings.relocation) + ); + } + + private @Nullable String interpolate(@Nullable String s) { + return s == null ? null : propertyPlaceholders.replacePlaceholders(s, propertyResolver); + } + } + + @Nullable + String decrypt(@Nullable String fieldValue, @Nullable String password) { + if (fieldValue == null || fieldValue.isEmpty() || password == null) { + return null; + } + + try { + byte[] encryptedText = extractPassword(fieldValue); + + byte[] salt = new byte[8]; + System.arraycopy(encryptedText, 0, salt, 0, 8); + + int padLength = encryptedText[8]; + byte[] encryptedBytes = new byte[encryptedText.length - 9 - padLength]; + System.arraycopy(encryptedText, 9, encryptedBytes, 0, encryptedBytes.length); + + byte[] keyAndIV = new byte[32]; + byte[] pwdBytes = extractPassword(password); + int offset = 0; + while (offset < 32) { + java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256"); + digest.update(pwdBytes); + digest.update(salt); + byte[] hash = digest.digest(); + System.arraycopy(hash, 0, keyAndIV, offset, Math.min(hash.length, 32 - offset)); + offset += hash.length; + } + + Key key = new SecretKeySpec(keyAndIV, 0, 16, "AES"); + IvParameterSpec iv = new IvParameterSpec(keyAndIV, 16, 16); + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, key, iv); + byte[] clearBytes = cipher.doFinal(encryptedBytes); + + int paddingLength = clearBytes[clearBytes.length - 1]; + byte[] decryptedBytes = new byte[clearBytes.length - paddingLength]; + System.arraycopy(clearBytes, 0, decryptedBytes, 0, decryptedBytes.length); + return new String(decryptedBytes, StandardCharsets.UTF_8); + } catch (NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | + InvalidKeyException | InvalidAlgorithmParameterException | IllegalArgumentException e) { + return null; + } + } + + private byte[] extractPassword(String pwd) throws IllegalArgumentException { + Pattern pattern = Pattern.compile(".*?[^\\\\]?\\{(.*?)}.*"); + Matcher matcher = pattern.matcher(pwd); + if (matcher.find()) { + return Base64.getDecoder().decode(matcher.group(1)); + } + return pwd.getBytes(StandardCharsets.UTF_8); + } +} diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/MavenSettings.java b/rewrite-maven/src/main/java/org/openrewrite/maven/MavenSettings.java index ae23c9ff06b..2c56bd6ddee 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/MavenSettings.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/MavenSettings.java @@ -34,12 +34,25 @@ import org.openrewrite.maven.tree.MavenRepository; import org.openrewrite.maven.tree.ProfileActivation; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; import java.util.*; import java.util.function.UnaryOperator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static java.util.Collections.emptyList; import static org.openrewrite.maven.tree.MavenRepository.MAVEN_LOCAL_DEFAULT; @@ -109,10 +122,40 @@ public MavenSettings(@Nullable String localRepository, @Nullable Profiles profil .filter(MavenSettings::exists) .map(path -> parse(path, ctx)); final MavenSettings installSettings = findMavenHomeSettings().map(path -> parse(path, ctx)).orElse(null); - return userSettings.map(mavenSettings -> mavenSettings.merge(installSettings)) + MavenSettings settings = userSettings.map(mavenSettings -> mavenSettings.merge(installSettings)) .orElse(installSettings); + + if (settings != null) { + settings.maybeDecryptPasswords(ctx); + } + + return settings; } + void maybeDecryptPasswords(ExecutionContext ctx) { + MavenSecuritySettings security = MavenSecuritySettings.readMavenSecuritySettingsFromDisk(ctx); + if (security == null) { + return; + } + + String decryptedMasterPassword = security.decrypt(security.getMaster(), "settings.security"); + if (decryptedMasterPassword != null) { + if (mavenLocal != null) { + String password = security.decrypt(mavenLocal.getPassword(), decryptedMasterPassword); + if (password != null) { + mavenLocal = mavenLocal.withPassword(password); + } + } + if (servers != null) { + servers.servers = ListUtils.map(servers.servers, server -> { + String password = security.decrypt(server.getPassword(), decryptedMasterPassword); + return password == null ? server : server.withPassword(password); + }); + } + } + } + + public static boolean readFromDiskEnabled() { final String propertyValue = System.getProperty("org.openrewrite.test.readMavenSettingsFromDisk"); return propertyValue != null && !propertyValue.equalsIgnoreCase("false"); @@ -158,7 +201,7 @@ public List getActiveRepositories(Iterable a if (profiles != null) { for (Profile profile : profiles.getProfiles()) { if (profile.isActive(activeProfiles) || (this.activeProfiles != null && - profile.isActive(this.activeProfiles.getActiveProfiles()))) { + profile.isActive(this.activeProfiles.getActiveProfiles()))) { if (profile.repositories != null) { for (RawRepositories.Repository repository : profile.repositories.getRepositories()) { activeRepositories.put(repository.getId(), repository); @@ -409,7 +452,8 @@ public static class Server { @JsonIgnoreProperties(value = "httpHeaders") public static class ServerConfiguration { @JacksonXmlProperty(localName = "property") - @JacksonXmlElementWrapper(localName = "httpHeaders", useWrapping = true) // wrapping is disabled by default on MavenXmlMapper + @JacksonXmlElementWrapper(localName = "httpHeaders", useWrapping = true) + // wrapping is disabled by default on MavenXmlMapper @Nullable List httpHeaders; diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/MavenSecuritySettingsTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/MavenSecuritySettingsTest.java new file mode 100644 index 00000000000..1166ba41b81 --- /dev/null +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/MavenSecuritySettingsTest.java @@ -0,0 +1,297 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.maven; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.openrewrite.InMemoryExecutionContext; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +class MavenSecuritySettingsTest { + + private static final String MASTER_PASS_ENCRYPTED = "FyoLIiN2Fx8HpT8O0aBsTn2/s3pYmtLRRCpoWPzhN4A="; // "master" + private static final String USER_PASS_ENCRYPTED = "ERozWEamSJoHRBT+wVx51V2Emr9PazZR9txMntZPlJc="; // "testpass" + private static final String USER_PASS_DECRYPTED = "testpass"; + + private String originalUserHome; + + @TempDir + Path tempDir; + + @BeforeEach + void setUp() throws IOException { + originalUserHome = System.getProperty("user.home"); + System.setProperty("user.home", tempDir.toString()); + Files.createDirectories(tempDir.resolve(".m2")); + } + + @AfterEach + void tearDown() { + System.setProperty("user.home", originalUserHome); + } + + @Test + void decryptCredentials() throws IOException { + // Create settings-security.xml with master password + Files.writeString(tempDir.resolve(".m2/settings-security.xml"), + //language=xml + """ + + + {%s} + + """.formatted(MASTER_PASS_ENCRYPTED)); + + // Create settings.xml with encrypted password + Files.writeString(tempDir.resolve(".m2/settings.xml"), + //language=xml + """ + + + + + test-server + admin + {%s} + + + + """.formatted(USER_PASS_ENCRYPTED)); + + // Use the public API to read settings + var ctx = new InMemoryExecutionContext(t -> { + throw new RuntimeException(t); + }); + MavenSettings settings = MavenSettings.readMavenSettingsFromDisk(ctx); + assert settings != null && settings.getServers() != null; + assertThat(settings.getServers().getServers()) + .hasSize(1) + .first() + .satisfies(server -> { + assertThat(server.getId()).isEqualTo("test-server"); + assertThat(server.getUsername()).isEqualTo("admin"); + assertThat(server.getPassword()).isEqualTo(USER_PASS_DECRYPTED); + }); + } + + @Test + void relocatedCredentials() throws IOException { + // Create settings-security.xml with relocation + Path relocated = tempDir.resolve(".m2/relocation-settings-security.xml"); + Files.writeString(tempDir.resolve(".m2/settings-security.xml"), + //language=xml + """ + + + %s + + """.formatted(relocated)); + // Create relocation-settings-security.xml with master password + Files.writeString(relocated, + //language=xml + """ + + + {%s} + + """.formatted(MASTER_PASS_ENCRYPTED)); + + // Create settings.xml with encrypted password + Files.writeString(tempDir.resolve(".m2/settings.xml"), + //language=xml + """ + + + + + test-server + admin + {%s} + + + + """.formatted(USER_PASS_ENCRYPTED)); + + // Use the public API to read settings + var ctx = new InMemoryExecutionContext(t -> { + throw new RuntimeException(t); + }); + MavenSettings settings = MavenSettings.readMavenSettingsFromDisk(ctx); + assert settings != null && settings.getServers() != null; + assertThat(settings.getServers().getServers()) + .hasSize(1) + .first() + .satisfies(server -> { + assertThat(server.getId()).isEqualTo("test-server"); + assertThat(server.getUsername()).isEqualTo("admin"); + assertThat(server.getPassword()).isEqualTo(USER_PASS_DECRYPTED); + }); + } + + @Test + void handleInvalidEncryptedPassword() throws IOException { + // Create settings-security.xml with master password + Files.writeString(tempDir.resolve(".m2/settings-security.xml"), + //language=xml + """ + + + {jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=} + + """); + + // Create settings.xml with invalid encrypted password + Files.writeString(tempDir.resolve(".m2/settings.xml"), + //language=xml + """ + + + + + test-server + admin + {invalid_format} + + + + """); + + var ctx = new InMemoryExecutionContext(t -> { + throw new RuntimeException(t); + }); + MavenSettings settings = MavenSettings.readMavenSettingsFromDisk(ctx); + assert settings != null && settings.getServers() != null; + assertThat(settings.getServers().getServers()).hasSize(1) + .first() + .satisfies(server -> assertThat(server.getPassword()).isEqualTo("{invalid_format}")); + } + + @Test + void noSecuritySettingsNoDecryption() throws IOException { + // Only create settings.xml without settings-security.xml + Files.writeString(tempDir.resolve(".m2/settings.xml"), + //language=xml + """ + + + + + test-server + admin + {encrypted_password} + + + + """); + + var ctx = new InMemoryExecutionContext(t -> { + throw new RuntimeException(t); + }); + MavenSettings settings = MavenSettings.readMavenSettingsFromDisk(ctx); + assert settings != null && settings.getServers() != null; + assertThat(settings.getServers().getServers()) + .hasSize(1) + .first() + .satisfies(server -> assertThat(server.getPassword()).isEqualTo("{encrypted_password}")); + } + + @Test + void decryptPasswordWithComments() throws IOException { + // Create settings-security.xml with master password + Files.writeString(tempDir.resolve(".m2/settings-security.xml"), + //language=xml + """ + + + {%s} + + """.formatted(MASTER_PASS_ENCRYPTED)); + + // Create settings.xml with password containing comments + Files.writeString(tempDir.resolve(".m2/settings.xml"), + //language=xml + """ + + + + + test-server + admin + Oleg reset this password on 2009-03-11, expires on 2009-04-11 {%s} + + + + """.formatted(USER_PASS_ENCRYPTED)); + + var ctx = new InMemoryExecutionContext(t -> { + throw new RuntimeException(t); + }); + MavenSettings settings = MavenSettings.readMavenSettingsFromDisk(ctx); + assert settings != null && settings.getServers() != null; + assertThat(settings.getServers().getServers()) + .hasSize(1) + .first() + .satisfies(server -> assertThat(server.getPassword()).isEqualTo(USER_PASS_DECRYPTED)); + } + + @Test + void invalidMasterPasswordButValidPasswordFormat() throws IOException { + // Create settings-security.xml with invalid master password + Files.writeString(tempDir.resolve(".m2/settings-security.xml"), + //language=xml + """ + + + {invalid_master_password} + + """); + + // Create settings.xml with valid encrypted password + Files.writeString(tempDir.resolve(".m2/settings.xml"), + //language=xml + """ + + + + + test-server + admin + {%s} + + + + """.formatted(USER_PASS_ENCRYPTED)); + + var ctx = new InMemoryExecutionContext(t -> { + throw new RuntimeException(t); + }); + MavenSettings settings = MavenSettings.readMavenSettingsFromDisk(ctx); + assert settings != null && settings.getServers() != null; + assertThat(settings.getServers().getServers()) + .hasSize(1) + .first() + .satisfies(server -> + // Password should remain in encrypted form since master password is invalid + assertThat(server.getPassword()).isEqualTo("{%s}".formatted(USER_PASS_ENCRYPTED))); + } +} From 1095923b6e433860af8f5d71d7ab9a2a8f0c8a06 Mon Sep 17 00:00:00 2001 From: Leanne Kerford Date: Mon, 9 Dec 2024 11:49:25 -0800 Subject: [PATCH 025/179] Make sure provided download target exist before writing files to it (#4762) When we use the default download location we create the folder if it is missing. We also need to do this if a custom location is provided --- .../test/java/org/openrewrite/java/JavaParserTest.java | 10 ++++++++++ .../java/JavaParserExecutionContextView.java | 9 ++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java index ccfe243aec1..3115386c7d7 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java @@ -107,6 +107,16 @@ void dependenciesFromResources(@TempDir Path temp) throws Exception { "directory contains guava-30.0-jre.jar which has the same prefix"); } + @Test + void getParserClasspathDownloadCreateRequiredFolder(@TempDir Path temp) throws Exception { + Path updatedTemp = Path.of(temp.toString(), "someFolder"); + assertThat(updatedTemp.toFile().exists()).isFalse(); + JavaParserExecutionContextView ctx = JavaParserExecutionContextView.view(new InMemoryExecutionContext()); + ctx.setParserClasspathDownloadTarget(updatedTemp.toFile()); + ctx.getParserClasspathDownloadTarget(); + assertThat(updatedTemp.toFile().exists()).isTrue(); + } + @Test @Issue("https://github.com/openrewrite/rewrite/issues/3222") void parseFromByteArray() { diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaParserExecutionContextView.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaParserExecutionContextView.java index 884104913ab..266ee8928a8 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaParserExecutionContextView.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaParserExecutionContextView.java @@ -45,11 +45,10 @@ public JavaParserExecutionContextView setParserClasspathDownloadTarget(File fold public File getParserClasspathDownloadTarget() { File target = getMessage(PARSER_CLASSPATH_DOWNLOAD_LOCATION); if (target == null) { - File defaultTarget = new File(System.getProperty("user.home") + "/.rewrite/classpath"); - if (!defaultTarget.mkdirs() && !defaultTarget.exists()) { - throw new UncheckedIOException(new IOException("Failed to create directory " + defaultTarget.getAbsolutePath())); - } - return defaultTarget; + target = new File(System.getProperty("user.home") + "/.rewrite/classpath"); + } + if (!target.mkdirs() && !target.exists()) { + throw new UncheckedIOException(new IOException("Failed to create directory " + target.getAbsolutePath())); } return target; } From 3403f7e426baa64ffd22f4105ca79ec40557c2e7 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Tue, 10 Dec 2024 10:58:26 +0100 Subject: [PATCH 026/179] `AddOrUpdateAnnotationAttribute` should also visit nested annotations Fixes #4765 --- .../org/openrewrite/java/AddOrUpdateAnnotationAttribute.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java b/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java index be098009e16..a62f0be4967 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java @@ -85,7 +85,7 @@ public TreeVisitor getVisitor() { return Preconditions.check(new UsesType<>(annotationType, false), new JavaIsoVisitor() { @Override public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { - J.Annotation original = a; + J.Annotation original = super.visitAnnotation(a, ctx); if (!TypeUtils.isOfClassType(a.getType(), annotationType)) { return a; } From 54a205783a326404a717d66b50f9efab032f28a0 Mon Sep 17 00:00:00 2001 From: dralagen Date: Tue, 10 Dec 2024 14:49:22 +0100 Subject: [PATCH 027/179] `RemoveMethodInvocationsVisitor` can remove static method (#4754) * Add test on RemoveMethodInvocationsVisitor to remove static method * First implementation * Improved implementation * Improved tests * Improved tests * Improved tests * Improved tests [skip ci] * Complete it * Remove redundant parentheses * Better mame of tests * Add failing test for scenario not yet covered * Improvement --------- Co-authored-by: lingenj Co-authored-by: Tim te Beek --- .../java/RemoveMethodInvocationsVisitor.java | 27 +++- .../RemoveMethodInvocationsVisitorTest.java | 140 +++++++++++++++++- 2 files changed, 157 insertions(+), 10 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/RemoveMethodInvocationsVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/RemoveMethodInvocationsVisitor.java index 7cf86789aeb..4682c999ffa 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/RemoveMethodInvocationsVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/RemoveMethodInvocationsVisitor.java @@ -69,26 +69,32 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) return j; } - private @Nullable J removeMethods(Expression expression, int depth, boolean isLambdaBody, Stack selectAfter) { - if (!(expression instanceof J.MethodInvocation)) { + private @Nullable J removeMethods(@Nullable Expression expression, int depth, boolean isLambdaBody, Stack selectAfter) { + if (!(expression instanceof J.MethodInvocation) || ((J.MethodInvocation) expression).getMethodType() == null) { return expression; } - boolean isStatement = isStatement(); J.MethodInvocation m = (J.MethodInvocation) expression; + boolean isStatic = m.getMethodType().hasFlags(Flag.Static); - if (m.getMethodType() == null || m.getSelect() == null) { + if (isStatic && !isStatementInParentBlock(m)) { return expression; } + boolean isStatement = isStatement(); + if (matchers.entrySet().stream().anyMatch(entry -> matches(m, entry.getKey(), entry.getValue()))) { - boolean hasSameReturnType = TypeUtils.isAssignableTo(m.getMethodType().getReturnType(), m.getSelect().getType()); - boolean removable = (isStatement && depth == 0) || hasSameReturnType; + boolean hasSameReturnType = m.getSelect() != null && TypeUtils.isAssignableTo(m.getMethodType().getReturnType(), m.getSelect().getType()); + boolean removable = ((isStatement || isStatic) && depth == 0) || hasSameReturnType; if (!removable) { return expression; } - if (m.getSelect() instanceof J.Identifier || m.getSelect() instanceof J.NewClass) { + maybeRemoveImport(m.getMethodType().getDeclaringType()); + + if (m.getSelect() == null) { + return null; + } else if (m.getSelect() instanceof J.Identifier || m.getSelect() instanceof J.NewClass) { boolean keepSelect = depth != 0; if (keepSelect) { selectAfter.add(getSelectAfter(m)); @@ -131,6 +137,11 @@ private boolean isStatement() { ).getValue() instanceof J.Block; } + private boolean isStatementInParentBlock(Statement method) { + J.Block parentBlock = getCursor().firstEnclosing(J.Block.class); + return parentBlock == null || parentBlock.getStatements().contains(method); + } + private boolean isLambdaBody() { if (getCursor().getParent() == null) { return false; @@ -241,7 +252,7 @@ public J.Block visitBlock(J.Block block, ExecutionContext ctx) { @Value @With - static class ToBeRemoved implements Marker { + private static class ToBeRemoved implements Marker { UUID id; static J2 withMarker(J2 j) { return j.withMarkers(j.getMarkers().addIfAbsent(new ToBeRemoved(randomId()))); diff --git a/rewrite-java/src/test/java/org/openrewrite/java/RemoveMethodInvocationsVisitorTest.java b/rewrite-java/src/test/java/org/openrewrite/java/RemoveMethodInvocationsVisitorTest.java index c94f455eb16..279e70c1a8b 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/RemoveMethodInvocationsVisitorTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/RemoveMethodInvocationsVisitorTest.java @@ -15,13 +15,14 @@ */ package org.openrewrite.java; +import java.util.List; + import org.junit.jupiter.api.Test; import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.DocumentExample; import org.openrewrite.Recipe; import org.openrewrite.test.RewriteTest; -import java.util.List; import static org.openrewrite.java.Assertions.java; import static org.openrewrite.test.RewriteTest.toRecipe; @@ -172,7 +173,6 @@ void method() { } @Test - @ExpectedToFail void removeWithoutSelect() { rewriteRun( spec -> spec.recipe(createRemoveMethodsRecipe("Test foo()")), @@ -492,4 +492,140 @@ public void method() { ) ); } + + @Test + void removeStaticMethodFromImport() { + rewriteRun( + spec -> spec.recipe(createRemoveMethodsRecipe("org.junit.jupiter.api.Assertions assertTrue(..)")), + // language=java + java( + """ + import static org.junit.jupiter.api.Assertions.assertTrue; + + class Test { + void method() { + assertTrue(true); + } + } + """, + """ + class Test { + void method() { + } + } + """ + ) + ); + } + + @Test + void keepStaticMethodFromImportWithAssignment() { + rewriteRun( + spec -> spec.recipe(createRemoveMethodsRecipe("java.util.Collections emptyList()")), + // language=java + java( + """ + import java.util.List; + + import static java.util.Collections.emptyList; + + class Test { + void method() { + List emptyList = emptyList(); + emptyList.isEmpty(); + } + } + """ + ) + ); + } + + @Test + void keepStaticMethodFromImportClassField() { + rewriteRun( + spec -> spec.recipe(createRemoveMethodsRecipe("java.util.Collections emptyList()")), + // language=java + java( + """ + import java.util.List; + + import static java.util.Collections.emptyList; + + class Test { + List emptyList = emptyList(); + void method() { + emptyList.isEmpty(); + } + } + """ + ) + ); + } + + @Test + void removeStaticMethod() { + rewriteRun( + spec -> spec.recipe(createRemoveMethodsRecipe("org.junit.jupiter.api.Assertions assertTrue(..)")), + // language=java + java( + """ + import org.junit.jupiter.api.Assertions; + + class Test { + void method() { + Assertions.assertTrue(true); + } + } + """, + """ + class Test { + void method() { + } + } + """ + ) + ); + } + + @Test + void keepStaticMethodWithAssignment() { + rewriteRun( + spec -> spec.recipe(createRemoveMethodsRecipe("java.util.Collections emptyList()")), + // language=java + java( + """ + import java.util.List; + import java.util.Collections; + + class Test { + void method() { + List emptyList = Collections.emptyList(); + emptyList.size(); + } + } + """ + ) + ); + } + + @Test + void keepStaticMethodClassField() { + rewriteRun( + spec -> spec.recipe(createRemoveMethodsRecipe("java.util.Collections emptyList()")), + // language=java + java( + """ + import java.util.List; + import java.util.Collections; + + class Test { + List emptyList = Collections.emptyList(); + void method() { + emptyList.size(); + } + } + """ + ) + ); + } } From a117884e6e5a3d5a0eaaf9ce795250b897bf8f41 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Tue, 10 Dec 2024 15:03:35 +0100 Subject: [PATCH 028/179] Various refactorings --- .../isolated/ReloadableJava11TypeMapping.java | 67 ++++++++-- .../isolated/ReloadableJava17TypeMapping.java | 65 +++++----- .../isolated/ReloadableJava21TypeMapping.java | 54 ++++---- .../openrewrite/java/Java21ParserTest.java | 12 +- .../java/ReloadableJava8TypeMapping.java | 67 ++++++++-- .../openrewrite/java/tree/AnnotationTest.java | 115 ++++++++++++++++-- .../internal/JavaReflectionTypeMapping.java | 8 +- .../org/openrewrite/java/tree/JavaType.java | 55 ++++++--- 8 files changed, 325 insertions(+), 118 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java index 93bf4a8b988..973e84db769 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java @@ -18,6 +18,7 @@ import com.sun.source.tree.Tree; import com.sun.tools.javac.code.*; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.Pair; import lombok.RequiredArgsConstructor; import org.jspecify.annotations.Nullable; import org.openrewrite.java.JavaTypeMapping; @@ -34,6 +35,7 @@ import java.util.stream.Collectors; import static java.util.Collections.singletonList; +import static java.util.Objects.requireNonNull; import static org.openrewrite.java.tree.JavaType.GenericTypeVariable.Variance.*; @RequiredArgsConstructor @@ -682,21 +684,64 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { } } - private @Nullable List listAnnotations(Symbol symb) { + private @Nullable List listAnnotations(Symbol sym) { List annotations = null; - if (!symb.getDeclarationAttributes().isEmpty()) { - annotations = new ArrayList<>(symb.getDeclarationAttributes().size()); - for (Attribute.Compound a : symb.getDeclarationAttributes()) { - JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(a.type)); - if (annotType == null) { - continue; - } - List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList()); - JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + if (!sym.getDeclarationAttributes().isEmpty()) { + annotations = new ArrayList<>(sym.getDeclarationAttributes().size()); + for (Attribute.Compound a : sym.getDeclarationAttributes()) { + JavaType.Annotation annotation = annotationType(a); + if (annotation == null) continue; annotations.add(annotation); } } return annotations; } + + private JavaType.@Nullable Annotation annotationType(Attribute.Compound compound) { + JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(compound.type)); + if (annotType == null) { + return null; + } + List elementValues = new ArrayList<>(); + for (Pair attr : compound.values) { + Object value = annotationElementValue(attr.snd.getValue()); + JavaType.Method element = requireNonNull(methodDeclarationType(attr.fst, annotType)); + JavaType.Annotation.ElementValue elementValue = value instanceof Object[] ? + new JavaType.Annotation.ArrayElementValue(element, ((Object[]) value)) : + new JavaType.Annotation.SingleElementValue(element, value); + elementValues.add(elementValue); + } + return new JavaType.Annotation(annotType, elementValues); + } + + private Object annotationElementValue(Object value) { + if (value instanceof Symbol.VarSymbol) { + return requireNonNull(variableType((Symbol.VarSymbol) value)); + } else if (value instanceof Type.ClassType) { + return type((Type.ClassType) value); + } else if (value instanceof Attribute.Array) { + List<@Nullable Object> list = new ArrayList<>(); + for (Attribute attribute : ((Attribute.Array) value).values) { + list.add(annotationElementValue(attribute)); + } + return list.toArray(new Object[0]); + } else if (value instanceof List) { + List<@Nullable Object> list = new ArrayList<>(); + for (Object o : ((List) value)) { + list.add(annotationElementValue(o)); + } + return list.toArray(new Object[0]); + } else if (value instanceof Attribute.Class) { + return type(((Attribute.Class) value).classType); + } else if (value instanceof Attribute.Compound) { + return requireNonNull(annotationType((Attribute.Compound) value)); + } else if (value instanceof Attribute.Constant) { + return annotationElementValue(((Attribute.Constant) value).value); + } else if (value instanceof Attribute.Enum) { + return annotationElementValue(((Attribute.Enum) value).value); + } else if (value instanceof Attribute.Error) { + return JavaType.Unknown.getInstance(); + } + return value; + } } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java index 411d4e5fd35..c6492644776 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java @@ -30,11 +30,11 @@ import javax.lang.model.type.NullType; import javax.lang.model.type.TypeMirror; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import static java.util.Collections.singletonList; +import static java.util.Objects.requireNonNull; import static org.openrewrite.java.tree.JavaType.GenericTypeVariable.Variance.*; @RequiredArgsConstructor @@ -257,7 +257,7 @@ private JavaType.FullyQualified classType(Type.ClassType classType, String signa List interfaces = null; if (symType.interfaces_field != null) { interfaces = new ArrayList<>(symType.interfaces_field.length()); - for (com.sun.tools.javac.code.Type iParam : symType.interfaces_field) { + for (Type iParam : symType.interfaces_field) { JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(iParam)); if (javaType != null) { interfaces.add(javaType); @@ -457,7 +457,7 @@ public JavaType.Primitive primitive(TypeTag tag) { * @param symbol The method symbol. * @return Method type attribution. */ - public JavaType.@Nullable Method methodInvocationType(com.sun.tools.javac.code.@Nullable Type selectType, @Nullable Symbol symbol) { + public JavaType.@Nullable Method methodInvocationType(@Nullable Type selectType, @Nullable Symbol symbol) { if (selectType == null || selectType instanceof Type.ErrorType || symbol == null || symbol.kind == Kinds.Kind.ERR || symbol.type instanceof Type.UnknownType) { return null; } @@ -506,7 +506,7 @@ public JavaType.Primitive primitive(TypeTag tag) { if (!methodType.argtypes.isEmpty()) { parameterTypes = new ArrayList<>(methodType.argtypes.size()); - for (com.sun.tools.javac.code.Type argtype : methodType.argtypes) { + for (Type argtype : methodType.argtypes) { if (argtype != null) { JavaType javaType = type(argtype); parameterTypes.add(javaType); @@ -588,7 +588,7 @@ public JavaType.Primitive primitive(TypeTag tag) { .collect(Collectors.toList()); } else { try { - defaultValues = Collections.singletonList(methodSymbol.getDefaultValue().getValue().toString()); + defaultValues = singletonList(methodSymbol.getDefaultValue().getValue().toString()); } catch (UnsupportedOperationException e) { // not all Attribute implementations define `getValue()` } @@ -662,7 +662,7 @@ public JavaType.Primitive primitive(TypeTag tag) { if (!mt.argtypes.isEmpty()) { parameterTypes = new ArrayList<>(mt.argtypes.size()); - for (com.sun.tools.javac.code.Type argtype : mt.argtypes) { + for (Type argtype : mt.argtypes) { if (argtype != null) { JavaType javaType = type(argtype); parameterTypes.add(javaType); @@ -696,7 +696,7 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (!sym.getDeclarationAttributes().isEmpty()) { annotations = new ArrayList<>(sym.getDeclarationAttributes().size()); for (Attribute.Compound a : sym.getDeclarationAttributes()) { - JavaType.Annotation annotation = annotationValue(a); + JavaType.Annotation annotation = annotationType(a); if (annotation == null) continue; annotations.add(annotation); } @@ -704,51 +704,50 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { return annotations; } - private JavaType.@Nullable Annotation annotationValue(Attribute.Compound compound) { + private JavaType.@Nullable Annotation annotationType(Attribute.Compound compound) { JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(compound.type)); if (annotType == null) { return null; } - List annotationValues = new ArrayList<>(); + List elementValues = new ArrayList<>(); for (Pair attr : compound.values) { - JavaType.AnnotationValue annotationValue = new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), annotationAttributeValue(attr.snd.getValue())); - annotationValues.add(annotationValue); - } - return new JavaType.Annotation(annotType, annotationValues); + Object value = annotationElementValue(attr.snd.getValue()); + JavaType.Method element = requireNonNull(methodDeclarationType(attr.fst, annotType)); + JavaType.Annotation.ElementValue elementValue = value instanceof Object[] ? + new JavaType.Annotation.ArrayElementValue(element, ((Object[]) value)) : + new JavaType.Annotation.SingleElementValue(element, value); + elementValues.add(elementValue); + } + return new JavaType.Annotation(annotType, elementValues); } - private @Nullable Object annotationAttributeValue(Object value) { + private Object annotationElementValue(Object value) { if (value instanceof Symbol.VarSymbol) { - return variableType((Symbol.VarSymbol) value); + return requireNonNull(variableType((Symbol.VarSymbol) value)); } else if (value instanceof Type.ClassType) { return type((Type.ClassType) value); } else if (value instanceof Attribute.Array) { List<@Nullable Object> list = new ArrayList<>(); for (Attribute attribute : ((Attribute.Array) value).values) { - list.add(annotationAttributeValue(attribute)); + list.add(annotationElementValue(attribute)); + } + return list.toArray(new Object[0]); + } else if (value instanceof List) { + List<@Nullable Object> list = new ArrayList<>(); + for (Object o : ((List) value)) { + list.add(annotationElementValue(o)); } - return list; + return list.toArray(new Object[0]); } else if (value instanceof Attribute.Class) { return type(((Attribute.Class) value).classType); } else if (value instanceof Attribute.Compound) { - return annotationValue((Attribute.Compound) value); + return requireNonNull(annotationType((Attribute.Compound) value)); } else if (value instanceof Attribute.Constant) { - return annotationAttributeValue(((Attribute.Constant) value).value); + return annotationElementValue(((Attribute.Constant) value).value); } else if (value instanceof Attribute.Enum) { - return annotationAttributeValue(((Attribute.Enum) value).value); - } else if (value instanceof List) { - List<@Nullable Object> list = new ArrayList<>(); - for (Object o : ((List) value)) { - list.add(annotationAttributeValue(o)); - } - return list; - } else if (value instanceof String) { - return value; - } else if (value instanceof Boolean) { - return value; - } else if (value instanceof Integer) { - return value; + return annotationElementValue(((Attribute.Enum) value).value); + } else if (value instanceof Attribute.Error) { + return JavaType.Unknown.getInstance(); } return value; } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index 51f3232487d..236f0049715 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -35,6 +35,7 @@ import java.util.stream.Collectors; import static java.util.Collections.singletonList; +import static java.util.Objects.requireNonNull; import static org.openrewrite.java.tree.JavaType.GenericTypeVariable.Variance.*; @RequiredArgsConstructor @@ -707,7 +708,7 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (!sym.getDeclarationAttributes().isEmpty()) { annotations = new ArrayList<>(sym.getDeclarationAttributes().size()); for (Attribute.Compound a : sym.getDeclarationAttributes()) { - JavaType.Annotation annotation = annotationValue(a); + JavaType.Annotation annotation = annotationType(a); if (annotation == null) continue; annotations.add(annotation); } @@ -715,51 +716,50 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { return annotations; } - private JavaType.@Nullable Annotation annotationValue(Attribute.Compound compound) { + private JavaType.@Nullable Annotation annotationType(Attribute.Compound compound) { JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(compound.type)); if (annotType == null) { return null; } - List annotationValues = new ArrayList<>(); + List elementValues = new ArrayList<>(); for (Pair attr : compound.values) { - JavaType.AnnotationValue annotationValue = new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), annotationAttributeValue(attr.snd.getValue())); - annotationValues.add(annotationValue); - } - return new JavaType.Annotation(annotType, annotationValues); + Object value = annotationElementValue(attr.snd.getValue()); + JavaType.Method element = requireNonNull(methodDeclarationType(attr.fst, annotType)); + JavaType.Annotation.ElementValue elementValue = value instanceof Object[] ? + new JavaType.Annotation.ArrayElementValue(element, ((Object[]) value)) : + new JavaType.Annotation.SingleElementValue(element, value); + elementValues.add(elementValue); + } + return new JavaType.Annotation(annotType, elementValues); } - private @Nullable Object annotationAttributeValue(Object value) { + private Object annotationElementValue(Object value) { if (value instanceof Symbol.VarSymbol) { - return variableType((Symbol.VarSymbol) value); + return requireNonNull(variableType((Symbol.VarSymbol) value)); } else if (value instanceof Type.ClassType) { return type((Type.ClassType) value); } else if (value instanceof Attribute.Array) { List<@Nullable Object> list = new ArrayList<>(); for (Attribute attribute : ((Attribute.Array) value).values) { - list.add(annotationAttributeValue(attribute)); + list.add(annotationElementValue(attribute)); + } + return list.toArray(new Object[0]); + } else if (value instanceof List) { + List<@Nullable Object> list = new ArrayList<>(); + for (Object o : ((List) value)) { + list.add(annotationElementValue(o)); } - return list; + return list.toArray(new Object[0]); } else if (value instanceof Attribute.Class) { return type(((Attribute.Class) value).classType); } else if (value instanceof Attribute.Compound) { - return annotationValue((Attribute.Compound) value); + return requireNonNull(annotationType((Attribute.Compound) value)); } else if (value instanceof Attribute.Constant) { - return annotationAttributeValue(((Attribute.Constant) value).value); + return annotationElementValue(((Attribute.Constant) value).value); } else if (value instanceof Attribute.Enum) { - return annotationAttributeValue(((Attribute.Enum) value).value); - } else if (value instanceof List) { - List<@Nullable Object> list = new ArrayList<>(); - for (Object o : ((List) value)) { - list.add(annotationAttributeValue(o)); - } - return list; - } else if (value instanceof String) { - return value; - } else if (value instanceof Boolean) { - return value; - } else if (value instanceof Integer) { - return value; + return annotationElementValue(((Attribute.Enum) value).value); + } else if (value instanceof Attribute.Error) { + return JavaType.Unknown.getInstance(); } return value; } diff --git a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java index c1132c9ddba..821cb2600a4 100644 --- a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java +++ b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java @@ -39,9 +39,9 @@ void shouldLoadResourceFromClasspath() throws IOException { } @Test - void testPreserveAnnotationsFromClasspath() throws IOException { + void testPreserveAnnotationsFromClasspath() { JavaParser p = JavaParser.fromJavaVersion().build(); - /** + /* * Using these annotations in core library for testing this feature: * * @Deprecated(since="1.2", forRemoval=true) @@ -67,16 +67,16 @@ public void test() { JavaType.Annotation annotation = (JavaType.Annotation) mi.getMethodType().getAnnotations().get(0); // Thread.currentThread().stop(); - assertEquals("java.lang.Deprecated" ,annotation.type.getFullyQualifiedName()); - assertEquals("since", annotation.getValues().get(0).getMethod().getName()); + assertEquals("java.lang.Deprecated" ,annotation.getType().getFullyQualifiedName()); + assertEquals("since", annotation.getValues().get(0).getElement().getName()); assertEquals("1.2", annotation.getValues().get(0).getValue()); - assertEquals("forRemoval", annotation.getValues().get(1).getMethod().getName()); + assertEquals("forRemoval", annotation.getValues().get(1).getElement().getName()); assertEquals(Boolean.TRUE, annotation.getValues().get(1).getValue()); // Thread.currentThread().getContextClassLoader(); mi = (J.MethodInvocation) md.getBody().getStatements().get(1); annotation = (JavaType.Annotation) mi.getMethodType().getAnnotations().get(0); - assertEquals("jdk.internal.reflect.CallerSensitive" ,annotation.type.getFullyQualifiedName()); + assertEquals("jdk.internal.reflect.CallerSensitive" ,annotation.getType().getFullyQualifiedName()); assertTrue(annotation.getValues().isEmpty()); } } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java index 5cbb1690d95..3f1a5ce597b 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java @@ -18,6 +18,7 @@ import com.sun.source.tree.Tree; import com.sun.tools.javac.code.*; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.Pair; import lombok.RequiredArgsConstructor; import org.jspecify.annotations.Nullable; import org.openrewrite.java.internal.JavaTypeCache; @@ -33,6 +34,7 @@ import java.util.stream.Collectors; import static java.util.Collections.singletonList; +import static java.util.Objects.requireNonNull; import static org.openrewrite.java.tree.JavaType.GenericTypeVariable.Variance.CONTRAVARIANT; import static org.openrewrite.java.tree.JavaType.GenericTypeVariable.Variance.COVARIANT; import static org.openrewrite.java.tree.JavaType.GenericTypeVariable.Variance.INVARIANT; @@ -683,21 +685,64 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { } } - private @Nullable List listAnnotations(Symbol symb) { + private @Nullable List listAnnotations(Symbol sym) { List annotations = null; - if (!symb.getDeclarationAttributes().isEmpty()) { - annotations = new ArrayList<>(symb.getDeclarationAttributes().size()); - for (Attribute.Compound a : symb.getDeclarationAttributes()) { - JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(a.type)); - if (annotType == null) { - continue; - } - List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( - methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).collect(Collectors.toList()); - JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + if (!sym.getDeclarationAttributes().isEmpty()) { + annotations = new ArrayList<>(sym.getDeclarationAttributes().size()); + for (Attribute.Compound a : sym.getDeclarationAttributes()) { + JavaType.Annotation annotation = annotationType(a); + if (annotation == null) continue; annotations.add(annotation); } } return annotations; } + + private JavaType.@Nullable Annotation annotationType(Attribute.Compound compound) { + JavaType.FullyQualified annotType = TypeUtils.asFullyQualified(type(compound.type)); + if (annotType == null) { + return null; + } + List elementValues = new ArrayList<>(); + for (Pair attr : compound.values) { + Object value = annotationElementValue(attr.snd.getValue()); + JavaType.Method element = requireNonNull(methodDeclarationType(attr.fst, annotType)); + JavaType.Annotation.ElementValue elementValue = value instanceof Object[] ? + new JavaType.Annotation.ArrayElementValue(element, ((Object[]) value)) : + new JavaType.Annotation.SingleElementValue(element, value); + elementValues.add(elementValue); + } + return new JavaType.Annotation(annotType, elementValues); + } + + private Object annotationElementValue(Object value) { + if (value instanceof Symbol.VarSymbol) { + return requireNonNull(variableType((Symbol.VarSymbol) value)); + } else if (value instanceof Type.ClassType) { + return type((Type.ClassType) value); + } else if (value instanceof Attribute.Array) { + List<@Nullable Object> list = new ArrayList<>(); + for (Attribute attribute : ((Attribute.Array) value).values) { + list.add(annotationElementValue(attribute)); + } + return list.toArray(new Object[0]); + } else if (value instanceof List) { + List<@Nullable Object> list = new ArrayList<>(); + for (Object o : ((List) value)) { + list.add(annotationElementValue(o)); + } + return list.toArray(new Object[0]); + } else if (value instanceof Attribute.Class) { + return type(((Attribute.Class) value).classType); + } else if (value instanceof Attribute.Compound) { + return requireNonNull(annotationType((Attribute.Compound) value)); + } else if (value instanceof Attribute.Constant) { + return annotationElementValue(((Attribute.Constant) value).value); + } else if (value instanceof Attribute.Enum) { + return annotationElementValue(((Attribute.Enum) value).value); + } else if (value instanceof Attribute.Error) { + return JavaType.Unknown.getInstance(); + } + return value; + } } diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java index 9a89ce50b27..b9992b3ac92 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java @@ -19,13 +19,20 @@ import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; import org.openrewrite.Issue; +import org.openrewrite.SourceFile; import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.MinimumJava21; import org.openrewrite.java.service.AnnotationService; import org.openrewrite.test.RewriteTest; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.openrewrite.java.Assertions.java; import static org.openrewrite.test.RewriteTest.toRecipe; @@ -38,7 +45,14 @@ void annotationWithDefaultArgument() { """ @SuppressWarnings("ALL") public class A {} - """ + """, spec -> spec.afterRecipe(cu -> { + J.ClassDeclaration c = cu.getClasses().get(0); + JavaType.Class type = (JavaType.Class) c.getType(); + JavaType.Annotation a = (JavaType.Annotation) type.getAnnotations().get(0); + assertThat(a.getValues()).hasSize(1); + assertThat(a.getValues().get(0).getValue()).isEqualTo(singletonList("ALL")); + } + ) ) ); } @@ -50,7 +64,7 @@ void annotationWithArgument() { """ @SuppressWarnings(value = "ALL") public class A {} - """ + """ ) ); } @@ -62,7 +76,7 @@ void preserveOptionalEmptyParentheses() { """ @Deprecated ( ) public class A {} - """ + """ ) ); } @@ -74,7 +88,7 @@ void newArrayArgument() { """ import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; - + @Target({ FIELD, PARAMETER }) public @interface Annotation {} """ @@ -144,7 +158,7 @@ void typeParameterAnnotations() { import java.lang.annotation.*; class TypeAnnotationTest { List<@A ? extends @A String> list; - + @Target({ ElementType.FIELD, ElementType.TYPE_USE, ElementType.TYPE_PARAMETER }) private @interface A { } @@ -215,10 +229,10 @@ public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext p) """ import java.lang.annotation.*; public class TypeAnnotationTest { - + public @Deprecated @A TypeAnnotationTest() { } - + @Target({ ElementType.TYPE, ElementType.TYPE_USE, ElementType.TYPE_PARAMETER }) private @interface A { } @@ -227,10 +241,10 @@ public class TypeAnnotationTest { """ import java.lang.annotation.*; public class TypeAnnotationTest { - + public @Deprecated TypeAnnotationTest() { } - + @Target({ ElementType.TYPE, ElementType.TYPE_USE, ElementType.TYPE_PARAMETER }) private @interface A { } @@ -397,4 +411,87 @@ public J.ArrayType visitArrayType(J.ArrayType arrayType, Object o) { ) ); } + + @Test + void recursiveElementValue() { + rewriteRun( + java( + """ + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + + @Target(ElementType.TYPE) + private @interface A { + A[] value() default @A; + } + + @A({@A, @A(@A)}) + class TypeAnnotationTest { + } + """, spec -> spec.afterRecipe(cu -> { + J.ClassDeclaration c = cu.getClasses().get(1); + JavaType.Class type = (JavaType.Class) c.getType(); + JavaType.Annotation a = (JavaType.Annotation) type.getAnnotations().get(0); + assertThat(a.getValues()).satisfiesExactly( + v -> { + assertThat(a.getMethods()).contains(v.getElement()); + assertThat((List) (((JavaType.Annotation.ArrayElementValue) v).getValues())).satisfiesExactly( + a1 -> { + assertThat(a1.getType()).isSameAs(a.getType()); + assertThat(a1.getValues()).isEmpty(); + }, + a2 -> { + assertThat(a2.getType()).isSameAs(a.getType()); + assertThat(a2.getValues()).hasSize(1); + } + ); + } + ); + }) + ) + ); + } + + @Test + @MinimumJava21 + void testPreserveAnnotationsFromClasspath() { + JavaParser p = JavaParser.fromJavaVersion().build(); + /* + * Using these annotations in core library for testing this feature: + * + * @Deprecated(since="1.2", forRemoval=true) + * public final void stop() + * + * @CallerSensitive + * public ClassLoader getContextClassLoader() { + */ + List sourceFiles = p.parse( + """ + class Test { + public void test() { + Thread.currentThread().stop(); + Thread.currentThread().getContextClassLoader(); + } + } + """ + ).toList(); + J.CompilationUnit cu = (J.CompilationUnit) sourceFiles.get(0); + + J.MethodDeclaration md = (J.MethodDeclaration) cu.getClasses().get(0).getBody().getStatements().get(0); + J.MethodInvocation mi = (J.MethodInvocation) md.getBody().getStatements().get(0); + JavaType.Annotation annotation = (JavaType.Annotation) mi.getMethodType().getAnnotations().get(0); + + // Thread.currentThread().stop(); + assertEquals("java.lang.Deprecated" ,annotation.getType().getFullyQualifiedName()); + assertEquals("since", annotation.getValues().get(0).getElement().getName()); + assertEquals("1.2", annotation.getValues().get(0).getValue()); + assertEquals("forRemoval", annotation.getValues().get(1).getElement().getName()); + assertEquals(Boolean.TRUE, annotation.getValues().get(1).getValue()); + + // Thread.currentThread().getContextClassLoader(); + mi = (J.MethodInvocation) md.getBody().getStatements().get(1); + annotation = (JavaType.Annotation) mi.getMethodType().getAnnotations().get(0); + assertEquals("jdk.internal.reflect.CallerSensitive" ,annotation.getType().getFullyQualifiedName()); + assertTrue(annotation.getValues().isEmpty()); + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java index a7fb142280a..1ce0603dc2b 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java @@ -153,7 +153,7 @@ private JavaType.FullyQualified classTypeWithoutParameters(Class clazz) { annotations = new ArrayList<>(clazz.getDeclaredAnnotations().length); for (Annotation a : clazz.getDeclaredAnnotations()) { JavaType.FullyQualified type = (JavaType.FullyQualified) type(a.annotationType()); - annotations.add(type); + annotations.add(new JavaType.Annotation(type, emptyList())); } } @@ -298,7 +298,7 @@ private JavaType.Variable field(Field field) { annotations = new ArrayList<>(field.getDeclaredAnnotations().length); for (Annotation a : field.getDeclaredAnnotations()) { JavaType.FullyQualified type = (JavaType.FullyQualified) type(a.annotationType()); - annotations.add(type); + annotations.add(new JavaType.Annotation(type, emptyList())); } } @@ -359,7 +359,7 @@ private JavaType.Method method(Constructor method, JavaType.FullyQualified de annotations = new ArrayList<>(method.getDeclaredAnnotations().length); for (Annotation a : method.getDeclaredAnnotations()) { JavaType.FullyQualified fullyQualified = (JavaType.FullyQualified) type(a.annotationType()); - annotations.add(fullyQualified); + annotations.add(new JavaType.Annotation(fullyQualified, emptyList())); } } @@ -465,7 +465,7 @@ private JavaType.Method method(Method method, JavaType.FullyQualified declaringT annotations = new ArrayList<>(method.getDeclaredAnnotations().length); for (Annotation a : method.getDeclaredAnnotations()) { JavaType.FullyQualified fullyQualified = (JavaType.FullyQualified) type(a.annotationType()); - annotations.add(fullyQualified); + annotations.add(new JavaType.Annotation(fullyQualified, emptyList())); } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index 6f279172767..aef9c20969a 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -19,10 +19,7 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; -import lombok.AccessLevel; -import lombok.Data; -import lombok.Getter; -import lombok.With; +import lombok.*; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; import org.jspecify.annotations.Nullable; @@ -49,7 +46,7 @@ public interface JavaType { Method[] EMPTY_METHOD_ARRAY = new Method[0]; String[] EMPTY_STRING_ARRAY = new String[0]; JavaType[] EMPTY_JAVA_TYPE_ARRAY = new JavaType[0]; - AnnotationValue[] EMPTY_ANNOTATION_VALUE_ARRAY = new AnnotationValue[0]; + Annotation.ElementValue[] EMPTY_ANNOTATION_VALUE_ARRAY = new Annotation.ElementValue[0]; // TODO: To be removed with OpenRewrite 9 default @Nullable Integer getManagedReference() { @@ -631,23 +628,21 @@ public static ShallowClass build(String fullyQualifiedName) { } } - @Data - class AnnotationValue { - private final Method method; - private final @Nullable Object value; - } - class Annotation extends FullyQualified { - public final AnnotationValue @Nullable [] values; - public final FullyQualified type; + private final FullyQualified type; + private final ElementValue @Nullable [] values; - public Annotation(FullyQualified type, List values) { + public Annotation(FullyQualified type, List values) { this.type = type; this.values = ListUtils.arrayOrNullIfEmpty(values, EMPTY_ANNOTATION_VALUE_ARRAY); } - public List getValues() { + public FullyQualified getType() { + return type; + } + + public List getValues() { return values == null ? emptyList() : Arrays.asList(values); } @@ -658,7 +653,7 @@ public String getFullyQualifiedName() { @Override public FullyQualified withFullyQualifiedName(String fullyQualifiedName) { - return null; + return this; } @Override @@ -668,7 +663,7 @@ public List getAnnotations() { @Override public boolean hasFlags(Flag... test) { - return type.hasFlags(); + return type.hasFlags(test); } @Override @@ -710,6 +705,32 @@ public List getTypeParameters() { public @Nullable FullyQualified getSupertype() { return type.getSupertype(); } + + public interface ElementValue { + Method getElement(); + Object getValue(); + } + + @Value + public static class SingleElementValue implements ElementValue { + Method element; + Object value; + } + + @Value + public static class ArrayElementValue implements ElementValue { + Method element; + Object[] values; + + @Override + public Object getValue() { + return getValues(); + } + + public List getValues() { + return Arrays.asList(values); + } + } } @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) From bdb85c5b0bf560a6aac3bb69af6d52050eb920d3 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Tue, 10 Dec 2024 15:06:33 +0100 Subject: [PATCH 029/179] Polish --- .../org/openrewrite/java/tree/JavaType.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index 84b8fd34b17..c0c47f4ec55 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -19,7 +19,10 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; -import lombok.*; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Value; +import lombok.With; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; import org.jspecify.annotations.Nullable; @@ -322,16 +325,16 @@ public String getPackageName() { public boolean isAssignableTo(String fullyQualifiedName) { return TypeUtils.fullyQualifiedNamesAreEqual(getFullyQualifiedName(), fullyQualifiedName) || - getInterfaces().stream().anyMatch(anInterface -> anInterface.isAssignableTo(fullyQualifiedName)) || - (getSupertype() != null && getSupertype().isAssignableTo(fullyQualifiedName)); + getInterfaces().stream().anyMatch(anInterface -> anInterface.isAssignableTo(fullyQualifiedName)) || + (getSupertype() != null && getSupertype().isAssignableTo(fullyQualifiedName)); } public boolean isAssignableFrom(@Nullable JavaType type) { if (type instanceof FullyQualified) { FullyQualified clazz = (FullyQualified) type; return TypeUtils.fullyQualifiedNamesAreEqual(getFullyQualifiedName(), clazz.getFullyQualifiedName()) || - isAssignableFrom(clazz.getSupertype()) || - clazz.getInterfaces().stream().anyMatch(this::isAssignableFrom); + isAssignableFrom(clazz.getSupertype()) || + clazz.getInterfaces().stream().anyMatch(this::isAssignableFrom); } else if (type instanceof GenericTypeVariable) { GenericTypeVariable generic = (GenericTypeVariable) type; for (JavaType bound : generic.getBounds()) { @@ -576,7 +579,7 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Class aClass = (Class) o; return TypeUtils.fullyQualifiedNamesAreEqual(fullyQualifiedName, aClass.fullyQualifiedName) && - (typeParameters == null && aClass.typeParameters == null || typeParameters != null && Arrays.equals(typeParameters, aClass.typeParameters)); + (typeParameters == null && aClass.typeParameters == null || typeParameters != null && Arrays.equals(typeParameters, aClass.typeParameters)); } @Override @@ -708,6 +711,7 @@ public List getTypeParameters() { public interface ElementValue { Method getElement(); + Object getValue(); } @@ -958,7 +962,7 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; GenericTypeVariable that = (GenericTypeVariable) o; return name.equals(that.name) && variance == that.variance && - (variance == Variance.INVARIANT && bounds == null && that.bounds == null || bounds != null && Arrays.equals(bounds, that.bounds)); + (variance == Variance.INVARIANT && bounds == null && that.bounds == null || bounds != null && Arrays.equals(bounds, that.bounds)); } @Override @@ -1462,9 +1466,9 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Method method = (Method) o; return Objects.equals(declaringType, method.declaringType) && - name.equals(method.name) && - Objects.equals(returnType, method.returnType) && - Arrays.equals(parameterTypes, method.parameterTypes); + name.equals(method.name) && + Objects.equals(returnType, method.returnType) && + Arrays.equals(parameterTypes, method.parameterTypes); } @Override From 865540c14f87d691bd9d445924e0351a2fabc3c5 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Tue, 10 Dec 2024 15:17:16 +0100 Subject: [PATCH 030/179] Polish --- .../main/java/org/openrewrite/java/JavaTypeMappingTest.java | 2 +- .../java/internal/JavaReflectionTypeMappingTest.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java index 3dc8d562eef..5cc91ef765f 100644 --- a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java +++ b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java @@ -221,7 +221,7 @@ default void enumTypeB() { } @Test - default void ignoreSourceRetentionAnnotations() { + default void includeSourceRetentionAnnotations() { JavaType.Parameterized goat = goatType(); assertThat(goat.getAnnotations()).satisfiesExactlyInAnyOrder( a -> assertThat(a.getClassName()).isEqualTo("AnnotationWithRuntimeRetention"), diff --git a/rewrite-java/src/test/java/org/openrewrite/java/internal/JavaReflectionTypeMappingTest.java b/rewrite-java/src/test/java/org/openrewrite/java/internal/JavaReflectionTypeMappingTest.java index 6c2e192fac9..06d20326f58 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/internal/JavaReflectionTypeMappingTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/internal/JavaReflectionTypeMappingTest.java @@ -26,7 +26,7 @@ @SuppressWarnings("ConstantConditions") class JavaReflectionTypeMappingTest implements JavaTypeMappingTest { - JavaReflectionTypeMapping typeMapping = new JavaReflectionTypeMapping(new AdaptiveRadixJavaTypeCache()); + JavaReflectionTypeMapping typeMapping = new JavaReflectionTypeMapping(new JavaTypeCache()); JavaType.Parameterized goat = TypeUtils.asParameterized(typeMapping.type(JavaTypeGoat.class)); @Override @@ -61,7 +61,8 @@ public void enumTypeB() { @Test @Override - public void ignoreSourceRetentionAnnotations() { + // The JavaReflectionTypeMapping cannot include source retention annotations + public void includeSourceRetentionAnnotations() { JavaType.Parameterized goat = goatType(); assertThat(goat.getAnnotations()).satisfiesExactlyInAnyOrder( a -> assertThat(a.getClassName()).isEqualTo("AnnotationWithRuntimeRetention") From 99ad9cd9f25313f3163170a65d3bb1e0c20732a6 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Tue, 10 Dec 2024 15:46:40 +0100 Subject: [PATCH 031/179] Fix failing tests --- .../java/isolated/ReloadableJava11TypeMapping.java | 6 ++++-- .../java/isolated/ReloadableJava17TypeMapping.java | 6 ++++-- .../java/isolated/ReloadableJava21TypeMapping.java | 6 ++++-- .../org/openrewrite/java/ReloadableJava8TypeMapping.java | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java index 973e84db769..94b6b2a1605 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java @@ -716,7 +716,8 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { private Object annotationElementValue(Object value) { if (value instanceof Symbol.VarSymbol) { - return requireNonNull(variableType((Symbol.VarSymbol) value)); + JavaType.Variable mapped = variableType((Symbol.VarSymbol) value); + return mapped != null ? mapped : JavaType.Unknown.getInstance(); } else if (value instanceof Type.ClassType) { return type((Type.ClassType) value); } else if (value instanceof Attribute.Array) { @@ -734,7 +735,8 @@ private Object annotationElementValue(Object value) { } else if (value instanceof Attribute.Class) { return type(((Attribute.Class) value).classType); } else if (value instanceof Attribute.Compound) { - return requireNonNull(annotationType((Attribute.Compound) value)); + JavaType.Annotation mapped = annotationType((Attribute.Compound) value); + return mapped != null ? mapped : JavaType.Unknown.getInstance(); } else if (value instanceof Attribute.Constant) { return annotationElementValue(((Attribute.Constant) value).value); } else if (value instanceof Attribute.Enum) { diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java index c6492644776..3c8e04a33fb 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java @@ -723,7 +723,8 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { private Object annotationElementValue(Object value) { if (value instanceof Symbol.VarSymbol) { - return requireNonNull(variableType((Symbol.VarSymbol) value)); + JavaType.Variable mapped = variableType((Symbol.VarSymbol) value); + return mapped != null ? mapped : JavaType.Unknown.getInstance(); } else if (value instanceof Type.ClassType) { return type((Type.ClassType) value); } else if (value instanceof Attribute.Array) { @@ -741,7 +742,8 @@ private Object annotationElementValue(Object value) { } else if (value instanceof Attribute.Class) { return type(((Attribute.Class) value).classType); } else if (value instanceof Attribute.Compound) { - return requireNonNull(annotationType((Attribute.Compound) value)); + JavaType.Annotation mapped = annotationType((Attribute.Compound) value); + return mapped != null ? mapped : JavaType.Unknown.getInstance(); } else if (value instanceof Attribute.Constant) { return annotationElementValue(((Attribute.Constant) value).value); } else if (value instanceof Attribute.Enum) { diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index 236f0049715..913d7b745b5 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -735,7 +735,8 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { private Object annotationElementValue(Object value) { if (value instanceof Symbol.VarSymbol) { - return requireNonNull(variableType((Symbol.VarSymbol) value)); + JavaType.Variable mapped = variableType((Symbol.VarSymbol) value); + return mapped != null ? mapped : JavaType.Unknown.getInstance(); } else if (value instanceof Type.ClassType) { return type((Type.ClassType) value); } else if (value instanceof Attribute.Array) { @@ -753,7 +754,8 @@ private Object annotationElementValue(Object value) { } else if (value instanceof Attribute.Class) { return type(((Attribute.Class) value).classType); } else if (value instanceof Attribute.Compound) { - return requireNonNull(annotationType((Attribute.Compound) value)); + JavaType.Annotation mapped = annotationType((Attribute.Compound) value); + return mapped != null ? mapped : JavaType.Unknown.getInstance(); } else if (value instanceof Attribute.Constant) { return annotationElementValue(((Attribute.Constant) value).value); } else if (value instanceof Attribute.Enum) { diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java index 3f1a5ce597b..4f71eb4fb45 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java @@ -717,7 +717,8 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { private Object annotationElementValue(Object value) { if (value instanceof Symbol.VarSymbol) { - return requireNonNull(variableType((Symbol.VarSymbol) value)); + JavaType.Variable mapped = variableType((Symbol.VarSymbol) value); + return mapped != null ? mapped : JavaType.Unknown.getInstance(); } else if (value instanceof Type.ClassType) { return type((Type.ClassType) value); } else if (value instanceof Attribute.Array) { @@ -735,7 +736,8 @@ private Object annotationElementValue(Object value) { } else if (value instanceof Attribute.Class) { return type(((Attribute.Class) value).classType); } else if (value instanceof Attribute.Compound) { - return requireNonNull(annotationType((Attribute.Compound) value)); + JavaType.Annotation mapped = annotationType((Attribute.Compound) value); + return mapped != null ? mapped : JavaType.Unknown.getInstance(); } else if (value instanceof Attribute.Constant) { return annotationElementValue(((Attribute.Constant) value).value); } else if (value instanceof Attribute.Enum) { From d86eeaa8731b05f4f382bdbc95f695c5285cb409 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Tue, 10 Dec 2024 15:48:43 +0100 Subject: [PATCH 032/179] Polish --- .../openrewrite/java/Java21ParserTest.java | 49 ------------------- .../openrewrite/java/tree/AnnotationTest.java | 5 +- 2 files changed, 3 insertions(+), 51 deletions(-) diff --git a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java index 821cb2600a4..d5255503810 100644 --- a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java +++ b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java @@ -17,18 +17,11 @@ import org.junit.jupiter.api.Test; import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.SourceFile; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaType; import org.openrewrite.test.RewriteTest; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; class Java21ParserTest implements RewriteTest { @@ -37,46 +30,4 @@ void shouldLoadResourceFromClasspath() throws IOException { Files.deleteIfExists(Paths.get(System.getProperty("user.home"), ".rewrite", "classpath", "jackson-annotations-2.17.1.jar")); rewriteRun(spec -> spec.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "jackson-annotations"))); } - - @Test - void testPreserveAnnotationsFromClasspath() { - JavaParser p = JavaParser.fromJavaVersion().build(); - /* - * Using these annotations in core library for testing this feature: - * - * @Deprecated(since="1.2", forRemoval=true) - * public final void stop() - * - * @CallerSensitive - * public ClassLoader getContextClassLoader() { - */ - List sourceFiles = p.parse( - """ - class Test { - public void test() { - Thread.currentThread().stop(); - Thread.currentThread().getContextClassLoader(); - } - } - """ - ).toList(); - J.CompilationUnit cu = (J.CompilationUnit) sourceFiles.get(0); - - J.MethodDeclaration md = (J.MethodDeclaration) cu.getClasses().get(0).getBody().getStatements().get(0); - J.MethodInvocation mi = (J.MethodInvocation) md.getBody().getStatements().get(0); - JavaType.Annotation annotation = (JavaType.Annotation) mi.getMethodType().getAnnotations().get(0); - - // Thread.currentThread().stop(); - assertEquals("java.lang.Deprecated" ,annotation.getType().getFullyQualifiedName()); - assertEquals("since", annotation.getValues().get(0).getElement().getName()); - assertEquals("1.2", annotation.getValues().get(0).getValue()); - assertEquals("forRemoval", annotation.getValues().get(1).getElement().getName()); - assertEquals(Boolean.TRUE, annotation.getValues().get(1).getValue()); - - // Thread.currentThread().getContextClassLoader(); - mi = (J.MethodInvocation) md.getBody().getStatements().get(1); - annotation = (JavaType.Annotation) mi.getMethodType().getAnnotations().get(0); - assertEquals("jdk.internal.reflect.CallerSensitive" ,annotation.getType().getFullyQualifiedName()); - assertTrue(annotation.getValues().isEmpty()); - } } diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java index b9992b3ac92..2a78b225c19 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java @@ -421,6 +421,7 @@ void recursiveElementValue() { import java.lang.annotation.Target; @Target(ElementType.TYPE) + @A private @interface A { A[] value() default @A; } @@ -453,8 +454,8 @@ class TypeAnnotationTest { } @Test - @MinimumJava21 - void testPreserveAnnotationsFromClasspath() { + @MinimumJava21 // Because of `@Deprecated#forRemoval` + void annotationElementValues() { JavaParser p = JavaParser.fromJavaVersion().build(); /* * Using these annotations in core library for testing this feature: From bee3e2f46e75671a4740fdefda2ed64e2a643c5f Mon Sep 17 00:00:00 2001 From: Shannon Pamperl Date: Tue, 10 Dec 2024 21:10:08 -0600 Subject: [PATCH 033/179] Remove redundant versions for Gradle (#4492) * Remove versions that are equal when compared to Gradle platform * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Add implementation for more test cases * Fix implementation to handle transitive configurations and reduce scope to the current buildscript only * Polish * Fix handling of freestanding scripts which don't contain dependency configurations. Include fix for ChangeDependencyClassifier for G.MapLiteral types --------- Co-authored-by: Tim te Beek Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../gradle/ChangeDependencyClassifier.java | 6 +- .../RemoveRedundantDependencyVersions.java | 316 ++++++++++++++++++ ...RemoveRedundantDependencyVersionsTest.java | 310 +++++++++++++++++ 3 files changed, 627 insertions(+), 5 deletions(-) create mode 100644 rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java create mode 100644 rewrite-gradle/src/test/java/org/openrewrite/gradle/RemoveRedundantDependencyVersionsTest.java diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyClassifier.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyClassifier.java index fcc162cea02..007f0c45ef4 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyClassifier.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/ChangeDependencyClassifier.java @@ -214,11 +214,7 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu G.MapEntry mapEntry = null; String classifierStringDelimiter = null; int index = 0; - for (Expression e : depArgs) { - if (!(e instanceof G.MapEntry)) { - continue; - } - G.MapEntry arg = (G.MapEntry) e; + for (G.MapEntry arg : map.getElements()) { if (!(arg.getKey() instanceof J.Literal) || !(arg.getValue() instanceof J.Literal)) { continue; } diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java new file mode 100644 index 00000000000..4f6804c6e07 --- /dev/null +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java @@ -0,0 +1,316 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.gradle; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.jspecify.annotations.Nullable; +import org.openrewrite.*; +import org.openrewrite.gradle.marker.GradleDependencyConfiguration; +import org.openrewrite.gradle.marker.GradleProject; +import org.openrewrite.gradle.trait.GradleDependency; +import org.openrewrite.gradle.util.ChangeStringLiteral; +import org.openrewrite.gradle.util.Dependency; +import org.openrewrite.gradle.util.DependencyStringNotationConverter; +import org.openrewrite.groovy.GroovyIsoVisitor; +import org.openrewrite.groovy.tree.G; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.maven.MavenDownloadingException; +import org.openrewrite.maven.internal.MavenPomDownloader; +import org.openrewrite.maven.tree.GroupArtifactVersion; +import org.openrewrite.maven.tree.ResolvedDependency; +import org.openrewrite.maven.tree.ResolvedPom; +import org.openrewrite.semver.ExactVersion; +import org.openrewrite.semver.LatestIntegration; +import org.openrewrite.semver.Semver; +import org.openrewrite.semver.VersionComparator; + +import java.util.*; + +@Value +@EqualsAndHashCode(callSuper = false) +public class RemoveRedundantDependencyVersions extends Recipe { + @Option(displayName = "Group", + description = "Group glob expression pattern used to match dependencies that should be managed." + + "Group is the first part of a dependency coordinate `com.google.guava:guava:VERSION`.", + example = "com.google.*", + required = false) + @Nullable + String groupPattern; + + @Option(displayName = "Artifact", + description = "Artifact glob expression pattern used to match dependencies that should be managed." + + "Artifact is the second part of a dependency coordinate `com.google.guava:guava:VERSION`.", + example = "guava*", + required = false) + @Nullable + String artifactPattern; + + @Option(displayName = "Only if managed version is ...", + description = "Only remove the explicit version if the managed version has the specified comparative relationship to the explicit version. " + + "For example, `gte` will only remove the explicit version if the managed version is the same or newer. " + + "Default `eq`.", + valid = {"any", "eq", "lt", "lte", "gt", "gte"}, + required = false) + @Nullable + Comparator onlyIfManagedVersionIs; + + @Option(displayName = "Except", + description = "Accepts a list of GAVs. Dependencies matching a GAV will be ignored by this recipe." + + " GAV versions are ignored if provided.", + example = "com.jcraft:jsch", + required = false) + @Nullable + List except; + + public enum Comparator { + ANY, + EQ, + LT, + LTE, + GT, + GTE + } + + @Override + public String getDisplayName() { + return "Remove redundant explicit dependency versions"; + } + + @Override + public String getDescription() { + return "Remove explicitly-specified dependency versions that are managed by a Gradle `platform`/`enforcedPlatform`."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check( + new IsBuildGradle<>(), + new GroovyIsoVisitor() { + GradleProject gp; + final Map> platforms = new HashMap<>(); + + @Override + public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionContext ctx) { + Optional maybeGp = cu.getMarkers().findFirst(GradleProject.class); + if (!maybeGp.isPresent()) { + return cu; + } + + gp = maybeGp.get(); + new GroovyIsoVisitor() { + final MethodMatcher platformMatcher = new MethodMatcher("org.gradle.api.artifacts.dsl.DependencyHandler platform(..)"); + final MethodMatcher enforcedPlatformMatcher = new MethodMatcher("org.gradle.api.artifacts.dsl.DependencyHandler enforcedPlatform(..)"); + + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext p) { + J.MethodInvocation m = super.visitMethodInvocation(method, p); + if (!platformMatcher.matches(m) && !enforcedPlatformMatcher.matches(m)) { + return m; + } + + if (m.getArguments().get(0) instanceof J.Literal) { + J.Literal l = (J.Literal) m.getArguments().get(0); + if (l.getType() != JavaType.Primitive.String) { + return m; + } + + Dependency dependency = DependencyStringNotationConverter.parse((String) l.getValue()); + MavenPomDownloader mpd = new MavenPomDownloader(p); + try { + ResolvedPom platformPom = mpd.download(new GroupArtifactVersion(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion()), null, null, gp.getMavenRepositories()) + .resolve(Collections.emptyList(), mpd, p); + platforms.computeIfAbsent(getCursor().getParent(1).firstEnclosing(J.MethodInvocation.class).getSimpleName(), k -> new ArrayList<>()).add(platformPom); + } catch (MavenDownloadingException e) { + return m; + } + } else if (m.getArguments().get(0) instanceof G.MapEntry) { + String groupId = null; + String artifactId = null; + String version = null; + + for (Expression arg : m.getArguments()) { + if (!(arg instanceof G.MapEntry)) { + continue; + } + + G.MapEntry entry = (G.MapEntry) arg; + if (!(entry.getKey() instanceof J.Literal) || !(entry.getValue() instanceof J.Literal)) { + continue; + } + + J.Literal key = (J.Literal) entry.getKey(); + J.Literal value = (J.Literal) entry.getValue(); + if (key.getType() != JavaType.Primitive.String || value.getType() != JavaType.Primitive.String) { + continue; + } + + switch ((String) key.getValue()) { + case "group": + groupId = (String) value.getValue(); + break; + case "name": + artifactId = (String) value.getValue(); + break; + case "version": + version = (String) value.getValue(); + break; + } + } + + if (groupId == null || artifactId == null || version == null) { + return m; + } + + MavenPomDownloader mpd = new MavenPomDownloader(p); + try { + ResolvedPom platformPom = mpd.download(new GroupArtifactVersion(groupId, artifactId, version), null, null, gp.getMavenRepositories()) + .resolve(Collections.emptyList(), mpd, p); + platforms.computeIfAbsent(getCursor().getParent(1).firstEnclosing(J.MethodInvocation.class).getSimpleName(), k -> new ArrayList<>()).add(platformPom); + } catch (MavenDownloadingException e) { + return m; + } + } + return m; + } + }.visit(cu, ctx); + + return super.visitCompilationUnit(cu, ctx); + } + + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); + + Optional maybeGradleDependency = new GradleDependency.Matcher() + .groupId(groupPattern) + .artifactId(artifactPattern) + .get(getCursor()); + if (!maybeGradleDependency.isPresent()) { + return m; + } + + GradleDependency gradleDependency = maybeGradleDependency.get(); + ResolvedDependency d = gradleDependency.getResolvedDependency(); + if (StringUtils.isBlank(d.getVersion())) { + return m; + } + + if (platforms.containsKey(m.getSimpleName())) { + for (ResolvedPom platform : platforms.get(m.getSimpleName())) { + String managedVersion = platform.getManagedVersion(d.getGroupId(), d.getArtifactId(), null, d.getRequested().getClassifier()); + if (matchesComparator(managedVersion, d.getVersion())) { + return maybeRemoveVersion(m); + } + } + } + GradleDependencyConfiguration gdc = gp.getConfiguration(m.getSimpleName()); + if (gdc != null) { + for (GradleDependencyConfiguration configuration : gdc.allExtendsFrom()) { + if (platforms.containsKey(configuration.getName())) { + for (ResolvedPom platform : platforms.get(configuration.getName())) { + String managedVersion = platform.getManagedVersion(d.getGroupId(), d.getArtifactId(), null, d.getRequested().getClassifier()); + if (matchesComparator(managedVersion, d.getVersion())) { + return maybeRemoveVersion(m); + } + } + } + } + } + + return m; + } + + private J.MethodInvocation maybeRemoveVersion(J.MethodInvocation m) { + if (m.getArguments().get(0) instanceof J.Literal) { + J.Literal l = (J.Literal) m.getArguments().get(0); + if (l.getType() != JavaType.Primitive.String) { + return m; + } + + Dependency dep = DependencyStringNotationConverter.parse((String) l.getValue()) + .withVersion(null); + if (dep.getClassifier() != null || dep.getExt() != null) { + return m; + } + + return m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> ChangeStringLiteral.withStringValue(l, dep.toStringNotation()))); + } else if (m.getArguments().get(0) instanceof G.MapLiteral) { + return m.withArguments(ListUtils.mapFirst(m.getArguments(), arg -> { + G.MapLiteral mapLiteral = (G.MapLiteral) arg; + return mapLiteral.withElements(ListUtils.map(mapLiteral.getElements(), entry -> { + if (entry.getKey() instanceof J.Literal && + "version".equals(((J.Literal) entry.getKey()).getValue())) { + return null; + } + return entry; + })); + })); + } else if (m.getArguments().get(0) instanceof G.MapEntry) { + return m.withArguments(ListUtils.map(m.getArguments(), arg -> { + G.MapEntry entry = (G.MapEntry) arg; + if (entry.getKey() instanceof J.Literal && + "version".equals(((J.Literal) entry.getKey()).getValue())) { + return null; + } + return entry; + })); + } + return m; + } + } + ); + } + + private Comparator determineComparator() { + if (onlyIfManagedVersionIs != null) { + return onlyIfManagedVersionIs; + } + return Comparator.EQ; + } + + private boolean matchesComparator(@Nullable String managedVersion, String requestedVersion) { + Comparator comparator = determineComparator(); + if (managedVersion == null) { + return false; + } + if (comparator.equals(Comparator.ANY)) { + return true; + } + if (!isExact(managedVersion)) { + return false; + } + int comparison = new LatestIntegration(null) + .compare(null, managedVersion, requestedVersion); + if (comparison < 0) { + return comparator.equals(Comparator.LT) || comparator.equals(Comparator.LTE); + } else if (comparison > 0) { + return comparator.equals(Comparator.GT) || comparator.equals(Comparator.GTE); + } else { + return comparator.equals(Comparator.EQ) || comparator.equals(Comparator.LTE) || comparator.equals(Comparator.GTE); + } + } + + private boolean isExact(String managedVersion) { + Validated maybeVersionComparator = Semver.validate(managedVersion, null); + return maybeVersionComparator.isValid() && maybeVersionComparator.getValue() instanceof ExactVersion; + } +} diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/RemoveRedundantDependencyVersionsTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/RemoveRedundantDependencyVersionsTest.java new file mode 100644 index 00000000000..379b0381291 --- /dev/null +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/RemoveRedundantDependencyVersionsTest.java @@ -0,0 +1,310 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.gradle; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.gradle.Assertions.buildGradle; +import static org.openrewrite.gradle.toolingapi.Assertions.withToolingApi; + +class RemoveRedundantDependencyVersionsTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec.beforeRecipe(withToolingApi()) + .recipe(new RemoveRedundantDependencyVersions(null, null, null, null)); + } + + @DocumentExample + @Test + void literal() { + rewriteRun( + buildGradle( + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation("org.apache.commons:commons-lang3:3.14.0") + } + """, + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation("org.apache.commons:commons-lang3") + } + """ + ) + ); + } + + @Test + void mapEntry() { + rewriteRun( + buildGradle( + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation(group: "org.apache.commons", name: "commons-lang3", version: "3.14.0") + } + """, + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation(group: "org.apache.commons", name: "commons-lang3") + } + """ + ) + ); + } + + @Test + void mapLiteral() { + rewriteRun( + buildGradle( + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation([group: "org.apache.commons", name: "commons-lang3", version: "3.14.0"]) + } + """, + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation([group: "org.apache.commons", name: "commons-lang3"]) + } + """ + ) + ); + } + + @Test + void enforcedPlatform() { + rewriteRun( + buildGradle( + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation(enforcedPlatform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation("org.apache.commons:commons-lang3:3.14.0") + } + """, + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation(enforcedPlatform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation("org.apache.commons:commons-lang3") + } + """ + ) + ); + } + + @Test + void platformUsingMapEntry() { + rewriteRun( + buildGradle( + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation(enforcedPlatform(group: "org.springframework.boot", name: "spring-boot-dependencies", version: "3.3.3")) + implementation("org.apache.commons:commons-lang3:3.14.0") + } + """, + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation(enforcedPlatform(group: "org.springframework.boot", name: "spring-boot-dependencies", version: "3.3.3")) + implementation("org.apache.commons:commons-lang3") + } + """ + ) + ); + } + + @Test + void freestandingScript() { + rewriteRun( + buildGradle( + """ + repositories { + mavenCentral() + } + + dependencies { + implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation("org.apache.commons:commons-lang3:3.14.0") + } + """, + """ + repositories { + mavenCentral() + } + + dependencies { + implementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation("org.apache.commons:commons-lang3") + } + """, + spec -> spec.path("dependencies.gradle") + ), + buildGradle( + """ + plugins { + id("java") + } + + apply from: 'dependencies.gradle' + """ + ) + ); + } + + @Test + void transitiveConfiguration() { + rewriteRun( + buildGradle( + """ + plugins { + id "java-library" + } + + repositories { + mavenCentral() + } + + dependencies { + api(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation("org.apache.commons:commons-lang3:3.14.0") + } + """, + """ + plugins { + id "java-library" + } + + repositories { + mavenCentral() + } + + dependencies { + api(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + implementation("org.apache.commons:commons-lang3") + } + """ + ) + ); + } + + @Test + void unmanagedDependency() { + rewriteRun( + buildGradle( + """ + plugins { + id "java" + } + + repositories { + mavenCentral() + } + + dependencies { + implementation("org.apache.commons:commons-lang3:3.14.0") + + testImplementation(platform("org.springframework.boot:spring-boot-dependencies:3.3.3")) + } + """ + ) + ); + } +} From 1c90a621288f392af0845d8df9c7d682dec3e204 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Wed, 11 Dec 2024 08:23:12 +0100 Subject: [PATCH 034/179] Change return type of `JavaType.Annotation.ElementValue#getElement()` --- .../openrewrite/java/tree/AnnotationTest.java | 6 ++-- .../org/openrewrite/java/tree/JavaType.java | 32 +++++++++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java index 2a78b225c19..5dd60f9aa76 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java @@ -435,7 +435,7 @@ class TypeAnnotationTest { JavaType.Annotation a = (JavaType.Annotation) type.getAnnotations().get(0); assertThat(a.getValues()).satisfiesExactly( v -> { - assertThat(a.getMethods()).contains(v.getElement()); + assertThat(v.getElement()).isIn(a.getMethods()); assertThat((List) (((JavaType.Annotation.ArrayElementValue) v).getValues())).satisfiesExactly( a1 -> { assertThat(a1.getType()).isSameAs(a.getType()); @@ -484,9 +484,9 @@ public void test() { // Thread.currentThread().stop(); assertEquals("java.lang.Deprecated" ,annotation.getType().getFullyQualifiedName()); - assertEquals("since", annotation.getValues().get(0).getElement().getName()); + assertEquals("since", ((JavaType.Method) annotation.getValues().get(0).getElement()).getName()); assertEquals("1.2", annotation.getValues().get(0).getValue()); - assertEquals("forRemoval", annotation.getValues().get(1).getElement().getName()); + assertEquals("forRemoval", ((JavaType.Method) annotation.getValues().get(1).getElement()).getName()); assertEquals(Boolean.TRUE, annotation.getValues().get(1).getValue()); // Thread.currentThread().getContextClassLoader(); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index c0c47f4ec55..6062c9d6579 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -631,24 +631,36 @@ public static ShallowClass build(String fullyQualifiedName) { } } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) class Annotation extends FullyQualified { - private final FullyQualified type; - private final ElementValue @Nullable [] values; + @Getter + @With + final FullyQualified type; + + final ElementValue @Nullable [] values; public Annotation(FullyQualified type, List values) { - this.type = type; - this.values = ListUtils.arrayOrNullIfEmpty(values, EMPTY_ANNOTATION_VALUE_ARRAY); + this(type, arrayOrNullIfEmpty(values, EMPTY_ANNOTATION_VALUE_ARRAY)); } - public FullyQualified getType() { - return type; + Annotation(FullyQualified type, ElementValue @Nullable [] values) { + this.type = type; + this.values = nullIfEmpty(values); } public List getValues() { return values == null ? emptyList() : Arrays.asList(values); } + public Annotation withValues(@Nullable List values) { + ElementValue[] valuesArray = arrayOrNullIfEmpty(values, EMPTY_ANNOTATION_VALUE_ARRAY); + if (Arrays.equals(valuesArray, this.values)) { + return this; + } + return new Annotation(type, valuesArray); + } + @Override public String getFullyQualifiedName() { return type.getFullyQualifiedName(); @@ -656,7 +668,7 @@ public String getFullyQualifiedName() { @Override public FullyQualified withFullyQualifiedName(String fullyQualifiedName) { - return this; + return withType(type.withFullyQualifiedName(fullyQualifiedName)); } @Override @@ -710,20 +722,20 @@ public List getTypeParameters() { } public interface ElementValue { - Method getElement(); + JavaType getElement(); Object getValue(); } @Value public static class SingleElementValue implements ElementValue { - Method element; + JavaType element; Object value; } @Value public static class ArrayElementValue implements ElementValue { - Method element; + JavaType element; Object[] values; @Override From ecfb0e5059504736017f5edb1adf51c95229980f Mon Sep 17 00:00:00 2001 From: Peter Streef Date: Wed, 11 Dec 2024 08:34:33 +0100 Subject: [PATCH 035/179] Allow building uri from origin, path and service type (#4767) * Allow building uri from origin, path and service type * remove redundant test --- .../main/java/org/openrewrite/GitRemote.java | 30 +++++++++++-------- .../java/org/openrewrite/GitRemoteTest.java | 24 +++++++-------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/GitRemote.java b/rewrite-core/src/main/java/org/openrewrite/GitRemote.java index 6816c8e9c8b..371827b21b6 100644 --- a/rewrite-core/src/main/java/org/openrewrite/GitRemote.java +++ b/rewrite-core/src/main/java/org/openrewrite/GitRemote.java @@ -113,51 +113,55 @@ public Parser() { * @return the clone url */ public URI toUri(GitRemote remote, String protocol) { + return buildUri(remote.service, remote.origin, remote.path, protocol); + } + + public URI buildUri(Service service, String origin, String path, String protocol) { if (!ALLOWED_PROTOCOLS.contains(protocol)) { throw new IllegalArgumentException("Invalid protocol: " + protocol + ". Must be one of: " + ALLOWED_PROTOCOLS); } URI selectedBaseUrl; - if (remote.service == Service.Unknown) { - if (PORT_PATTERN.matcher(remote.origin).find()) { - throw new IllegalArgumentException("Unable to determine protocol/port combination for an unregistered origin with a port: " + remote.origin); + if (service == Service.Unknown) { + if (PORT_PATTERN.matcher(origin).find()) { + throw new IllegalArgumentException("Unable to determine protocol/port combination for an unregistered origin with a port: " + origin); } - selectedBaseUrl = URI.create(protocol + "://" + stripProtocol(remote.origin)); + selectedBaseUrl = URI.create(protocol + "://" + stripProtocol(origin)); } else { selectedBaseUrl = servers.stream() .filter(server -> server.allOrigins() .stream() - .anyMatch(origin -> origin.equalsIgnoreCase(stripProtocol(remote.origin))) + .anyMatch(o -> o.equalsIgnoreCase(stripProtocol(origin))) ) .flatMap(server -> server.getUris().stream()) .filter(uri -> uri.getScheme().equals(protocol)) .findFirst() .orElseGet(() -> { - URI normalizedUri = Parser.normalize(remote.origin); + URI normalizedUri = Parser.normalize(origin); if (!normalizedUri.getScheme().equals(protocol)) { - throw new IllegalStateException("No matching server found that supports ssh for origin: " + remote.origin); + throw new IllegalStateException("No matching server found that supports ssh for origin: " + origin); } return normalizedUri; }); } - String path = remote.path.replaceFirst("^/", ""); + path = path.replaceFirst("^/", ""); boolean ssh = protocol.equals("ssh"); - switch (remote.service) { + switch (service) { case Bitbucket: if (!ssh) { - path = "scm/" + remote.path; + path = "scm/" + path; } break; case AzureDevOps: if (ssh) { - path = "v3/" + remote.path; + path = "v3/" + path; } else { - path = remote.path.replaceFirst("([^/]+)/([^/]+)/(.*)", "$1/$2/_git/$3"); + path = path.replaceFirst("([^/]+)/([^/]+)/(.*)", "$1/$2/_git/$3"); } break; } - if (remote.service != Service.AzureDevOps) { + if (service != Service.AzureDevOps) { path += ".git"; } String maybeSlash = selectedBaseUrl.toString().endsWith("/") ? "" : "/"; diff --git a/rewrite-core/src/test/java/org/openrewrite/GitRemoteTest.java b/rewrite-core/src/test/java/org/openrewrite/GitRemoteTest.java index 410eb17df9b..baa12ba993d 100644 --- a/rewrite-core/src/test/java/org/openrewrite/GitRemoteTest.java +++ b/rewrite-core/src/test/java/org/openrewrite/GitRemoteTest.java @@ -265,18 +265,18 @@ void parseOriginCaseInsensitive(String cloneUrl, String expectedOrigin, String e @ParameterizedTest @CsvSource(textBlock = """ - GitHub, GitHub - GITLAB, GitLab - bitbucket, Bitbucket - BitbucketCloud, BitbucketCloud - Bitbucket Cloud, BitbucketCloud - BITBUCKET_CLOUD, BitbucketCloud - AzureDevOps, AzureDevOps - AZURE_DEVOPS, AzureDevOps - Azure DevOps, AzureDevOps - idontknow, Unknown - """) - void findServiceForName(String name, GitRemote.Service service){ + GitHub, GitHub + GITLAB, GitLab + bitbucket, Bitbucket + BitbucketCloud, BitbucketCloud + Bitbucket Cloud, BitbucketCloud + BITBUCKET_CLOUD, BitbucketCloud + AzureDevOps, AzureDevOps + AZURE_DEVOPS, AzureDevOps + Azure DevOps, AzureDevOps + idontknow, Unknown + """) + void findServiceForName(String name, GitRemote.Service service) { assertThat(GitRemote.Service.forName(name)).isEqualTo(service); } From 7489e3aae307ddbf07e08972e75b4c5ecaffd721 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 11 Dec 2024 12:27:35 +0100 Subject: [PATCH 036/179] Apply OpenRewrite best practices, and make those easier to apply Following https://github.com/openrewrite/gh-automation/commit/7e877b4df8a74e79ffab0d4bb1c5f1cce1f2aa20 --- .github/workflows/receive-pr.yml | 61 ------------------- .../RemoveRedundantDependencyVersions.java | 12 ++-- rewrite.yml | 60 ++++++++++++++++++ 3 files changed, 66 insertions(+), 67 deletions(-) create mode 100644 rewrite.yml diff --git a/.github/workflows/receive-pr.yml b/.github/workflows/receive-pr.yml index 63e17f40a67..67d695322ed 100644 --- a/.github/workflows/receive-pr.yml +++ b/.github/workflows/receive-pr.yml @@ -17,64 +17,3 @@ jobs: uses: openrewrite/gh-automation/.github/workflows/receive-pr.yml@main with: recipe: 'org.openrewrite.recipes.OpenRewriteBestPracticesSubset' - rewrite_yml: | - --- - type: specs.openrewrite.org/v1beta/recipe - name: org.openrewrite.recipes.OpenRewriteBestPracticesSubset - displayName: OpenRewrite best practices - description: Best practices for OpenRewrite recipe development. - recipeList: - - org.openrewrite.recipes.JavaRecipeBestPracticesSubset - - org.openrewrite.recipes.RecipeTestingBestPracticesSubset - - org.openrewrite.recipes.RecipeNullabilityBestPracticesSubset - #- org.openrewrite.java.OrderImports - - org.openrewrite.java.format.EmptyNewlineAtEndOfFile - - org.openrewrite.staticanalysis.InlineVariable - - org.openrewrite.staticanalysis.MissingOverrideAnnotation - - org.openrewrite.staticanalysis.UseDiamondOperator - --- - type: specs.openrewrite.org/v1beta/recipe - name: org.openrewrite.recipes.JavaRecipeBestPracticesSubset - displayName: Java Recipe best practices - description: Best practices for Java recipe development. - preconditions: - - org.openrewrite.java.search.FindTypes: - fullyQualifiedTypeName: org.openrewrite.Recipe - checkAssignability: true - recipeList: - - org.openrewrite.java.recipes.BlankLinesAroundFieldsWithAnnotations - - org.openrewrite.java.recipes.ExecutionContextParameterName - - org.openrewrite.java.recipes.MissingOptionExample - - org.openrewrite.java.recipes.RecipeEqualsAndHashCodeCallSuper - - org.openrewrite.java.recipes.UseTreeRandomId - - org.openrewrite.staticanalysis.NeedBraces - #- org.openrewrite.staticanalysis.RemoveSystemOutPrintln - --- - type: specs.openrewrite.org/v1beta/recipe - name: org.openrewrite.recipes.RecipeTestingBestPracticesSubset - displayName: Recipe testing best practices - description: Best practices for testing recipes. - preconditions: - - org.openrewrite.java.search.FindTypes: - fullyQualifiedTypeName: org.openrewrite.test.RewriteTest - checkAssignability: true - recipeList: - - org.openrewrite.java.recipes.RewriteTestClassesShouldNotBePublic - #- org.openrewrite.java.recipes.SelectRecipeExamples - - org.openrewrite.java.recipes.SourceSpecTextBlockIndentation - - org.openrewrite.java.testing.cleanup.RemoveTestPrefix - - org.openrewrite.java.testing.cleanup.TestsShouldNotBePublic - - org.openrewrite.staticanalysis.NeedBraces - - org.openrewrite.staticanalysis.RemoveSystemOutPrintln - --- - type: specs.openrewrite.org/v1beta/recipe - name: org.openrewrite.recipes.RecipeNullabilityBestPracticesSubset - displayName: Recipe nullability best practices - description: Use OpenRewrite internal nullability annotations; drop JetBrains annotations; use `package-info.java` instead. - recipeList: - - org.openrewrite.staticanalysis.NullableOnMethodReturnType - - org.openrewrite.java.RemoveAnnotation: - annotationPattern: '@org.jetbrains.annotations.NotNull' - - org.openrewrite.java.RemoveAnnotation: - annotationPattern: '@jakarta.annotation.Nonnull' - #- org.openrewrite.java.jspecify.MigrateToJspecify diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java index 4f6804c6e07..3aaa09f6a4e 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java @@ -121,8 +121,8 @@ public G.CompilationUnit visitCompilationUnit(G.CompilationUnit cu, ExecutionCon final MethodMatcher enforcedPlatformMatcher = new MethodMatcher("org.gradle.api.artifacts.dsl.DependencyHandler enforcedPlatform(..)"); @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext p) { - J.MethodInvocation m = super.visitMethodInvocation(method, p); + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); if (!platformMatcher.matches(m) && !enforcedPlatformMatcher.matches(m)) { return m; } @@ -134,10 +134,10 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu } Dependency dependency = DependencyStringNotationConverter.parse((String) l.getValue()); - MavenPomDownloader mpd = new MavenPomDownloader(p); + MavenPomDownloader mpd = new MavenPomDownloader(ctx); try { ResolvedPom platformPom = mpd.download(new GroupArtifactVersion(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion()), null, null, gp.getMavenRepositories()) - .resolve(Collections.emptyList(), mpd, p); + .resolve(Collections.emptyList(), mpd, ctx); platforms.computeIfAbsent(getCursor().getParent(1).firstEnclosing(J.MethodInvocation.class).getSimpleName(), k -> new ArrayList<>()).add(platformPom); } catch (MavenDownloadingException e) { return m; @@ -180,10 +180,10 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu return m; } - MavenPomDownloader mpd = new MavenPomDownloader(p); + MavenPomDownloader mpd = new MavenPomDownloader(ctx); try { ResolvedPom platformPom = mpd.download(new GroupArtifactVersion(groupId, artifactId, version), null, null, gp.getMavenRepositories()) - .resolve(Collections.emptyList(), mpd, p); + .resolve(Collections.emptyList(), mpd, ctx); platforms.computeIfAbsent(getCursor().getParent(1).firstEnclosing(J.MethodInvocation.class).getSimpleName(), k -> new ArrayList<>()).add(platformPom); } catch (MavenDownloadingException e) { return m; diff --git a/rewrite.yml b/rewrite.yml new file mode 100644 index 00000000000..8f5dec62d1e --- /dev/null +++ b/rewrite.yml @@ -0,0 +1,60 @@ +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.recipes.OpenRewriteBestPracticesSubset +displayName: OpenRewrite best practices +description: Best practices for OpenRewrite recipe development. +recipeList: + - org.openrewrite.recipes.JavaRecipeBestPracticesSubset + - org.openrewrite.recipes.RecipeTestingBestPracticesSubset + - org.openrewrite.recipes.RecipeNullabilityBestPracticesSubset + #- org.openrewrite.java.OrderImports + - org.openrewrite.java.format.EmptyNewlineAtEndOfFile + - org.openrewrite.staticanalysis.InlineVariable + - org.openrewrite.staticanalysis.MissingOverrideAnnotation + - org.openrewrite.staticanalysis.UseDiamondOperator +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.recipes.JavaRecipeBestPracticesSubset +displayName: Java Recipe best practices +description: Best practices for Java recipe development. +preconditions: + - org.openrewrite.java.search.FindTypes: + fullyQualifiedTypeName: org.openrewrite.Recipe + checkAssignability: true +recipeList: + - org.openrewrite.java.recipes.BlankLinesAroundFieldsWithAnnotations + - org.openrewrite.java.recipes.ExecutionContextParameterName + - org.openrewrite.java.recipes.MissingOptionExample + - org.openrewrite.java.recipes.RecipeEqualsAndHashCodeCallSuper + - org.openrewrite.java.recipes.UseTreeRandomId + - org.openrewrite.staticanalysis.NeedBraces + #- org.openrewrite.staticanalysis.RemoveSystemOutPrintln +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.recipes.RecipeTestingBestPracticesSubset +displayName: Recipe testing best practices +description: Best practices for testing recipes. +preconditions: + - org.openrewrite.java.search.FindTypes: + fullyQualifiedTypeName: org.openrewrite.test.RewriteTest + checkAssignability: true +recipeList: + - org.openrewrite.java.recipes.RewriteTestClassesShouldNotBePublic + #- org.openrewrite.java.recipes.SelectRecipeExamples + - org.openrewrite.java.recipes.SourceSpecTextBlockIndentation + - org.openrewrite.java.testing.cleanup.RemoveTestPrefix + - org.openrewrite.java.testing.cleanup.TestsShouldNotBePublic + - org.openrewrite.staticanalysis.NeedBraces + - org.openrewrite.staticanalysis.RemoveSystemOutPrintln +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.recipes.RecipeNullabilityBestPracticesSubset +displayName: Recipe nullability best practices +description: Use OpenRewrite internal nullability annotations; drop JetBrains annotations; use `package-info.java` instead. +recipeList: + - org.openrewrite.staticanalysis.NullableOnMethodReturnType + - org.openrewrite.java.RemoveAnnotation: + annotationPattern: '@org.jetbrains.annotations.NotNull' + - org.openrewrite.java.RemoveAnnotation: + annotationPattern: '@jakarta.annotation.Nonnull' + #- org.openrewrite.java.jspecify.MigrateToJspecify \ No newline at end of file From 2bcf39466a4839e52949c7c8b072bce4d1ac325e Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 11 Dec 2024 12:32:17 +0100 Subject: [PATCH 037/179] Document the use of `rewrite.yml` --- rewrite.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/rewrite.yml b/rewrite.yml index 8f5dec62d1e..6ed6b2ee876 100644 --- a/rewrite.yml +++ b/rewrite.yml @@ -1,3 +1,21 @@ +# +# Copyright 2024 the original author or authors. +#

+# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +#

+# https://www.apache.org/licenses/LICENSE-2.0 +#

+# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +--- +# Apply a subset of best practices to OpenRewrite recipes; typically run before committing changes. +# Any differences produced by this recipe will result in code suggestion comments on pull requests. --- type: specs.openrewrite.org/v1beta/recipe name: org.openrewrite.recipes.OpenRewriteBestPracticesSubset From d789bcb8418c985982b4ed5ef9a1a4b010ca8bf0 Mon Sep 17 00:00:00 2001 From: Niels de Bruin Date: Wed, 11 Dec 2024 12:33:51 +0100 Subject: [PATCH 038/179] Performance improvements of `Find` recipe (#4758) * Implement some performance improvements on Find recipe * Add extra tests * Modify last test * Restore linked list * More performance gains --------- Co-authored-by: Tim te Beek --- .../main/java/org/openrewrite/text/Find.java | 48 +++++-- .../java/org/openrewrite/text/FindTest.java | 117 ++++++++++++++++++ 2 files changed, 157 insertions(+), 8 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/text/Find.java b/rewrite-core/src/main/java/org/openrewrite/text/Find.java index 90450be6d64..e0503c6d73a 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/Find.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/Find.java @@ -26,9 +26,7 @@ import org.openrewrite.remote.Remote; import org.openrewrite.table.TextMatches; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -91,6 +89,22 @@ public String getDescription() { @Nullable String filePattern; + private static Deque findAllNewLineIndexes(String input, int offset) { + ArrayDeque indexes = new ArrayDeque<>(); + int index = input.lastIndexOf('\n', offset); // Find the first occurrence + if (index != -1) { + indexes.add(index); + } + + index = input.indexOf('\n', offset); // Find occurrence after the offset + while (index != -1) { + indexes.add(index); // Add the index to the list + index = input.indexOf('\n', index + 1); // Find the next occurrence + } + + return indexes; + } + @Override public TreeVisitor getVisitor() { @@ -123,24 +137,42 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { return sourceFile; } matcher.reset(); + + String sourceFilePath = sourceFile.getSourcePath().toString(); + List snippets = new ArrayList<>(); int previousEnd = 0; + + Deque newlineIndexes = null; + int lastNewLineIndex = -1; + while (matcher.find()) { + if (newlineIndexes == null) { + newlineIndexes = findAllNewLineIndexes(rawText, matcher.start()); + } + int matchStart = matcher.start(); snippets.add(snippet(rawText.substring(previousEnd, matchStart))); snippets.add(SearchResult.found(snippet(rawText.substring(matchStart, matcher.end())))); previousEnd = matcher.end(); - int startLine = Math.max(0, rawText.substring(0, matchStart).lastIndexOf('\n') + 1); + while (!newlineIndexes.isEmpty() && newlineIndexes.peek() < matchStart) { + lastNewLineIndex = newlineIndexes.pop(); + } + int startLine = Math.max(0, lastNewLineIndex + 1); + int endLine = rawText.indexOf('\n', matcher.end()); if (endLine == -1) { endLine = rawText.length(); } textMatches.insertRow(ctx, new TextMatches.Row( - sourceFile.getSourcePath().toString(), - rawText.substring(startLine, matcher.start()) + "~~>" + - rawText.substring(matcher.start(), endLine) + sourceFilePath, + new StringBuilder(endLine - startLine + 3) + .append(rawText, startLine, matcher.start()) + .append("~~>") + .append(rawText, matcher.start(), endLine) + .toString() )); } snippets.add(snippet(rawText.substring(previousEnd))); @@ -160,8 +192,8 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { return visitor; } - private static PlainText.Snippet snippet(String text) { return new PlainText.Snippet(Tree.randomId(), Markers.EMPTY, text); } + } diff --git a/rewrite-core/src/test/java/org/openrewrite/text/FindTest.java b/rewrite-core/src/test/java/org/openrewrite/text/FindTest.java index 0bfae8cadbb..b887986efb1 100644 --- a/rewrite-core/src/test/java/org/openrewrite/text/FindTest.java +++ b/rewrite-core/src/test/java/org/openrewrite/text/FindTest.java @@ -111,4 +111,121 @@ void caseInsensitive() { ) ); } + + @Test + void regexBasicMultiLine() { + rewriteRun( + spec -> spec.recipe(new Find("[T\\s]", true, true, true, null, null)), + text( + """ + This is\ttext. + This is\ttext. + """, + """ + ~~>This~~> is~~>\ttext.~~> + ~~>This~~> is~~>\ttext. + """ + ) + ); + } + + @Test + void regexWithoutMultilineAndDotall() { + rewriteRun( + spec -> spec.recipe(new Find("^This.*below\\.$", true, true, false, false, null)), + text( + """ + This is text. + This is a line below. + This is a line above. + This is text. + This is a line below. + """ + ) + ); + } + + @Test + void regexMatchingWhitespaceWithoutMultilineWithDotall() { + rewriteRun( + spec -> spec.recipe(new Find("One.Two$", true, true, false, true, null)), + //language=csv + text( // the `.` above matches the space character on the same line + """ + Zero + One Two + Three + """ + ) + ); + } + + @Test + void regexWithoutMultilineAndWithDotAll() { + rewriteRun( + spec -> spec.recipe(new Find("^This.*below\\.$", true, true, false, true, null)), + text( + """ + This is text. + This is a line below. + This is a line above. + This is text. + This is a line below. + """, + """ + ~~>This is text. + This is a line below. + This is a line above. + This is text. + This is a line below. + """ + ) + ); + } + + @Test + void regexWithMultilineAndWithoutDotall() { + rewriteRun( + spec -> spec.recipe(new Find("^This.*below\\.$", true, true, true, false, null)), + text( + """ + This is text. + This is a line below. + This is a line above. + This is text. + This is a line below. + """, + """ + This is text. + ~~>This is a line below. + This is a line above. + This is text. + ~~>This is a line below. + """ + ) + ); + } + + @Test + void regexWithBothMultilineAndDotAll() { + rewriteRun( + spec -> spec.recipe(new Find("^This.*below\\.$", true, true, true, true, null)), + text( + """ + The first line. + This is a line below. + This is a line above. + This is text. + This is a line below. + """, + """ + The first line. + ~~>This is a line below. + This is a line above. + This is text. + This is a line below. + """ + ) + ); + } } From ecc2d628a03f289558e4d93097cd1e9aa9f734c7 Mon Sep 17 00:00:00 2001 From: Peter Streef Date: Wed, 11 Dec 2024 14:31:20 +0100 Subject: [PATCH 039/179] Strip origin in findRemoteServer (#4771) * Strip origin in findRemoteServer * fix test --- .../main/java/org/openrewrite/GitRemote.java | 18 ++++++++++++++++-- .../java/org/openrewrite/GitRemoteTest.java | 10 ++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/GitRemote.java b/rewrite-core/src/main/java/org/openrewrite/GitRemote.java index 371827b21b6..85f3063024c 100644 --- a/rewrite-core/src/main/java/org/openrewrite/GitRemote.java +++ b/rewrite-core/src/main/java/org/openrewrite/GitRemote.java @@ -116,6 +116,14 @@ public URI toUri(GitRemote remote, String protocol) { return buildUri(remote.service, remote.origin, remote.path, protocol); } + /** + * Build a {@link URI} clone url from components, if that protocol is supported (configured) by the matched server + * @param service the type of SCM service + * @param origin the origin of the SCM service, any protocol will be stripped (and not used for matching) + * @param path the path to the repository + * @param protocol the protocol to use. Supported protocols: ssh, http, https + * @return + */ public URI buildUri(Service service, String origin, String path, String protocol) { if (!ALLOWED_PROTOCOLS.contains(protocol)) { throw new IllegalArgumentException("Invalid protocol: " + protocol + ". Must be one of: " + ALLOWED_PROTOCOLS); @@ -207,11 +215,17 @@ public Parser registerRemote(Service service, String origin) { return this; } + /** + * Find a registered remote server by an origin. + * @param origin the origin of the server. Any protocol will be stripped (and not used to match) + * @return The server if found, or an unknown type server with a normalized url/origin if not found. + */ public RemoteServer findRemoteServer(String origin) { - return servers.stream().filter(server -> server.origin.equalsIgnoreCase(origin)) + String strippedOrigin = stripProtocol(origin); + return servers.stream().filter(server -> server.origin.equalsIgnoreCase(strippedOrigin)) .findFirst() .orElseGet(() -> { - URI normalizedUri = normalize(origin); + URI normalizedUri = normalize(strippedOrigin); String normalizedOrigin = normalizedUri.getHost() + maybePort(normalizedUri.getPort(), normalizedUri.getScheme()); return new RemoteServer(Service.Unknown, normalizedOrigin, normalizedUri); }); diff --git a/rewrite-core/src/test/java/org/openrewrite/GitRemoteTest.java b/rewrite-core/src/test/java/org/openrewrite/GitRemoteTest.java index baa12ba993d..37581c2f934 100644 --- a/rewrite-core/src/test/java/org/openrewrite/GitRemoteTest.java +++ b/rewrite-core/src/test/java/org/openrewrite/GitRemoteTest.java @@ -232,11 +232,21 @@ void shouldNotStripJgit() { assertThat(remote.getPath()).isEqualTo("openrewrite/jgit"); } + @Test + void shouldNotReplaceExistingWellKnownServer(){ + GitRemote.Parser parser = new GitRemote.Parser() + .registerRemote(GitRemote.Service.GitHub, URI.create("https://github.com"), List.of(URI.create("ssh://notgithub.com"))); + + assertThat(parser.findRemoteServer("github.com").getUris()) + .containsExactlyInAnyOrder(URI.create("https://github.com"), URI.create("ssh://git@github.com")); + } + @Test void findRemote() { GitRemote.Parser parser = new GitRemote.Parser() .registerRemote(GitRemote.Service.Bitbucket, URI.create("scm.company.com/stash"), Collections.emptyList()); assertThat(parser.findRemoteServer("github.com").getService()).isEqualTo(GitRemote.Service.GitHub); + assertThat(parser.findRemoteServer("https://github.com").getService()).isEqualTo(GitRemote.Service.GitHub); assertThat(parser.findRemoteServer("gitlab.com").getService()).isEqualTo(GitRemote.Service.GitLab); assertThat(parser.findRemoteServer("bitbucket.org").getService()).isEqualTo(GitRemote.Service.BitbucketCloud); assertThat(parser.findRemoteServer("dev.azure.com").getService()).isEqualTo(GitRemote.Service.AzureDevOps); From a473f26e58ebc2e8cdbbce933f1bc71ec6a069c8 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Wed, 11 Dec 2024 18:15:58 +0100 Subject: [PATCH 040/179] Groovy parser does not support multiple closure arguments without parentheses (#4772) * Add tests * Working implementation * Improvement * Add `copySpec` to gradle test * Rename test function methods * improvement * improvement * improvement * `hasParentheses` improvement * better comment * improvement * Remove deprecated groovy `OmitParentheses` * Revert "Remove deprecated groovy `OmitParentheses`" This reverts commit 4c21910bf7c9f5b2baf8985749a01d3cea933cec. --------- Co-authored-by: Tim te Beek --- .../groovy/GroovyParserVisitor.java | 38 ++++++--- .../org/openrewrite/groovy/GroovyPrinter.java | 44 ++++++----- .../groovy/tree/MethodInvocationTest.java | 79 +++++++++++++++++++ 3 files changed, 132 insertions(+), 29 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index b710c0c78cc..39e8a02f4be 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -805,11 +805,11 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { int saveCursor = cursor; Space beforeOpenParen = whitespace(); - OmitParentheses omitParentheses = null; + boolean hasParentheses = true; if (source.charAt(cursor) == '(') { cursor++; } else { - omitParentheses = new OmitParentheses(randomId()); + hasParentheses = false; beforeOpenParen = EMPTY; cursor = saveCursor; } @@ -853,25 +853,26 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { if (unparsedArgs.isEmpty()) { args.add(JRightPadded.build((Expression) new J.Empty(randomId(), whitespace(), Markers.EMPTY)) - .withAfter(omitParentheses == null ? sourceBefore(")") : EMPTY)); + .withAfter(hasParentheses ? sourceBefore(")") : EMPTY)); } else { + boolean lastArgumentsAreAllClosures = endsWithClosures(expression.getExpressions()); for (int i = 0; i < unparsedArgs.size(); i++) { org.codehaus.groovy.ast.expr.Expression rawArg = unparsedArgs.get(i); Expression arg = visit(rawArg); - if (omitParentheses != null) { - arg = arg.withMarkers(arg.getMarkers().add(omitParentheses)); + if (!hasParentheses) { + arg = arg.withMarkers(arg.getMarkers().add(new OmitParentheses(randomId()))); } Space after = EMPTY; if (i == unparsedArgs.size() - 1) { - if (omitParentheses == null) { + if (hasParentheses) { after = sourceBefore(")"); } - } else { + } else if (!(arg instanceof J.Lambda && lastArgumentsAreAllClosures && !hasParentheses)) { after = whitespace(); if (source.charAt(cursor) == ')') { - // the next argument will have an OmitParentheses marker - omitParentheses = new OmitParentheses(randomId()); + // next argument(s), if they exists, are trailing closures and will have an OmitParentheses marker + hasParentheses = false; } cursor++; } @@ -883,6 +884,25 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { queue.add(JContainer.build(beforeOpenParen, args, Markers.EMPTY)); } + public boolean endsWithClosures(List list) { + if (!(list.get(list.size() - 1) instanceof ClosureExpression)) { + return false; + } + + boolean foundNonClosure = false; + for (int i = list.size() - 2; i >= 0; i--) { + if (list.get(i) instanceof ClosureExpression) { + if (foundNonClosure) { + return false; + } + } else { + foundNonClosure = true; + } + } + + return true; + } + @Override public void visitClassExpression(ClassExpression clazz) { String unresolvedName = clazz.getType().getUnresolvedName().replace('$', '.'); diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java index e0d462843cb..17e0a466a6c 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java @@ -295,16 +295,16 @@ public J visitLambda(J.Lambda lambda, PrintOutputCapture

p) { LambdaStyle ls = lambda.getMarkers().findFirst(LambdaStyle.class) .orElse(new LambdaStyle(null, false, !lambda.getParameters().getParameters().isEmpty())); boolean parenthesized = lambda.getParameters().isParenthesized(); - if(!ls.isJavaStyle()) { + if (!ls.isJavaStyle()) { p.append('{'); } visitMarkers(lambda.getParameters().getMarkers(), p); visitSpace(lambda.getParameters().getPrefix(), Space.Location.LAMBDA_PARAMETERS_PREFIX, p); - if(parenthesized) { + if (parenthesized) { p.append('('); } visitRightPadded(lambda.getParameters().getPadding().getParameters(), JRightPadded.Location.LAMBDA_PARAM, ",", p); - if(parenthesized) { + if (parenthesized) { p.append(')'); } if (ls.isArrow()) { @@ -318,7 +318,7 @@ public J visitLambda(J.Lambda lambda, PrintOutputCapture

p) { } else { visit(lambda.getBody(), p); } - if(!ls.isJavaStyle()) { + if (!ls.isJavaStyle()) { p.append('}'); } afterSyntax(lambda, p); @@ -358,6 +358,7 @@ public J visitForEachLoop(J.ForEachLoop forEachLoop, PrintOutputCapture

p) { afterSyntax(forEachLoop, p); return forEachLoop; } + @Override public J visitMethodDeclaration(J.MethodDeclaration method, PrintOutputCapture

p) { beforeSyntax(method, Space.Location.METHOD_DECLARATION_PREFIX, p); @@ -417,29 +418,32 @@ public J visitMethodInvocation(J.MethodInvocation method, PrintOutputCapture

visitSpace(argContainer.getBefore(), Space.Location.METHOD_INVOCATION_ARGUMENTS, p); List> args = argContainer.getPadding().getElements(); + boolean argsAreAllClosures = args.stream().allMatch(it -> it.getElement() instanceof J.Lambda); + boolean hasParentheses = true; + boolean applyTrailingLambdaParenthese = true; for (int i = 0; i < args.size(); i++) { JRightPadded arg = args.get(i); - boolean omitParens = arg.getElement().getMarkers() - .findFirst(OmitParentheses.class) - .isPresent() || - arg.getElement().getMarkers() - .findFirst(org.openrewrite.java.marker.OmitParentheses.class) - .isPresent(); - - if (i == 0 && !omitParens) { - p.append('('); - } else if (i > 0 && omitParens && ( - !args.get(0).getElement().getMarkers().findFirst(OmitParentheses.class).isPresent() && - !args.get(0).getElement().getMarkers().findFirst(org.openrewrite.java.marker.OmitParentheses.class).isPresent() - )) { - p.append(')'); - } else if (i > 0) { + boolean omitParensCurrElem = arg.getElement().getMarkers().findFirst(OmitParentheses.class).isPresent() || + arg.getElement().getMarkers().findFirst(org.openrewrite.java.marker.OmitParentheses.class).isPresent(); + + if (i == 0) { + if (omitParensCurrElem) { + hasParentheses = false; + } else { + p.append('('); + } + } else if (hasParentheses && omitParensCurrElem) { // first trailing lambda, eg: `stage('Build..') {}`, should close the method + if (applyTrailingLambdaParenthese) { // apply once, to support multiple closures: `foo("baz") {} {} + p.append(')'); + applyTrailingLambdaParenthese = false; + } + } else if (hasParentheses || !argsAreAllClosures) { p.append(','); } visitRightPadded(arg, JRightPadded.Location.METHOD_INVOCATION_ARGUMENT, p); - if (i == args.size() - 1 && !omitParens) { + if (i == args.size() - 1 && !omitParensCurrElem) { p.append(')'); } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java index cd5ea56bed3..a0714126901 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java @@ -69,6 +69,19 @@ void emptyArgsWithParens() { ); } + @Test + void noParentheses() { + rewriteRun( + groovy( + """ + class SomeObject {} + def foo(String a, int b, SomeObject c, String d) {} + foo "a", 3, new SomeObject(), "d" + """ + ) + ); + } + @Test @SuppressWarnings("GroovyVariableNotAssigned") void nullSafeDereference() { @@ -180,6 +193,72 @@ def acceptsClosure(Closure cl) {} ); } + @Issue("https://github.com/openrewrite/rewrite/issues/4766") + @Test + void gradleFileWithMultipleClosuresWithoutParentheses() { + rewriteRun( + groovy( + """ + copySpec { + from { 'src/main/webapp' } { exclude "**/*.jpg" } + rename '(.+)-staging(.+)', '$1$2' + } + """ + ) + ); + } + + @Test + void multipleClosureArgumentsWithoutParentheses() { + rewriteRun( + groovy( + """ + def foo(Closure a, Closure b, Closure c) {} + foo { } { } { + } + """ + ) + ); + } + + @Test + void multipleClosureArgumentsWithParentheses() { + rewriteRun( + groovy( + """ + def foo(Closure a, Closure b, Closure c) {} + foo({ }, { }, { + }) + """ + ) + ); + } + + @Test + void multipleArgumentsWithClosuresAndNonClosuresWithoutParentheses() { + rewriteRun( + groovy( + """ + def foo(String a, Closure b, Closure c, String d) {} + foo "a", { }, { + }, "d" + """ + ) + ); + } + + @Test + void trailingClosures() { + rewriteRun( + groovy( + """ + def foo(String a, int b, String c, Closure d, Closure e, Closure f) {} + foo("bar", 3, "baz") { } { } {} + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/1236") @Test @SuppressWarnings("GroovyAssignabilityCheck") From 15f250220fd5cbf1fa594b88b32bd47d80057fb1 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Thu, 12 Dec 2024 10:05:57 +0100 Subject: [PATCH 041/179] Correct `J.FieldAccess#isFullyQualifiedClassReference()` (#4774) * Correct `J.FieldAccess.isFullyQualifiedClassReference()` The commit e536ed273fda87ce6857b06f200488130b3ef5f3 introduced a regression here. Fixes: #4773 * Fix * Fix again * More improvements and tests * More improvements * Polish * Polish * Polish * Polish * Exclude `JavaType.Unknown` from being matched --- .../org/openrewrite/java/ChangeTypeTest.java | 116 +++++++++++++++++- .../SimplifyBooleanExpressionVisitorTest.java | 2 +- .../java/org/openrewrite/java/tree/J.java | 10 +- 3 files changed, 123 insertions(+), 5 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java index ad20be88dc7..c453a2246fb 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/ChangeTypeTest.java @@ -208,7 +208,7 @@ class Test { class Test { List p; - List p2; + java.util.List p2; java.util.List p3; } """ @@ -2072,10 +2072,12 @@ void changeTypeInPropertiesFile() { properties( """ a.property=java.lang.String + c.property=java.lang.StringBuilder b.property=String """, """ a.property=java.lang.Integer + c.property=java.lang.StringBuilder b.property=String """, spec -> spec.path("application.properties")) ); @@ -2104,4 +2106,116 @@ void changeTypeInYaml() { ) ); } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4773") + void noRenameOfTypeWithMatchingPrefix() { + rewriteRun( + spec -> spec.recipe(new ChangeType("org.codehaus.jackson.annotate.JsonIgnoreProperties", "com.fasterxml.jackson.annotation.JsonIgnoreProperties", false)) + .parser(JavaParser.fromJavaVersion() + .dependsOn( + """ + package org.codehaus.jackson.annotate; + public @interface JsonIgnoreProperties { + boolean ignoreUnknown() default false; + } + """, + """ + package org.codehaus.jackson.annotate; + public @interface JsonIgnore { + } + """ + ) + ), + java( + """ + import org.codehaus.jackson.annotate.JsonIgnore; + import org.codehaus.jackson.annotate.JsonIgnoreProperties; + + @JsonIgnoreProperties(ignoreUnknown = true) + public class myClass { + @JsonIgnore + public boolean isDirty() { + return false; + } + } + """, + """ + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import org.codehaus.jackson.annotate.JsonIgnore; + + @JsonIgnoreProperties(ignoreUnknown = true) + public class myClass { + @JsonIgnore + public boolean isDirty() { + return false; + } + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4764") + void changeTypeOfInnerClass() { + rewriteRun( + spec -> spec.recipe(new ChangeType("foo.A$Builder", "bar.A$Builder", true)) + .parser(JavaParser.fromJavaVersion().dependsOn( + """ + package foo; + + public class A { + public A.Builder builder() { + return new A.Builder(); + } + + public static class Builder { + public A build() { + return new A(); + } + } + } + """, + """ + package bar; + + public class A { + public A.Builder builder() { + return new A.Builder(); + } + + public static class Builder { + public A build() { + return new A(); + } + } + } + """ + ) + ), + java( + """ + import foo.A; + import foo.A.Builder; + + class Test { + A test() { + A.Builder b = A.builder(); + return b.build(); + } + } + """, """ + import foo.A; + + class Test { + A test() { + bar.A.Builder b = A.builder(); + return b.build(); + } + } + """ + ) + ); + } } diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java index 6b8d5b62381..4264fcf0986 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java @@ -64,7 +64,7 @@ public class A { @DocumentExample @Test - void foo() { + void skipMissingTypeAttribution() { rewriteRun( spec -> spec.typeValidationOptions(TypeValidation.builder().identifiers(false).build()), java( diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java index 7afe8698797..1ad1cee2193 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java @@ -1979,10 +1979,14 @@ public List getSideEffects() { } public boolean isFullyQualifiedClassReference(String className) { - if (!className.contains(".")) { + if (getName().getFieldType() == null && getName().getType() instanceof JavaType.FullyQualified && + !(getName().getType() instanceof JavaType.Unknown) && + TypeUtils.fullyQualifiedNamesAreEqual(((JavaType.FullyQualified) getName().getType()).getFullyQualifiedName(), className)) { + return true; + } else if (!className.contains(".")) { return false; } - return isFullyQualifiedClassReference(this, className, className.length()); + return isFullyQualifiedClassReference(this, TypeUtils.toFullyQualifiedName(className), className.length()); } private boolean isFullyQualifiedClassReference(J.FieldAccess fieldAccess, String className, int prevDotIndex) { @@ -1991,7 +1995,7 @@ private boolean isFullyQualifiedClassReference(J.FieldAccess fieldAccess, String return false; } String simpleName = fieldAccess.getName().getSimpleName(); - if (!simpleName.regionMatches(0, className, dotIndex + 1, simpleName.length())) { + if (!simpleName.regionMatches(0, className, dotIndex + 1, Math.max(simpleName.length(), prevDotIndex - dotIndex - 1))) { return false; } if (fieldAccess.getTarget() instanceof J.FieldAccess) { From f4f1996cffdded3e8029d7ff666288fe3749fe62 Mon Sep 17 00:00:00 2001 From: Peter Streef Date: Thu, 12 Dec 2024 17:04:48 +0100 Subject: [PATCH 042/179] Normalize server URLs to avoid missing scheme (#4780) * Pre-normalize server URLs to avoid missing scheme or other pieces. This changes the output slightly (no more user in the URL) but that is fine as the user is not required/used in matching anyway. Also fixed the comment and exception text. * fix comment * improve error message * Revert test changes and normalize on the fly when matching protocols * change to use only `IllegalArgumentException` --- .../main/java/org/openrewrite/GitRemote.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/GitRemote.java b/rewrite-core/src/main/java/org/openrewrite/GitRemote.java index 85f3063024c..fd42a076e68 100644 --- a/rewrite-core/src/main/java/org/openrewrite/GitRemote.java +++ b/rewrite-core/src/main/java/org/openrewrite/GitRemote.java @@ -118,18 +118,19 @@ public URI toUri(GitRemote remote, String protocol) { /** * Build a {@link URI} clone url from components, if that protocol is supported (configured) by the matched server + * * @param service the type of SCM service * @param origin the origin of the SCM service, any protocol will be stripped (and not used for matching) * @param path the path to the repository * @param protocol the protocol to use. Supported protocols: ssh, http, https - * @return + * @return the clone URL if it could be created. + * @throws IllegalArgumentException if the protocol is not supported by the server. */ public URI buildUri(Service service, String origin, String path, String protocol) { if (!ALLOWED_PROTOCOLS.contains(protocol)) { throw new IllegalArgumentException("Invalid protocol: " + protocol + ". Must be one of: " + ALLOWED_PROTOCOLS); } URI selectedBaseUrl; - if (service == Service.Unknown) { if (PORT_PATTERN.matcher(origin).find()) { throw new IllegalArgumentException("Unable to determine protocol/port combination for an unregistered origin with a port: " + origin); @@ -142,12 +143,12 @@ public URI buildUri(Service service, String origin, String path, String protocol .anyMatch(o -> o.equalsIgnoreCase(stripProtocol(origin))) ) .flatMap(server -> server.getUris().stream()) - .filter(uri -> uri.getScheme().equals(protocol)) + .filter(uri -> Parser.normalize(uri).getScheme().equals(protocol)) .findFirst() .orElseGet(() -> { URI normalizedUri = Parser.normalize(origin); if (!normalizedUri.getScheme().equals(protocol)) { - throw new IllegalStateException("No matching server found that supports ssh for origin: " + origin); + throw new IllegalArgumentException("Unable to build clone URL. No matching server found that supports " + protocol + " for origin: " + origin); } return normalizedUri; }); @@ -217,6 +218,7 @@ public Parser registerRemote(Service service, String origin) { /** * Find a registered remote server by an origin. + * * @param origin the origin of the server. Any protocol will be stripped (and not used to match) * @return The server if found, or an unknown type server with a normalized url/origin if not found. */ @@ -299,6 +301,10 @@ private String repositoryPath(RemoteServerMatch match, URI normalizedUri) { private static final Pattern PORT_PATTERN = Pattern.compile(":\\d+(/.+)(/.+)+"); + static URI normalize(URI url) { + return normalize(url.toString()); + } + static URI normalize(String url) { try { URIish uri = new URIish(url); @@ -392,10 +398,11 @@ public Set allOrigins() { Set origins = new LinkedHashSet<>(); origins.add(origin); for (URI uri : uris) { - URI normalized = Parser.normalize(uri.toString()); + URI normalized = Parser.normalize(uri); origins.add(Parser.stripProtocol(normalized.toString())); } return origins; } + } } From fdc042b2be83f0d3c2b492475c3f3bbc32ea231d Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Thu, 12 Dec 2024 17:26:17 +0100 Subject: [PATCH 043/179] Remove a few `String#substring()` calls from Groovy parser --- .../org/openrewrite/groovy/GroovyParserVisitor.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 39e8a02f4be..e14a122df1f 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -235,7 +235,7 @@ public G.CompilationUnit visit(SourceUnit unit, ModuleNode ast) throws GroovyPar null, pkg, statements, - format(source.substring(cursor)) + format(source, cursor, source.length()) ); } @@ -2455,9 +2455,14 @@ private Space sourceBefore(String untilDelim) { return EMPTY; // unable to find this delimiter } - String prefix = source.substring(cursor, delimIndex); - cursor += prefix.length() + untilDelim.length(); // advance past the delimiter - return Space.format(prefix); + if (delimIndex == cursor) { + cursor += untilDelim.length(); + return EMPTY; + } + + Space space = format(source, cursor, delimIndex); + cursor = delimIndex + untilDelim.length(); // advance past the delimiter + return space; } /** From ceb3dab8908244dcde92ea0e569ac8930d6b2626 Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Thu, 12 Dec 2024 11:51:08 -0500 Subject: [PATCH 044/179] Fix duplicate data table entries. A while ago we changed how search results work, which inadvertently led to duplicate results in data tables like this one. --- .../org/openrewrite/java/search/FindTypesTest.java | 4 ++++ .../java/org/openrewrite/java/search/FindTypes.java | 13 ++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindTypesTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindTypesTest.java index d85bd134a47..321f560b763 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindTypesTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/search/FindTypesTest.java @@ -47,6 +47,10 @@ public static void stat() {} @Test void simpleName() { rewriteRun( + spec -> spec.dataTable(TypeUses.Row.class, rows -> assertThat(rows) + .containsExactly( + new TypeUses.Row("B.java", "A1", "a.A1") + )), java( """ import a.A1; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java index 3b9c7f4d254..f9e4a051cf7 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java @@ -206,11 +206,14 @@ public J visitFieldAccess(J.FieldAccess fieldAccess, ExecutionContext ctx) { private J2 found(J2 j, ExecutionContext ctx) { JavaType.FullyQualified fqn = TypeUtils.asFullyQualified(j.getType()); - typeUses.insertRow(ctx, new TypeUses.Row( - getCursor().firstEnclosingOrThrow(SourceFile.class).getSourcePath().toString(), - j.printTrimmed(getCursor().getParentTreeCursor()), - fqn == null ? j.getType().toString() : fqn.getFullyQualifiedName() - )); + if (!j.getMarkers().findFirst(SearchResult.class).isPresent()) { + // Avoid double-counting results in the data table + typeUses.insertRow(ctx, new TypeUses.Row( + getCursor().firstEnclosingOrThrow(SourceFile.class).getSourcePath().toString(), + j.printTrimmed(getCursor().getParentTreeCursor()), + fqn == null ? j.getType().toString() : fqn.getFullyQualifiedName() + )); + } return SearchResult.found(j); } } From 5cb394544e43a3b1e4d58229fd41f363bc27843e Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 12 Dec 2024 18:57:58 +0100 Subject: [PATCH 045/179] Drop unused GraphvizResolutionEventListener & dependency (#4778) * Drop unused GraphvizResolutionEventListener & dependency * Drop inadvertent use of logger --- rewrite-maven/build.gradle.kts | 3 - rewrite-maven/dependency-viz.kt | 125 ---------- .../maven/internal/VersionRequirement.java | 9 +- .../tree/GraphvizResolutionEventListener.java | 216 ------------------ 4 files changed, 3 insertions(+), 350 deletions(-) delete mode 100644 rewrite-maven/dependency-viz.kt delete mode 100644 rewrite-maven/src/main/java/org/openrewrite/maven/tree/GraphvizResolutionEventListener.java diff --git a/rewrite-maven/build.gradle.kts b/rewrite-maven/build.gradle.kts index 64b4be8bef4..d6efe37c616 100755 --- a/rewrite-maven/build.gradle.kts +++ b/rewrite-maven/build.gradle.kts @@ -26,8 +26,6 @@ dependencies { // needed by AddDependency implementation(project(":rewrite-java")) - compileOnly("guru.nidi:graphviz-java:latest.release") - compileOnly("org.rocksdb:rocksdbjni:latest.release") compileOnly(project(":rewrite-yaml")) implementation(project(":rewrite-properties")) @@ -41,7 +39,6 @@ dependencies { testImplementation("com.squareup.okhttp3:okhttp-tls:4.+") testImplementation("com.squareup.okio:okio-jvm:3.9.1") testImplementation("org.mapdb:mapdb:latest.release") - testImplementation("guru.nidi:graphviz-java:latest.release") testRuntimeOnly("org.mapdb:mapdb:latest.release") testRuntimeOnly(project(":rewrite-java-17")) diff --git a/rewrite-maven/dependency-viz.kt b/rewrite-maven/dependency-viz.kt deleted file mode 100644 index b9ee2bd1a84..00000000000 --- a/rewrite-maven/dependency-viz.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2021 the original author or authors. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * https://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.openrewrite.maven - -import guru.nidi.graphviz.engine.Format -import org.openrewrite.ExecutionContext -import org.openrewrite.InMemoryExecutionContext -import org.openrewrite.maven.tree.GraphvizResolutionEventListener -import org.openrewrite.maven.tree.MavenResolutionResult -import org.openrewrite.maven.tree.Scope -import java.net.URL -import java.nio.file.Path -import java.nio.file.Paths -import kotlin.io.path.exists - -fun visualize( - ctx: ExecutionContext = InMemoryExecutionContext { t -> throw t }, - scope: Scope = Scope.Compile, - outputFileLocation: Path = Paths.get("diagrams"), - outputFilePrefix: String = "maven", - showProperties: Boolean = false, - showManagedDependencies: Boolean = false, - runnable: () -> T -) { - val viz = GraphvizResolutionEventListener(scope, showProperties, showManagedDependencies) - MavenExecutionContextView(ctx).setResolutionListener(viz) - try { - runnable() - } finally { - viz.graphviz().render(Format.DOT).toFile(outputFileLocation.resolve("${outputFilePrefix}.dot").toFile()) - viz.graphviz() - .postProcessor { result, _, _ -> - result.mapString { svg -> - svg.replace("font-family=\"Times,serif\" ", "") - .replace("a xlink:href", "a target=\"_blank\" xlink:href") - } - } - .render(Format.SVG) - .toFile(outputFileLocation.resolve("${outputFilePrefix}.svg").toFile()) - - val panZoom = outputFileLocation.resolve("svg-pan-zoom.min.js") - if (!panZoom.exists()) { - panZoom.toFile().writeText( - URL("https://raw.githubusercontent.com/bumbu/svg-pan-zoom/master/dist/svg-pan-zoom.min.js") - .openStream().bufferedReader().readText() - ) - } - - outputFileLocation.resolve("${outputFilePrefix}.html").toFile().writeText( - //language=html - """ - - - - - - - - - - - """.trimIndent() - ) - } -} - -fun visualize( - gav: String, - ctx: ExecutionContext = InMemoryExecutionContext { t -> throw t }, - scope: Scope = Scope.Compile, - showProperties: Boolean = false, - showManagedDependencies: Boolean = false -) { - visualize(ctx, scope, Paths.get("diagrams"), gav.replace(':', '_'), showProperties, showManagedDependencies) { - parse(gav, ctx) - } -} - -fun parse(gav: String, ctx: ExecutionContext = InMemoryExecutionContext { t -> throw t }): MavenResolutionResult { - val (group, artifact, version) = gav.split(":") - val maven = MavenParser.builder().build().parse( - ctx, """ - - org.openrewrite - dependency-viz - 0.0.1 - - - ${group} - ${artifact} - ${version} - - - - """ - )[0] - - return maven.mavenResolutionResult() -} diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/internal/VersionRequirement.java b/rewrite-maven/src/main/java/org/openrewrite/maven/internal/VersionRequirement.java index f488d30f79b..ee67ff652f4 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/internal/VersionRequirement.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/internal/VersionRequirement.java @@ -30,8 +30,6 @@ import org.openrewrite.maven.tree.MavenMetadata; import org.openrewrite.maven.tree.MavenRepository; import org.openrewrite.maven.tree.Version; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Iterator; import java.util.List; @@ -41,7 +39,6 @@ @RequiredArgsConstructor public class VersionRequirement { - private static final Logger logger = LoggerFactory.getLogger(VersionRequirement.class); @Nullable private final VersionRequirement nearer; @@ -100,7 +97,7 @@ static VersionSpec build(String requested, boolean direct) { CharStreams.fromString(requested)))); parser.removeErrorListeners(); - parser.addErrorListener(new LoggingErrorListener()); + parser.addErrorListener(new PrintingErrorListener()); return new VersionRangeParserBaseVisitor() { @Override @@ -287,11 +284,11 @@ public String toString() { }); } - private static class LoggingErrorListener extends BaseErrorListener { + private static class PrintingErrorListener extends BaseErrorListener { @Override public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { - logger.warn("Syntax error at line {}:{} {}", line, charPositionInLine, msg); + System.out.printf("Syntax error at line %d:%d %s%n", line, charPositionInLine, msg); } } } diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/tree/GraphvizResolutionEventListener.java b/rewrite-maven/src/main/java/org/openrewrite/maven/tree/GraphvizResolutionEventListener.java deleted file mode 100644 index cf94887334e..00000000000 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/tree/GraphvizResolutionEventListener.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2021 the original author or authors. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * https://www.apache.org/licenses/LICENSE-2.0 - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.openrewrite.maven.tree; - -import guru.nidi.graphviz.attribute.Color; -import guru.nidi.graphviz.attribute.Label; -import guru.nidi.graphviz.attribute.Shape; -import guru.nidi.graphviz.attribute.Style; -import guru.nidi.graphviz.engine.Graphviz; -import guru.nidi.graphviz.model.Link; -import guru.nidi.graphviz.model.MutableGraph; -import guru.nidi.graphviz.model.MutableNode; -import lombok.RequiredArgsConstructor; -import org.jspecify.annotations.Nullable; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.stream.Collectors; - -import static guru.nidi.graphviz.model.Factory.mutGraph; -import static guru.nidi.graphviz.model.Factory.mutNode; -import static guru.nidi.graphviz.model.Link.to; -import static java.util.Collections.emptySet; - -@RequiredArgsConstructor -public class GraphvizResolutionEventListener implements ResolutionEventListener { - public static final String GRAPH_NAME = "resolution"; - - private final Map propToNode = new HashMap<>(); - private final Map pomToNode = new HashMap<>(); - private final Map> alreadySeen = new HashMap<>(); - - private MutableGraph g = mutGraph(GRAPH_NAME).setDirected(true); - - private final Scope scope; - private final boolean showProperties; - private final boolean showManagedDependencies; - - private int parentLinks; - private int dependencyLinks; - private int managedDependencies; - - @Override - public void clear() { - g = mutGraph(GRAPH_NAME).setDirected(true); - propToNode.clear(); - pomToNode.clear(); - alreadySeen.clear(); - parentLinks = 0; - dependencyLinks = 0; - managedDependencies = 0; - } - - @Override - public void parent(Pom parent, Pom containing) { - if (alreadySeen.getOrDefault(simplifyGav(containing.getGav()), emptySet()).contains(simplifyGav(parent.getGav()))) { - return; - } - alreadySeen.computeIfAbsent(simplifyGav(containing.getGav()), g -> new HashSet<>()).add(simplifyGav(parent.getGav())); - - Link link = to(gavNode(parent.getGav()).add(Style.FILLED, Color.rgb("deefee"))).with(Style.DASHED); - if (parentLinks++ == 0) { - link = link.with(Label.of("parent")); - } - gavNode(containing.getGav()).addLink(link); - } - - @Override - public void dependency(Scope scope, ResolvedDependency resolvedDependency, ResolvedPom containing) { - if (scope != this.scope) { - return; - } - - Link link = to(gavNode(resolvedDependency.getGav()).add(Style.FILLED, Color.rgb("e6eaff"))); - if (dependencyLinks++ == 0) { - link = link.with(Label.of("dependency")); - } - gavNode(containing.getGav()).addLink(link); - } - - @Override - public void property(String key, String value, Pom containing) { - if (!showProperties) { - return; - } - gavNode(containing.getGav()).addLink(propNode(key, value)); - } - - @Override - public void dependencyManagement(ManagedDependency dependencyManagement, Pom containing) { - if (!showManagedDependencies) { - return; - } - GroupArtifactVersion gav = new GroupArtifactVersion(dependencyManagement.getGroupId(), dependencyManagement.getArtifactId(), dependencyManagement.getVersion()); - - if (alreadySeen.getOrDefault(simplifyGav(containing.getGav()), emptySet()).contains(gav)) { - return; - } - alreadySeen.computeIfAbsent(simplifyGav(containing.getGav()), g -> new HashSet<>()).add(gav); - - Link link = to(dmNode(gav).add(Style.FILLED, Color.rgb("d6d6de"))); - if (managedDependencies++ == 0) { - link = link.with(Label.of("dependencyManagement")); - } - gavNode(containing.getGav()).addLink(link); - } - - @Override - public void downloadError(GroupArtifactVersion gav, List attemptedUris, @Nullable Pom containing) { - Link link = to(gavNode(gav).add(Style.FILLED, Color.rgb("ff1947"))) - .with(Label.of("error")); - if(containing != null) { - gavNode(containing.getGav()) - .addLink(link); - } - } - - @Override - public void bomImport(ResolvedGroupArtifactVersion gav, Pom containing) { - if (alreadySeen.getOrDefault(simplifyGav(containing.getGav()), emptySet()).contains(simplifyGav(gav))) { - return; - } - alreadySeen.computeIfAbsent(simplifyGav(containing.getGav()), g -> new HashSet<>()).add(simplifyGav(gav)); - - Link link = to(gavNode(gav).add(Style.FILLED, Color.rgb("e6eaff"))); - if (dependencyLinks++ == 0) { - link = link.with(Label.of("dependency")); - } - gavNode(containing.getGav()).addLink(link); - } - - @SuppressWarnings("unused") - public Graphviz graphviz() { - return Graphviz.fromGraph(g); - } - - private GroupArtifactVersion simplifyGav(ResolvedGroupArtifactVersion gav) { - return new GroupArtifactVersion(gav.getGroupId(), gav.getArtifactId(), - gav.getDatedSnapshotVersion() == null ? gav.getVersion() : gav.getDatedSnapshotVersion()); - } - - private MutableNode gavNode(ResolvedGroupArtifactVersion gav) { - return gavNode(simplifyGav(gav)); - } - - private MutableNode gavNode(GroupArtifactVersion gav) { - return pomToNode.computeIfAbsent(gav, ignored -> { - MutableNode node = mutNode(Label.lines(gav.getGroupId(), gav.getArtifactId(), gav.getVersion())) - .add(Shape.RECTANGLE, Style.FILLED, Color.rgb("f9a91b")); - String url = gavUrl(gav); - if (url != null) { - node = node.add("URL", url); - } - g.add(node); - return node; - }); - } - - private MutableNode dmNode(GroupArtifactVersion gav) { - return pomToNode.computeIfAbsent(gav, ignored -> { - MutableNode node = mutNode(Label.lines(gav.getGroupId(), gav.getArtifactId(), gav.getVersion())).add(Shape.RECTANGLE); - String url = gavUrl(gav); - if (url != null) { - node = node.add("URL", url); - } - g.add(node); - return node; - }); - } - - private MutableNode propNode(String key, String value) { - return propToNode.computeIfAbsent(key + "=" + value, ignored -> { - MutableNode node = mutNode(Label.lines(key, value)); - g.add(node); - return node; - }); - } - - private @Nullable String gavUrl(GroupArtifactVersion gav) { - if (gav.getGroupId() == null || gav.getArtifactId() == null || gav.getVersion() == null) { - return null; - } - try { - return "https://repo1.maven.org/maven2/" + - Arrays.stream(gav.getGroupId().split("\\.")) - .map(g -> { - try { - return URLEncoder.encode(g, StandardCharsets.UTF_8.name()); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - }) - .collect(Collectors.joining("/")) + '/' + - URLEncoder.encode(gav.getArtifactId(), StandardCharsets.UTF_8.name()) + '/' + - URLEncoder.encode(gav.getVersion(), StandardCharsets.UTF_8.name()) + '/' + - URLEncoder.encode(gav.getArtifactId() + '-' + gav.getVersion() + ".pom", StandardCharsets.UTF_8.name()); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } -} From abb80e16f579275811d4166bfd6387f504b25b16 Mon Sep 17 00:00:00 2001 From: adastraperangusta <39689932+adastraperangusta@users.noreply.github.com> Date: Thu, 12 Dec 2024 23:21:23 +0100 Subject: [PATCH 046/179] Allow pom download failures (#4738) * add configuration option * add configuration option to allow pom download failure * code formatting and typo * Apply formatter to minimize diff * Update rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java Co-authored-by: Tim te Beek * add test for the expected behaviour * file scheme handling * we don't nedd a property anymore * prepare test for remote repository case * tests updates * try for jar if remote pom doesn't exist * Don't download the jar bytes; only check if response is successful * Minimize diff as compared to main for now * Record the absence of the pom file when jar is found * Minor polish --------- Co-authored-by: Stef Co-authored-by: Tim te Beek Co-authored-by: Tim te Beek --- .../maven/internal/MavenPomDownloader.java | 114 +++++++++++++----- .../internal/MavenPomDownloaderTest.java | 93 ++++++++++++++ .../maven/tree/ResolvedPomTest.java | 104 ++++++++++++++++ 3 files changed, 283 insertions(+), 28 deletions(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java b/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java index 364078042d7..26e59770b35 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java @@ -561,51 +561,75 @@ public Pom download(GroupArtifactVersion gav, Path inputPath = Paths.get(gav.getGroupId(), gav.getArtifactId(), gav.getVersion()); try { - File f = new File(uri); + File pomFile = new File(uri); + File jarFile = pomFile.toPath().resolveSibling(gav.getArtifactId() + '-' + versionMaybeDatedSnapshot + ".jar").toFile(); - //NOTE: The pom may exist without a .jar artifact if the pom packaging is "pom" - if (!f.exists()) { + //NOTE: + // - The pom may exist without a .jar artifact if the pom packaging is "pom" + // - The jar may exist without a pom, if manually installed + if (!pomFile.exists() && !jarFile.exists()) { continue; } - try (FileInputStream fis = new FileInputStream(f)) { - RawPom rawPom = RawPom.parse(fis, Objects.equals(versionMaybeDatedSnapshot, gav.getVersion()) ? null : versionMaybeDatedSnapshot); - Pom pom = rawPom.toPom(inputPath, repo).withGav(resolvedGav); - - if (pom.getPackaging() == null || pom.hasJarPackaging()) { - File jar = f.toPath().resolveSibling(gav.getArtifactId() + '-' + versionMaybeDatedSnapshot + ".jar").toFile(); - if (!jar.exists() || jar.length() == 0) { - // The jar has not been downloaded, making this dependency unusable. - continue; - } + RawPom rawPom; + if (pomFile.exists()) { + try (FileInputStream fis = new FileInputStream(pomFile)) { + rawPom = RawPom.parse(fis, Objects.equals(versionMaybeDatedSnapshot, gav.getVersion()) ? null : versionMaybeDatedSnapshot); } + } else { + // Record the absense of the pom file + ctx.getResolutionListener().downloadError(gav, uris, (containingPom == null) ? null : containingPom.getRequested()); + // infer rawPom from jar + rawPom = rawPomFromGav(gav); + } - if (repo.getUri().equals(MavenRepository.MAVEN_LOCAL_DEFAULT.getUri())) { - // so that the repository path is the same regardless of username - pom = pom.withRepository(MavenRepository.MAVEN_LOCAL_USER_NEUTRAL); - } + Pom pom = rawPom.toPom(inputPath, repo).withGav(resolvedGav); - if (!Objects.equals(versionMaybeDatedSnapshot, pom.getVersion())) { - pom = pom.withGav(pom.getGav().withDatedSnapshotVersion(versionMaybeDatedSnapshot)); + if (pom.getPackaging() == null || pom.hasJarPackaging()) { + if (!jarFile.exists() || jarFile.length() == 0) { + // The jar has not been downloaded, making this dependency unusable. + continue; } - mavenCache.putPom(resolvedGav, pom); - ctx.getResolutionListener().downloadSuccess(resolvedGav, containingPom); - sample.stop(timer.tags("outcome", "from maven local").register(Metrics.globalRegistry)); - return pom; } + + if (repo.getUri().equals(MavenRepository.MAVEN_LOCAL_DEFAULT.getUri())) { + // so that the repository path is the same regardless of username + pom = pom.withRepository(MavenRepository.MAVEN_LOCAL_USER_NEUTRAL); + } + + if (!Objects.equals(versionMaybeDatedSnapshot, pom.getVersion())) { + pom = pom.withGav(pom.getGav().withDatedSnapshotVersion(versionMaybeDatedSnapshot)); + } + mavenCache.putPom(resolvedGav, pom); + ctx.getResolutionListener().downloadSuccess(resolvedGav, containingPom); + sample.stop(timer.tags("outcome", "from maven local").register(Metrics.globalRegistry)); + return pom; } catch (IOException e) { // unable to read the pom from a file-based repository. repositoryResponses.put(repo, e.getMessage()); } } else { try { - byte[] responseBody = requestAsAuthenticatedOrAnonymous(repo, uri.toString()); + RawPom rawPom; + try { + byte[] responseBody = requestAsAuthenticatedOrAnonymous(repo, uri.toString()); + rawPom = RawPom.parse( + new ByteArrayInputStream(responseBody), + Objects.equals(versionMaybeDatedSnapshot, gav.getVersion()) ? null : versionMaybeDatedSnapshot + ); + } catch (HttpSenderResponseException e) { + repositoryResponses.put(repo, e.getMessage()); + // When `pom` is not found, try to see if `jar` exists for the same GAV + if (!e.isClientSideException() || !jarExistsForPomUri(repo, uri.toString())) { + throw e; + } + // Record the absense of the pom file + ctx.getResolutionListener().downloadError(gav, uris, (containingPom == null) ? null : containingPom.getRequested()); + // Continue with a recreated pom + rawPom = rawPomFromGav(gav); + } Path inputPath = Paths.get(gav.getGroupId(), gav.getArtifactId(), gav.getVersion()); - RawPom rawPom = RawPom.parse( - new ByteArrayInputStream(responseBody), - Objects.equals(versionMaybeDatedSnapshot, gav.getVersion()) ? null : versionMaybeDatedSnapshot - ); Pom pom = rawPom.toPom(inputPath, repo).withGav(resolvedGav); if (!Objects.equals(versionMaybeDatedSnapshot, pom.getVersion())) { pom = pom.withGav(pom.getGav().withDatedSnapshotVersion(versionMaybeDatedSnapshot)); @@ -637,6 +661,12 @@ public Pom download(GroupArtifactVersion gav, .setRepositoryResponses(repositoryResponses); } + private RawPom rawPomFromGav(GroupArtifactVersion gav) { + return new RawPom(null, null, gav.getGroupId(), gav.getArtifactId(), gav.getVersion(), null, + null, null, null, "jar", null, null, null, + null, null, null, null, null, null); + } + /** * Gets the base version from snapshot timestamp version. */ @@ -850,6 +880,34 @@ private ReachabilityResult reachable(HttpSender.Request.Builder request) { } } + private boolean jarExistsForPomUri(MavenRepository repo, String pomUrl) { + String jarUrl = pomUrl.replaceAll("\\.pom$", ".jar"); + try { + try { + return Failsafe.with(retryPolicy).get(() -> { + HttpSender.Request authenticated = applyAuthenticationAndTimeoutToRequest(repo, httpSender.get(jarUrl)).build(); + try (HttpSender.Response response = httpSender.send(authenticated)) { + return response.isSuccessful(); + } + }); + } catch (FailsafeException failsafeException) { + Throwable cause = failsafeException.getCause(); + if (cause instanceof HttpSenderResponseException && hasCredentials(repo) && + ((HttpSenderResponseException) cause).isClientSideException()) { + return Failsafe.with(retryPolicy).get(() -> { + HttpSender.Request unauthenticated = httpSender.get(jarUrl).build(); + try (HttpSender.Response response = httpSender.send(unauthenticated)) { + return response.isSuccessful(); + } + }); + } + } + } catch (Throwable e) { + // Not interested in exceptions downloading the jar; we'll throw the original exception for the pom + } + return false; + } + /** * Replicates Apache Maven's behavior to attempt anonymous download if repository credentials prove invalid diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java index f16810183a6..152265c02fd 100755 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java @@ -573,6 +573,42 @@ void skipsLocalInvalidArtifactsEmptyJar(@TempDir Path localRepository) throws IO .download(new GroupArtifactVersion("com.bad", "bad-artifact", "1"), null, null, List.of(mavenLocal))); } + @Test + void dontAllowPomDowloadFailureWithoutJar(@TempDir Path localRepository) throws IOException, MavenDownloadingException { + MavenRepository mavenLocal = MavenRepository.builder() + .id("local") + .uri(localRepository.toUri().toString()) + .snapshots(false) + .knownToExist(true) + .build(); + + // Do not return invalid dependency + assertThrows(MavenDownloadingException.class, () -> new MavenPomDownloader(emptyMap(), ctx) + .download(new GroupArtifactVersion("com.bad", "bad-artifact", "1"), null, null, List.of(mavenLocal))); + } + + @Test + void allowPomDowloadFailureWithJar(@TempDir Path localRepository) throws IOException, MavenDownloadingException { + MavenRepository mavenLocal = MavenRepository.builder() + .id("local") + .uri(localRepository.toUri().toString()) + .snapshots(false) + .knownToExist(true) + .build(); + + // Create a valid jar + Path localJar = localRepository.resolve("com/some/some-artifact/1/some-artifact-1.jar"); + assertThat(localJar.getParent().toFile().mkdirs()).isTrue(); + Files.writeString(localJar, "some content not to be empty"); + + // Do not throw exception since we have a jar + var result = new MavenPomDownloader(emptyMap(), ctx) + .download(new GroupArtifactVersion("com.some", "some-artifact", "1"), null, null, List.of(mavenLocal)); + assertThat(result.getGav().getGroupId()).isEqualTo("com.some"); + assertThat(result.getGav().getArtifactId()).isEqualTo("some-artifact"); + assertThat(result.getGav().getVersion()).isEqualTo("1"); + } + @Test void doNotRenameRepoForCustomMavenLocal(@TempDir Path tempDir) throws MavenDownloadingException, IOException { GroupArtifactVersion gav = createArtifact(tempDir); @@ -1023,5 +1059,62 @@ public MockResponse dispatch(RecordedRequest recordedRequest) { throw new RuntimeException(e); } } + + @Test + @DisplayName("Throw exception if there is no pom and no jar for the artifact") + @Issue("https://github.com/openrewrite/rewrite/issues/4687") + void pomNotFoundWithNoJarShouldThrow() throws Exception { + try (MockWebServer mockRepo = getMockServer()) { + mockRepo.setDispatcher(new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest recordedRequest) { + assert recordedRequest.getPath() != null; + return new MockResponse().setResponseCode(404).setBody(""); + } + }); + mockRepo.start(); + var repositories = List.of(MavenRepository.builder() + .id("id") + .uri("http://%s:%d/maven".formatted(mockRepo.getHostName(), mockRepo.getPort())) + .username("user") + .password("pass") + .build()); + + var downloader = new MavenPomDownloader(emptyMap(), ctx); + var gav = new GroupArtifactVersion("fred", "fred", "1"); + assertThrows(MavenDownloadingException.class, () -> downloader.download(gav, null, null, repositories)); + } + } + + @Test + @DisplayName("Don't throw exception if there is no pom and but there is a jar for the artifact") + @Issue("https://github.com/openrewrite/rewrite/issues/4687") + void pomNotFoundWithJarFoundShouldntThrow() throws Exception { + try (MockWebServer mockRepo = getMockServer()) { + mockRepo.setDispatcher(new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest recordedRequest) { + assert recordedRequest.getPath() != null; + if (recordedRequest.getPath().endsWith("fred/fred/1/fred-1.pom")) + return new MockResponse().setResponseCode(404).setBody(""); + return new MockResponse().setResponseCode(200).setBody("some bytes so the jar isn't empty"); + } + }); + mockRepo.start(); + var repositories = List.of(MavenRepository.builder() + .id("id") + .uri("http://%s:%d/maven".formatted(mockRepo.getHostName(), mockRepo.getPort())) + .username("user") + .password("pass") + .build()); + + var gav = new GroupArtifactVersion("fred", "fred", "1"); + var downloader = new MavenPomDownloader(emptyMap(), ctx); + Pom downloaded = downloader.download(gav, null, null, repositories); + assertThat(downloaded.getGav().getGroupId()).isEqualTo("fred"); + assertThat(downloaded.getGav().getArtifactId()).isEqualTo("fred"); + assertThat(downloaded.getGav().getVersion()).isEqualTo("1"); + } + } } } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/tree/ResolvedPomTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/tree/ResolvedPomTest.java index 0d2714390ab..b1c0e12f1bd 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/tree/ResolvedPomTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/tree/ResolvedPomTest.java @@ -16,9 +16,20 @@ package org.openrewrite.maven.tree; import com.fasterxml.jackson.databind.ObjectMapper; +import org.intellij.lang.annotations.Language; +import org.jspecify.annotations.Nullable; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.Issue; +import org.openrewrite.maven.MavenExecutionContextView; import org.openrewrite.test.RewriteTest; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -278,4 +289,97 @@ void resolveExecutionsFromDifferentParents() { ) ); } + + @Nested + @Issue("https://github.com/openrewrite/rewrite/issues/4687") + class TolerateMissingPom { + + @Language("xml") + private static final String POM_WITH_DEPENDENCY = """ + + 4.0.0 + foo + bar + 1.0-SNAPSHOT + + + com.some + some-artifact + 1 + + + + """; + + @TempDir + Path localRepository; + @TempDir + Path localRepository2; + + @Test + void singleRepositoryContainingJar() throws IOException { + MavenRepository mavenLocal = createMavenRepository(localRepository, "local"); + createJarFile(localRepository); + + List> downloadErrorArgs = new ArrayList<>(); + MavenExecutionContextView ctx = MavenExecutionContextView.view(new InMemoryExecutionContext(Throwable::printStackTrace)); + ctx.setRepositories(List.of(mavenLocal)); + ctx.setResolutionListener(new ResolutionEventListener() { + @Override + public void downloadError(GroupArtifactVersion gav, List attemptedUris, @Nullable Pom containing) { + List list = new ArrayList<>(); + list.add(gav); + list.add(attemptedUris); + list.add(containing); + downloadErrorArgs.add(list); + } + }); + rewriteRun( + spec -> spec.executionContext(ctx), + pomXml(POM_WITH_DEPENDENCY) + ); + assertThat(downloadErrorArgs).hasSize(1); + } + + @Test + void twoRepositoriesSecondContainingJar() throws IOException { + MavenRepository mavenLocal = createMavenRepository(localRepository, "local"); + MavenRepository mavenLocal2 = createMavenRepository(localRepository2, "local2"); + createJarFile(localRepository2); + + List> downloadErrorArgs = new ArrayList<>(); + MavenExecutionContextView ctx = MavenExecutionContextView.view(new InMemoryExecutionContext(Throwable::printStackTrace)); + ctx.setRepositories(List.of(mavenLocal, mavenLocal2)); + ctx.setResolutionListener(new ResolutionEventListener() { + @Override + public void downloadError(GroupArtifactVersion gav, List attemptedUris, @Nullable Pom containing) { + List list = new ArrayList<>(); + list.add(gav); + list.add(attemptedUris); + list.add(containing); + downloadErrorArgs.add(list); + } + }); + rewriteRun( + spec -> spec.executionContext(ctx), + pomXml(POM_WITH_DEPENDENCY) + ); + assertThat(downloadErrorArgs).hasSize(1); + } + + private static void createJarFile(Path localRepository1) throws IOException { + Path localJar = localRepository1.resolve("com/some/some-artifact/1/some-artifact-1.jar"); + assertThat(localJar.getParent().toFile().mkdirs()).isTrue(); + Files.writeString(localJar, "some content not to be empty"); + } + + private static MavenRepository createMavenRepository(Path localRepository, String name) { + return MavenRepository.builder() + .id(name) + .uri(localRepository.toUri().toString()) + .snapshots(false) + .knownToExist(true) + .build(); + } + } } From 8cfcf0c8c26f3a4abb361456ba83c8bf37e51ca5 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Fri, 13 Dec 2024 08:45:54 +0100 Subject: [PATCH 047/179] Remove `Find#findAllNewLineIndexes()` Minor performance optimization. --- .../main/java/org/openrewrite/text/Find.java | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/text/Find.java b/rewrite-core/src/main/java/org/openrewrite/text/Find.java index e0503c6d73a..8a8e3a18b7c 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/Find.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/Find.java @@ -26,7 +26,9 @@ import org.openrewrite.remote.Remote; import org.openrewrite.table.TextMatches; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -89,22 +91,6 @@ public String getDescription() { @Nullable String filePattern; - private static Deque findAllNewLineIndexes(String input, int offset) { - ArrayDeque indexes = new ArrayDeque<>(); - int index = input.lastIndexOf('\n', offset); // Find the first occurrence - if (index != -1) { - indexes.add(index); - } - - index = input.indexOf('\n', offset); // Find occurrence after the offset - while (index != -1) { - indexes.add(index); // Add the index to the list - index = input.indexOf('\n', index + 1); // Find the next occurrence - } - - return indexes; - } - @Override public TreeVisitor getVisitor() { @@ -143,35 +129,42 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { List snippets = new ArrayList<>(); int previousEnd = 0; - Deque newlineIndexes = null; int lastNewLineIndex = -1; + boolean isFirstMatch = true; while (matcher.find()) { - if (newlineIndexes == null) { - newlineIndexes = findAllNewLineIndexes(rawText, matcher.start()); - } - int matchStart = matcher.start(); snippets.add(snippet(rawText.substring(previousEnd, matchStart))); snippets.add(SearchResult.found(snippet(rawText.substring(matchStart, matcher.end())))); previousEnd = matcher.end(); - while (!newlineIndexes.isEmpty() && newlineIndexes.peek() < matchStart) { - lastNewLineIndex = newlineIndexes.pop(); + // For the first match, search backwards + if (isFirstMatch) { + lastNewLineIndex = rawText.lastIndexOf('\n', matchStart); + isFirstMatch = false; + } else { + int nextNewLineIndex = rawText.indexOf('\n', lastNewLineIndex + 1); + + // Advance lastNewLineIndex while before match start + while (nextNewLineIndex != -1 && nextNewLineIndex < matchStart) { + lastNewLineIndex = nextNewLineIndex; + nextNewLineIndex = rawText.indexOf('\n', lastNewLineIndex + 1); + } } - int startLine = Math.max(0, lastNewLineIndex + 1); + int startLine = lastNewLineIndex + 1; int endLine = rawText.indexOf('\n', matcher.end()); if (endLine == -1) { endLine = rawText.length(); } + //noinspection StringBufferReplaceableByString textMatches.insertRow(ctx, new TextMatches.Row( sourceFilePath, new StringBuilder(endLine - startLine + 3) - .append(rawText, startLine, matcher.start()) + .append(rawText, startLine, matchStart) .append("~~>") - .append(rawText, matcher.start(), endLine) + .append(rawText, matchStart, endLine) .toString() )); } From 51d340da9905fda859620173599486578fa7ebe9 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Fri, 13 Dec 2024 08:53:56 +0100 Subject: [PATCH 048/179] `Find`: Small improvement --- rewrite-core/src/main/java/org/openrewrite/text/Find.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/text/Find.java b/rewrite-core/src/main/java/org/openrewrite/text/Find.java index 8a8e3a18b7c..7d112823c23 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/Find.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/Find.java @@ -130,6 +130,7 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { int previousEnd = 0; int lastNewLineIndex = -1; + int nextNewLineIndex = -1; boolean isFirstMatch = true; while (matcher.find()) { @@ -141,10 +142,9 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { // For the first match, search backwards if (isFirstMatch) { lastNewLineIndex = rawText.lastIndexOf('\n', matchStart); + nextNewLineIndex = rawText.indexOf('\n', lastNewLineIndex + 1); isFirstMatch = false; - } else { - int nextNewLineIndex = rawText.indexOf('\n', lastNewLineIndex + 1); - + } else if (nextNewLineIndex != -1 && nextNewLineIndex < matchStart) { // Advance lastNewLineIndex while before match start while (nextNewLineIndex != -1 && nextNewLineIndex < matchStart) { lastNewLineIndex = nextNewLineIndex; From 4201b5caf304cb3f8cd922daf16a7525db36576d Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Fri, 13 Dec 2024 08:58:19 +0100 Subject: [PATCH 049/179] `Find`: Small improvement --- rewrite-core/src/main/java/org/openrewrite/text/Find.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/text/Find.java b/rewrite-core/src/main/java/org/openrewrite/text/Find.java index 7d112823c23..eb8fb30c09a 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/Find.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/Find.java @@ -122,7 +122,6 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { if (!matcher.find()) { return sourceFile; } - matcher.reset(); String sourceFilePath = sourceFile.getSourcePath().toString(); @@ -133,7 +132,7 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { int nextNewLineIndex = -1; boolean isFirstMatch = true; - while (matcher.find()) { + do { int matchStart = matcher.start(); snippets.add(snippet(rawText.substring(previousEnd, matchStart))); snippets.add(SearchResult.found(snippet(rawText.substring(matchStart, matcher.end())))); @@ -167,7 +166,7 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { .append(rawText, matchStart, endLine) .toString() )); - } + } while (matcher.find()); snippets.add(snippet(rawText.substring(previousEnd))); return plainText.withText("").withSnippets(snippets); } From cdb945ff320f58af236f844c66a60c3d3582219f Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Fri, 13 Dec 2024 13:48:40 +0100 Subject: [PATCH 050/179] Move the OkHttpSender to rewrite-maven tests (#4782) As it's only ever used there; reduces the dependencies pulled into rewrite-core. --- rewrite-core/build.gradle.kts | 4 ---- rewrite-maven/build.gradle.kts | 2 ++ .../src/test/java/org/openrewrite/maven/MavenParserTest.java | 2 +- .../test/java/org/openrewrite/maven}/http/OkHttpSender.java | 3 ++- .../openrewrite/maven/internal/MavenPomDownloaderTest.java | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) rename {rewrite-core/src/main/java/org/openrewrite/ipc => rewrite-maven/src/test/java/org/openrewrite/maven}/http/OkHttpSender.java (97%) diff --git a/rewrite-core/build.gradle.kts b/rewrite-core/build.gradle.kts index ef8625e288e..e3a59325a5f 100644 --- a/rewrite-core/build.gradle.kts +++ b/rewrite-core/build.gradle.kts @@ -15,10 +15,6 @@ dependencies { api("org.jspecify:jspecify:latest.release") - // Pinning okhttp while waiting on 5.0.0 - // https://github.com/openrewrite/rewrite/issues/1479 - compileOnly("com.squareup.okhttp3:okhttp:4.9.3") - implementation("org.apache.commons:commons-compress:latest.release") implementation("io.micrometer:micrometer-core:1.9.+") diff --git a/rewrite-maven/build.gradle.kts b/rewrite-maven/build.gradle.kts index d6efe37c616..ac44b44e905 100755 --- a/rewrite-maven/build.gradle.kts +++ b/rewrite-maven/build.gradle.kts @@ -35,6 +35,8 @@ dependencies { implementation("org.apache.commons:commons-text:latest.release") testImplementation(project(":rewrite-test")) + + testImplementation("com.squareup.okhttp3:okhttp:4.+") testImplementation("com.squareup.okhttp3:mockwebserver:4.+") testImplementation("com.squareup.okhttp3:okhttp-tls:4.+") testImplementation("com.squareup.okio:okio-jvm:3.9.1") diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java index b3cbe440c88..cef61f90ef3 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java @@ -31,7 +31,7 @@ import org.openrewrite.Issue; import org.openrewrite.ParseExceptionResult; import org.openrewrite.Parser; -import org.openrewrite.ipc.http.OkHttpSender; +import org.openrewrite.maven.http.OkHttpSender; import org.openrewrite.maven.internal.MavenParsingException; import org.openrewrite.maven.tree.*; import org.openrewrite.test.RewriteTest; diff --git a/rewrite-core/src/main/java/org/openrewrite/ipc/http/OkHttpSender.java b/rewrite-maven/src/test/java/org/openrewrite/maven/http/OkHttpSender.java similarity index 97% rename from rewrite-core/src/main/java/org/openrewrite/ipc/http/OkHttpSender.java rename to rewrite-maven/src/test/java/org/openrewrite/maven/http/OkHttpSender.java index eb42f70c913..e92a9359c1d 100644 --- a/rewrite-core/src/main/java/org/openrewrite/ipc/http/OkHttpSender.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/http/OkHttpSender.java @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.openrewrite.ipc.http; +package org.openrewrite.maven.http; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.RequestBody; import okhttp3.ResponseBody; +import org.openrewrite.ipc.http.HttpSender; import java.io.IOException; import java.io.UncheckedIOException; diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java index 152265c02fd..4c19fc87f33 100755 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java @@ -33,7 +33,7 @@ import org.openrewrite.*; import org.openrewrite.ipc.http.HttpSender; import org.openrewrite.ipc.http.HttpUrlConnectionSender; -import org.openrewrite.ipc.http.OkHttpSender; +import org.openrewrite.maven.http.OkHttpSender; import org.openrewrite.maven.MavenDownloadingException; import org.openrewrite.maven.MavenExecutionContextView; import org.openrewrite.maven.MavenParser; From 601fec7db38de41e05d1cb75a2b86a6963574c2f Mon Sep 17 00:00:00 2001 From: Bramli <39566577+BramliAK@users.noreply.github.com> Date: Sun, 15 Dec 2024 13:27:14 +0100 Subject: [PATCH 051/179] Add explicit imports to avoid conflicts with classes added to java.lang, like record (#4785) * rewrite-migrate-java issue 540 : Add explicit imports to avoid conflicts with classes added to java.lang, like Record * change test name * Split conditional and add clarifying comments on Record handling * Add issue links to clarify the reason these tests were added --------- Co-authored-by: Tim te Beek --- .../org/openrewrite/java/AddImportTest.java | 45 +++++++++++++++++++ .../java/org/openrewrite/java/AddImport.java | 11 +++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java index d82981f8863..ac15fd5da84 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java @@ -184,6 +184,51 @@ class A { ); } + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/540") + @Test + void forceImportNoJavaRecord() { + // Add import for a class named `Record`, even within the same package, to avoid conflicts with java.lang.Record + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new AddImport<>("com.acme.bank.Record", null, false))), + //language=java + java( + """ + package com.acme.bank; + + class Foo { + } + """, + """ + package com.acme.bank; + + import com.acme.bank.Record; + + class Foo { + } + """, + spec -> spec.markers(javaVersion(11)) + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/540") + @Test + void notForceImportJavaRecord() { + // Do not add import for java.lang.Record by default + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new AddImport<>("java.lang.Record", null, false))), + //language=java + java( + """ + package com.acme.bank; + + class Foo { + } + """, + spec -> spec.markers(javaVersion(11)) + ) + ); + } @Test void dontImportJavaLang() { rewriteRun( diff --git a/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java b/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java index 9aecd66f89f..4299ef1dd08 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java @@ -105,9 +105,14 @@ public AddImport(@Nullable String packageName, String typeName, @Nullable String return cu; } - // No need to add imports if the class to import is in java.lang, or if the classes are within the same package - if (("java.lang".equals(packageName) && StringUtils.isBlank(member)) || (cu.getPackageDeclaration() != null && - packageName.equals(cu.getPackageDeclaration().getExpression().printTrimmed(getCursor())))) { + // No need to add imports if the class to import is in java.lang + if ("java.lang".equals(packageName) && StringUtils.isBlank(member)) { + return cu; + } + // Nor if the classes are within the same package + if (!"Record".equals(typeName) && // Record's late addition to `java.lang` might conflict with user class + cu.getPackageDeclaration() != null && + packageName.equals(cu.getPackageDeclaration().getExpression().printTrimmed(getCursor()))) { return cu; } From 36acd596ac08ac408f427f89885b1e04aaff98b6 Mon Sep 17 00:00:00 2001 From: Bramli <39566577+BramliAK@users.noreply.github.com> Date: Sun, 15 Dec 2024 20:23:51 +0100 Subject: [PATCH 052/179] Always add import for `Record` classes not from `java.lang` package, to avoid conflicts on Java 14+ (#4787) * force Import No Java Record * Apply formatter * Minor polish --------- Co-authored-by: Tim te Beek --- .../org/openrewrite/java/AddImportTest.java | 37 ++++++++++++++++++- .../java/org/openrewrite/java/AddImport.java | 29 +++++++-------- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java index ac15fd5da84..96a4a160793 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/AddImportTest.java @@ -186,10 +186,11 @@ class A { @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/540") @Test - void forceImportNoJavaRecord() { + void forceImportNonJavaLangRecord() { // Add import for a class named `Record`, even within the same package, to avoid conflicts with java.lang.Record rewriteRun( - spec -> spec.recipe(toRecipe(() -> new AddImport<>("com.acme.bank.Record", null, false))), + spec -> spec.recipe(toRecipe(() -> new AddImport<>("com.acme.bank.Record", null, false))) + .parser(JavaParser.fromJavaVersion().dependsOn("package com.acme.bank; public class Record {}")), //language=java java( """ @@ -211,6 +212,38 @@ class Foo { ); } + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/540") + @Test + void forceImportNonJavaLangRecordFromWildcardImport() { + // Add import for a class named `Record`, even within the same package, to avoid conflicts with java.lang.Record + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new AddImport<>("com.acme.bank.Record", null, false))) + .parser(JavaParser.fromJavaVersion().dependsOn("package com.acme.bank; public class Record {}")), + //language=java + java( + """ + package com.acme.bank; + + import com.acme.bank.*; + + class Foo { + } + """, + """ + package com.acme.bank; + + import com.acme.bank.*; + + import com.acme.bank.Record; + + class Foo { + } + """, + spec -> spec.markers(javaVersion(11)) + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/540") @Test void notForceImportJavaRecord() { diff --git a/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java b/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java index 4299ef1dd08..2e23df27adb 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/AddImport.java @@ -110,8 +110,7 @@ public AddImport(@Nullable String packageName, String typeName, @Nullable String return cu; } // Nor if the classes are within the same package - if (!"Record".equals(typeName) && // Record's late addition to `java.lang` might conflict with user class - cu.getPackageDeclaration() != null && + if (!"Record".equals(typeName) && cu.getPackageDeclaration() != null && packageName.equals(cu.getPackageDeclaration().getExpression().printTrimmed(getCursor()))) { return cu; } @@ -120,7 +119,7 @@ public AddImport(@Nullable String packageName, String typeName, @Nullable String return cu; } - if (cu.getImports().stream().anyMatch(i -> { + if (!"Record".equals(typeName) && cu.getImports().stream().anyMatch(i -> { String ending = i.getQualid().getSimpleName(); if (member == null) { return !i.isStatic() && i.getPackageName().equals(packageName) && @@ -143,19 +142,17 @@ public AddImport(@Nullable String packageName, String typeName, @Nullable String List> imports = new ArrayList<>(cu.getPadding().getImports()); - if (imports.isEmpty() && !cu.getClasses().isEmpty()) { - if (cu.getPackageDeclaration() == null) { - // leave javadocs on the class and move other comments up to the import - // (which could include license headers and the like) - Space firstClassPrefix = cu.getClasses().get(0).getPrefix(); - importToAdd = importToAdd.withPrefix(firstClassPrefix - .withComments(ListUtils.map(firstClassPrefix.getComments(), comment -> comment instanceof Javadoc ? null : comment)) - .withWhitespace("")); - - cu = cu.withClasses(ListUtils.mapFirst(cu.getClasses(), clazz -> - clazz.withComments(ListUtils.map(clazz.getComments(), comment -> comment instanceof Javadoc ? comment : null)) - )); - } + if (imports.isEmpty() && !cu.getClasses().isEmpty() && cu.getPackageDeclaration() == null) { + // leave javadocs on the class and move other comments up to the import + // (which could include license headers and the like) + Space firstClassPrefix = cu.getClasses().get(0).getPrefix(); + importToAdd = importToAdd.withPrefix(firstClassPrefix + .withComments(ListUtils.map(firstClassPrefix.getComments(), comment -> comment instanceof Javadoc ? null : comment)) + .withWhitespace("")); + + cu = cu.withClasses(ListUtils.mapFirst(cu.getClasses(), clazz -> + clazz.withComments(ListUtils.map(clazz.getComments(), comment -> comment instanceof Javadoc ? comment : null)) + )); } ImportLayoutStyle layoutStyle = Optional.ofNullable(((SourceFile) cu).getStyle(ImportLayoutStyle.class)) From d4494909e99fbcad0e884a0f5b418bfac532d74f Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sun, 15 Dec 2024 20:40:41 +0100 Subject: [PATCH 053/179] Add `testRuntimeOnly` dependency on `junit-platform-launcher` with Gradle 8.+ (#4786) --- .../resources/META-INF/rewrite/gradle-8.yml | 16 ++++ .../gradle/AddJUnitPlatformLauncherTest.java | 74 +++++++++++++++++++ rewrite-test/build.gradle.kts | 1 + 3 files changed, 91 insertions(+) create mode 100644 rewrite-gradle/src/test/java/org/openrewrite/gradle/AddJUnitPlatformLauncherTest.java diff --git a/rewrite-gradle/src/main/resources/META-INF/rewrite/gradle-8.yml b/rewrite-gradle/src/main/resources/META-INF/rewrite/gradle-8.yml index 9babdf64095..097b7a669da 100644 --- a/rewrite-gradle/src/main/resources/META-INF/rewrite/gradle-8.yml +++ b/rewrite-gradle/src/main/resources/META-INF/rewrite/gradle-8.yml @@ -24,6 +24,9 @@ recipeList: version: 8.x addIfMissing: false + # https://docs.gradle.org/8.11.1/userguide/upgrading_version_8.html#test_framework_implementation_dependencies + - org.openrewrite.gradle.AddJUnitPlatformLauncher + # https://github.com/gradle/gradle/blob/v7.6.4/subprojects/core/src/main/java/org/gradle/api/internal/FeaturePreviews.java # https://github.com/gradle/gradle/blob/v8.10.1/subprojects/core/src/main/java/org/gradle/api/internal/FeaturePreviews.java - org.openrewrite.gradle.RemoveEnableFeaturePreview: @@ -32,3 +35,16 @@ recipeList: previewFeatureName: VERSION_ORDERING_V2 - org.openrewrite.gradle.RemoveEnableFeaturePreview: previewFeatureName: VERSION_CATALOGS +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.gradle.AddJUnitPlatformLauncher +displayName: Add JUnit Platform Launcher +description: Add the JUnit Platform Launcher to the buildscript dependencies. +recipeList: + - org.openrewrite.gradle.AddDependency: + groupId: org.junit.platform + artifactId: junit-platform-launcher + version: 1.x + acceptTransitive: true + configuration: testRuntimeOnly + onlyIfUsing: org.junit.jupiter.api.Test diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/AddJUnitPlatformLauncherTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/AddJUnitPlatformLauncherTest.java new file mode 100644 index 00000000000..0c120dc8bce --- /dev/null +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/AddJUnitPlatformLauncherTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.gradle; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.openrewrite.gradle.Assertions.buildGradle; +import static org.openrewrite.gradle.toolingapi.Assertions.withToolingApi; +import static org.openrewrite.java.Assertions.*; + +class AddJUnitPlatformLauncherTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec + .beforeRecipe(withToolingApi()) + .parser(JavaParser.fromJavaVersion().classpath("junit-jupiter-api")) + .recipeFromResources("org.openrewrite.gradle.AddJUnitPlatformLauncher"); + } + + @DocumentExample + @Test + void addJUnitPlatformLauncher() { + rewriteRun( + mavenProject("project", + srcTestJava( + java( + """ + import org.junit.jupiter.api.Test; + public class A { + @Test + void foo() { + } + } + """ + ) + ), + buildGradle( + """ + plugins { + id "java-library" + } + + repositories { + mavenCentral() + } + """, + spec -> spec.after(buildGradle -> { + assertThat(buildGradle).contains("testRuntimeOnly \"org.junit.platform:junit-platform-launcher:"); + return buildGradle; + }) + ) + ) + ); + } +} diff --git a/rewrite-test/build.gradle.kts b/rewrite-test/build.gradle.kts index f8dbafd3a40..3e97814c353 100644 --- a/rewrite-test/build.gradle.kts +++ b/rewrite-test/build.gradle.kts @@ -8,6 +8,7 @@ dependencies { compileOnly("io.micrometer:micrometer-core:latest.release") api("org.junit.jupiter:junit-jupiter-api") api("org.junit.jupiter:junit-jupiter-params") + api("org.junit.platform:junit-platform-launcher") implementation("org.assertj:assertj-core:latest.release") implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-csv") From 5f2d11ca3bc093774da965e742634f5e7b246ef8 Mon Sep 17 00:00:00 2001 From: Laurens Westerlaken Date: Tue, 17 Dec 2024 12:55:42 +0100 Subject: [PATCH 054/179] Fix groovy multivariable declaration (#4757) * Fix parsing of multiple variable assignments in one statement * Minor improvement * Add another testcase and make sure it works * Simplify * Clarify * Revert formatting * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Fixed * Fixed * Move tests to AssignmentTest + add `final def` case * Should have done it this way initially ;) * Add testcase for regression * Polish * Extra testcase * Add `noKeyword` test * Return String instead of passing StringBuilder Include subpart of remainder to give an indication where the issue occurred * Further convert to using String * Simplify * Different approach using marker * Remove unused code and FMT * Remove specific exception cases for VariableDeclarations * Change to startsWith with offset --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: lingenj Co-authored-by: Tim te Beek --- .../gradle/AddDependencyVisitor.java | 16 +-- .../groovy/GroovyParserVisitor.java | 101 ++++++++++++------ .../org/openrewrite/groovy/GroovyPrinter.java | 10 +- .../groovy/marker/MultiVariable.java | 30 ++++++ .../groovy/tree/AssignmentTest.java | 83 ++++++++++++++ 5 files changed, 189 insertions(+), 51 deletions(-) create mode 100644 rewrite-groovy/src/main/java/org/openrewrite/groovy/marker/MultiVariable.java diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependencyVisitor.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependencyVisitor.java index 61659730458..64e58977947 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependencyVisitor.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependencyVisitor.java @@ -290,22 +290,10 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, Execu } } else { Space originalPrefix = addDependencyInvocation.getPrefix(); - if (currentStatement instanceof J.VariableDeclarations) { - J.VariableDeclarations variableDeclarations = (J.VariableDeclarations) currentStatement; - if (variableDeclarations.getTypeExpression() != null) { - addDependencyInvocation = addDependencyInvocation.withPrefix(variableDeclarations.getTypeExpression().getPrefix()); - } - } else { - addDependencyInvocation = addDependencyInvocation.withPrefix(currentStatement.getPrefix()); - } + addDependencyInvocation = addDependencyInvocation.withPrefix(currentStatement.getPrefix()); if (addDependencyInvocation.getSimpleName().equals(beforeDependency.getSimpleName())) { - if (currentStatement instanceof J.VariableDeclarations) { - J.VariableDeclarations variableDeclarations = (J.VariableDeclarations) currentStatement; - if (variableDeclarations.getTypeExpression() != null && !variableDeclarations.getTypeExpression().getPrefix().equals(originalPrefix)) { - statements.set(i, variableDeclarations.withTypeExpression(variableDeclarations.getTypeExpression().withPrefix(originalPrefix))); - } - } else if (!currentStatement.getPrefix().equals(originalPrefix)) { + if (!currentStatement.getPrefix().equals(originalPrefix)) { statements.set(i, currentStatement.withPrefix(originalPrefix)); } } diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index e14a122df1f..abf35207e2e 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -39,9 +39,9 @@ import org.openrewrite.java.marker.OmitParentheses; import org.openrewrite.java.marker.Semicolon; import org.openrewrite.java.marker.TrailingComma; -import org.openrewrite.java.tree.*; import org.openrewrite.java.tree.Expression; import org.openrewrite.java.tree.Statement; +import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; import java.math.BigDecimal; @@ -113,16 +113,16 @@ private static boolean isOlderThanGroovy3() { } /** - * Groovy methods can be declared with "def" AND a return type - * In these cases the "def" is semantically meaningless but needs to be preserved for source code accuracy - * If there is both a def and a return type, this method returns a RedundantDef object and advances the cursor - * position past the "def" keyword, leaving the return type to be parsed as normal. - * In any other situation an empty Optional is returned and the cursor is not advanced. + * Groovy methods can be declared with "def" AND a return type + * In these cases the "def" is semantically meaningless but needs to be preserved for source code accuracy + * If there is both a def and a return type, this method returns a RedundantDef object and advances the cursor + * position past the "def" keyword, leaving the return type to be parsed as normal. + * In any other situation an empty Optional is returned and the cursor is not advanced. */ private Optional maybeRedundantDef(ClassNode type, String name) { int saveCursor = cursor; Space defPrefix = whitespace(); - if(source.startsWith("def", cursor)) { + if (source.startsWith("def", cursor)) { skip("def"); // The def is redundant only when it is followed by the method's return type // I hope no one puts an annotation between "def" and the return type @@ -182,8 +182,8 @@ public G.CompilationUnit visit(SourceUnit unit, ModuleNode ast) throws GroovyPar for (ClassNode aClass : ast.getClasses()) { if (aClass.getSuperClass() == null || !("groovy.lang.Script".equals(aClass.getSuperClass().getName()) || - "RewriteGradleProject".equals(aClass.getSuperClass().getName()) || - "RewriteSettings".equals(aClass.getSuperClass().getName()))) { + "RewriteGradleProject".equals(aClass.getSuperClass().getName()) || + "RewriteSettings".equals(aClass.getSuperClass().getName()))) { sortedByPosition.computeIfAbsent(pos(aClass), i -> new ArrayList<>()).add(aClass); } } @@ -822,8 +822,8 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { // When named parameters are in use they may appear before, after, or intermixed with any positional arguments if (unparsedArgs.size() > 1 && unparsedArgs.get(0) instanceof MapExpression && (unparsedArgs.get(0).getLastLineNumber() > unparsedArgs.get(1).getLastLineNumber() || - (unparsedArgs.get(0).getLastLineNumber() == unparsedArgs.get(1).getLastLineNumber() && - unparsedArgs.get(0).getLastColumnNumber() > unparsedArgs.get(1).getLastColumnNumber()))) { + (unparsedArgs.get(0).getLastLineNumber() == unparsedArgs.get(1).getLastLineNumber() && + unparsedArgs.get(0).getLastColumnNumber() > unparsedArgs.get(1).getLastColumnNumber()))) { // Figure out the source-code ordering of the expressions MapExpression namedArgExpressions = (MapExpression) unparsedArgs.get(0); @@ -1099,7 +1099,7 @@ public void visitBlockStatement(BlockStatement block) { J expr = visit(statement); if (i == blockStatements.size() - 1 && (expr instanceof Expression)) { if (parent instanceof ClosureExpression || (parent instanceof MethodNode && - !JavaType.Primitive.Void.equals(typeMapping.type(((MethodNode) parent).getReturnType())))) { + !JavaType.Primitive.Void.equals(typeMapping.type(((MethodNode) parent).getReturnType())))) { expr = new J.Return(randomId(), expr.getPrefix(), Markers.EMPTY, expr.withPrefix(EMPTY)); expr = expr.withMarkers(expr.getMarkers().add(new ImplicitReturn(randomId()))); @@ -1438,7 +1438,10 @@ public void visitNotExpression(NotExpression expression) { @Override public void visitDeclarationExpression(DeclarationExpression expression) { + Space prefix = whitespace(); Optional redundantDef = maybeRedundantDef(expression.getVariableExpression().getType(), expression.getVariableExpression().getName()); + Optional multiVariable = maybeMultiVariable(); + List modifiers = getModifiers(); TypeTree typeExpr = visitVariableExpressionType(expression.getVariableExpression()); J.VariableDeclarations.NamedVariable namedVariable; @@ -1466,19 +1469,60 @@ public void visitDeclarationExpression(DeclarationExpression expression) { J.VariableDeclarations variableDeclarations = new J.VariableDeclarations( randomId(), - EMPTY, - redundantDef.map(Markers.EMPTY::add).orElse(Markers.EMPTY), - emptyList(), + prefix, + Markers.EMPTY, emptyList(), + modifiers, typeExpr, null, emptyList(), singletonList(JRightPadded.build(namedVariable)) ); + if (redundantDef.isPresent()) { + variableDeclarations = variableDeclarations.withMarkers(variableDeclarations.getMarkers().add(redundantDef.get())); + } + if (multiVariable.isPresent()) { + variableDeclarations = variableDeclarations.withMarkers(variableDeclarations.getMarkers().add(multiVariable.get())); + } queue.add(variableDeclarations); } + private Optional maybeMultiVariable() { + int saveCursor = cursor; + Space commaPrefix = whitespace(); + if (source.startsWith(",", cursor)) { + skip(","); + return Optional.of(new MultiVariable(randomId(), commaPrefix)); + } + cursor = saveCursor; + return Optional.empty(); + } + + private List getModifiers() { + List modifiers = new ArrayList<>(); + int saveCursor = cursor; + Space prefix = whitespace(); + while (source.startsWith("def", cursor) || source.startsWith("var", cursor) || source.startsWith("final", cursor)) { + if (source.startsWith("var", cursor)) { + modifiers.add(new J.Modifier(randomId(), prefix, Markers.EMPTY, "var", J.Modifier.Type.LanguageExtension, emptyList())); + cursor += 3; + } else if (source.startsWith("def", cursor)) { + modifiers.add(new J.Modifier(randomId(), prefix, Markers.EMPTY, "def", J.Modifier.Type.LanguageExtension, emptyList())); + cursor += 3; + } else if (source.startsWith("final", cursor)) { + modifiers.add(new J.Modifier(randomId(), prefix, Markers.EMPTY, "final", J.Modifier.Type.LanguageExtension, emptyList())); + cursor += 5; + } else { + break; + } + saveCursor = cursor; + prefix = whitespace(); + } + cursor = saveCursor; + return modifiers; + } + @Override public void visitEmptyExpression(EmptyExpression expression) { queue.add(new J.Empty(randomId(), EMPTY, Markers.EMPTY)); @@ -1766,7 +1810,7 @@ public void visitMethodCallExpression(MethodCallExpression call) { MethodNode methodNode = (MethodNode) call.getNodeMetaData().get(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET); JavaType.Method methodType = null; if (methodNode == null && call.getObjectExpression() instanceof VariableExpression && - ((VariableExpression) call.getObjectExpression()).getAccessedVariable() != null) { + ((VariableExpression) call.getObjectExpression()).getAccessedVariable() != null) { // Groovy doesn't know what kind of object this method is being invoked on // But if this invocation is inside a Closure we may have already enriched its parameters with types from the static type checker // Use any such type information to attempt to find a matching method @@ -2097,29 +2141,18 @@ public void visitPrefixExpression(PrefixExpression unary) { public TypeTree visitVariableExpressionType(VariableExpression expression) { JavaType type = typeMapping.type(staticType(((org.codehaus.groovy.ast.expr.Expression) expression))); + Space prefix = whitespace(); + String typeName = ""; - if (expression.isDynamicTyped()) { - Space prefix = whitespace(); - String keyword; - if (source.substring(cursor).startsWith("final")) { - keyword = "final"; - } else { - keyword = source.substring(cursor, cursor + 3); - } - cursor += keyword.length(); - return new J.Identifier(randomId(), - prefix, - Markers.EMPTY, - emptyList(), - keyword, - type, null); + if (!expression.isDynamicTyped() && source.startsWith(expression.getOriginType().getUnresolvedName(), cursor)) { + typeName = expression.getOriginType().getUnresolvedName(); + cursor += typeName.length(); } - Space prefix = sourceBefore(expression.getOriginType().getUnresolvedName()); J.Identifier ident = new J.Identifier(randomId(), EMPTY, Markers.EMPTY, emptyList(), - expression.getOriginType().getUnresolvedName(), + typeName, type, null); if (expression.getOriginType().getGenericsTypes() != null) { return new J.ParameterizedType(randomId(), prefix, Markers.EMPTY, ident, visitTypeParameterizations( @@ -2671,7 +2704,7 @@ private String name() { Can contain a J.FieldAccess, as in a variable declaration with fully qualified type parameterization: List */ - private JContainer visitTypeParameterizations(GenericsType @Nullable[] genericsTypes) { + private JContainer visitTypeParameterizations(GenericsType @Nullable [] genericsTypes) { Space prefix = sourceBefore("<"); List> parameters; diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java index 17e0a466a6c..0ab2bb60c2c 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java @@ -265,13 +265,17 @@ public J visitVariableDeclarations(J.VariableDeclarations multiVariable, PrintOu beforeSyntax(multiVariable, Space.Location.VARIABLE_DECLARATIONS_PREFIX, p); visitSpace(Space.EMPTY, Space.Location.ANNOTATIONS, p); visit(multiVariable.getLeadingAnnotations(), p); - for (J.Modifier m : multiVariable.getModifiers()) { - visitModifier(m, p); - } multiVariable.getMarkers().findFirst(RedundantDef.class).ifPresent(def -> { visitSpace(def.getPrefix(), Space.Location.LANGUAGE_EXTENSION, p); p.append("def"); }); + for (J.Modifier m : multiVariable.getModifiers()) { + visitModifier(m, p); + } + multiVariable.getMarkers().findFirst(MultiVariable.class).ifPresent(multiVar -> { + visitSpace(multiVar.getPrefix(), Space.Location.NAMED_VARIABLE_SUFFIX, p); + p.append(","); + }); visit(multiVariable.getTypeExpression(), p); // For backwards compatibility. for (JLeftPadded dim : multiVariable.getDimensionsBeforeName()) { diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/marker/MultiVariable.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/marker/MultiVariable.java new file mode 100644 index 00000000000..3554529bf6b --- /dev/null +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/marker/MultiVariable.java @@ -0,0 +1,30 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.groovy.marker; + +import lombok.Value; +import lombok.With; +import org.openrewrite.java.tree.Space; +import org.openrewrite.marker.Marker; + +import java.util.UUID; + +@Value +@With +public class MultiVariable implements Marker { + UUID id; + Space prefix; +} diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java index 8a15073a41b..e1421259a9d 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java @@ -24,6 +24,41 @@ @SuppressWarnings({"GroovyUnusedAssignment", "GrUnnecessarySemicolon"}) class AssignmentTest implements RewriteTest { + @Test + void noKeyword() { + rewriteRun( + groovy( + """ + x = "s" + """ + ) + ); + } + + @Test + void simple() { + rewriteRun( + groovy( + """ + def x = "s" + """ + ) + ); + } + + @Test + void simpleWithFinal() { + rewriteRun( + groovy( + """ + final def x = "x" + def final y = "y" + final z = "z" + """ + ) + ); + } + @Test void concat() { rewriteRun( @@ -91,4 +126,52 @@ void baseNConversions() { ) ); } + + @Test + void multipleAssignmentsAtOneLine() { + rewriteRun( + groovy( + """ + def startItem = '| ', endItem = ' |' + def repeatLength = startItem.length() + output.length() + endItem.length() + println("\\n" + ("-" * repeatLength) + "\\n" + startItem + output + endItem + "\\n" + ("-" * repeatLength)) + """ + ) + ); + } + + @Test + void multipleAssignmentsAtOneLineSimple() { + rewriteRun( + groovy( + """ + def a = '1', b = '2' + """ + ) + ); + } + + @Test + void multipleAssignmentsAtMultipleLineDynamicType() { + rewriteRun( + groovy( + """ + def a = '1' , + b = '2' + """ + ) + ); + } + + @Test + void multipleAssignmentsAtMultipleLineStaticType() { + rewriteRun( + groovy( + """ + String a = '1' , + b = '2' + """ + ) + ); + } } From 372246cbdc55d39dc8507f1cc5c7dae7c84b8d2e Mon Sep 17 00:00:00 2001 From: sullis Date: Tue, 17 Dec 2024 13:51:28 -0800 Subject: [PATCH 055/179] enhance UpgradeDependencyVersionTest (#4788) * enhance UpgradeDependencyVersionTest * Make the tests more expressive when they fail --------- Co-authored-by: Tim te Beek --- .../gradle/UpgradeDependencyVersionTest.java | 260 +++++++++++------- 1 file changed, 158 insertions(+), 102 deletions(-) diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java index 5e9ecf85f34..e8d6d145923 100644 --- a/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java @@ -44,18 +44,18 @@ public void defaults(RecipeSpec spec) { @DocumentExample @Test - void guava() { + void guavaCompileOnly() { rewriteRun( buildGradle( """ plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { compileOnly 'com.google.guava:guava:29.0-jre' runtimeOnly ('com.google.guava:guava:29.0-jre') @@ -65,11 +65,11 @@ void guava() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { compileOnly 'com.google.guava:guava:30.1.1-jre' runtimeOnly ('com.google.guava:guava:30.1.1-jre') @@ -78,21 +78,77 @@ void guava() { spec -> spec.afterRecipe(after -> { Optional maybeGp = after.getMarkers().findFirst(GradleProject.class); assertThat(maybeGp).isPresent(); - GradleProject gp = maybeGp.get(); - GradleDependencyConfiguration compileClasspath = gp.getConfiguration("compileClasspath"); + GradleDependencyConfiguration compileClasspath = maybeGp.get().getConfiguration("compileClasspath"); assertThat(compileClasspath).isNotNull(); - assertThat( - compileClasspath.getRequested().stream() - .filter(dep -> "com.google.guava".equals(dep.getGroupId()) && "guava".equals(dep.getArtifactId()) && "30.1.1-jre".equals(dep.getVersion())) - .findAny()) + assertThat(compileClasspath.getRequested()) .as("GradleProject requested dependencies should have been updated with the new version of guava") - .isPresent(); - assertThat( - compileClasspath.getResolved().stream() - .filter(dep -> "com.google.guava".equals(dep.getGroupId()) && "guava".equals(dep.getArtifactId()) && "30.1.1-jre".equals(dep.getVersion())) - .findAny()) - .as("GradleProject requested dependencies should have been updated with the new version of guava") - .isPresent(); + .anySatisfy(dep -> { + assertThat(dep.getGroupId()).isEqualTo("com.google.guava"); + assertThat(dep.getArtifactId()).isEqualTo("guava"); + assertThat(dep.getVersion()).isEqualTo("30.1.1-jre"); + }); + assertThat(compileClasspath.getResolved()) + .as("GradleProject resolved dependencies should have been updated with the new version of guava") + .anySatisfy(dep -> { + assertThat(dep.getGroupId()).isEqualTo("com.google.guava"); + assertThat(dep.getArtifactId()).isEqualTo("guava"); + assertThat(dep.getVersion()).isEqualTo("30.1.1-jre"); + }); + }) + ) + ); + } + + @Test + void mockitoTestImplementation() { + rewriteRun(recipeSpec -> { + recipeSpec.beforeRecipe(withToolingApi()) + .recipe(new UpgradeDependencyVersion("org.mockito", "*", "4.11.0", null)); + }, + buildGradle( + """ + plugins { + id 'java-library' + } + + repositories { + mavenCentral() + } + + dependencies { + testImplementation("org.mockito:mockito-junit-jupiter:3.12.4") + } + """, + """ + plugins { + id 'java-library' + } + + repositories { + mavenCentral() + } + + dependencies { + testImplementation("org.mockito:mockito-junit-jupiter:4.11.0") + } + """, + spec -> spec.afterRecipe(after -> { + Optional maybeGp = after.getMarkers().findFirst(GradleProject.class); + assertThat(maybeGp).isPresent(); + GradleDependencyConfiguration testCompileClasspath = maybeGp.get().getConfiguration("testCompileClasspath"); + assertThat(testCompileClasspath).isNotNull(); + assertThat(testCompileClasspath.getRequested()) + .as("GradleProject requested dependencies should have been updated with the new version of mockito") + .anySatisfy(dep -> { + assertThat(dep.getGroupId()).isEqualTo("org.mockito"); + assertThat(dep.getArtifactId()).isEqualTo("mockito-junit-jupiter"); + }); + assertThat(testCompileClasspath.getResolved()) + .as("GradleProject resolved dependencies should have been updated with the new version of mockito") + .anySatisfy(dep -> { + assertThat(dep.getGroupId()).isEqualTo("org.mockito"); + assertThat(dep.getArtifactId()).isEqualTo("mockito-junit-jupiter"); + }); }) ) ); @@ -106,13 +162,13 @@ void updateVersionInVariable() { plugins { id 'java-library' } - + def guavaVersion = '29.0-jre' def otherVersion = "latest.release" repositories { mavenCentral() } - + dependencies { implementation ("com.google.guava:guava:$guavaVersion") implementation "com.fasterxml.jackson.core:jackson-databind:$otherVersion" @@ -122,13 +178,13 @@ void updateVersionInVariable() { plugins { id 'java-library' } - + def guavaVersion = '30.1.1-jre' def otherVersion = "latest.release" repositories { mavenCentral() } - + dependencies { implementation ("com.google.guava:guava:$guavaVersion") implementation "com.fasterxml.jackson.core:jackson-databind:$otherVersion" @@ -146,7 +202,7 @@ void deeplyNestedProjectDependency() { plugins { id 'java-library' } - + dependencies { implementation project(":foo:bar:baz:qux:quux") } @@ -178,11 +234,11 @@ void varargsDependency() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation( 'com.google.guava:guava-gwt:29.0-jre', @@ -193,11 +249,11 @@ void varargsDependency() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation( 'com.google.guava:guava-gwt:29.0-jre', @@ -215,12 +271,12 @@ void mapNotationVariable() { plugins { id 'java-library' } - + def guavaVersion = '29.0-jre' repositories { mavenCentral() } - + dependencies { implementation group: "com.google.guava", name: "guava", version: guavaVersion } @@ -229,12 +285,12 @@ void mapNotationVariable() { plugins { id 'java-library' } - + def guavaVersion = '30.1.1-jre' repositories { mavenCentral() } - + dependencies { implementation group: "com.google.guava", name: "guava", version: guavaVersion } @@ -251,11 +307,11 @@ void mapNotationLiteral() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation (group: "com.google.guava", name: "guava", version: '29.0-jre') } @@ -264,11 +320,11 @@ void mapNotationLiteral() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation (group: "com.google.guava", name: "guava", version: '30.1.1-jre') } @@ -286,11 +342,11 @@ void worksWithPlatform() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation platform("com.google.guava:guava:29.0-jre") } @@ -299,11 +355,11 @@ implementation platform("com.google.guava:guava:29.0-jre") plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation platform("com.google.guava:guava:30.1.1-jre") } @@ -328,19 +384,19 @@ void upgradesVariablesDefinedInExtraProperties() { classpath("com.google.guava:guava:${guavaVersion}") } } - + plugins { id "java" } - + repositories { mavenCentral() } - + ext { guavaVersion2 = "29.0-jre" } - + dependencies { implementation "com.google.guava:guava:${guavaVersion2}" } @@ -357,19 +413,19 @@ void upgradesVariablesDefinedInExtraProperties() { classpath("com.google.guava:guava:${guavaVersion}") } } - + plugins { id "java" } - + repositories { mavenCentral() } - + ext { guavaVersion2 = "30.1.1-jre" } - + dependencies { implementation "com.google.guava:guava:${guavaVersion2}" } @@ -387,15 +443,15 @@ void matchesGlobs() { plugins { id "java" } - + repositories { mavenCentral() } - + ext { guavaVersion = "29.0-jre" } - + def guavaVersion2 = "29.0-jre" dependencies { implementation("com.google.guava:guava:29.0-jre") @@ -408,15 +464,15 @@ void matchesGlobs() { plugins { id "java" } - + repositories { mavenCentral() } - + ext { guavaVersion = "30.1.1-jre" } - + def guavaVersion2 = "30.1.1-jre" dependencies { implementation("com.google.guava:guava:30.1.1-jre") @@ -438,11 +494,11 @@ void defaultsToLatestRelease() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation 'com.google.guava:guava:29.0-jre' } @@ -488,11 +544,11 @@ void versionInPropertiesFile() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation ("com.google.guava:guava:$guavaVersion") } @@ -515,11 +571,11 @@ void versionInPropertiesFileNotUpdatedIfNoDependencyVariable() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation ("com.google.guava:guava:30.1.1-jre") } @@ -554,11 +610,11 @@ void versionInParentAndMultiModulePropertiesFiles() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation ("com.google.guava:guava:$guavaVersion") } @@ -570,11 +626,11 @@ void versionInParentAndMultiModulePropertiesFiles() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation ("com.google.guava:guava:$guavaVersion") } @@ -601,18 +657,18 @@ void versionInParentSubprojectDefinitionWithPropertiesFiles() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + subprojects { repositories { mavenCentral() } - + apply plugin: "java-library" - + dependencies { implementation ("com.google.guava:guava:$guavaVersion") } @@ -631,7 +687,7 @@ void versionInParentSubprojectDefinitionWithPropertiesFiles() { plugins { id 'java-library' } - + repositories { mavenCentral() } @@ -659,11 +715,11 @@ void versionOnlyInMultiModuleChildPropertiesFiles() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation ("com.google.guava:guava:$guavaVersion") } @@ -694,7 +750,7 @@ void mapNotationVariableInPropertiesFile() { repositories { mavenCentral() } - + dependencies { implementation group: "com.google.guava", name: "guava", version: guavaVersion } @@ -720,11 +776,11 @@ void mapNotationGStringVariableInPropertiesFile() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation group: "com.google.guava", name: "guava", version: "${guavaVersion}" } @@ -753,11 +809,11 @@ void globVersionsInPropertiesFileWithMultipleVersionsOnlyUpdatesCorrectProperty( plugins { id 'java' } - + repositories { mavenCentral() } - + dependencies { implementation("org.springframework.boot:spring-boot-starter-actuator:${springBootVersion}") implementation("org.springframework.security:spring-security-oauth2-core:${springSecurityVersion}") @@ -783,11 +839,11 @@ void disallowDowngrade() { plugins { id 'java' } - + repositories { mavenCentral() } - + dependencies { implementation("org.springframework.boot:spring-boot-starter-actuator:${springBootVersion}") implementation("org.springframework.security:spring-security-oauth2-core:${springSecurityVersion}") @@ -806,11 +862,11 @@ void dontDowngradeWhenExactVersion() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation 'com.google.guava:guava:29.0-jre' } @@ -828,11 +884,11 @@ void leaveConstraintsAlone() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { constraints { implementation("com.google.guava:guava:28.0-jre") @@ -854,11 +910,11 @@ void unknownConfiguration() { id 'java' id "org.hidetake.swagger.generator" version "2.18.2" } - + repositories { mavenCentral() } - + dependencies { swaggerCodegen "org.openapitools:openapi-generator-cli:5.2.0" } @@ -868,11 +924,11 @@ void unknownConfiguration() { id 'java' id "org.hidetake.swagger.generator" version "2.18.2" } - + repositories { mavenCentral() } - + dependencies { swaggerCodegen "org.openapitools:openapi-generator-cli:5.2.1" } @@ -890,11 +946,11 @@ void noActionForNonStringLiterals() { plugins { id 'java' } - + repositories { mavenCentral() } - + dependencies { implementation(gradleApi()) jar { @@ -908,7 +964,7 @@ void noActionForNonStringLiterals() { @Test @Issue("https://github.com/openrewrite/rewrite-java-dependencies/pull/106") - void isAcceptable(){ + void isAcceptable() { // Mimic org.openrewrite.java.dependencies.UpgradeTransitiveDependencyVersion#getVisitor UpgradeDependencyVersion guava = new UpgradeDependencyVersion("com.google.guava", "guava", "30.x", "-jre"); TreeVisitor visitor = guava.getVisitor(); @@ -930,11 +986,11 @@ void exactVersionWithExactPattern() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation('com.google.guava:guava:29.0-jre') } @@ -943,11 +999,11 @@ void exactVersionWithExactPattern() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation('com.google.guava:guava:32.1.1-jre') } @@ -966,11 +1022,11 @@ void exactVersionWithRegexPattern() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation('com.google.guava:guava:29.0-android') } @@ -979,11 +1035,11 @@ void exactVersionWithRegexPattern() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation('com.google.guava:guava:32.1.1-android') } @@ -1001,11 +1057,11 @@ void upgradesDependencyVersionDefinedInJvmTestSuite() { id "java-library" id 'jvm-test-suite' } - + repositories { mavenCentral() } - + testing { suites { test { @@ -1021,11 +1077,11 @@ void upgradesDependencyVersionDefinedInJvmTestSuite() { id "java-library" id 'jvm-test-suite' } - + repositories { mavenCentral() } - + testing { suites { test { @@ -1091,11 +1147,11 @@ void issue4655() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + version='ORC-246-1-SNAPSHOT' dependencies { implementation "com.veon.eurasia.oraculum:jira-api:$version" From 65c9cf166faeafa72c6ac81e2bd28c692903ed07 Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Tue, 17 Dec 2024 17:09:26 -0800 Subject: [PATCH 056/179] Add a "latest minor" semver selector. We have them for major versions and patch versions might as well have minor, too. --- .../org/openrewrite/semver/LatestMinor.java | 60 +++++++++++++++++++ .../org/openrewrite/semver/LatestRelease.java | 2 +- .../java/org/openrewrite/semver/Semver.java | 1 + .../openrewrite/semver/LatestMinorTest.java | 38 ++++++++++++ 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 rewrite-core/src/main/java/org/openrewrite/semver/LatestMinor.java create mode 100644 rewrite-core/src/test/java/org/openrewrite/semver/LatestMinorTest.java diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/LatestMinor.java b/rewrite-core/src/main/java/org/openrewrite/semver/LatestMinor.java new file mode 100644 index 00000000000..17737b52488 --- /dev/null +++ b/rewrite-core/src/main/java/org/openrewrite/semver/LatestMinor.java @@ -0,0 +1,60 @@ +/* + * Copyright 2021 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.semver; + +import lombok.Value; +import org.jspecify.annotations.Nullable; +import org.openrewrite.Validated; + +@Value +public class LatestMinor implements VersionComparator { + @Nullable + String metadataPattern; + + @Override + public boolean isValid(@Nullable String currentVersion, String version) { + Validated validated = currentVersion == null ? + LatestRelease.buildLatestRelease("latest.release", metadataPattern) : + TildeRange.build("~" + Semver.majorVersion(currentVersion), metadataPattern); + + if (validated.isValid()) { + VersionComparator comparator = validated.getValue(); + if (comparator != null) { + return comparator.isValid(currentVersion, version); + } + } + return false; + } + + @Override + public int compare(@Nullable String currentVersion, String v1, String v2) { + if(currentVersion == null) { + return new LatestRelease(null) + .compare(null, v1, v2); + } + + //noinspection ConstantConditions + return TildeRange.build("~" + Semver.majorVersion(currentVersion) + "." + Semver.minorVersion(currentVersion), metadataPattern) + .getValue() + .compare(currentVersion, v1, v2); + } + + public static Validated build(String toVersion, @Nullable String metadataPattern) { + return "latest.minor".equalsIgnoreCase(toVersion) ? + Validated.valid("latestMinor", new LatestMinor(metadataPattern)) : + Validated.invalid("latestMinor", toVersion, "not latest release"); + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/LatestRelease.java b/rewrite-core/src/main/java/org/openrewrite/semver/LatestRelease.java index 18fc5d4b12e..df8fac8951c 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/LatestRelease.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/LatestRelease.java @@ -168,7 +168,7 @@ public int compare(@Nullable String currentVersion, String v1, String v2) { } public static Validated buildLatestRelease(String toVersion, @Nullable String metadataPattern) { - return "latest.release".equalsIgnoreCase(toVersion) ? + return "latest.release".equalsIgnoreCase(toVersion) || "latest.major".equalsIgnoreCase(toVersion) ? Validated.valid("latestRelease", new LatestRelease(metadataPattern)) : Validated.invalid("latestRelease", toVersion, "not latest release"); } diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/Semver.java b/rewrite-core/src/main/java/org/openrewrite/semver/Semver.java index d4d6388702a..e47ec996629 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/Semver.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/Semver.java @@ -59,6 +59,7 @@ public static Validated validate(String toVersion, @Nullable ).and(Validated.none() .or(LatestRelease.buildLatestRelease(toVersion, metadataPattern)) .or(LatestIntegration.build(toVersion, metadataPattern)) + .or(LatestMinor.build(toVersion, metadataPattern)) .or(LatestPatch.build(toVersion, metadataPattern)) .or(HyphenRange.build(toVersion, metadataPattern)) .or(XRange.build(toVersion, metadataPattern)) diff --git a/rewrite-core/src/test/java/org/openrewrite/semver/LatestMinorTest.java b/rewrite-core/src/test/java/org/openrewrite/semver/LatestMinorTest.java new file mode 100644 index 00000000000..ef551e1d882 --- /dev/null +++ b/rewrite-core/src/test/java/org/openrewrite/semver/LatestMinorTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.semver; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LatestMinorTest { + private final LatestMinor latestMinor = new LatestMinor(null); + + @Test + void isValidWhenCurrentIsNull() { + assertThat(latestMinor.isValid(null, "1.0.0")).isTrue(); + } + @Test + void isValid() { + assertThat(latestMinor.isValid("1.0.0", "1.0.0")).isTrue(); + assertThat(latestMinor.isValid("1.0.0", "1.0.0.1")).isTrue(); + assertThat(latestMinor.isValid("1.0.0", "1.0.1")).isTrue(); + assertThat(latestMinor.isValid("1.0", "1.0.1")).isTrue(); + assertThat(latestMinor.isValid("1.0.0", "1.1.0")).isTrue(); + assertThat(latestMinor.isValid("1.0.0", "2.0.0")).isFalse(); + } +} From 2882fdcfe8f13c7078841eb57790919c67d90633 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 18 Dec 2024 23:40:56 +0100 Subject: [PATCH 057/179] Expand `SimplifyBooleanExpressionVisitor` to include String comparisons For https://github.com/openrewrite/rewrite-feature-flags/issues/40 --- .../SimplifyBooleanExpressionVisitorTest.java | 33 +++++++++++++++++++ .../SimplifyBooleanExpressionVisitor.java | 10 ++++++ 2 files changed, 43 insertions(+) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java index 4264fcf0986..6030207335c 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java @@ -733,4 +733,37 @@ void foo(String a) { rewriteRun(java(beforeJava, template.formatted(after))); } } + + @Issue("https://github.com/openrewrite/rewrite-feature-flags/issues/40") + @Test + void simplifyStringLiteralEqualsStringLiteral() { + rewriteRun( + java( + """ + class A { + { + String foo = "foo"; + if ("foo".equals("foo")) {} + if (foo.equals(foo)) {} + if (foo.equals("foo")) {} + if ("foo".equals(foo)) {} + if ("foo".equals("bar")) {} + } + } + """, + """ + class A { + { + String foo = "foo"; + if (true) {} + if (true) {} + if (foo.equals("foo")) {} + if ("foo".equals(foo)) {} + if (false) {} + } + } + """ + ) + ); + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java index 742fcca4a04..71bc99f825c 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java @@ -240,6 +240,7 @@ private J.Binary.Type maybeNegate(J.Binary.Type operator) { } private final MethodMatcher isEmpty = new MethodMatcher("java.lang.String isEmpty()"); + private final MethodMatcher equals = new MethodMatcher("java.lang.String equals(java.lang.Object)"); @Override public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) { @@ -250,6 +251,15 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext execu select instanceof J.Literal && select.getType() == JavaType.Primitive.String) { return booleanLiteral(method, J.Literal.isLiteralValue(select, "")); + } else if (equals.matches(asMethod)) { + Expression arg = asMethod.getArguments().get(0); + if (arg instanceof J.Literal && select instanceof J.Literal) { + return booleanLiteral(method, ((J.Literal) select).getValue().equals(((J.Literal) arg).getValue())); + } else if (arg instanceof J.Identifier && select instanceof J.Identifier) { + return booleanLiteral(method, SemanticallyEqual.areEqual(select, arg)); + } if (arg instanceof J.FieldAccess && select instanceof J.FieldAccess) { + return booleanLiteral(method, SemanticallyEqual.areEqual(select, arg)); + } } return j; } From 6b2b63c718b4c4d12c57d4b50b1d5d21c4f0991c Mon Sep 17 00:00:00 2001 From: Jon Black Date: Wed, 18 Dec 2024 23:42:07 +0100 Subject: [PATCH 058/179] fix[maven]: update plugin dependencies (#4798) * fix[maven]: update plugin dependencies * Also change plugin dependencies --------- Co-authored-by: Tim te Beek --- .../ChangeDependencyGroupIdAndArtifactId.java | 2 +- ...ngeDependencyGroupIdAndArtifactIdTest.java | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactId.java b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactId.java index 96e6b4a5eaa..4bb4ccce955 100755 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactId.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactId.java @@ -175,7 +175,7 @@ public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) { maybeUpdateModel(); return t; } - if (isOldDependencyTag) { + if (isOldDependencyTag || isPluginDependencyTag(oldGroupId, oldArtifactId)) { String groupId = newGroupId; if (groupId != null) { t = changeChildTagValue(t, "groupId", groupId, ctx); diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java index 70bfef61989..a0fb4005f9c 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/ChangeDependencyGroupIdAndArtifactIdTest.java @@ -1557,4 +1557,71 @@ void changeProfileDependencyGroupIdAndArtifactId() { ) ); } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4779") + void changePluginDependencyGroupIdAndArtifactId() { + rewriteRun( + spec -> spec.recipe(new ChangeDependencyGroupIdAndArtifactId( + "javax.activation", + "javax.activation-api", + "jakarta.activation", + "jakarta.activation-api", + null, + null + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + + + + com.mycompany.myplugin + my-plugin + 1.0.0 + + + javax.activation + javax.activation-api + 1.2.0 + + + + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + + + + com.mycompany.myplugin + my-plugin + 1.0.0 + + + jakarta.activation + jakarta.activation-api + 1.2.0 + + + + + + + """ + ) + ); + } } From e5d93375ba5a12572e9bf62d2b0684317c6e4dd0 Mon Sep 17 00:00:00 2001 From: Udayani Vaka <79973862+vudayani@users.noreply.github.com> Date: Thu, 19 Dec 2024 13:56:49 +0530 Subject: [PATCH 059/179] Handle erroneous nodes in open rewrite (#4412) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Handle erroneous nodes in a tree * Add visitErroneous to all java parser visitors * Override the visitVariable to handle erroneous identifier names set by JavacParser * retain name and suffix for erroneous varDecl * override the visitVariable to handle error identifiers in all java parser visitors * Remove sysout * Update rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * handle errors in method params, variable declarations, fix tests * Add missing license headers * fix compilation error * fix compilation error in Java8ParserVisitor * Apply code suggestions from bot * fix cases for statementDelim * fix block statement template generator to handle adding semicolon * fix ChangeStaticFieldToMethod recipe * Record compiler errors from erroneous LST nodes * Adjustments for comments * Java 17 parser adjustment alos in 8, 11 and 21 * Add `FindCompileErrorsTest` & move away from deprecated `print()` --------- Co-authored-by: Jonathan Schnéider Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tim te Beek Co-authored-by: aboyko --- .../ReloadableJava11ParserVisitor.java | 103 ++++++++++++++- .../ReloadableJava17ParserVisitor.java | 103 ++++++++++++++- .../ReloadableJava21ParserVisitor.java | 100 +++++++++++++- .../java/ReloadableJava8ParserVisitor.java | 103 ++++++++++++++- .../org/openrewrite/java/JavaParserTest.java | 125 ++++++++++++++++++ .../org/openrewrite/java/JavaVisitorTest.java | 36 +++++ .../java/ChangeStaticFieldToMethod.java | 44 ++---- .../org/openrewrite/java/JavaIsoVisitor.java | 6 + .../org/openrewrite/java/JavaPrinter.java | 26 +++- .../org/openrewrite/java/JavaVisitor.java | 7 + .../BlockStatementTemplateGenerator.java | 3 +- .../java/search/FindCompileErrors.java | 56 ++++++++ .../openrewrite/java/table/CompileErrors.java | 40 ++++++ .../java/org/openrewrite/java/tree/J.java | 48 +++++++ .../java/org/openrewrite/java/tree/Space.java | 1 + .../java/search/FindCompileErrorsTest.java | 61 +++++++++ 16 files changed, 805 insertions(+), 57 deletions(-) create mode 100644 rewrite-java/src/main/java/org/openrewrite/java/search/FindCompileErrors.java create mode 100644 rewrite-java/src/main/java/org/openrewrite/java/table/CompileErrors.java create mode 100644 rewrite-java/src/test/java/org/openrewrite/java/search/FindCompileErrorsTest.java diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index 243acd89904..22086c5db31 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -30,9 +30,11 @@ import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; import org.openrewrite.FileAttributes; +import org.openrewrite.PrintOutputCapture; import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; import org.openrewrite.java.JavaParsingException; +import org.openrewrite.java.JavaPrinter; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.OmitParentheses; import org.openrewrite.java.tree.*; @@ -191,6 +193,16 @@ public J visitAssignment(AssignmentTree node, Space fmt) { typeMapping.type(node)); } + @Override + public J visitErroneous(ErroneousTree node, Space fmt) { + String erroneousNode = source.substring(((JCTree) node).getStartPosition(), ((JCTree) node).getEndPosition(endPosTable)); + return new J.Erroneous( + randomId(), + fmt, + Markers.EMPTY, + erroneousNode); + } + @Override public J visitBinary(BinaryTree node, Space fmt) { Expression left = convert(node.getLeftOperand()); @@ -1439,6 +1451,22 @@ public J visitUnary(UnaryTree node, Space fmt) { @Override public J visitVariable(VariableTree node, Space fmt) { + JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) node; + if ("".equals(jcVariableDecl.getName().toString())) { + int startPos = jcVariableDecl.getStartPosition(); + int endPos = jcVariableDecl.getEndPosition(endPosTable); + + if (startPos == endPos) { + endPos = startPos + 1; + } + String erroneousNode = source.substring(startPos, endPos); + return new J.Erroneous( + randomId(), + fmt, + Markers.EMPTY, + erroneousNode + ); + } return hasFlag(node.getModifiers(), Flags.ENUM) ? visitEnumVariable(node, fmt) : visitVariables(singletonList(node), fmt); // method arguments cannot be multi-declarations @@ -1619,10 +1647,43 @@ private JRightPadded convert(Tree t, Function su J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); - cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it + int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace()); + if (idx >= 0) { + rightPadded = (JRightPadded) JRightPadded.build(getErroneous(List.of(rightPadded))); + } + // Cursor hasn't been updated but points at the end of erroneous node already + // This means that error node start position == end position + // Therefore ensure that cursor has moved to the end of erroneous node bu adding its length to the cursor + // Example `/pet` results in 2 erroeneous nodes: `/` and `pet`. The `/` node would have start and end position the + // same from the JC compiler. + if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) { + cursor += ((J.Erroneous) rightPadded.getElement()).getText().length(); + } else { + cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it + } return rightPadded; } + private J.Erroneous getErroneous(List> converted) { + PrintOutputCapture p = new PrintOutputCapture<>(0); + new JavaPrinter<>().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); + return new J.Erroneous( + org.openrewrite.Tree.randomId(), + EMPTY, + Markers.EMPTY, + p.getOut() + ); + } + + private static int findFirstNonWhitespaceChar(String s) { + for (int i = 0; i < s.length(); i++) { + if (!Character.isWhitespace(s.charAt(i))) { + return i; + } + } + return -1; + } + private long lineNumber(Tree tree) { return source.substring(0, ((JCTree) tree).getStartPosition()).chars().filter(c -> c == '\n').count() + 1; } @@ -1687,9 +1748,7 @@ private Space statementDelim(@Nullable Tree t) { t instanceof JCNewClass || t instanceof JCReturn || t instanceof JCThrow || - t instanceof JCUnary || - t instanceof JCExpressionStatement || - t instanceof JCVariableDecl) { + t instanceof JCUnary) { return sourceBefore(";"); } @@ -1697,9 +1756,39 @@ private Space statementDelim(@Nullable Tree t) { return statementDelim(((JCLabeledStatement) t).getStatement()); } + if (t instanceof JCExpressionStatement) { + ExpressionTree expTree = ((ExpressionStatementTree) t).getExpression(); + if (expTree instanceof ErroneousTree) { + return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable),((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); + } else { + return sourceBefore(";"); + } + } + + if (t instanceof JCVariableDecl) { + JCTree.JCVariableDecl varTree = (JCTree.JCVariableDecl) t; + if ("".contentEquals(varTree.getName())) { + int start = varTree.vartype.getEndPosition(endPosTable); + int end = varTree.getEndPosition(endPosTable); + String whitespace = source.substring(start, end); + if (whitespace.contains("\n")) { + return EMPTY; + } else { + return Space.build(source.substring(start, end), Collections.emptyList()); + } + } + return sourceBefore(";"); + } + if (t instanceof JCMethodDecl) { JCMethodDecl m = (JCMethodDecl) t; - return sourceBefore(m.body == null || m.defaultValue != null ? ";" : ""); + if (m.body == null || m.defaultValue != null) { + String suffix = source.substring(cursor, positionOfNext(";", null)); + int idx = findFirstNonWhitespaceChar(suffix); + return sourceBefore(idx >= 0 ? "" : ";"); + } else { + return sourceBefore(""); + } } return EMPTY; @@ -1724,6 +1813,10 @@ private List> convertStatements(@Nullable List> converted = new ArrayList<>(treesGroupedByStartPosition.size()); for (List treeGroup : treesGroupedByStartPosition.values()) { if (treeGroup.size() == 1) { + Tree t = treeGroup.get(0); + int startPosition = ((JCTree) t).getStartPosition(); + if (cursor > startPosition) + continue; converted.add(convert(treeGroup.get(0), suffix)); } else { // multi-variable declarations are split into independent overlapping JCVariableDecl's by the OpenJDK AST diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 25b78628c07..6dea46ebda4 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -31,9 +31,11 @@ import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; import org.openrewrite.FileAttributes; +import org.openrewrite.PrintOutputCapture; import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; import org.openrewrite.java.JavaParsingException; +import org.openrewrite.java.JavaPrinter; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.CompactConstructor; import org.openrewrite.java.marker.OmitParentheses; @@ -199,6 +201,16 @@ public J visitAssignment(AssignmentTree node, Space fmt) { typeMapping.type(node)); } + @Override + public J visitErroneous(ErroneousTree node, Space fmt) { + String erroneousNode = source.substring(((JCTree) node).getStartPosition(), ((JCTree) node).getEndPosition(endPosTable)); + return new J.Erroneous( + randomId(), + fmt, + Markers.EMPTY, + erroneousNode); + } + @Override public J visitBinary(BinaryTree node, Space fmt) { Expression left = convert(node.getLeftOperand()); @@ -1521,6 +1533,22 @@ public J visitUnary(UnaryTree node, Space fmt) { @Override public J visitVariable(VariableTree node, Space fmt) { + JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) node; + if ("".equals(jcVariableDecl.getName().toString())) { + int startPos = jcVariableDecl.getStartPosition(); + int endPos = jcVariableDecl.getEndPosition(endPosTable); + + if (startPos == endPos) { + endPos = startPos + 1; // For cases where the error node is a single character like "/" + } + String erroneousNode = source.substring(startPos, endPos); + return new J.Erroneous( + randomId(), + fmt, + Markers.EMPTY, + erroneousNode + ); + } return hasFlag(node.getModifiers(), Flags.ENUM) ? visitEnumVariable(node, fmt) : visitVariables(singletonList(node), fmt); // method arguments cannot be multi-declarations @@ -1732,11 +1760,45 @@ private void reportJavaParsingException(Throwable ex) { return null; } J2 j = convert(t); - JRightPadded rightPadded = new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); - cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it + @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : + new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); + int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace()); + if (idx >= 0) { + rightPadded = (JRightPadded) JRightPadded.build(getErroneous(List.of(rightPadded))); + } + // Cursor hasn't been updated but points at the end of erroneous node already + // This means that error node start position == end position + // Therefore ensure that cursor has moved to the end of erroneous node bu adding its length to the cursor + // Example `/pet` results in 2 erroeneous nodes: `/` and `pet`. The `/` node would have start and end position the + // same from the JC compiler. + if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) { + cursor += ((J.Erroneous) rightPadded.getElement()).getText().length(); + } else { + cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it + } return rightPadded; } + private J.Erroneous getErroneous(List> converted) { + PrintOutputCapture p = new PrintOutputCapture<>(0); + new JavaPrinter<>().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); + return new J.Erroneous( + org.openrewrite.Tree.randomId(), + EMPTY, + Markers.EMPTY, + p.getOut() + ); + } + + private static int findFirstNonWhitespaceChar(String s) { + for (int i = 0; i < s.length(); i++) { + if (!Character.isWhitespace(s.charAt(i))) { + return i; + } + } + return -1; + } + private long lineNumber(Tree tree) { return source.substring(0, ((JCTree) tree).getStartPosition()).chars().filter(c -> c == '\n').count() + 1; } @@ -1783,25 +1845,50 @@ private List> convertAll(List tr private Space statementDelim(@Nullable Tree t) { switch (t.getKind()) { + case CONTINUE: + case RETURN: + case BREAK: case ASSERT: case ASSIGNMENT: - case BREAK: - case CONTINUE: case DO_WHILE_LOOP: case IMPORT: case METHOD_INVOCATION: case NEW_CLASS: - case RETURN: case THROW: + return sourceBefore(";"); case EXPRESSION_STATEMENT: + ExpressionTree expTree = ((ExpressionStatementTree) t).getExpression(); + if (expTree instanceof ErroneousTree) { + return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable),((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); + } else { + return sourceBefore(";"); + } case VARIABLE: + JCTree.JCVariableDecl varTree = (JCTree.JCVariableDecl) t; + if ("".contentEquals(varTree.getName())) { + int start = varTree.vartype.getEndPosition(endPosTable); + int end = varTree.getEndPosition(endPosTable); + String whitespace = source.substring(start, end); + if (whitespace.contains("\n")) { + return EMPTY; + } else { + return Space.build(source.substring(start, end), Collections.emptyList()); + } + } + return sourceBefore(";"); case YIELD: return sourceBefore(";"); case LABELED_STATEMENT: return statementDelim(((JCLabeledStatement) t).getStatement()); case METHOD: JCMethodDecl m = (JCMethodDecl) t; - return sourceBefore(m.body == null || m.defaultValue != null ? ";" : ""); + if (m.body == null || m.defaultValue != null) { + String suffix = source.substring(cursor, positionOfNext(";", null)); + int idx = findFirstNonWhitespaceChar(suffix); + return sourceBefore(idx >= 0 ? "" : ";"); + } else { + return sourceBefore(""); + } default: return t instanceof JCAssignOp || t instanceof JCUnary ? sourceBefore(";") : EMPTY; } @@ -1829,6 +1916,10 @@ private List> convertStatements(@Nullable List> converted = new ArrayList<>(treesGroupedByStartPosition.size()); for (List treeGroup : treesGroupedByStartPosition.values()) { if (treeGroup.size() == 1) { + Tree t = treeGroup.get(0); + int startPosition = ((JCTree) t).getStartPosition(); + if (cursor > startPosition) + continue; converted.add(convert(treeGroup.get(0), suffix)); } else { // multi-variable declarations are split into independent overlapping JCVariableDecl's by the OpenJDK AST diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index a64eeab242f..8fd8d2809d9 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -30,9 +30,11 @@ import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; import org.openrewrite.FileAttributes; +import org.openrewrite.PrintOutputCapture; import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; import org.openrewrite.java.JavaParsingException; +import org.openrewrite.java.JavaPrinter; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.CompactConstructor; import org.openrewrite.java.marker.OmitParentheses; @@ -198,6 +200,16 @@ public J visitAssignment(AssignmentTree node, Space fmt) { typeMapping.type(node)); } + @Override + public J visitErroneous(ErroneousTree node, Space fmt) { + String erroneousNode = source.substring(((JCTree) node).getStartPosition(), ((JCTree) node).getEndPosition(endPosTable)); + return new J.Erroneous( + randomId(), + fmt, + Markers.EMPTY, + erroneousNode); + } + @Override public J visitBinary(BinaryTree node, Space fmt) { Expression left = convert(node.getLeftOperand()); @@ -1517,6 +1529,22 @@ public J visitUnary(UnaryTree node, Space fmt) { @Override public J visitVariable(VariableTree node, Space fmt) { + JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) node; + if ("".equals(jcVariableDecl.getName().toString())) { + int startPos = jcVariableDecl.getStartPosition(); + int endPos = jcVariableDecl.getEndPosition(endPosTable); + + if (startPos == endPos) { + endPos = startPos + 1; // For cases where the error node is a single character like "/" + } + String erroneousNode = source.substring(startPos, endPos); + return new J.Erroneous( + randomId(), + fmt, + Markers.EMPTY, + erroneousNode + ); + } return hasFlag(node.getModifiers(), Flags.ENUM) ? visitEnumVariable(node, fmt) : visitVariables(singletonList(node), fmt); // method arguments cannot be multi-declarations @@ -1707,10 +1735,43 @@ private JRightPadded convert(Tree t, Function su J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); - cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it + int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace()); + if (idx >= 0) { + rightPadded = (JRightPadded) JRightPadded.build(getErroneous(List.of(rightPadded))); + } + // Cursor hasn't been updated but points at the end of erroneous node already + // This means that error node start position == end position + // Therefore ensure that cursor has moved to the end of erroneous node bu adding its length to the cursor + // Example `/pet` results in 2 erroeneous nodes: `/` and `pet`. The `/` node would have start and end position the + // same from the JC compiler. + if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) { + cursor += ((J.Erroneous) rightPadded.getElement()).getText().length(); + } else { + cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it + } return rightPadded; } + private J.Erroneous getErroneous(List> converted) { + PrintOutputCapture p = new PrintOutputCapture<>(0); + new JavaPrinter<>().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); + return new J.Erroneous( + org.openrewrite.Tree.randomId(), + EMPTY, + Markers.EMPTY, + p.getOut() + ); + } + + private static int findFirstNonWhitespaceChar(String s) { + for (int i = 0; i < s.length(); i++) { + if (!Character.isWhitespace(s.charAt(i))) { + return i; + } + } + return -1; + } + private long lineNumber(Tree tree) { return source.substring(0, ((JCTree) tree).getStartPosition()).chars().filter(c -> c == '\n').count() + 1; } @@ -1765,25 +1826,50 @@ private List> convertAll(List tr private Space statementDelim(@Nullable Tree t) { switch (t.getKind()) { + case CONTINUE: + case RETURN: + case BREAK: case ASSERT: case ASSIGNMENT: - case BREAK: - case CONTINUE: case DO_WHILE_LOOP: case IMPORT: case METHOD_INVOCATION: case NEW_CLASS: - case RETURN: case THROW: + return sourceBefore(";"); case EXPRESSION_STATEMENT: + ExpressionTree expTree = ((ExpressionStatementTree) t).getExpression(); + if (expTree instanceof ErroneousTree) { + return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable),((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); + } else { + return sourceBefore(";"); + } case VARIABLE: + JCTree.JCVariableDecl varTree = (JCTree.JCVariableDecl) t; + if ("".contentEquals(varTree.getName())) { + int start = varTree.vartype.getEndPosition(endPosTable); + int end = varTree.getEndPosition(endPosTable); + String whitespace = source.substring(start, end); + if (whitespace.contains("\n")) { + return EMPTY; + } else { + return Space.build(source.substring(start, end), Collections.emptyList()); + } + } + return sourceBefore(";"); case YIELD: return sourceBefore(";"); case LABELED_STATEMENT: return statementDelim(((JCLabeledStatement) t).getStatement()); case METHOD: JCMethodDecl m = (JCMethodDecl) t; - return sourceBefore(m.body == null || m.defaultValue != null ? ";" : ""); + if (m.body == null || m.defaultValue != null) { + String suffix = source.substring(cursor, positionOfNext(";", null)); + int idx = findFirstNonWhitespaceChar(suffix); + return sourceBefore(idx >= 0 ? "" : ";"); + } else { + return sourceBefore(""); + } default: return t instanceof JCAssignOp || t instanceof JCUnary ? sourceBefore(";") : EMPTY; } @@ -1808,6 +1894,10 @@ private List> convertStatements(@Nullable List> converted = new ArrayList<>(treesGroupedByStartPosition.size()); for (List treeGroup : treesGroupedByStartPosition.values()) { if (treeGroup.size() == 1) { + Tree t = treeGroup.get(0); + int startPosition = ((JCTree) t).getStartPosition(); + if (cursor > startPosition) + continue; converted.add(convert(treeGroup.get(0), suffix)); } else { // multi-variable declarations are split into independent overlapping JCVariableDecl's by the OpenJDK AST diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index b07b7f18999..e9123f68062 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -29,9 +29,11 @@ import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; import org.openrewrite.FileAttributes; +import org.openrewrite.PrintOutputCapture; import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; import org.openrewrite.java.internal.JavaTypeCache; +import org.openrewrite.java.JavaPrinter; import org.openrewrite.java.marker.OmitParentheses; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; @@ -189,6 +191,16 @@ public J visitAssignment(AssignmentTree node, Space fmt) { typeMapping.type(node)); } + @Override + public J visitErroneous(ErroneousTree node, Space fmt) { + String erroneousNode = source.substring(((JCTree) node).getStartPosition(), ((JCTree) node).getEndPosition(endPosTable)); + return new J.Erroneous( + randomId(), + fmt, + Markers.EMPTY, + erroneousNode); + } + @Override public J visitBinary(BinaryTree node, Space fmt) { Expression left = convert(node.getLeftOperand()); @@ -1433,6 +1445,22 @@ public J visitUnary(UnaryTree node, Space fmt) { @Override public J visitVariable(VariableTree node, Space fmt) { + JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) node; + if ("".equals(jcVariableDecl.getName().toString())) { + int startPos = jcVariableDecl.getStartPosition(); + int endPos = jcVariableDecl.getEndPosition(endPosTable); + + if (startPos == endPos) { + endPos = startPos + 1; + } + String erroneousNode = source.substring(startPos, endPos); + return new J.Erroneous( + randomId(), + fmt, + Markers.EMPTY, + erroneousNode + ); + } return hasFlag(node.getModifiers(), Flags.ENUM) ? visitEnumVariable(node, fmt) : visitVariables(singletonList(node), fmt); // method arguments cannot be multi-declarations @@ -1606,10 +1634,43 @@ private JRightPadded convert(Tree t, Function su J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); - cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it + int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace()); + if (idx >= 0) { + rightPadded = (JRightPadded) JRightPadded.build(getErroneous(Collections.singletonList(rightPadded))); + } + // Cursor hasn't been updated but points at the end of erroneous node already + // This means that error node start position == end position + // Therefore ensure that cursor has moved to the end of erroneous node bu adding its length to the cursor + // Example `/pet` results in 2 erroeneous nodes: `/` and `pet`. The `/` node would have start and end position the + // same from the JC compiler. + if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) { + cursor += ((J.Erroneous) rightPadded.getElement()).getText().length(); + } else { + cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it + } return rightPadded; } + private J.Erroneous getErroneous(List> converted) { + PrintOutputCapture p = new PrintOutputCapture<>(0); + new JavaPrinter<>().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); + return new J.Erroneous( + org.openrewrite.Tree.randomId(), + EMPTY, + Markers.EMPTY, + p.getOut() + ); + } + + private static int findFirstNonWhitespaceChar(String s) { + for (int i = 0; i < s.length(); i++) { + if (!Character.isWhitespace(s.charAt(i))) { + return i; + } + } + return -1; + } + private long lineNumber(Tree tree) { int lineNumber = 1; for (char c : source.substring(0, ((JCTree) tree).getStartPosition()).toCharArray()) { @@ -1680,9 +1741,7 @@ private Space statementDelim(@Nullable Tree t) { t instanceof JCNewClass || t instanceof JCReturn || t instanceof JCThrow || - t instanceof JCUnary || - t instanceof JCExpressionStatement || - t instanceof JCVariableDecl) { + t instanceof JCUnary) { return sourceBefore(";"); } @@ -1690,9 +1749,39 @@ private Space statementDelim(@Nullable Tree t) { return statementDelim(((JCLabeledStatement) t).getStatement()); } + if (t instanceof JCExpressionStatement) { + ExpressionTree expTree = ((ExpressionStatementTree) t).getExpression(); + if (expTree instanceof ErroneousTree) { + return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable),((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); + } else { + return sourceBefore(";"); + } + } + + if (t instanceof JCVariableDecl) { + JCTree.JCVariableDecl varTree = (JCTree.JCVariableDecl) t; + if ("".contentEquals(varTree.getName())) { + int start = varTree.vartype.getEndPosition(endPosTable); + int end = varTree.getEndPosition(endPosTable); + String whitespace = source.substring(start, end); + if (whitespace.contains("\n")) { + return EMPTY; + } else { + return Space.build(source.substring(start, end), Collections.emptyList()); + } + } + return sourceBefore(";"); + } + if (t instanceof JCMethodDecl) { JCMethodDecl m = (JCMethodDecl) t; - return sourceBefore(m.body == null || m.defaultValue != null ? ";" : ""); + if (m.body == null || m.defaultValue != null) { + String suffix = source.substring(cursor, positionOfNext(";", null)); + int idx = findFirstNonWhitespaceChar(suffix); + return sourceBefore(idx >= 0 ? "" : ";"); + } else { + return sourceBefore(""); + } } return EMPTY; @@ -1717,6 +1806,10 @@ private List> convertStatements(@Nullable List> converted = new ArrayList<>(treesGroupedByStartPosition.size()); for (List treeGroup : treesGroupedByStartPosition.values()) { if (treeGroup.size() == 1) { + Tree t = treeGroup.get(0); + int startPosition = ((JCTree) t).getStartPosition(); + if (cursor > startPosition) + continue; converted.add(convert(treeGroup.get(0), suffix)); } else { // multi-variable declarations are split into independent overlapping JCVariableDecl's by the OpenJDK AST diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java index 3115386c7d7..4314094918f 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java @@ -25,6 +25,7 @@ import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.Issue; import org.openrewrite.SourceFile; +import org.openrewrite.java.search.FindCompileErrors; import org.openrewrite.java.tree.J; import org.openrewrite.test.RewriteTest; @@ -178,6 +179,130 @@ void moduleInfo() { assertFalse(JavaParser.fromJavaVersion().build().accept(Path.of("src/main/java/foo/module-info.java"))); } + @ParameterizedTest + //language=java + @ValueSource(strings = { + """ + package com.example.demo; + class FooBar { + public void test() { + ownerR + } + } + """, + """ + package com.example.demo; + class FooBar { + public void test(int num string msg) { + String a; this.ownerR + System.out.println(); + } + } + """, + """ + package com.example.demo; + class FooBar { + public void test(int num string s, int b) { + String a; this.ownerR + System.out.println(); + } + } + """, + """ + package com.example.demo; + class FooBar { + public void test(int num) { + String a; this.ownerR // comment + System.out.println(); + } + } + """, + """ + package com.example.demo; + class FooBar { + public void test(int num) { + // comment + this.ownerR + } + } + """, + """ + package com.example.demo; + class FooBar { + public void test(int param ) { + this.ownerR + // comment + } + } + """ + }) + void erroneousExpressionStatements(@Language("java") String source) { + rewriteRun( + java(source) + ); + } + + @Test + void erroneousVariableDeclarations() { + rewriteRun( + spec -> spec.recipe(new FindCompileErrors()), + java( + """ + package com.example.demo; + class Foo { + /pet + public void test() { + } + } + """, + """ + package com.example.demo; + class Foo { + /*~~>*///*~~>*/pet + public void test() { + } + } + """ + ), + java( + """ + package com.example.demo; + class Bar { + pet + public void test() { + } + } + """, + """ + package com.example.demo; + class Bar { + /*~~>*/pet + public void test() { + } + } + """ + ), + java( + """ + package com.example.demo; + class Baz { + -pet + public void test() { + } + } + """, + """ + package com.example.demo; + class Baz { + /*~~>*/-/*~~>*/pet + public void test() { + } + } + """ + ) + ); + } + @Test @Issue("https://github.com/openrewrite/rewrite/pull/4624") void shouldParseComments() { diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaVisitorTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaVisitorTest.java index 8c3e7fc9e22..de0f9daa151 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaVisitorTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaVisitorTest.java @@ -132,4 +132,40 @@ public void method2() { """) ); } + + @Test + void javaVisitorHandlesErroneousNodes() { + rewriteRun( + spec -> spec + .expectedCyclesThatMakeChanges(2) + .recipes( + toRecipe(() -> new JavaIsoVisitor<>() { + @Override + public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext p) { + if (method.getSimpleName().equals("test")) { + return JavaTemplate.builder("Exception").contextSensitive().build() + .apply(getCursor(), method.getCoordinates().replaceThrows()); + } + return method; + } + }) + ), + java( + """ + class A { + void test() { + owner + } + } + """, + """ + class A { + void test() throws Exception { + owner + } + } + """ + ) + ); + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ChangeStaticFieldToMethod.java b/rewrite-java/src/main/java/org/openrewrite/java/ChangeStaticFieldToMethod.java index d4c278783cc..6155a3b433d 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/ChangeStaticFieldToMethod.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/ChangeStaticFieldToMethod.java @@ -90,9 +90,9 @@ public J visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ct @Override public J visitFieldAccess(J.FieldAccess fieldAccess, ExecutionContext ctx) { if (getCursor().firstEnclosing(J.Import.class) == null && - TypeUtils.isOfClassType(fieldAccess.getTarget().getType(), oldClassName) && - fieldAccess.getSimpleName().equals(oldFieldName)) { - return useNewMethod(fieldAccess); + TypeUtils.isOfClassType(fieldAccess.getTarget().getType(), oldClassName) && + fieldAccess.getSimpleName().equals(oldFieldName)) { + return useNewMethod(fieldAccess, fieldAccess.getCoordinates().replace()); } return super.visitFieldAccess(fieldAccess, ctx); } @@ -101,43 +101,18 @@ public J visitFieldAccess(J.FieldAccess fieldAccess, ExecutionContext ctx) { public J visitIdentifier(J.Identifier ident, ExecutionContext ctx) { JavaType.Variable varType = ident.getFieldType(); if (varType != null && - TypeUtils.isOfClassType(varType.getOwner(), oldClassName) && - varType.getName().equals(oldFieldName)) { - return useNewMethod(ident); + TypeUtils.isOfClassType(varType.getOwner(), oldClassName) && + varType.getName().equals(oldFieldName)) { + return useNewMethod(ident, ident.getCoordinates().replace()); } return ident; } - private J useNewMethod(TypeTree tree) { + private J useNewMethod(TypeTree tree, JavaCoordinates coordinates) { String newClass = newClassName == null ? oldClassName : newClassName; - maybeRemoveImport(oldClassName); maybeAddImport(newClass); - - Cursor statementCursor = getCursor().dropParentUntil(Statement.class::isInstance); - Statement statement = statementCursor.getValue(); - J applied = makeNewMethod(newClass).apply(statementCursor, statement.getCoordinates().replace()); - - J.MethodInvocation method = null; - if (applied instanceof J.Block) { - J.Block block = (J.Block) applied; - method = block.getStatements().get(0).withPrefix(tree.getPrefix()); - } else if (applied instanceof J.NewArray) { - J.NewArray newArray = (J.NewArray) applied; - method = (J.MethodInvocation) newArray.getInitializer().get(0); - } - if (method == null || method.getMethodType() == null) { - throw new IllegalArgumentException("Error while changing a static field to a method. The generated template using a the new class [" + - newClass + "] and the method [" + newMethodName + "] resulted in a null method type."); - } - if (tree.getType() != null) { - JavaType.Method mt = method.getMethodType().withReturnType(tree.getType()); - method = method.withMethodType(mt); - if (method.getName().getType() != null) { - method = method.withName(method.getName().withType(mt)); - } - } - return method; + return makeNewMethod(newClass).apply(getCursor(), coordinates); } @NonNull @@ -145,7 +120,8 @@ private JavaTemplate makeNewMethod(String newClass) { String packageName = StringUtils.substringBeforeLast(newClass, "."); String simpleClassName = StringUtils.substringAfterLast(newClass, "."); - String methodInvocationTemplate = "{" + simpleClassName + (newTarget != null ? "." + newTarget + "." : ".") + newMethodName + "();}"; + + String methodInvocationTemplate = simpleClassName + (newTarget != null ? "." + newTarget + "." : ".") + newMethodName + "()"; @Language("java") String methodStub; if (newTarget == null) { diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaIsoVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaIsoVisitor.java index b15951d90e8..99234db3a4e 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaIsoVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaIsoVisitor.java @@ -364,4 +364,10 @@ public J.Wildcard visitWildcard(J.Wildcard wildcard, P p) { public J.Yield visitYield(J.Yield yield, P p) { return (J.Yield) super.visitYield(yield, p); } + + @Override + public J.Erroneous visitErroneous(J.Erroneous erroneous, P p) { + return (J.Erroneous) super.visitErroneous(erroneous, p); + } + } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java index f6b8081eca3..b75e24d02c3 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java @@ -18,6 +18,7 @@ import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; import org.openrewrite.PrintOutputCapture; +import org.openrewrite.Tree; import org.openrewrite.java.marker.CompactConstructor; import org.openrewrite.java.marker.OmitParentheses; import org.openrewrite.java.tree.*; @@ -27,6 +28,7 @@ import java.util.Iterator; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.UnaryOperator; public class JavaPrinter

extends JavaVisitor> { @@ -414,7 +416,8 @@ protected void printStatementTerminator(Statement s, PrintOutputCapture

p) { } if (s instanceof MethodDeclaration && ((MethodDeclaration) s).getBody() == null) { - p.append(';'); + if (!hasError(s)) + p.append(';'); return; } @@ -445,6 +448,19 @@ protected void printStatementTerminator(Statement s, PrintOutputCapture

p) { } } + private static boolean hasError(Tree tree) { + AtomicBoolean isError = new AtomicBoolean(false); + new JavaIsoVisitor() { + + @Override + public Erroneous visitErroneous(Erroneous erroneous, AtomicBoolean atomicBoolean) { + atomicBoolean.set(true); + return erroneous; + } + }.visit(tree, isError); + return isError.get(); + } + @Override public J visitBreak(Break breakStatement, PrintOutputCapture

p) { beforeSyntax(breakStatement, Space.Location.BREAK_PREFIX, p); @@ -1196,6 +1212,14 @@ public J visitYield(Yield yield, PrintOutputCapture

p) { return yield; } + @Override + public J visitErroneous(Erroneous error, PrintOutputCapture

p) { + beforeSyntax(error, Space.Location.ERRONEOUS, p); + p.append(error.getText()); + afterSyntax(error, p); + return error; + } + private static final UnaryOperator JAVA_MARKER_WRAPPER = out -> "/*~~" + out + (out.isEmpty() ? "" : "~~") + ">*/"; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java index fe218390396..eec6aeb187d 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java @@ -1423,6 +1423,13 @@ public J visitYield(J.Yield yield, P p) { JContainer.build(before, js, container.getMarkers()); } + public J visitErroneous(J.Erroneous erroneous, P p) { + J.Erroneous u = erroneous; + u = u.withPrefix(visitSpace(u.getPrefix(), Space.Location.ERRONEOUS, p)); + u = u.withMarkers(visitMarkers(u.getMarkers(), p)); + return u; + } + /** * Check if a child AST element is in the same lexical scope as that of the AST element associated with the base * cursor. (i.e.: Are the variables and declarations visible in the base scope also visible to the child AST diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java index e39d37b01ea..f586b011fcb 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java @@ -466,7 +466,8 @@ private void contextTemplate(Cursor cursor, J prior, StringBuilder before, Strin J firstEnclosing = cursor.getParentOrThrow().firstEnclosing(J.class); if (m.getArguments().stream().anyMatch(arg -> referToSameElement(prior, arg))) { before.insert(0, "__M__.any("); - if (firstEnclosing instanceof J.Block || firstEnclosing instanceof J.Case) { + if (firstEnclosing instanceof J.Block || firstEnclosing instanceof J.Case || + firstEnclosing instanceof J.If || firstEnclosing instanceof J.If.Else) { after.append(");"); } else { after.append(")"); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindCompileErrors.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindCompileErrors.java new file mode 100644 index 00000000000..21fd93439c2 --- /dev/null +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindCompileErrors.java @@ -0,0 +1,56 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.search; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.table.CompileErrors; +import org.openrewrite.java.tree.J; +import org.openrewrite.marker.SearchResult; + +public class FindCompileErrors extends Recipe { + + transient CompileErrors report = new CompileErrors(this); + + @Override + public String getDisplayName() { + return "Find compile errors"; + } + + @Override + public String getDescription() { + return "Compile errors result in a particular LST structure that can be searched for."; + } + + @Override + public TreeVisitor getVisitor() { + return new JavaIsoVisitor() { + @Override + public J.Erroneous visitErroneous(J.Erroneous erroneous, ExecutionContext ctx) { + J.CompilationUnit cu = getCursor().firstEnclosing(J.CompilationUnit.class); + String sourceFile = cu != null ? cu.getSourcePath().toString() : "Unknown source file"; + String code = erroneous.print(getCursor()); + report.insertRow(ctx, new CompileErrors.Row( + sourceFile, + code + )); + return SearchResult.found(erroneous); + } + }; + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/table/CompileErrors.java b/rewrite-java/src/main/java/org/openrewrite/java/table/CompileErrors.java new file mode 100644 index 00000000000..ff39951e875 --- /dev/null +++ b/rewrite-java/src/main/java/org/openrewrite/java/table/CompileErrors.java @@ -0,0 +1,40 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.table; + +import lombok.Value; +import org.openrewrite.Column; +import org.openrewrite.DataTable; +import org.openrewrite.Recipe; + +public class CompileErrors extends DataTable { + public CompileErrors(Recipe recipe) { + super(recipe, + "Compile errors", + "The source code of compile errors."); + } + + @Value + public static class Row { + @Column(displayName = "Source file", + description = "The source file that the method call occurred in.") + String sourceFile; + + @Column(displayName = "Source", + description = "The source code of the type use.") + String code; + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java index 1ad1cee2193..417db943f5f 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java @@ -6268,4 +6268,52 @@ public

J acceptJava(JavaVisitor

v, P p) { } } } + + /** + * A node that represents an erroneous element. + */ + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @Data + @With + final class Erroneous implements Statement, Expression { + @With + @EqualsAndHashCode.Include + UUID id; + + @With + Space prefix; + + @With + Markers markers; + + @With + String text; + + @Override + public

J acceptJava(JavaVisitor

v, P p) { + return v.visitErroneous(this, p); + } + + @Override + public @Nullable JavaType getType() { + return JavaType.Unknown.getInstance(); + } + + @Override + public T withType(@Nullable JavaType type) { + return (T) this; + } + + @Override + @Transient + public CoordinateBuilder.Statement getCoordinates() { + return new CoordinateBuilder.Statement(this); + } + + @Override + public String toString() { + return withPrefix(Space.EMPTY).printTrimmed(new JavaPrinter<>()); + } + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java index 834fb6b6800..fc40698f5d9 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java @@ -344,6 +344,7 @@ public enum Location { ENUM_VALUE_PREFIX, ENUM_VALUE_SET_PREFIX, ENUM_VALUE_SUFFIX, + ERRONEOUS, EXPRESSION_PREFIX, EXTENDS, FIELD_ACCESS_NAME, diff --git a/rewrite-java/src/test/java/org/openrewrite/java/search/FindCompileErrorsTest.java b/rewrite-java/src/test/java/org/openrewrite/java/search/FindCompileErrorsTest.java new file mode 100644 index 00000000000..168e88ee0ec --- /dev/null +++ b/rewrite-java/src/test/java/org/openrewrite/java/search/FindCompileErrorsTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.search; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.java.table.CompileErrors; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.openrewrite.java.Assertions.java; + +class FindCompileErrorsTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipes(new FindCompileErrors()); + } + + @DocumentExample + @Test + void javaVisitorHandlesErroneousNodes() { + rewriteRun( + spec -> spec.dataTable(CompileErrors.Row.class, + rows -> assertThat(rows).singleElement().satisfies(row -> { + assertThat(row.getSourceFile()).isEqualTo("A.java"); + assertThat(row.getCode()).isEqualTo("\n owner"); + })), + java( + """ + class A { + void test() { + owner + } + } + """, + """ + class A { + void test() { + /*~~>*/owner + } + } + """ + ) + ); + } +} From 91a031a3d517be1fe78656eb6b841141b336c085 Mon Sep 17 00:00:00 2001 From: Laurens Westerlaken Date: Thu, 19 Dec 2024 17:51:47 +0100 Subject: [PATCH 060/179] Make Groovy Parser correctly handle nested parenthesis (#4801) * WIP * Format * Format * Move grabbing of whitespace and resetting cursor to where it is actually required * Extra check is not required * Use toString * Add `emptyListLiteralWithParentheses` test * Add `insideFourParenthesesAndEnters` test * Move list tests all to ListTest * Add `emptyMapLiteralWithParentheses` * Review feedback and fix new testcases * Add `attributeWithParentheses` * Improve AttributeTest * Improve AttributeTest * Improve AttributeTest * Improve AttributeTest * Improve AttributeTest * Review fix new testcases * Revert edit to testcase * Add and fix testcase with newline * Add JavaDoc and move logic regarding whitespace and resetting cursor --------- Co-authored-by: lingenj --- .../org/openrewrite/internal/StringUtils.java | 10 ++ .../groovy/GroovyParserVisitor.java | 142 +++++++++++------- .../groovy/tree/AttributeTest.java | 25 +-- .../openrewrite/groovy/tree/BinaryTest.java | 31 +++- .../org/openrewrite/groovy/tree/CastTest.java | 17 ++- .../org/openrewrite/groovy/tree/ListTest.java | 34 +++++ .../openrewrite/groovy/tree/LiteralTest.java | 23 --- .../openrewrite/groovy/tree/MapEntryTest.java | 7 + .../groovy/tree/MethodInvocationTest.java | 61 +++++++- .../openrewrite/groovy/tree/RangeTest.java | 2 - 10 files changed, 255 insertions(+), 97 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java b/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java index 7cafdeb341a..4f0f76ae578 100644 --- a/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java @@ -720,4 +720,14 @@ public static String formatUriForPropertiesFile(String uri) { public static boolean hasLineBreak(@Nullable String s) { return s != null && LINE_BREAK.matcher(s).find(); } + + public static boolean containsWhitespace(String s) { + for (int i = 0; i < s.length(); ++i) { + if (Character.isWhitespace(s.charAt(i))) { + return true; + } + } + + return false; + } } diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index abf35207e2e..2e8b26ae7b3 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -34,6 +34,7 @@ import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.StringUtils; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.ImplicitReturn; import org.openrewrite.java.marker.OmitParentheses; @@ -1350,20 +1351,20 @@ public void visitConstantExpression(ConstantExpression expression) { jType = JavaType.Primitive.Short; } else if (type == ClassHelper.STRING_TYPE) { jType = JavaType.Primitive.String; - // String literals value returned by getValue()/getText() has already processed sequences like "\\" -> "\" - int length = sourceLengthOfString(expression); // this is an attribute selector - if (source.startsWith("@" + value, cursor)) { - length += 1; + boolean attributeSelector = source.startsWith("@" + value, cursor); + int length = lengthAccordingToAst(expression); + Integer insideParenthesesLevel = getInsideParenthesesLevel(expression); + if (insideParenthesesLevel != null) { + length = length - insideParenthesesLevel * 2; } - text = source.substring(cursor, cursor + length); - int delimiterLength = 0; - if (text.startsWith("$/")) { - delimiterLength = 2; - } else if (text.startsWith("\"\"\"") || text.startsWith("'''")) { - delimiterLength = 3; - } else if (text.startsWith("/") || text.startsWith("\"") || text.startsWith("'")) { - delimiterLength = 1; + String valueAccordingToAST = source.substring(cursor, cursor + length + (attributeSelector ? 1 : 0)); + int delimiterLength = getDelimiterLength(); + if (StringUtils.containsWhitespace(valueAccordingToAST)) { + length = delimiterLength + expression.getValue().toString().length() + delimiterLength; + text = source.substring(cursor, cursor + length + (attributeSelector ? 1 : 0)); + } else { + text = valueAccordingToAST; } value = text.substring(delimiterLength, text.length() - delimiterLength); } else if (expression.isNullExpression()) { @@ -1690,15 +1691,18 @@ public void visitGStringExpression(GStringExpression gstring) { @Override public void visitListExpression(ListExpression list) { - if (list.getExpressions().isEmpty()) { - queue.add(new G.ListLiteral(randomId(), sourceBefore("["), Markers.EMPTY, - JContainer.build(singletonList(new JRightPadded<>(new J.Empty(randomId(), EMPTY, Markers.EMPTY), sourceBefore("]"), Markers.EMPTY))), - typeMapping.type(list.getType()))); - } else { - queue.add(new G.ListLiteral(randomId(), sourceBefore("["), Markers.EMPTY, - JContainer.build(visitRightPadded(list.getExpressions().toArray(new ASTNode[0]), "]")), - typeMapping.type(list.getType()))); - } + queue.add(insideParentheses(list, fmt -> { + skip("["); + if (list.getExpressions().isEmpty()) { + return new G.ListLiteral(randomId(), fmt, Markers.EMPTY, + JContainer.build(singletonList(new JRightPadded<>(new J.Empty(randomId(), EMPTY, Markers.EMPTY), sourceBefore("]"), Markers.EMPTY))), + typeMapping.type(list.getType())); + } else { + return new G.ListLiteral(randomId(), fmt, Markers.EMPTY, + JContainer.build(visitRightPadded(list.getExpressions().toArray(new ASTNode[0]), "]")), + typeMapping.type(list.getType())); + } + })); } @Override @@ -1713,17 +1717,19 @@ public void visitMapEntryExpression(MapEntryExpression expression) { @Override public void visitMapExpression(MapExpression map) { - Space prefix = sourceBefore("["); - JContainer entries; - if (map.getMapEntryExpressions().isEmpty()) { - entries = JContainer.build(Collections.singletonList(JRightPadded.build( - new G.MapEntry(randomId(), whitespace(), Markers.EMPTY, - JRightPadded.build(new J.Empty(randomId(), sourceBefore(":"), Markers.EMPTY)), - new J.Empty(randomId(), sourceBefore("]"), Markers.EMPTY), null)))); - } else { - entries = JContainer.build(visitRightPadded(map.getMapEntryExpressions().toArray(new ASTNode[0]), "]")); - } - queue.add(new G.MapLiteral(randomId(), prefix, Markers.EMPTY, entries, typeMapping.type(map.getType()))); + queue.add(insideParentheses(map, fmt -> { + skip("["); + JContainer entries; + if (map.getMapEntryExpressions().isEmpty()) { + entries = JContainer.build(Collections.singletonList(JRightPadded.build( + new G.MapEntry(randomId(), whitespace(), Markers.EMPTY, + JRightPadded.build(new J.Empty(randomId(), sourceBefore(":"), Markers.EMPTY)), + new J.Empty(randomId(), sourceBefore("]"), Markers.EMPTY), null)))); + } else { + entries = JContainer.build(visitRightPadded(map.getMapEntryExpressions().toArray(new ASTNode[0]), "]")); + } + return new G.MapLiteral(randomId(), fmt, Markers.EMPTY, entries, typeMapping.type(map.getType())); + })); } @Override @@ -1901,23 +1907,24 @@ public void visitStaticMethodCallExpression(StaticMethodCallExpression call) { @Override public void visitAttributeExpression(AttributeExpression attr) { - Space fmt = whitespace(); - Expression target = visit(attr.getObjectExpression()); - Space beforeDot = attr.isSafe() ? sourceBefore("?.") : - sourceBefore(attr.isSpreadSafe() ? "*." : "."); - J name = visit(attr.getProperty()); - if (name instanceof J.Literal) { - String nameStr = ((J.Literal) name).getValueSource(); - assert nameStr != null; - name = new J.Identifier(randomId(), name.getPrefix(), Markers.EMPTY, emptyList(), nameStr, null, null); - } - if (attr.isSpreadSafe()) { - name = name.withMarkers(name.getMarkers().add(new StarDot(randomId()))); - } - if (attr.isSafe()) { - name = name.withMarkers(name.getMarkers().add(new NullSafe(randomId()))); - } - queue.add(new J.FieldAccess(randomId(), fmt, Markers.EMPTY, target, padLeft(beforeDot, (J.Identifier) name), null)); + queue.add(insideParentheses(attr, fmt -> { + Expression target = visit(attr.getObjectExpression()); + Space beforeDot = attr.isSafe() ? sourceBefore("?.") : + sourceBefore(attr.isSpreadSafe() ? "*." : "."); + J name = visit(attr.getProperty()); + if (name instanceof J.Literal) { + String nameStr = ((J.Literal) name).getValueSource(); + assert nameStr != null; + name = new J.Identifier(randomId(), name.getPrefix(), Markers.EMPTY, emptyList(), nameStr, null, null); + } + if (attr.isSpreadSafe()) { + name = name.withMarkers(name.getMarkers().add(new StarDot(randomId()))); + } + if (attr.isSafe()) { + name = name.withMarkers(name.getMarkers().add(new NullSafe(randomId()))); + } + return new J.FieldAccess(randomId(), fmt, Markers.EMPTY, target, padLeft(beforeDot, (J.Identifier) name), null); + })); } @Override @@ -2522,15 +2529,48 @@ private int sourceLengthOfString(ConstantExpression expr) { return lengthAccordingToAst; } - private static @Nullable Integer getInsideParenthesesLevel(ASTNode node) { + private @Nullable Integer getInsideParenthesesLevel(ASTNode node) { Object rawIpl = node.getNodeMetaData("_INSIDE_PARENTHESES_LEVEL"); if (rawIpl instanceof AtomicInteger) { // On Java 11 and newer _INSIDE_PARENTHESES_LEVEL is an AtomicInteger return ((AtomicInteger) rawIpl).get(); - } else { + } else if (rawIpl instanceof Integer) { // On Java 8 _INSIDE_PARENTHESES_LEVEL is a regular Integer return (Integer) rawIpl; + } else if (node instanceof MethodCallExpression) { + MethodCallExpression expr = (MethodCallExpression) node; + return determineParenthesisLevel(expr.getObjectExpression().getLineNumber(), expr.getLineNumber(), expr.getObjectExpression().getColumnNumber(), expr.getColumnNumber()); } + return null; + } + + /** + * @param childLineNumber the beginning line number of the first sub node + * @param parentLineNumber the beginning line number of the parent node + * @param childColumn the column on the {@code childLineNumber} line where the sub node starts + * @param parentColumn the column on the {@code parentLineNumber} line where the parent node starts + * @return the level of parenthesis parsed from the source + */ + private int determineParenthesisLevel(int childLineNumber, int parentLineNumber, int childColumn, int parentColumn) { + int saveCursor = cursor; + whitespace(); + int childBeginCursor = cursor; + if (childLineNumber > parentLineNumber) { + for (int i = 0; i < (childColumn - parentLineNumber); i++) { + childBeginCursor = source.indexOf('\n', childBeginCursor); + } + childBeginCursor += childColumn; + } else { + childBeginCursor += childColumn - parentColumn; + } + int count = 0; + for (int i = cursor; i < childBeginCursor; i++) { + if (source.charAt(i) == '(') { + count++; + } + } + cursor = saveCursor; + return count; } private int getDelimiterLength() { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java index bfbadb76655..2b7d4c82756 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java @@ -20,19 +20,26 @@ import static org.openrewrite.groovy.Assertions.groovy; -@SuppressWarnings({"GroovyUnusedAssignment", "GrUnnecessarySemicolon"}) class AttributeTest implements RewriteTest { @Test - void usingGroovyNode() { + void attribute() { rewriteRun( - groovy( - """ - def xml = new Node(null, "ivy") - def n = xml.dependencies.dependency.find { it.@name == 'test-module' } - n.@conf = 'runtime->default;docs->docs;sources->sources' - """ - ) + groovy("new User('Bob').@name") + ); + } + + @Test + void attributeInClosure() { + rewriteRun( + groovy("[new User('Bob')].collect { it.@name }") + ); + } + + @Test + void attributeWithParentheses() { + rewriteRun( + groovy("(new User('Bob').@name)") ); } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java index 13239c0fc76..aca502d3571 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java @@ -15,7 +15,6 @@ */ package org.openrewrite.groovy.tree; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -34,6 +33,7 @@ void insideParentheses() { // NOT inside parentheses, but verifies the parser's // test for "inside parentheses" condition + groovy("( 1 ) + 1"), groovy("(1) + 1"), // And combine the two cases groovy("((1) + 1)") @@ -216,6 +216,35 @@ void stringMultipliedInParentheses() { ); } + @Issue("https://github.com/openrewrite/rewrite/issues/4703") + @Test + void cxds() { + rewriteRun( + groovy( + """ + def differenceInDays(int time) { + return (int) ((time)/(1000*60*60*24)) + } + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite/issues/4703") + @Test + void extraParensAroundInfixOxxxperator() { + rewriteRun( + groovy( + """ + def timestamp(int hours, int minutes, int seconds) { + 30 * (hours) + (((((hours))))) * 30 + } + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/4703") @Test void extraParensAroundInfixOperator() { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java index 5cf82ae85be..4c009de95e3 100755 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java @@ -16,7 +16,6 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -25,6 +24,18 @@ @SuppressWarnings({"UnnecessaryQualifiedReference", "GroovyUnusedAssignment", "GrUnnecessarySemicolon"}) class CastTest implements RewriteTest { + @Test + void cast() { + rewriteRun( + groovy( + """ + String foo = ( String ) "hallo" + String bar = "hallo" as String + """ + ) + ); + } + @Test void javaStyleCast() { rewriteRun( @@ -74,14 +85,13 @@ void groovyCastAndInvokeMethod() { rewriteRun( groovy( """ - ( "" as String ).toString() + ( "x" as String ).toString() """ ) ); } @Test - @ExpectedToFail("Parentheses with method invocation is not yet supported") void groovyCastAndInvokeMethodWithParentheses() { rewriteRun( groovy( @@ -103,7 +113,6 @@ void javaCastAndInvokeMethod() { ); } - @ExpectedToFail("Parentheses with method invocation is not yet supported") @Test void javaCastAndInvokeMethodWithParentheses() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java index b42f9579fd4..d921377b661 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java @@ -23,6 +23,29 @@ @SuppressWarnings("GroovyUnusedAssignment") class ListTest implements RewriteTest { + @Test + void emptyListLiteral() { + rewriteRun( + groovy( + """ + def a = [] + def b = [ ] + """ + ) + ); + } + + @Test + void emptyListLiteralWithParentheses() { + rewriteRun( + groovy( + """ + def y = ([]) + """ + ) + ); + } + @Test void listLiteral() { rewriteRun( @@ -33,4 +56,15 @@ void listLiteral() { ) ); } + + @Test + void listLiteralTrailingComma() { + rewriteRun( + groovy( + """ + def a = [ "foo" /* "foo" suffix */ , /* "]" prefix */ ] + """ + ) + ); + } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java index 46851b2f65a..12d638870d4 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java @@ -216,18 +216,6 @@ void literalValueAndTypeAgree() { ); } - @Test - void emptyListLiteral() { - rewriteRun( - groovy( - """ - def a = [] - def b = [ ] - """ - ) - ); - } - @Test void multilineStringWithApostrophes() { rewriteRun( @@ -254,17 +242,6 @@ void mapLiteralTrailingComma() { ); } - @Test - void listLiteralTrailingComma() { - rewriteRun( - groovy( - """ - def a = [ "foo" /* "foo" suffix */ , /* "]" prefix */ ] - """ - ) - ); - } - @Test void gStringThatHasEmptyValueExpressionForUnknownReason() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java index 65bb4a17492..67ee80177cd 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java @@ -55,6 +55,13 @@ void emptyMapLiteral() { ); } + @Test + void emptyMapLiteralWithParentheses() { + rewriteRun( + groovy("Map m = ([ : ])") + ); + } + @Test void mapAccess() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java index a0714126901..42a73d160a0 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java @@ -16,7 +16,6 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -31,11 +30,11 @@ void gradle() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation 'org.hibernate:hibernate-core:3.6.7.Final' api 'com.google.guava:guava:23.0' @@ -46,7 +45,6 @@ void gradle() { ); } - @ExpectedToFail("Parentheses with method invocation is not yet supported") @Test @Issue("https://github.com/openrewrite/rewrite/issues/4615") void gradleWithParentheses() { @@ -349,7 +347,7 @@ class StringUtils { static boolean isEmpty(String value) { return value == null || value.isEmpty() } - + static void main(String[] args) { isEmpty("") } @@ -359,7 +357,29 @@ static void main(String[] args) { ); } - @ExpectedToFail("Parentheses with method invocation is not yet supported") + @Issue("https://github.com/openrewrite/rewrite/issues/4703") + @Test + void insideParenthesesSimple() { + rewriteRun( + groovy( + """ + ((a.invoke "b" )) + """ + ) + ); + } + + @Test + void lotOfSpacesAroundConstantWithParentheses() { + rewriteRun( + groovy( + """ + ( ( ( "x" ) ).toString() ) + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/4703") @Test void insideParentheses() { @@ -375,7 +395,21 @@ static def foo(Map map) { ); } - @ExpectedToFail("Parentheses with method invocation is not yet supported") + @Test + void insideParenthesesWithNewline() { + rewriteRun( + groovy( + """ + static def foo(Map map) { + (( + map.containsKey("foo")) + && ((map.get("foo")).equals("bar"))) + } + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/4703") @Test void insideParenthesesWithoutNewLineAndEscapedMethodName() { @@ -387,4 +421,17 @@ static def foo(Map someMap) {((((((someMap.get("(bar")))) ).'equals' "baz" ) ) ) ); } + + @Test + void insideFourParenthesesAndEnters() { + rewriteRun( + groovy( + """ + (((( + something(a) + )))) + """ + ) + ); + } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java index ac839e34d88..e0ff32f3d94 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java @@ -16,7 +16,6 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.test.RewriteTest; import static org.openrewrite.groovy.Assertions.groovy; @@ -48,7 +47,6 @@ void parenthesized() { ); } - @ExpectedToFail("Parentheses with method invocation is not yet supported") @Test void parenthesizedAndInvokeMethodWithParentheses() { rewriteRun( From 2631a7e1b968239b32f028d7a19130c57433940f Mon Sep 17 00:00:00 2001 From: Peter Streef Date: Fri, 20 Dec 2024 12:31:58 +0100 Subject: [PATCH 061/179] suppress javax.json (#4804) * suppress javax.json * Update suppressions.xml --- suppressions.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/suppressions.xml b/suppressions.xml index adba34b3922..329d8806f0f 100644 --- a/suppressions.xml +++ b/suppressions.xml @@ -39,4 +39,12 @@ ^pkg:maven/org\.glassfish/javax\.json@.*$ CVE-2023-7272 + + + ^pkg:maven/org\.glassfish/javax\.json@.*$ + CVE-2023-7272 + From 697ae150aab87d16d0b4adda519843e0c37472cb Mon Sep 17 00:00:00 2001 From: Laurens Westerlaken Date: Fri, 20 Dec 2024 15:33:17 +0100 Subject: [PATCH 062/179] Refactor SpringReference (#4805) * Separating and clearer naming * Add license header * Review feedback --- ...Reference.java => SpringXmlReference.java} | 55 +++------------- .../openrewrite/xml/trait/XmlReference.java | 64 +++++++++++++++++++ .../org.openrewrite.trait.Reference$Provider | 2 +- ...eTest.java => SpringXmlReferenceTest.java} | 4 +- 4 files changed, 75 insertions(+), 50 deletions(-) rename rewrite-xml/src/main/java/org/openrewrite/xml/trait/{SpringReference.java => SpringXmlReference.java} (67%) create mode 100644 rewrite-xml/src/main/java/org/openrewrite/xml/trait/XmlReference.java rename rewrite-xml/src/test/java/org/openrewrite/xml/trait/{SpringReferenceTest.java => SpringXmlReferenceTest.java} (96%) diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringReference.java b/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringXmlReference.java similarity index 67% rename from rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringReference.java rename to rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringXmlReference.java index a2a78481461..41523a89b8a 100644 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringReference.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringXmlReference.java @@ -18,9 +18,7 @@ import lombok.Value; import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; -import org.openrewrite.ExecutionContext; import org.openrewrite.SourceFile; -import org.openrewrite.Tree; import org.openrewrite.trait.Reference; import org.openrewrite.trait.SimpleTraitMatcher; import org.openrewrite.xml.XPathMatcher; @@ -32,54 +30,17 @@ import java.util.regex.Pattern; @Value -class SpringReference implements Reference { +public class SpringXmlReference extends XmlReference { + Cursor cursor; Kind kind; - @Override - public Tree getTree() { - return Reference.super.getTree(); - } - @Override public Kind getKind() { return kind; } - @Override - public String getValue() { - if (getTree() instanceof Xml.Attribute) { - Xml.Attribute attribute = (Xml.Attribute) getTree(); - return attribute.getValueAsString(); - } else if (getTree() instanceof Xml.Tag) { - Xml.Tag tag = (Xml.Tag) getTree(); - if (tag.getValue().isPresent()) { - return tag.getValue().get(); - } - } - throw new IllegalArgumentException("getTree() must be an Xml.Attribute or Xml.Tag: " + getTree().getClass()); - } - - @Override - public boolean supportsRename() { - return true; - } - - @Override - public Tree rename(Renamer renamer, Cursor cursor, ExecutionContext ctx) { - Tree tree = cursor.getValue(); - if (tree instanceof Xml.Attribute) { - Xml.Attribute attribute = (Xml.Attribute) tree; - String renamed = renamer.rename(this); - return attribute.withValue(attribute.getValue().withValue(renamed)); - } else if (tree instanceof Xml.Tag && ((Xml.Tag) tree).getValue().isPresent()) { - String renamed = renamer.rename(this); - return ((Xml.Tag) tree).withValue(renamed); - } - return tree; - } - - static class Matcher extends SimpleTraitMatcher { + static class Matcher extends SimpleTraitMatcher { private final Pattern referencePattern = Pattern.compile("\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*(?:\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*"); private final XPathMatcher classXPath = new XPathMatcher("//@class"); private final XPathMatcher typeXPath = new XPathMatcher("//@type"); @@ -88,14 +49,14 @@ static class Matcher extends SimpleTraitMatcher { private final XPathMatcher tags = new XPathMatcher("//value"); @Override - protected @Nullable SpringReference test(Cursor cursor) { + protected @Nullable SpringXmlReference test(Cursor cursor) { Object value = cursor.getValue(); if (value instanceof Xml.Attribute) { Xml.Attribute attrib = (Xml.Attribute) value; if (classXPath.matches(cursor) || typeXPath.matches(cursor) || keyTypeXPath.matches(cursor) || valueTypeXPath.matches(cursor)) { String stringVal = attrib.getValueAsString(); if (referencePattern.matcher(stringVal).matches()) { - return new SpringReference(cursor, determineKind(stringVal)); + return new SpringXmlReference(cursor, determineKind(stringVal)); } } } else if (value instanceof Xml.Tag) { @@ -103,15 +64,15 @@ static class Matcher extends SimpleTraitMatcher { if (tags.matches(cursor)) { Optional stringVal = tag.getValue(); if (stringVal.isPresent() && referencePattern.matcher(stringVal.get()).matches()) { - return new SpringReference(cursor, determineKind(stringVal.get())); + return new SpringXmlReference(cursor, determineKind(stringVal.get())); } } } return null; } - Kind determineKind(String value) { - return Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Kind.TYPE : Kind.PACKAGE; + Reference.Kind determineKind(String value) { + return Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Reference.Kind.TYPE : Reference.Kind.PACKAGE; } } diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/trait/XmlReference.java b/rewrite-xml/src/main/java/org/openrewrite/xml/trait/XmlReference.java new file mode 100644 index 00000000000..25b87149d2d --- /dev/null +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/trait/XmlReference.java @@ -0,0 +1,64 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.xml.trait; + +import org.openrewrite.Cursor; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Tree; +import org.openrewrite.trait.Reference; +import org.openrewrite.xml.tree.Xml; + +public abstract class XmlReference implements Reference { + + @Override + public Tree getTree() { + return Reference.super.getTree(); + } + + @Override + public String getValue() { + if (getTree() instanceof Xml.Attribute) { + Xml.Attribute attribute = (Xml.Attribute) getTree(); + return attribute.getValueAsString(); + } else if (getTree() instanceof Xml.Tag) { + Xml.Tag tag = (Xml.Tag) getTree(); + if (tag.getValue().isPresent()) { + return tag.getValue().get(); + } + } + throw new IllegalArgumentException("getTree() must be an Xml.Attribute or Xml.Tag: " + getTree().getClass()); + } + + @Override + public boolean supportsRename() { + return true; + } + + @Override + public Tree rename(Renamer renamer, Cursor cursor, ExecutionContext ctx) { + Tree tree = cursor.getValue(); + if (tree instanceof Xml.Attribute) { + Xml.Attribute attribute = (Xml.Attribute) tree; + String renamed = renamer.rename(this); + return attribute.withValue(attribute.getValue().withValue(renamed)); + } else if (tree instanceof Xml.Tag && ((Xml.Tag) tree).getValue().isPresent()) { + String renamed = renamer.rename(this); + return ((Xml.Tag) tree).withValue(renamed); + } + return tree; + } + +} diff --git a/rewrite-xml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider b/rewrite-xml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider index 72d76d75ee4..e8a9ab1dc42 100644 --- a/rewrite-xml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider +++ b/rewrite-xml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider @@ -1 +1 @@ -org.openrewrite.xml.trait.SpringReference$Provider \ No newline at end of file +org.openrewrite.xml.trait.SpringXmlReference$Provider \ No newline at end of file diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringReferenceTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringXmlReferenceTest.java similarity index 96% rename from rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringReferenceTest.java rename to rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringXmlReferenceTest.java index d60f5a2e8a9..000d242b16e 100644 --- a/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringReferenceTest.java +++ b/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringXmlReferenceTest.java @@ -23,11 +23,11 @@ import static org.openrewrite.xml.Assertions.xml; -class SpringReferenceTest implements RewriteTest { +class SpringXmlReferenceTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.recipe(RewriteTest.toRecipe(() -> new SpringReference.Matcher() + spec.recipe(RewriteTest.toRecipe(() -> new SpringXmlReference.Matcher() .asVisitor(springJavaTypeReference -> SearchResult.found(springJavaTypeReference.getTree(), springJavaTypeReference.getValue())))); } From 59273da0f6cfa2c0b4063fcdd8ea4bb9789d998d Mon Sep 17 00:00:00 2001 From: Shannon Pamperl Date: Fri, 20 Dec 2024 16:51:50 -0600 Subject: [PATCH 063/179] refactor: Update Gradle wrapper (#4808) Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.gradle.UpdateGradleWrapper?organizationId=T3BlblJld3JpdGU%3D#defaults=W3sibmFtZSI6ImFkZElmTWlzc2luZyIsInZhbHVlIjoiRmFsc2UifV0= Co-authored-by: Moderne --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9751024bf3d..046b4f50491 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,8 +1,8 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 +distributionSha256Sum=7a00d51fb93147819aab76024feece20b6b84e420694101f276be952e08bef03 From dd2886c193ea20f416171b5b280a49086e969710 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sat, 21 Dec 2024 17:42:41 +0100 Subject: [PATCH 064/179] Add recipe to remove Gradle Enterprise and Develocity (#4809) * Add recipe to remove Gradle Enterprise and Develocity * Remove left over java plugin --- .../RemoveDevelocityConfiguration.java | 57 +++++++++++ .../resources/META-INF/rewrite/gradle.yml | 15 +++ .../gradle/plugins/RemoveDevelocityTest.java | 95 +++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/RemoveDevelocityConfiguration.java create mode 100644 rewrite-gradle/src/test/java/org/openrewrite/gradle/plugins/RemoveDevelocityTest.java diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/RemoveDevelocityConfiguration.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/RemoveDevelocityConfiguration.java new file mode 100644 index 00000000000..356c2dfab43 --- /dev/null +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/plugins/RemoveDevelocityConfiguration.java @@ -0,0 +1,57 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.gradle.plugins; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.gradle.IsBuildGradle; +import org.openrewrite.gradle.IsSettingsGradle; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.tree.J; + +import static org.openrewrite.Preconditions.or; + +public class RemoveDevelocityConfiguration extends Recipe { + @Override + public String getDisplayName() { + return "Remove Develocity configuration"; + } + + @Override + public String getDescription() { + return "Remove Develocity configuration from a Gradle build."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check( + or(new IsBuildGradle<>(), new IsSettingsGradle<>()), + new JavaIsoVisitor() { + @Override + public J.@Nullable MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + if ("develocity".equals(method.getSimpleName()) || + "gradleEnterprise".equals(method.getSimpleName())) { + return null; + } + return super.visitMethodInvocation(method, ctx); + } + } + ); + } +} diff --git a/rewrite-gradle/src/main/resources/META-INF/rewrite/gradle.yml b/rewrite-gradle/src/main/resources/META-INF/rewrite/gradle.yml index 7240bdf3672..6fdf529b07e 100644 --- a/rewrite-gradle/src/main/resources/META-INF/rewrite/gradle.yml +++ b/rewrite-gradle/src/main/resources/META-INF/rewrite/gradle.yml @@ -42,3 +42,18 @@ recipeList: key: org.gradle.parallel value: true filePattern: gradle.properties +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.gradle.plugins.RemoveDevelocity +displayName: Remove Develocity +description: Remove the Develocity plugin and configuration from the Gradle build and settings files. +recipeList: + - org.openrewrite.gradle.plugins.RemoveBuildPlugin: + pluginId: com.gradle.develocity + - org.openrewrite.gradle.plugins.RemoveSettingsPlugin: + pluginId: com.gradle.develocity + - org.openrewrite.gradle.plugins.RemoveBuildPlugin: + pluginId: com.gradle.enterprise + - org.openrewrite.gradle.plugins.RemoveSettingsPlugin: + pluginId: com.gradle.enterprise + - org.openrewrite.gradle.plugins.RemoveDevelocityConfiguration \ No newline at end of file diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/plugins/RemoveDevelocityTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/plugins/RemoveDevelocityTest.java new file mode 100644 index 00000000000..3c26e264f79 --- /dev/null +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/plugins/RemoveDevelocityTest.java @@ -0,0 +1,95 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.gradle.plugins; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.gradle.Assertions.settingsGradle; +import static org.openrewrite.gradle.toolingapi.Assertions.withToolingApi; + +class RemoveDevelocityTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .beforeRecipe(withToolingApi()) + .recipeFromResource("/META-INF/rewrite/gradle.yml", "org.openrewrite.gradle.plugins.RemoveDevelocity"); + } + + @Test + @DocumentExample + void removeGradleEnterprise() { + rewriteRun( + settingsGradle( + """ + plugins { + id 'com.gradle.enterprise' version '3.16' + } + gradleEnterprise { + server = 'https://ge.sam.com/' + allowUntrustedServer = true + buildScan { + publishAlways() + uploadInBackground = true + capture { + taskInputFiles = true + } + } + buildCache { + remote(gradleEnterprise.buildCache) { + enabled = true + push = System.getenv("CI") != null + } + } + } + """, + "" + ) + ); + } + + @Test + void removeDevelocity() { + rewriteRun( + settingsGradle( + """ + plugins { + id 'com.gradle.develocity' version '3.17.6' + } + develocity { + server = 'https://ge.sam.com/' + allowUntrustedServer = true + buildScan { + uploadInBackground = true + capture { + fileFingerprints = true + } + } + buildCache { + remote(develocity.buildCache) { + enabled = true + push = System.getenv("CI") != null + } + } + } + """, + "" + ) + ); + } +} From e93ec048be927787c80afbf35da4bcea1b789674 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sat, 21 Dec 2024 19:27:00 +0100 Subject: [PATCH 065/179] Add a UsesType precondition to ReplaceConstant --- .../main/java/org/openrewrite/java/ReplaceConstant.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ReplaceConstant.java b/rewrite-java/src/main/java/org/openrewrite/java/ReplaceConstant.java index eedef216d95..b8f7f001e14 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/ReplaceConstant.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/ReplaceConstant.java @@ -19,6 +19,7 @@ import lombok.Value; import org.jspecify.annotations.Nullable; import org.openrewrite.*; +import org.openrewrite.java.search.UsesType; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.TypeUtils; @@ -53,7 +54,7 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return new JavaVisitor() { + JavaVisitor replacementVisitor = new JavaVisitor() { J.@Nullable Literal literal; @Override @@ -117,5 +118,9 @@ private J.Literal buildLiteral() { return literal; } }; + return Preconditions.check( + new UsesType<>(owningType, true), + replacementVisitor + ); } } From da6561eab8cbbae90bb5de17e2882860bf2b01dc Mon Sep 17 00:00:00 2001 From: Peter Streef Date: Mon, 23 Dec 2024 12:01:57 +0100 Subject: [PATCH 066/179] Allow file scheme in `RemoteArchive` to simplify testing (#4791) * Allow file scheme in `RemoteArchive` to simplify testing While it might look a bit controversial, the file scheme can also point to a remote (for instance a mounted network share) file. By allowing the `file://` scheme we can use `RemoteArchive` for those files. As a useful side effect, this makes testing RemoteArchive handling a lot easier. * fix test * Update rewrite-core/src/test/java/org/openrewrite/remote/RemoteArchiveTest.java Co-authored-by: Sam Snyder --------- Co-authored-by: Sam Snyder --- .../org/openrewrite/remote/RemoteArchive.java | 4 +++ .../openrewrite/remote/RemoteArchiveTest.java | 26 +++++++++++++----- .../openrewrite/remote/RemoteFileTest.java | 4 +-- rewrite-core/src/test/resources/zipfile.zip | Bin 0 -> 193 bytes 4 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 rewrite-core/src/test/resources/zipfile.zip diff --git a/rewrite-core/src/main/java/org/openrewrite/remote/RemoteArchive.java b/rewrite-core/src/main/java/org/openrewrite/remote/RemoteArchive.java index 23de1da8810..6e553fdac4b 100644 --- a/rewrite-core/src/main/java/org/openrewrite/remote/RemoteArchive.java +++ b/rewrite-core/src/main/java/org/openrewrite/remote/RemoteArchive.java @@ -34,6 +34,7 @@ import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.List; import java.util.UUID; import java.util.regex.Pattern; @@ -92,6 +93,9 @@ public InputStream getInputStream(ExecutionContext ctx) { try { Path localArchive = cache.compute(uri, () -> { //noinspection resource + if ("file".equals(uri.getScheme())) { + return Files.newInputStream(Paths.get(uri)); + } HttpSender.Response response = httpSender.send(httpSender.get(uri.toString()).build()); if (response.isSuccessful()) { return response.getBody(); diff --git a/rewrite-core/src/test/java/org/openrewrite/remote/RemoteArchiveTest.java b/rewrite-core/src/test/java/org/openrewrite/remote/RemoteArchiveTest.java index f96eea97f00..e09fc8454f5 100644 --- a/rewrite-core/src/test/java/org/openrewrite/remote/RemoteArchiveTest.java +++ b/rewrite-core/src/test/java/org/openrewrite/remote/RemoteArchiveTest.java @@ -21,10 +21,12 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.HttpSenderExecutionContextView; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.PrintOutputCapture; import org.openrewrite.test.MockHttpSender; import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Paths; import java.util.concurrent.*; @@ -40,10 +42,6 @@ class RemoteArchiveTest { void gradleWrapper(String version) throws Exception { URL distributionUrl = requireNonNull(RemoteArchiveTest.class.getClassLoader().getResource("gradle-" + version + "-bin.zip")); ExecutionContext ctx = new InMemoryExecutionContext(); - RemoteExecutionContextView.view(ctx).setArtifactCache(new LocalRemoteArtifactCache( - Paths.get(System.getProperty("user.home") + "/.rewrite/remote/gradleWrapper"))); - HttpSenderExecutionContextView.view(ctx) - .setLargeFileHttpSender(new MockHttpSender(distributionUrl::openStream)); RemoteArchive remoteArchive = Remote .builder( @@ -58,10 +56,9 @@ void gradleWrapper(String version) throws Exception { @Test void gradleWrapperDownloadFails() throws Exception { - URL distributionUrl = requireNonNull(RemoteArchiveTest.class.getClassLoader().getResource("gradle-7.4.2-bin.zip")); + URL distributionUrl = new URL("http://example"); ExecutionContext ctx = new InMemoryExecutionContext(); - RemoteExecutionContextView.view(ctx).setArtifactCache(new LocalRemoteArtifactCache( - Paths.get(System.getProperty("user.home") + "/.rewrite/remote/gradleWrapperDownloadFails"))); + HttpSenderExecutionContextView.view(ctx) .setLargeFileHttpSender(new MockHttpSender(408)); @@ -116,6 +113,21 @@ void gradleWrapperConcurrent(String version) throws Exception { executorService.shutdown(); } + @Test + void printingRemoteArchive() throws URISyntaxException { + URL zipUrl = requireNonNull(RemoteArchiveTest.class.getClassLoader().getResource("zipfile.zip")); + + RemoteArchive remoteArchive = Remote + .builder( + Paths.get("content.txt"), + zipUrl.toURI() + ) + .build("content.txt"); + + String printed = remoteArchive.printAll(new PrintOutputCapture<>(0, PrintOutputCapture.MarkerPrinter.DEFAULT)); + assertThat(printed).isEqualTo("this is a zipped file"); + } + private Long getInputStreamSize(InputStream is) { BlackHoleOutputStream out = new BlackHoleOutputStream(); try { diff --git a/rewrite-core/src/test/java/org/openrewrite/remote/RemoteFileTest.java b/rewrite-core/src/test/java/org/openrewrite/remote/RemoteFileTest.java index 6e335a1eee3..de1b23476c8 100644 --- a/rewrite-core/src/test/java/org/openrewrite/remote/RemoteFileTest.java +++ b/rewrite-core/src/test/java/org/openrewrite/remote/RemoteFileTest.java @@ -55,10 +55,8 @@ void gradleWrapperProperties() throws Exception { @Test void gradleWrapperDownloadFails() throws Exception { - URL distributionUrl = requireNonNull(RemoteFileTest.class.getClassLoader().getResource("gradle-wrapper.properties")); + URL distributionUrl = new URL("http://example.com"); ExecutionContext ctx = new InMemoryExecutionContext(); - RemoteExecutionContextView.view(ctx).setArtifactCache(new LocalRemoteArtifactCache( - Paths.get(System.getProperty("user.home") + "/.rewrite/remote/gradleWrapperDownloadFails"))); HttpSenderExecutionContextView.view(ctx) .setLargeFileHttpSender(new MockHttpSender(408)); diff --git a/rewrite-core/src/test/resources/zipfile.zip b/rewrite-core/src/test/resources/zipfile.zip new file mode 100644 index 0000000000000000000000000000000000000000..028830c420ec4023f6e482cbe9dbbf38a606f654 GIT binary patch literal 193 zcmWIWW@h1H0DNs?36d)D(rZ%$(E!Z$>6LW?W`V0JSkN01aSR(g Date: Mon, 23 Dec 2024 18:21:51 +0100 Subject: [PATCH 067/179] Try alternative way of determining parenthesis level for `BinaryExpression` when AST doesn't provide `_INSIDE_PARENTHESES_LEVEL` flag (#4807) --- .../main/java/org/openrewrite/groovy/GroovyParserVisitor.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 2e8b26ae7b3..5ce8d628352 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -2540,6 +2540,10 @@ private int sourceLengthOfString(ConstantExpression expr) { } else if (node instanceof MethodCallExpression) { MethodCallExpression expr = (MethodCallExpression) node; return determineParenthesisLevel(expr.getObjectExpression().getLineNumber(), expr.getLineNumber(), expr.getObjectExpression().getColumnNumber(), expr.getColumnNumber()); + } else if (node instanceof BinaryExpression) { + BinaryExpression expr = (BinaryExpression) node; + return determineParenthesisLevel(expr.getLeftExpression().getLineNumber(), expr.getLineNumber(), expr.getLeftExpression().getColumnNumber(), expr.getColumnNumber()); + } return null; } From 804dea04bdda8eaab7bed8b1424c9b0fe3432c6a Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Tue, 24 Dec 2024 11:00:30 +0100 Subject: [PATCH 068/179] Add a `isClassAvailable` method to the ReflectionUtils (#4810) * Add a `isClassAvailable` method to the ReflectionUtils * Add a `isClassAvailable` method to the ReflectionUtils * Add a `isClassAvailable` method to the ReflectionUtils --- .../openrewrite/internal/ReflectionUtils.java | 17 ++++++-- .../internal/ReflectionUtilsTest.java | 41 +++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 rewrite-core/src/test/java/org/openrewrite/internal/ReflectionUtilsTest.java diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/ReflectionUtils.java b/rewrite-core/src/main/java/org/openrewrite/internal/ReflectionUtils.java index 8cda946a88d..b207a7232e9 100644 --- a/rewrite-core/src/main/java/org/openrewrite/internal/ReflectionUtils.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/ReflectionUtils.java @@ -36,7 +36,18 @@ public class ReflectionUtils { * Cache for {@link Class#getDeclaredMethods()} plus equivalent default methods * from Java 8 based interfaces, allowing for fast iteration. */ - private static final Map, Method[]> declaredMethodsCache = new ConcurrentHashMap<>(256); + private static final Map, Method[]> DECLARED_METHODS_CACHE = new ConcurrentHashMap<>(256); + + public static boolean isClassAvailable(String fullyQualifiedClassName) { + try { + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + ClassLoader classLoader = contextClassLoader == null ? ReflectionUtils.class.getClassLoader() : contextClassLoader; + Class.forName(fullyQualifiedClassName, false, classLoader); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } public static @Nullable Method findMethod(Class clazz, String name, Class... paramTypes) { Class searchType = clazz; @@ -54,7 +65,7 @@ public class ReflectionUtils { } private static Method[] getDeclaredMethods(Class clazz) { - Method[] result = declaredMethodsCache.get(clazz); + Method[] result = DECLARED_METHODS_CACHE.get(clazz); if (result == null) { try { Method[] declaredMethods = clazz.getDeclaredMethods(); @@ -70,7 +81,7 @@ private static Method[] getDeclaredMethods(Class clazz) { } else { result = declaredMethods; } - declaredMethodsCache.put(clazz, (result.length == 0 ? EMPTY_METHOD_ARRAY : result)); + DECLARED_METHODS_CACHE.put(clazz, (result.length == 0 ? EMPTY_METHOD_ARRAY : result)); } catch (Throwable ex) { throw new IllegalStateException("Failed to introspect Class [" + clazz.getName() + "] from ClassLoader [" + clazz.getClassLoader() + "]", ex); diff --git a/rewrite-core/src/test/java/org/openrewrite/internal/ReflectionUtilsTest.java b/rewrite-core/src/test/java/org/openrewrite/internal/ReflectionUtilsTest.java new file mode 100644 index 00000000000..83eb1763c75 --- /dev/null +++ b/rewrite-core/src/test/java/org/openrewrite/internal/ReflectionUtilsTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.internal; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ReflectionUtilsTest { + + @Test + void classAvailable() { + boolean result = ReflectionUtils.isClassAvailable("org.openrewrite.internal.ReflectionUtilsTest"); + assertTrue(result); + } + + @Test + void classNotAvailable() { + boolean result = ReflectionUtils.isClassAvailable("org.openrewrite.internal.ReflectionUtilsTest2"); + assertFalse(result); + } + + @Test + void classNotAvailableWhenFQNOmitted() { + boolean result = ReflectionUtils.isClassAvailable("ReflectionUtilsTest"); + assertFalse(result); + } +} From da57352794a42b15957a5e9fd0e51e1e45580a62 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Tue, 24 Dec 2024 15:33:14 +0100 Subject: [PATCH 069/179] Update rewrite.yml to enforce CompareEnumsWithEqualityOperator --- rewrite.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rewrite.yml b/rewrite.yml index 6ed6b2ee876..9ad48193b27 100644 --- a/rewrite.yml +++ b/rewrite.yml @@ -27,6 +27,7 @@ recipeList: - org.openrewrite.recipes.RecipeNullabilityBestPracticesSubset #- org.openrewrite.java.OrderImports - org.openrewrite.java.format.EmptyNewlineAtEndOfFile + - org.openrewrite.staticanalysis.CompareEnumsWithEqualityOperator - org.openrewrite.staticanalysis.InlineVariable - org.openrewrite.staticanalysis.MissingOverrideAnnotation - org.openrewrite.staticanalysis.UseDiamondOperator @@ -75,4 +76,4 @@ recipeList: annotationPattern: '@org.jetbrains.annotations.NotNull' - org.openrewrite.java.RemoveAnnotation: annotationPattern: '@jakarta.annotation.Nonnull' - #- org.openrewrite.java.jspecify.MigrateToJspecify \ No newline at end of file + #- org.openrewrite.java.jspecify.MigrateToJspecify From ef0f8456cde7f9a4ed43a4903d7529d10e0e6126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Schn=C3=A9ider?= Date: Tue, 24 Dec 2024 17:15:02 -0500 Subject: [PATCH 070/179] Correctly map generic return and parameter types in `JavaReflectionTypeMapping` (#4812) --- .../java/org/openrewrite/java/JavaTypeMappingTest.java | 5 +++++ .../java/internal/JavaReflectionTypeMapping.java | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java index 591d897bfc3..3783a9365cf 100644 --- a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java +++ b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java @@ -110,6 +110,11 @@ default void generic() { assertThat(generic.getName()).isEqualTo("?"); assertThat(generic.getVariance()).isEqualTo(COVARIANT); assertThat(TypeUtils.asFullyQualified(generic.getBounds().get(0)).getFullyQualifiedName()).isEqualTo("org.openrewrite.java.C"); + + generic = (JavaType.GenericTypeVariable) TypeUtils.asParameterized(methodType("generic").getReturnType()).getTypeParameters().get(0); + assertThat(generic.getName()).isEqualTo("?"); + assertThat(generic.getVariance()).isEqualTo(COVARIANT); + assertThat(TypeUtils.asFullyQualified(generic.getBounds().get(0)).getFullyQualifiedName()).isEqualTo("org.openrewrite.java.C"); } @Test diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java index a7fb142280a..440217560b4 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java @@ -472,13 +472,13 @@ private JavaType.Method method(Method method, JavaType.FullyQualified declaringT List parameterTypes = emptyList(); if (method.getParameters().length > 0) { parameterTypes = new ArrayList<>(method.getParameters().length); - for (Parameter parameter : method.getParameters()) { - Type parameterizedType = parameter.getParameterizedType(); - parameterTypes.add(type(parameterizedType == null ? parameter.getType() : parameterizedType)); + for (Type parameter : method.getGenericParameterTypes()) { + parameterTypes.add(type(parameter)); } } - mappedMethod.unsafeSet(declaringType, type(method.getReturnType()), parameterTypes, thrownExceptions, annotations); + JavaType returnType = type(method.getGenericReturnType()); + mappedMethod.unsafeSet(declaringType, returnType, parameterTypes, thrownExceptions, annotations); return mappedMethod; } } From 321c93b0e64817b5aafb89206c24010c935a1cae Mon Sep 17 00:00:00 2001 From: Jonathan Schneider Date: Tue, 24 Dec 2024 23:18:16 +0100 Subject: [PATCH 071/179] Polish formatting --- .../src/main/java/org/openrewrite/java/tree/JavaType.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index 2fa596187f4..171a6a2198e 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -387,7 +387,6 @@ class Class extends FullyQualified { @NonFinal FullyQualified owningClass; - @NonFinal FullyQualified @Nullable [] annotations; @@ -1100,7 +1099,6 @@ class Method implements JavaType { @NonFinal JavaType returnType; - @NonFinal String @Nullable [] parameterNames; From 4ca0c8ec3d292d32a1db5017124b8112a9d32d12 Mon Sep 17 00:00:00 2001 From: Jonathan Schneider Date: Tue, 24 Dec 2024 23:19:16 +0100 Subject: [PATCH 072/179] Add more scenarios to JavaTypeGoat for simply typed fields and methods that return exceptions. --- .../src/main/java/org/openrewrite/java/JavaTypeGoat.java | 6 ++++++ rewrite-java-test/src/main/resources/JavaTypeGoat.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeGoat.java b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeGoat.java index a32c6df44c4..8e8abd6fe37 100644 --- a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeGoat.java +++ b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeGoat.java @@ -15,6 +15,7 @@ */ package org.openrewrite.java; +import java.io.FileNotFoundException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -25,6 +26,8 @@ public abstract class JavaTypeGoat & C> { public static final PT parameterizedField = new PT() { }; + public static final Double PI = 3.14; + public static final double PI_PRIMITIVE = 3.14; public static abstract class InheritedJavaTypeGoat & C> extends JavaTypeGoat { public InheritedJavaTypeGoat() { @@ -73,6 +76,9 @@ public static class TypeB {} public abstract & C> U genericIntersection(U n); public abstract T genericT(T n); // remove after signatures are common. public abstract & Intersection> void recursiveIntersection(U n); + public abstract T nameShadow(T t); + public abstract void throwsException() throws FileNotFoundException; + public abstract void throwsGenericException() throws T, InterruptedException; } interface C { diff --git a/rewrite-java-test/src/main/resources/JavaTypeGoat.java b/rewrite-java-test/src/main/resources/JavaTypeGoat.java index 61953059cab..40e1696a15a 100644 --- a/rewrite-java-test/src/main/resources/JavaTypeGoat.java +++ b/rewrite-java-test/src/main/resources/JavaTypeGoat.java @@ -15,6 +15,7 @@ */ package org.openrewrite.java; +import java.io.FileNotFoundException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -25,6 +26,8 @@ public abstract class JavaTypeGoat & C> { public static final PT parameterizedField = new PT() { }; + public static final Double PI = 3.14; + public static final double PI_PRIMITIVE = 3.14; public static abstract class InheritedJavaTypeGoat & C> extends JavaTypeGoat { public InheritedJavaTypeGoat() { @@ -73,6 +76,9 @@ public static class TypeB {} public abstract & C> U genericIntersection(U n); public abstract T genericT(T n); // remove after signatures are common. public abstract & Intersection> void recursiveIntersection(U n); + public abstract T nameShadow(T t); + public abstract void throwsException() throws FileNotFoundException; + public abstract void throwsGenericException() throws T, InterruptedException; } interface C { From 15740e4b31de5a06cfa9f15a0800720637b2fc0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Schn=C3=A9ider?= Date: Wed, 25 Dec 2024 12:24:55 +0100 Subject: [PATCH 073/179] Support mapping of generic thrown exception types (#4813) --- .../openrewrite/groovy/GroovyTypeMapping.java | 2 +- .../isolated/ReloadableJava11TypeMapping.java | 36 +++--------------- .../isolated/ReloadableJava17TypeMapping.java | 38 ++++--------------- .../isolated/ReloadableJava21TypeMapping.java | 36 +++--------------- .../java/ReloadableJava8TypeMapping.java | 36 +++--------------- .../openrewrite/java/JavaTypeMappingTest.java | 24 ++++++++++++ .../java/JavaTemplateTest6Test.java | 4 +- .../org/openrewrite/java/JavaTypeVisitor.java | 2 +- .../java/UnsafeJavaTypeVisitor.java | 2 +- .../internal/JavaReflectionTypeMapping.java | 9 ++--- .../template/JavaTemplateJavaExtension.java | 4 +- .../org/openrewrite/java/tree/JavaType.java | 38 +++++++++---------- 12 files changed, 80 insertions(+), 151 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyTypeMapping.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyTypeMapping.java index 872160fa148..882943a2fb6 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyTypeMapping.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyTypeMapping.java @@ -244,7 +244,7 @@ private JavaType genericType(GenericsType g, String signature) { } } - List thrownExceptions = null; + List thrownExceptions = null; if(node.getExceptions() != null) { for (ClassNode e : node.getExceptions()) { thrownExceptions = new ArrayList<>(node.getExceptions().length); diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java index d0b90bea744..00ba35afbd5 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java @@ -492,7 +492,7 @@ public JavaType.Primitive primitive(TypeTag tag) { JavaType returnType = null; List parameterTypes = null; - List exceptionTypes = null; + List exceptionTypes = null; if (selectType instanceof Type.MethodType) { Type.MethodType methodType = (Type.MethodType) selectType; @@ -512,20 +512,8 @@ public JavaType.Primitive primitive(TypeTag tag) { if (!methodType.thrown.isEmpty()) { exceptionTypes = new ArrayList<>(methodType.thrown.size()); for (Type exceptionType : methodType.thrown) { - JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType)); - if (javaType == null) { - // if the type cannot be resolved to a class (it might not be on the classpath, or it might have - // been mapped to cyclic) - if (exceptionType instanceof Type.ClassType) { - Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym; - javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class, - null, null, null, null, null, null, null); - } - } - if (javaType != null) { - // if the exception type is not resolved, it is not added to the list of exceptions - exceptionTypes.add(javaType); - } + JavaType javaType = type(exceptionType); + exceptionTypes.add(javaType); } } } else if (selectType instanceof Type.UnknownType) { @@ -603,7 +591,7 @@ public JavaType.Primitive primitive(TypeTag tag) { ((Type.ForAll) methodSymbol.type).qtype : methodSymbol.type; - List exceptionTypes = null; + List exceptionTypes = null; Type selectType = methodSymbol.type; if (selectType instanceof Type.ForAll) { @@ -615,20 +603,8 @@ public JavaType.Primitive primitive(TypeTag tag) { if (!methodType.thrown.isEmpty()) { exceptionTypes = new ArrayList<>(methodType.thrown.size()); for (Type exceptionType : methodType.thrown) { - JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType)); - if (javaType == null) { - // if the type cannot be resolved to a class (it might not be on the classpath, or it might have - // been mapped to cyclic) - if (exceptionType instanceof Type.ClassType) { - Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym; - javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class, - null, null, null, null, null, null, null); - } - } - if (javaType != null) { - // if the exception type is not resolved, it is not added to the list of exceptions - exceptionTypes.add(javaType); - } + JavaType javaType = type(exceptionType); + exceptionTypes.add(javaType); } } } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java index 7d5ad9da3f6..d3a1ee1c9a7 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java @@ -500,7 +500,7 @@ public JavaType.Primitive primitive(TypeTag tag) { JavaType returnType = null; List parameterTypes = null; - List exceptionTypes = null; + List exceptionTypes = null; if (selectType instanceof Type.MethodType) { Type.MethodType methodType = (Type.MethodType) selectType; @@ -520,20 +520,8 @@ public JavaType.Primitive primitive(TypeTag tag) { if (!methodType.thrown.isEmpty()) { exceptionTypes = new ArrayList<>(methodType.thrown.size()); for (Type exceptionType : methodType.thrown) { - JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType)); - if (javaType == null) { - // if the type cannot be resolved to a class (it might not be on the classpath, or it might have - // been mapped to cyclic) - if (exceptionType instanceof Type.ClassType) { - Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym; - javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class, - null, null, null, null, null, null, null); - } - } - if (javaType != null) { - // if the exception type is not resolved, it is not added to the list of exceptions - exceptionTypes.add(javaType); - } + JavaType javaType = type(exceptionType); + exceptionTypes.add(javaType); } } } else if (selectType instanceof Type.UnknownType) { @@ -590,7 +578,7 @@ public JavaType.Primitive primitive(TypeTag tag) { } else { try { defaultValues = Collections.singletonList(methodSymbol.getDefaultValue().getValue().toString()); - } catch(UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { // not all Attribute implementations define `getValue()` } } @@ -611,7 +599,7 @@ public JavaType.Primitive primitive(TypeTag tag) { ((Type.ForAll) methodSymbol.type).qtype : methodSymbol.type; - List exceptionTypes = null; + List exceptionTypes = null; Type selectType = methodSymbol.type; if (selectType instanceof Type.ForAll) { @@ -623,20 +611,8 @@ public JavaType.Primitive primitive(TypeTag tag) { if (!methodType.thrown.isEmpty()) { exceptionTypes = new ArrayList<>(methodType.thrown.size()); for (Type exceptionType : methodType.thrown) { - JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType)); - if (javaType == null) { - // if the type cannot be resolved to a class (it might not be on the classpath, or it might have - // been mapped to cyclic) - if (exceptionType instanceof Type.ClassType) { - Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym; - javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class, - null, null, null, null, null, null, null); - } - } - if (javaType != null) { - // if the exception type is not resolved, it is not added to the list of exceptions - exceptionTypes.add(javaType); - } + JavaType javaType = type(exceptionType); + exceptionTypes.add(javaType); } } } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index 10d9b202c6f..bde8ecb7573 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -511,7 +511,7 @@ public JavaType.Primitive primitive(TypeTag tag) { JavaType returnType = null; List parameterTypes = null; - List exceptionTypes = null; + List exceptionTypes = null; if (selectType instanceof Type.MethodType) { Type.MethodType methodType = (Type.MethodType) selectType; @@ -531,20 +531,8 @@ public JavaType.Primitive primitive(TypeTag tag) { if (!methodType.thrown.isEmpty()) { exceptionTypes = new ArrayList<>(methodType.thrown.size()); for (Type exceptionType : methodType.thrown) { - JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType)); - if (javaType == null) { - // if the type cannot be resolved to a class (it might not be on the classpath, or it might have - // been mapped to cyclic) - if (exceptionType instanceof Type.ClassType) { - Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym; - javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class, - null, null, null, null, null, null, null); - } - } - if (javaType != null) { - // if the exception type is not resolved, it is not added to the list of exceptions - exceptionTypes.add(javaType); - } + JavaType javaType = type(exceptionType); + exceptionTypes.add(javaType); } } } else if (selectType instanceof Type.UnknownType) { @@ -622,7 +610,7 @@ public JavaType.Primitive primitive(TypeTag tag) { ((Type.ForAll) methodSymbol.type).qtype : methodSymbol.type; - List exceptionTypes = null; + List exceptionTypes = null; Type selectType = methodSymbol.type; if (selectType instanceof Type.ForAll) { @@ -634,20 +622,8 @@ public JavaType.Primitive primitive(TypeTag tag) { if (!methodType.thrown.isEmpty()) { exceptionTypes = new ArrayList<>(methodType.thrown.size()); for (Type exceptionType : methodType.thrown) { - JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType)); - if (javaType == null) { - // if the type cannot be resolved to a class (it might not be on the classpath, or it might have - // been mapped to cyclic) - if (exceptionType instanceof Type.ClassType) { - Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym; - javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class, - null, null, null, null, null, null, null); - } - } - if (javaType != null) { - // if the exception type is not resolved, it is not added to the list of exceptions - exceptionTypes.add(javaType); - } + JavaType javaType = type(exceptionType); + exceptionTypes.add(javaType); } } } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java index 988b0920206..9beaba2727b 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java @@ -494,7 +494,7 @@ public JavaType.Primitive primitive(TypeTag tag) { JavaType returnType = null; List parameterTypes = null; - List exceptionTypes = null; + List exceptionTypes = null; if (selectType instanceof Type.MethodType) { Type.MethodType methodType = (Type.MethodType) selectType; @@ -514,20 +514,8 @@ public JavaType.Primitive primitive(TypeTag tag) { if (!methodType.thrown.isEmpty()) { exceptionTypes = new ArrayList<>(methodType.thrown.size()); for (Type exceptionType : methodType.thrown) { - JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType)); - if (javaType == null) { - // if the type cannot be resolved to a class (it might not be on the classpath, or it might have - // been mapped to cyclic) - if (exceptionType instanceof Type.ClassType) { - Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym; - javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class, - null, null, null, null, null, null, null); - } - } - if (javaType != null) { - // if the exception type is not resolved, it is not added to the list of exceptions - exceptionTypes.add(javaType); - } + JavaType javaType = type(exceptionType); + exceptionTypes.add(javaType); } } } else if (selectType instanceof Type.UnknownType) { @@ -604,7 +592,7 @@ public JavaType.Primitive primitive(TypeTag tag) { ((Type.ForAll) methodSymbol.type).qtype : methodSymbol.type; - List exceptionTypes = null; + List exceptionTypes = null; Type selectType = methodSymbol.type; if (selectType instanceof Type.ForAll) { @@ -616,20 +604,8 @@ public JavaType.Primitive primitive(TypeTag tag) { if (!methodType.thrown.isEmpty()) { exceptionTypes = new ArrayList<>(methodType.thrown.size()); for (Type exceptionType : methodType.thrown) { - JavaType.FullyQualified javaType = TypeUtils.asFullyQualified(type(exceptionType)); - if (javaType == null) { - // if the type cannot be resolved to a class (it might not be on the classpath, or it might have - // been mapped to cyclic) - if (exceptionType instanceof Type.ClassType) { - Symbol.ClassSymbol sym = (Symbol.ClassSymbol) exceptionType.tsym; - javaType = new JavaType.Class(null, Flag.Public.getBitMask(), sym.flatName().toString(), JavaType.Class.Kind.Class, - null, null, null, null, null, null, null); - } - } - if (javaType != null) { - // if the exception type is not resolved, it is not added to the list of exceptions - exceptionTypes.add(javaType); - } + JavaType javaType = type(exceptionType); + exceptionTypes.add(javaType); } } } diff --git a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java index 3783a9365cf..2eba1ba1e0f 100644 --- a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java +++ b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java @@ -53,6 +53,16 @@ default JavaType firstMethodParameter(String methodName) { return methodType(methodName).getParameterTypes().get(0); } + @Test + default void declaringTypeRefersToParameterizedClass() { + JavaType.FullyQualified declaringType = methodType("nameShadow").getDeclaringType(); + assertThat(declaringType.getTypeParameters()) + .describedAs("If it points to the raw class, " + + "method level name shadowing of generic " + + "type variables cannot be detected.") + .isNotEmpty(); + } + @Test default void javaLangObjectHasNoSupertype() { assertThat(goatType().getSupertype().getSupertype()).isNull(); @@ -242,4 +252,18 @@ default void recursiveIntersection() { JavaType.GenericTypeVariable clazz = TypeUtils.asGeneric(firstMethodParameter("recursiveIntersection")); assertThat(clazz.toString()).isEqualTo("Generic{U extends org.openrewrite.java.JavaTypeGoat$Extension & org.openrewrite.java.Intersection}"); } + + @Test + default void throwsGenericExceptions() { + JavaType.Method method = methodType("throwsGenericException"); + JavaType ex = method.getThrownExceptions().get(0); + + assertThat(ex).isInstanceOf(JavaType.GenericTypeVariable.class); + + JavaType.GenericTypeVariable generic = (JavaType.GenericTypeVariable) ex; + assertThat(generic.getName()).isEqualTo("T"); + assertThat(generic.getVariance()).isEqualTo(COVARIANT); + assertThat(TypeUtils.asFullyQualified(generic.getBounds().get(0)) + .getFullyQualifiedName()).isEqualTo("java.io.FileNotFoundException"); + } } diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateTest6Test.java b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateTest6Test.java index b6dd28e6764..4b8cdb9d754 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateTest6Test.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateTest6Test.java @@ -255,7 +255,9 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, Ex })).afterRecipe(run -> { J.CompilationUnit cu = (J.CompilationUnit) run.getChangeset().getAllResults().get(0).getAfter(); J.MethodDeclaration testMethodDecl = (J.MethodDeclaration) cu.getClasses().get(0).getBody().getStatements().get(0); - assertThat(testMethodDecl.getMethodType().getThrownExceptions().stream().map(JavaType.FullyQualified::getFullyQualifiedName)) + assertThat(testMethodDecl.getMethodType().getThrownExceptions().stream() + .map(JavaType.FullyQualified.class::cast) + .map(JavaType.FullyQualified::getFullyQualifiedName)) .containsExactly("java.lang.Exception"); }), java( diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaTypeVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaTypeVisitor.java index f06a3501ec4..29ddbf14870 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaTypeVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaTypeVisitor.java @@ -148,7 +148,7 @@ public JavaType visitMethod(JavaType.Method method, P p) { m = m.withDeclaringType((JavaType.FullyQualified) visit(m.getDeclaringType(), p)); m = m.withReturnType(visit(m.getReturnType(), p)); m = m.withParameterTypes(ListUtils.map(m.getParameterTypes(), pt -> visit(pt, p))); - m = m.withThrownExceptions(ListUtils.map(m.getThrownExceptions(), t -> (JavaType.FullyQualified) visit(t, p))); + m = m.withThrownExceptions(ListUtils.map(m.getThrownExceptions(), t -> visit(t, p))); m = m.withAnnotations(ListUtils.map(m.getAnnotations(), a -> (JavaType.FullyQualified) visit(a, p))); return m; } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/UnsafeJavaTypeVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/UnsafeJavaTypeVisitor.java index 8eee53b3624..a28e6547241 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/UnsafeJavaTypeVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/UnsafeJavaTypeVisitor.java @@ -69,7 +69,7 @@ public JavaType visitMethod(JavaType.Method method, P p) { (JavaType.FullyQualified) visit(method.getDeclaringType(), p), visit(method.getReturnType(), p), mapInPlace(method.getParameterTypes().toArray(EMPTY_JAVA_TYPE_ARRAY), pt -> visit(pt, p)), - mapInPlace(method.getThrownExceptions().toArray(EMPTY_FULLY_QUALIFIED_ARRAY), t -> (JavaType.FullyQualified) visit(t, p)), + mapInPlace(method.getThrownExceptions().toArray(EMPTY_JAVA_TYPE_ARRAY), t -> visit(t, p)), mapInPlace(method.getAnnotations().toArray(EMPTY_FULLY_QUALIFIED_ARRAY), a -> (JavaType.FullyQualified) visit(a, p)) ); } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java index 440217560b4..ef7ee8de348 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java @@ -345,7 +345,7 @@ private JavaType.Method method(Constructor method, JavaType.FullyQualified de ); typeCache.put(signature, mappedMethod); - List thrownExceptions = null; + List thrownExceptions = null; if (method.getExceptionTypes().length > 0) { thrownExceptions = new ArrayList<>(method.getExceptionTypes().length); for (Class e : method.getExceptionTypes()) { @@ -451,12 +451,11 @@ private JavaType.Method method(Method method, JavaType.FullyQualified declaringT ); typeCache.put(signature, mappedMethod); - List thrownExceptions = null; + List thrownExceptions = null; if (method.getExceptionTypes().length > 0) { thrownExceptions = new ArrayList<>(method.getExceptionTypes().length); - for (Class e : method.getExceptionTypes()) { - JavaType.FullyQualified fullyQualified = (JavaType.FullyQualified) type(e); - thrownExceptions.add(fullyQualified); + for (Type e : method.getGenericExceptionTypes()) { + thrownExceptions.add(type(e)); } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateJavaExtension.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateJavaExtension.java index cfd9b9ea548..476aeaa2e03 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateJavaExtension.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateJavaExtension.java @@ -354,11 +354,11 @@ public J visitMethodDeclaration(J.MethodDeclaration method, Integer p) { // Update method type information to reflect the new checked exceptions JavaType.Method type = m.getMethodType(); if (type != null) { - List newThrows = new ArrayList<>(); + List newThrows = new ArrayList<>(); List throws_ = (m.getThrows() == null) ? emptyList() : m.getThrows(); for (NameTree t : throws_) { J.Identifier exceptionIdent = (J.Identifier) t; - newThrows.add((JavaType.FullyQualified) exceptionIdent.getType()); + newThrows.add(exceptionIdent.getType()); } type = type.withThrownExceptions(newThrows); } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index 171a6a2198e..95d936ff2df 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -323,16 +323,16 @@ public String getPackageName() { public boolean isAssignableTo(String fullyQualifiedName) { return TypeUtils.fullyQualifiedNamesAreEqual(getFullyQualifiedName(), fullyQualifiedName) || - getInterfaces().stream().anyMatch(anInterface -> anInterface.isAssignableTo(fullyQualifiedName)) || - (getSupertype() != null && getSupertype().isAssignableTo(fullyQualifiedName)); + getInterfaces().stream().anyMatch(anInterface -> anInterface.isAssignableTo(fullyQualifiedName)) || + (getSupertype() != null && getSupertype().isAssignableTo(fullyQualifiedName)); } public boolean isAssignableFrom(@Nullable JavaType type) { if (type instanceof FullyQualified) { FullyQualified clazz = (FullyQualified) type; return TypeUtils.fullyQualifiedNamesAreEqual(getFullyQualifiedName(), clazz.getFullyQualifiedName()) || - isAssignableFrom(clazz.getSupertype()) || - clazz.getInterfaces().stream().anyMatch(this::isAssignableFrom); + isAssignableFrom(clazz.getSupertype()) || + clazz.getInterfaces().stream().anyMatch(this::isAssignableFrom); } else if (type instanceof GenericTypeVariable) { GenericTypeVariable generic = (GenericTypeVariable) type; for (JavaType bound : generic.getBounds()) { @@ -576,7 +576,7 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Class aClass = (Class) o; return TypeUtils.fullyQualifiedNamesAreEqual(fullyQualifiedName, aClass.fullyQualifiedName) && - (typeParameters == null && aClass.typeParameters == null || typeParameters != null && Arrays.equals(typeParameters, aClass.typeParameters)); + (typeParameters == null && aClass.typeParameters == null || typeParameters != null && Arrays.equals(typeParameters, aClass.typeParameters)); } @Override @@ -853,7 +853,7 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; GenericTypeVariable that = (GenericTypeVariable) o; return name.equals(that.name) && variance == that.variance && - (variance == Variance.INVARIANT && bounds == null && that.bounds == null || bounds != null && Arrays.equals(bounds, that.bounds)); + (variance == Variance.INVARIANT && bounds == null && that.bounds == null || bounds != null && Arrays.equals(bounds, that.bounds)); } @Override @@ -1106,7 +1106,7 @@ class Method implements JavaType { JavaType @Nullable [] parameterTypes; @NonFinal - FullyQualified @Nullable [] thrownExceptions; + JavaType @Nullable [] thrownExceptions; @NonFinal FullyQualified @Nullable [] annotations; @@ -1118,7 +1118,7 @@ class Method implements JavaType { public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable FullyQualified declaringType, String name, @Nullable JavaType returnType, @Nullable List parameterNames, - @Nullable List parameterTypes, @Nullable List thrownExceptions, + @Nullable List parameterTypes, @Nullable List thrownExceptions, @Nullable List annotations) { this(managedReference, flagsBitMap, declaringType, name, returnType, parameterNames, parameterTypes, thrownExceptions, annotations, null); @@ -1126,7 +1126,7 @@ public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable Fu public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable FullyQualified declaringType, String name, @Nullable JavaType returnType, @Nullable List parameterNames, - @Nullable List parameterTypes, @Nullable List thrownExceptions, + @Nullable List parameterTypes, @Nullable List thrownExceptions, @Nullable List annotations, @Nullable List defaultValue) { this( managedReference, @@ -1144,7 +1144,7 @@ public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable Fu public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable FullyQualified declaringType, String name, @Nullable JavaType returnType, String @Nullable [] parameterNames, - JavaType @Nullable [] parameterTypes, FullyQualified @Nullable [] thrownExceptions, + JavaType @Nullable [] parameterTypes, JavaType @Nullable [] thrownExceptions, FullyQualified @Nullable [] annotations, @Nullable List defaultValue) { this.managedReference = managedReference; this.flagsBitMap = flagsBitMap & Flag.VALID_FLAGS; @@ -1171,12 +1171,12 @@ public Method unsafeSetManagedReference(Integer id) { public Method unsafeSet(@Nullable FullyQualified declaringType, @Nullable JavaType returnType, @Nullable List parameterTypes, - @Nullable List thrownExceptions, + @Nullable List thrownExceptions, @Nullable List annotations) { this.declaringType = unknownIfNull(declaringType); this.returnType = unknownIfNull(returnType); this.parameterTypes = arrayOrNullIfEmpty(parameterTypes, EMPTY_JAVA_TYPE_ARRAY); - this.thrownExceptions = arrayOrNullIfEmpty(thrownExceptions, EMPTY_FULLY_QUALIFIED_ARRAY); + this.thrownExceptions = arrayOrNullIfEmpty(thrownExceptions, EMPTY_JAVA_TYPE_ARRAY); this.annotations = arrayOrNullIfEmpty(annotations, EMPTY_FULLY_QUALIFIED_ARRAY); return this; } @@ -1184,7 +1184,7 @@ public Method unsafeSet(@Nullable FullyQualified declaringType, public Method unsafeSet(@Nullable FullyQualified declaringType, @Nullable JavaType returnType, JavaType @Nullable [] parameterTypes, - FullyQualified @Nullable [] thrownExceptions, + JavaType @Nullable [] thrownExceptions, FullyQualified @Nullable [] annotations) { this.declaringType = unknownIfNull(declaringType); this.returnType = unknownIfNull(returnType); @@ -1312,12 +1312,12 @@ public Method withParameterTypes(@Nullable List parameterTypes) { this.parameterNames, parameterTypesArray, this.thrownExceptions, this.annotations, this.defaultValue); } - public List getThrownExceptions() { + public List getThrownExceptions() { return thrownExceptions == null ? emptyList() : Arrays.asList(thrownExceptions); } - public Method withThrownExceptions(@Nullable List thrownExceptions) { - FullyQualified[] thrownExceptionsArray = arrayOrNullIfEmpty(thrownExceptions, EMPTY_FULLY_QUALIFIED_ARRAY); + public Method withThrownExceptions(@Nullable List thrownExceptions) { + JavaType[] thrownExceptionsArray = arrayOrNullIfEmpty(thrownExceptions, EMPTY_JAVA_TYPE_ARRAY); if (Arrays.equals(thrownExceptionsArray, this.thrownExceptions)) { return this; } @@ -1356,9 +1356,9 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; Method method = (Method) o; return Objects.equals(declaringType, method.declaringType) && - name.equals(method.name) && - Objects.equals(returnType, method.returnType) && - Arrays.equals(parameterTypes, method.parameterTypes); + name.equals(method.name) && + Objects.equals(returnType, method.returnType) && + Arrays.equals(parameterTypes, method.parameterTypes); } @Override From 5b14eb08401a4878367627e9762190a9bbbb4a43 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 25 Dec 2024 12:26:32 +0100 Subject: [PATCH 074/179] refactor: Enum values should be compared with "==" (#4811) Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.staticanalysis.CompareEnumsWithEqualityOperator?organizationId=T3BlblJld3JpdGU%3D Co-authored-by: Moderne --- .../openrewrite/SourceFileWithReferences.java | 2 +- .../config/YamlResourceLoader.java | 2 +- .../RemoveRedundantDependencyVersions.java | 8 ++--- .../groovy/GroovyParserVisitor.java | 2 +- .../java/org/openrewrite/hcl/HclTemplate.java | 10 +++--- .../hcl/format/AttributeSpaceVisitor.java | 4 +-- .../hcl/format/BracketsVisitor.java | 4 +-- .../hcl/format/TabsAndIndentsVisitor.java | 8 ++--- .../openrewrite/hcl/internal/HclPrinter.java | 2 +- .../openrewrite/hcl/tree/HclCoordinates.java | 2 +- .../java/org/openrewrite/hcl/tree/Space.java | 4 +-- ...ReloadableJava11ParserInputFileObject.java | 2 +- .../ReloadableJava11ParserVisitor.java | 2 +- ...ReloadableJava17ParserInputFileObject.java | 2 +- .../ReloadableJava17ParserVisitor.java | 2 +- ...ReloadableJava21ParserInputFileObject.java | 2 +- .../ReloadableJava21ParserVisitor.java | 2 +- .../java/Java8ParserInputFileObject.java | 2 +- .../java/ReloadableJava8Parser.java | 2 +- .../java/ReloadableJava8ParserVisitor.java | 2 +- .../org/openrewrite/java/JavaPrinter.java | 2 +- .../org/openrewrite/java/JavaVisitor.java | 2 +- .../org/openrewrite/java/PackageMatcher.java | 2 +- .../org/openrewrite/java/TypeMatcher.java | 2 +- .../openrewrite/java/VariableNameUtils.java | 2 +- .../java/format/TabsAndIndentsVisitor.java | 16 ++++----- .../BlockStatementTemplateGenerator.java | 2 +- .../template/JavaTemplateJavaExtension.java | 34 +++++++++---------- .../java/internal/template/Substitutions.java | 2 +- .../openrewrite/java/style/Autodetect.java | 2 +- .../java/tree/JavaCoordinates.java | 2 +- .../openrewrite/maven/RemoveDependency.java | 2 +- .../maven/RemoveManagedDependency.java | 2 +- .../RemoveRedundantDependencyVersions.java | 10 +++--- .../internal/InsertDependencyComparator.java | 2 +- .../org/openrewrite/xml/XmlParserTest.java | 4 +-- 36 files changed, 77 insertions(+), 77 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java b/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java index d53fa550e7a..0a8bb5faad8 100644 --- a/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java +++ b/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java @@ -45,7 +45,7 @@ public Collection findMatches(Reference.Matcher matcher, Reference.Ki private List findMatchesInternal(Reference.Matcher matcher, Reference.@Nullable Kind kind) { List list = new ArrayList<>(); for (Reference ref : references) { - if ((kind == null || ref.getKind().equals(kind)) && ref.matches(matcher) ) { + if ((kind == null || ref.getKind() == kind) && ref.matches(matcher) ) { list.add(ref); } } diff --git a/rewrite-core/src/main/java/org/openrewrite/config/YamlResourceLoader.java b/rewrite-core/src/main/java/org/openrewrite/config/YamlResourceLoader.java index 7d1f24d8ad1..1984d383600 100644 --- a/rewrite-core/src/main/java/org/openrewrite/config/YamlResourceLoader.java +++ b/rewrite-core/src/main/java/org/openrewrite/config/YamlResourceLoader.java @@ -200,7 +200,7 @@ private Collection> loadResources(ResourceType resourceType) for (Object resource : yaml.loadAll(yamlSource)) { if (resource instanceof Map) { @SuppressWarnings("unchecked") Map resourceMap = (Map) resource; - if (resourceType.equals(ResourceType.fromSpec((String) resourceMap.get("type")))) { + if (resourceType == ResourceType.fromSpec((String) resourceMap.get("type"))) { resources.add(resourceMap); } } diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java index 3aaa09f6a4e..a2cd1dab3b3 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/RemoveRedundantDependencyVersions.java @@ -292,7 +292,7 @@ private boolean matchesComparator(@Nullable String managedVersion, String reques if (managedVersion == null) { return false; } - if (comparator.equals(Comparator.ANY)) { + if (comparator == Comparator.ANY) { return true; } if (!isExact(managedVersion)) { @@ -301,11 +301,11 @@ private boolean matchesComparator(@Nullable String managedVersion, String reques int comparison = new LatestIntegration(null) .compare(null, managedVersion, requestedVersion); if (comparison < 0) { - return comparator.equals(Comparator.LT) || comparator.equals(Comparator.LTE); + return comparator == Comparator.LT || comparator == Comparator.LTE; } else if (comparison > 0) { - return comparator.equals(Comparator.GT) || comparator.equals(Comparator.GTE); + return comparator == Comparator.GT || comparator == Comparator.GTE; } else { - return comparator.equals(Comparator.EQ) || comparator.equals(Comparator.LTE) || comparator.equals(Comparator.GTE); + return comparator == Comparator.EQ || comparator == Comparator.LTE || comparator == Comparator.GTE; } } diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 5ce8d628352..af660485f32 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -1100,7 +1100,7 @@ public void visitBlockStatement(BlockStatement block) { J expr = visit(statement); if (i == blockStatements.size() - 1 && (expr instanceof Expression)) { if (parent instanceof ClosureExpression || (parent instanceof MethodNode && - !JavaType.Primitive.Void.equals(typeMapping.type(((MethodNode) parent).getReturnType())))) { + JavaType.Primitive.Void != typeMapping.type(((MethodNode) parent).getReturnType()))) { expr = new J.Return(randomId(), expr.getPrefix(), Markers.EMPTY, expr.withPrefix(EMPTY)); expr = expr.withMarkers(expr.getMarkers().add(new ImplicitReturn(randomId()))); diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclTemplate.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclTemplate.java index 5fb3297f4c3..e7b2dd0933e 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclTemplate.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclTemplate.java @@ -69,7 +69,7 @@ public H apply(Cursor scope, HclCoordinates coordinates, Object. @Override public Hcl visitConfigFile(Hcl.ConfigFile configFile, Integer p) { Hcl.ConfigFile c = (Hcl.ConfigFile) super.visitConfigFile(configFile, p); - if (loc.equals(Space.Location.CONFIG_FILE_EOF)) { + if (loc == Space.Location.CONFIG_FILE_EOF) { List gen = substitutions.unsubstitute(templateParser.parseBodyContent(substitutedTemplate)); if (coordinates.getComparator() != null) { @@ -100,7 +100,7 @@ public Hcl visitConfigFile(Hcl.ConfigFile configFile, Integer p) { ) ); } - } else if (loc.equals(Space.Location.CONFIG_FILE)) { + } else if (loc == Space.Location.CONFIG_FILE) { List gen = substitutions.unsubstitute(templateParser.parseBodyContent(substitutedTemplate)); c = c.withBody( ListUtils.concatAll( @@ -116,7 +116,7 @@ public Hcl visitConfigFile(Hcl.ConfigFile configFile, Integer p) { @Override public Hcl visitBlock(Hcl.Block block, Integer p) { Hcl.Block b = (Hcl.Block) super.visitBlock(block, p); - if (loc.equals(Space.Location.BLOCK_CLOSE)) { + if (loc == Space.Location.BLOCK_CLOSE) { if (b.isScope(insertionPoint)) { List gen = substitutions.unsubstitute(templateParser.parseBodyContent(substitutedTemplate)); @@ -145,7 +145,7 @@ public Hcl visitBlock(Hcl.Block block, Integer p) { .orElse(SpacesStyle.DEFAULT)).visit(b, p, getCursor().getParentOrThrow()); assert b != null; } - } else if (loc.equals(Space.Location.BLOCK)) { + } else if (loc == Space.Location.BLOCK) { if (b.isScope(insertionPoint)) { b = (Hcl.Block) autoFormat(templateParser.parseBodyContent(substitutedTemplate).get(0), p, getCursor().getParentOrThrow()); @@ -158,7 +158,7 @@ public Hcl visitBlock(Hcl.Block block, Integer p) { public Hcl visitExpression(Expression expression, Integer p) { Hcl e = super.visitExpression(expression, p); - if (loc.equals(Space.Location.EXPRESSION_PREFIX)) { + if (loc == Space.Location.EXPRESSION_PREFIX) { if (e.isScope(insertionPoint)) { e = templateParser.parseExpression(substitutedTemplate).withPrefix(expression.getPrefix()); } diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/AttributeSpaceVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/AttributeSpaceVisitor.java index dc497dd9af1..a384b1d7d4b 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/AttributeSpaceVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/AttributeSpaceVisitor.java @@ -52,7 +52,7 @@ public Hcl.Attribute visitAttribute(Hcl.Attribute attribute, P p) { if (parent instanceof Hcl.Block || parent instanceof Hcl.ObjectValue) { List siblingAttributes = getSiblingAttributes(parent); - if (attribute.getType().equals(Hcl.Attribute.Type.Assignment)) { + if (attribute.getType() == Hcl.Attribute.Type.Assignment) { HclLeftPadded type = a.getPadding().getType(); if (Boolean.TRUE.equals(style.getBodyContent().getColumnarAlignment())) { @@ -106,7 +106,7 @@ private List attributesInGroup(List siblings, Hcl. boolean groupFound = false; Hcl.Attribute perviousSibling = null; for (Hcl.Attribute sibling : siblings) { - if (sibling.getType().equals(Hcl.Attribute.Type.Assignment)) { + if (sibling.getType() == Hcl.Attribute.Type.Assignment) { boolean siblingPrefixHasNewLines = sibling.getPrefix().getWhitespace().split("\r\n|\r|\n").length > 2; boolean siblingIsMultiline = sibling.getValue().print(getCursor()).split("\r\n|\r|\n").length > 2; boolean previousSiblingIsMultiline = perviousSibling != null && perviousSibling.getValue().print(getCursor()).split("\r\n|\r|\n").length > 2; diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/BracketsVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/BracketsVisitor.java index 6bbd596c11e..cb885fa0818 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/BracketsVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/BracketsVisitor.java @@ -42,11 +42,11 @@ public BracketsVisitor(BracketsStyle style, @Nullable Tree stopAfter) { @Override public Space visitSpace(Space space, Space.Location loc, P p) { - if (loc.equals(Space.Location.BLOCK_CLOSE) && !space.getLastWhitespace().contains("\n")) { + if (loc == Space.Location.BLOCK_CLOSE && !space.getLastWhitespace().contains("\n")) { return space.withLastWhitespace("\n"); } - if (loc.equals(Space.Location.BLOCK_OPEN) && !space.getWhitespace().equals(" ")) { + if (loc == Space.Location.BLOCK_OPEN && !space.getWhitespace().equals(" ")) { return space.withWhitespace(" "); } diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/TabsAndIndentsVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/TabsAndIndentsVisitor.java index 8c2be10c242..1b561786f24 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/TabsAndIndentsVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/format/TabsAndIndentsVisitor.java @@ -103,7 +103,7 @@ public Space visitSpace(Space space, Space.Location loc, P p) { IndentType indentType = getCursor().getParentOrThrow().getNearestMessage("indentType", IndentType.ALIGN); // block spaces are always aligned to their parent - boolean alignBlockToParent = loc.equals(Space.Location.BLOCK_CLOSE) || loc.equals(Space.Location.OBJECT_VALUE_ATTRIBUTE_SUFFIX); + boolean alignBlockToParent = loc == Space.Location.BLOCK_CLOSE || loc == Space.Location.OBJECT_VALUE_ATTRIBUTE_SUFFIX; if (alignBlockToParent) { indentType = IndentType.ALIGN; @@ -266,7 +266,7 @@ private Space indentTo(Space space, int column, Space.Location spaceLocation) { space = space.withComments(ListUtils.map(space.getComments(), c -> { // The suffix of the last element in the comment list sets the whitespace for the end of the block. // The column for comments that come before the last element are incremented. - int incrementBy = spaceLocation.equals(Space.Location.BLOCK_CLOSE) && !c.equals(lastElement) ? style.getIndentSize() : 0; + int incrementBy = spaceLocation == Space.Location.BLOCK_CLOSE && !c.equals(lastElement) ? style.getIndentSize() : 0; return c.getStyle() == Comment.Style.INLINE ? indentMultilineComment(c, column + incrementBy) : indentSingleLineComment(c, column + incrementBy); @@ -274,8 +274,8 @@ private Space indentTo(Space space, int column, Space.Location spaceLocation) { // Prevent formatting trailing comments, the whitespace in a trailing comment won't have a new line character. // Compilation unit prefixes are an exception, since they do not exist in a block. - if (space.getWhitespace().contains("\n") || spaceLocation.equals(Space.Location.CONFIG_FILE)) { - int incrementBy = spaceLocation.equals(Space.Location.BLOCK_CLOSE) ? style.getIndentSize() : 0; + if (space.getWhitespace().contains("\n") || spaceLocation == Space.Location.CONFIG_FILE) { + int incrementBy = spaceLocation == Space.Location.BLOCK_CLOSE ? style.getIndentSize() : 0; int indent = getLengthOfWhitespace(space.getWhitespace()); if (indent != (column + incrementBy)) { int shift = column + incrementBy - indent; diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclPrinter.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclPrinter.java index 76bb09325a4..125040cbc4f 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclPrinter.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclPrinter.java @@ -90,7 +90,7 @@ public Hcl visitAttribute(Hcl.Attribute attribute, PrintOutputCapture

p) { beforeSyntax(attribute, Space.Location.ATTRIBUTE, p); visit(attribute.getName(), p); visitSpace(attribute.getPadding().getType().getBefore(), Space.Location.ATTRIBUTE_ASSIGNMENT, p); - p.append(attribute.getType().equals(Hcl.Attribute.Type.Assignment) ? "=" : ":"); + p.append(attribute.getType() == Hcl.Attribute.Type.Assignment ? "=" : ":"); visit(attribute.getValue(), p); if (attribute.getComma() != null) { visitSpace(attribute.getComma().getPrefix(), Space.Location.OBJECT_VALUE_ATTRIBUTE_COMMA, p); diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/HclCoordinates.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/HclCoordinates.java index 5616b533f28..39327ffbddb 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/HclCoordinates.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/HclCoordinates.java @@ -34,7 +34,7 @@ public class HclCoordinates implements Coordinates { Comparator comparator; public boolean isReplacement() { - return Mode.REPLACEMENT.equals(mode); + return Mode.REPLACEMENT == mode; } public enum Mode { diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java index 48d5282eb67..1b4c56e5bdc 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java @@ -156,7 +156,7 @@ public static Space format(String formatting) { for (char c : charArray) { switch (c) { case '#': - if (Comment.Style.LINE_SLASH.equals(inLineSlashOrHashComment)) { + if (Comment.Style.LINE_SLASH == inLineSlashOrHashComment) { comment.append(c); } else { if (inSingleLineComment) { @@ -169,7 +169,7 @@ public static Space format(String formatting) { } break; case '/': - if (Comment.Style.LINE_HASH.equals(inLineSlashOrHashComment)) { + if (Comment.Style.LINE_HASH == inLineSlashOrHashComment) { comment.append(c); } else { if (inSingleLineComment) { diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserInputFileObject.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserInputFileObject.java index 6ff41fecbd5..e117030dc6f 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserInputFileObject.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserInputFileObject.java @@ -111,7 +111,7 @@ public Kind getKind() { @Override public boolean isNameCompatible(String simpleName, Kind kind) { String baseName = simpleName + kind.extension; - return kind.equals(getKind()) && + return kind == getKind() && path.getFileName().toString().equals(baseName); } diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index 22086c5db31..ac0714e55af 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -761,7 +761,7 @@ public J visitLiteral(LiteralTree node, Space fmt) { singletonList(new J.Literal.UnicodeEscape(1, valueSource.substring(3, valueSource.length() - 1))), type); } - } else if (JavaType.Primitive.String.equals(type)) { + } else if (JavaType.Primitive.String == type) { StringBuilder valueSourceWithoutSurrogates = new StringBuilder(); List unicodeEscapes = null; diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserInputFileObject.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserInputFileObject.java index 49e01f39290..f4e6faf4c6d 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserInputFileObject.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserInputFileObject.java @@ -111,7 +111,7 @@ public Kind getKind() { @Override public boolean isNameCompatible(String simpleName, Kind kind) { String baseName = simpleName + kind.extension; - return kind.equals(getKind()) && + return kind == getKind() && path.getFileName().toString().equals(baseName); } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 6dea46ebda4..673d84fff4e 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -826,7 +826,7 @@ public J visitLiteral(LiteralTree node, Space fmt) { singletonList(new J.Literal.UnicodeEscape(1, valueSource.substring(3, valueSource.length() - 1))), type); } - } else if (JavaType.Primitive.String.equals(type)) { + } else if (JavaType.Primitive.String == type) { StringBuilder valueSourceWithoutSurrogates = new StringBuilder(); List unicodeEscapes = null; diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserInputFileObject.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserInputFileObject.java index fbb8065f806..8e05405ad90 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserInputFileObject.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserInputFileObject.java @@ -111,7 +111,7 @@ public Kind getKind() { @Override public boolean isNameCompatible(String simpleName, Kind kind) { String baseName = simpleName + kind.extension; - return kind.equals(getKind()) && + return kind == getKind() && path.getFileName().toString().equals(baseName); } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index 8fd8d2809d9..0eeba8521e6 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -823,7 +823,7 @@ public J visitLiteral(LiteralTree node, Space fmt) { singletonList(new J.Literal.UnicodeEscape(1, valueSource.substring(3, valueSource.length() - 1))), type); } - } else if (JavaType.Primitive.String.equals(type)) { + } else if (JavaType.Primitive.String == type) { StringBuilder valueSourceWithoutSurrogates = new StringBuilder(); List unicodeEscapes = null; diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/Java8ParserInputFileObject.java b/rewrite-java-8/src/main/java/org/openrewrite/java/Java8ParserInputFileObject.java index 122bdce7957..37e1eb655ae 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/Java8ParserInputFileObject.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/Java8ParserInputFileObject.java @@ -110,7 +110,7 @@ public Kind getKind() { @Override public boolean isNameCompatible(String simpleName, Kind kind) { String baseName = simpleName + kind.extension; - return kind.equals(getKind()) && + return kind == getKind() && path.getFileName().toString().equals(baseName); } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java index 227b6f3609c..de46c937d0a 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java @@ -318,7 +318,7 @@ public String inferBinaryName(Location location, JavaFileObject file) { @Override public Iterable list(Location location, String packageName, Set kinds, boolean recurse) throws IOException { - if (StandardLocation.CLASS_PATH.equals(location)) { + if (StandardLocation.CLASS_PATH == location) { Iterable listed = super.list(location, packageName, kinds, recurse); return Stream.concat( classByteClasspath.stream() diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index e9123f68062..8a502fd31b8 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -761,7 +761,7 @@ public J visitLiteral(LiteralTree node, Space fmt) { singletonList(new J.Literal.UnicodeEscape(1, valueSource.substring(3, valueSource.length() - 1))), type); } - } else if (JavaType.Primitive.String.equals(type)) { + } else if (JavaType.Primitive.String == type) { StringBuilder valueSourceWithoutSurrogates = new StringBuilder(); List unicodeEscapes = null; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java index b75e24d02c3..71a1d56ccac 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java @@ -537,7 +537,7 @@ public J visitClassDeclaration(ClassDeclaration classDecl, PrintOutputCapture

visitContainer("<", classDecl.getPadding().getTypeParameters(), JContainer.Location.TYPE_PARAMETERS, ",", ">", p); visitContainer("(", classDecl.getPadding().getPrimaryConstructor(), JContainer.Location.RECORD_STATE_VECTOR, ",", ")", p); visitLeftPadded("extends", classDecl.getPadding().getExtends(), JLeftPadded.Location.EXTENDS, p); - visitContainer(classDecl.getKind().equals(ClassDeclaration.Kind.Type.Interface) ? "extends" : "implements", + visitContainer(classDecl.getKind() == ClassDeclaration.Kind.Type.Interface ? "extends" : "implements", classDecl.getPadding().getImplements(), JContainer.Location.IMPLEMENTS, ",", null, p); visitContainer("permits", classDecl.getPadding().getPermits(), JContainer.Location.PERMITS, ",", null, p); visit(classDecl.getBody(), p); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java index eec6aeb187d..be5ca459848 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java @@ -1463,7 +1463,7 @@ protected boolean isInSameNameScope(Cursor base, Cursor child) { Object childScope = it.next(); if (childScope instanceof J.ClassDeclaration) { J.ClassDeclaration childClass = (J.ClassDeclaration) childScope; - if (!(childClass.getKind().equals(J.ClassDeclaration.Kind.Type.Class)) || + if (childClass.getKind() != J.ClassDeclaration.Kind.Type.Class || childClass.hasModifier(J.Modifier.Type.Static)) { //Short circuit the search if a terminating element is encountered. return false; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/PackageMatcher.java b/rewrite-java/src/main/java/org/openrewrite/java/PackageMatcher.java index 9c5f91105dc..55a93b768ab 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/PackageMatcher.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/PackageMatcher.java @@ -38,7 +38,7 @@ public PackageMatcher(@Nullable String targetPackage, boolean recursive) { @Override public boolean matchesReference(Reference reference) { - if (reference.getKind().equals(Reference.Kind.TYPE) || reference.getKind().equals(Reference.Kind.PACKAGE)) { + if (reference.getKind() == Reference.Kind.TYPE || reference.getKind() == Reference.Kind.PACKAGE) { String recursivePackageNamePrefix = targetPackage + "."; if (reference.getValue().equals(targetPackage) || recursive && reference.getValue().startsWith(recursivePackageNamePrefix)) { return true; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java b/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java index 1a1b5aa6f40..4d4f0e4133b 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/TypeMatcher.java @@ -112,7 +112,7 @@ private static boolean isPlainIdentifier(MethodSignatureParser.TargetTypePattern @Override public boolean matchesReference(Reference reference) { - return reference.getKind().equals(Reference.Kind.TYPE) && matchesTargetTypeName(reference.getValue()); + return reference.getKind() == Reference.Kind.TYPE && matchesTargetTypeName(reference.getValue()); } @Override diff --git a/rewrite-java/src/main/java/org/openrewrite/java/VariableNameUtils.java b/rewrite-java/src/main/java/org/openrewrite/java/VariableNameUtils.java index e9a880d0600..fc4f1ddc048 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/VariableNameUtils.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/VariableNameUtils.java @@ -50,7 +50,7 @@ public static String generateVariableName(String baseName, Cursor scope, Generat Set namesInScope = findNamesInScope(scope); // Generate a new name to prevent namespace shadowing. String newName = baseName; - if (GenerationStrategy.INCREMENT_NUMBER.equals(strategy)) { + if (GenerationStrategy.INCREMENT_NUMBER == strategy) { StringBuilder postFix = new StringBuilder(); char[] charArray = baseName.toCharArray(); for (int i = charArray.length - 1; i >= 0; i--) { diff --git a/rewrite-java/src/main/java/org/openrewrite/java/format/TabsAndIndentsVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/format/TabsAndIndentsVisitor.java index d333c9c04d9..a69183dd763 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/format/TabsAndIndentsVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/format/TabsAndIndentsVisitor.java @@ -143,18 +143,18 @@ public Space visitSpace(Space space, Space.Location loc, P p) { // block spaces are always aligned to their parent Object value = getCursor().getValue(); - boolean alignBlockPrefixToParent = loc.equals(Space.Location.BLOCK_PREFIX) && space.getWhitespace().contains("\n") && + boolean alignBlockPrefixToParent = loc == Space.Location.BLOCK_PREFIX && space.getWhitespace().contains("\n") && // ignore init blocks. (value instanceof J.Block && !(getCursor().getParentTreeCursor().getValue() instanceof J.Block)); - boolean alignBlockToParent = loc.equals(Space.Location.BLOCK_END) || - loc.equals(Space.Location.NEW_ARRAY_INITIALIZER_SUFFIX) || - loc.equals(Space.Location.CATCH_PREFIX) || - loc.equals(Space.Location.TRY_FINALLY) || - loc.equals(Space.Location.ELSE_PREFIX); + boolean alignBlockToParent = loc == Space.Location.BLOCK_END || + loc == Space.Location.NEW_ARRAY_INITIALIZER_SUFFIX || + loc == Space.Location.CATCH_PREFIX || + loc == Space.Location.TRY_FINALLY || + loc == Space.Location.ELSE_PREFIX; - if ((loc.equals(Space.Location.EXTENDS) && space.getWhitespace().contains("\n")) || - Space.Location.EXTENDS.equals(getCursor().getParent().getMessage("lastLocation"))) { + if ((loc == Space.Location.EXTENDS && space.getWhitespace().contains("\n")) || + Space.Location.EXTENDS == getCursor().getParent().getMessage("lastLocation")) { indentType = IndentType.CONTINUATION_INDENT; } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java index f586b011fcb..f0f22eceff2 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java @@ -60,7 +60,7 @@ public String template(Cursor cursor, String template, Space.Location location, // for CoordinateBuilder.MethodDeclaration#replaceBody() if (cursor.getValue() instanceof J.MethodDeclaration && - location.equals(Space.Location.BLOCK_PREFIX)) { + location == Space.Location.BLOCK_PREFIX) { J.MethodDeclaration method = cursor.getValue(); J.MethodDeclaration m = method.withBody(null).withLeadingAnnotations(emptyList()).withPrefix(Space.EMPTY); before.insert(0, m.printTrimmed(cursor.getParentOrThrow()).trim() + '{'); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateJavaExtension.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateJavaExtension.java index 476aeaa2e03..a3c8e1fd7ac 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateJavaExtension.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/JavaTemplateJavaExtension.java @@ -55,7 +55,7 @@ public TreeVisitor getMixin() { return new JavaVisitor() { @Override public J visitAnnotation(J.Annotation annotation, Integer integer) { - if (loc.equals(ANNOTATION_PREFIX) && mode.equals(JavaCoordinates.Mode.REPLACEMENT) && + if (loc == ANNOTATION_PREFIX && mode == JavaCoordinates.Mode.REPLACEMENT && annotation.isScope(insertionPoint)) { List gen = substitutions.unsubstitute(templateParser.parseAnnotations(getCursor(), substitutedTemplate)); if (gen.isEmpty()) { @@ -64,7 +64,7 @@ public J visitAnnotation(J.Annotation annotation, Integer integer) { "\nUse JavaTemplate.Builder.doBeforeParseTemplate() to see what stub is being generated and include it in any bug report."); } return gen.get(0).withPrefix(annotation.getPrefix()); - } else if (loc.equals(ANNOTATION_ARGUMENTS) && mode.equals(JavaCoordinates.Mode.REPLACEMENT) && + } else if (loc == ANNOTATION_ARGUMENTS && mode == JavaCoordinates.Mode.REPLACEMENT && annotation.isScope(insertionPoint)) { List gen = substitutions.unsubstitute(templateParser.parseAnnotations(getCursor(), "@Example(" + substitutedTemplate + ")")); return annotation.withArguments(gen.get(0).getArguments()); @@ -144,7 +144,7 @@ public J visitClassDeclaration(J.ClassDeclaration classDecl, Integer p) { case ANNOTATIONS: { List gen = substitutions.unsubstitute(templateParser.parseAnnotations(getCursor(), substitutedTemplate)); J.ClassDeclaration c = classDecl; - if (mode.equals(JavaCoordinates.Mode.REPLACEMENT)) { + if (mode == JavaCoordinates.Mode.REPLACEMENT) { c = c.withLeadingAnnotations(gen); if (c.getTypeParameters() != null) { c = c.withTypeParameters(ListUtils.map(c.getTypeParameters(), tp -> tp.withAnnotations(emptyList()))); @@ -176,7 +176,7 @@ public J visitClassDeclaration(J.ClassDeclaration classDecl, Integer p) { .collect(toList()); J.ClassDeclaration c = classDecl; - if (mode.equals(JavaCoordinates.Mode.REPLACEMENT)) { + if (mode == JavaCoordinates.Mode.REPLACEMENT) { c = c.withImplements(implementings); //noinspection ConstantConditions c = c.getPadding().withImplements(c.getPadding().getImplements().withBefore(Space.EMPTY)); @@ -202,8 +202,8 @@ public J visitClassDeclaration(J.ClassDeclaration classDecl, Integer p) { @Override public J visitExpression(Expression expression, Integer p) { - if ((loc.equals(EXPRESSION_PREFIX) || - loc.equals(STATEMENT_PREFIX) && expression instanceof Statement) && + if ((loc == EXPRESSION_PREFIX || + loc == STATEMENT_PREFIX && expression instanceof Statement) && expression.isScope(insertionPoint)) { return autoFormat(substitutions.unsubstitute(templateParser.parseExpression( getCursor(), @@ -216,13 +216,13 @@ public J visitExpression(Expression expression, Integer p) { @Override public J visitFieldAccess(J.FieldAccess fa, Integer p) { - if (loc.equals(FIELD_ACCESS_PREFIX) && fa.isScope(insertionPoint)) { + if (loc == FIELD_ACCESS_PREFIX && fa.isScope(insertionPoint)) { return autoFormat(substitutions.unsubstitute(templateParser.parseExpression( getCursor(), substitutedTemplate, loc)) .withPrefix(fa.getPrefix()), p); - } else if (loc.equals(STATEMENT_PREFIX) && fa.isScope(insertionPoint)) { + } else if (loc == STATEMENT_PREFIX && fa.isScope(insertionPoint)) { // NOTE: while `J.FieldAccess` inherits from `Statement` they can only ever be used as expressions return autoFormat(substitutions.unsubstitute(templateParser.parseExpression( getCursor(), @@ -236,7 +236,7 @@ public J visitFieldAccess(J.FieldAccess fa, Integer p) { @Override public J visitIdentifier(J.Identifier ident, Integer p) { // ONLY for backwards compatibility, otherwise the same as expression replacement - if (loc.equals(IDENTIFIER_PREFIX) && ident.isScope(insertionPoint)) { + if (loc == IDENTIFIER_PREFIX && ident.isScope(insertionPoint)) { return autoFormat(substitutions.unsubstitute(templateParser.parseExpression( getCursor(), substitutedTemplate, @@ -248,7 +248,7 @@ public J visitIdentifier(J.Identifier ident, Integer p) { @Override public J visitLambda(J.Lambda lambda, Integer p) { - if (loc.equals(LAMBDA_PARAMETERS_PREFIX) && lambda.getParameters().isScope(insertionPoint)) { + if (loc == LAMBDA_PARAMETERS_PREFIX && lambda.getParameters().isScope(insertionPoint)) { return lambda.withParameters(substitutions.unsubstitute(templateParser.parseLambdaParameters(getCursor(), substitutedTemplate))); } return maybeReplaceStatement(lambda, J.class, 0); @@ -261,7 +261,7 @@ public J visitMethodDeclaration(J.MethodDeclaration method, Integer p) { case ANNOTATIONS: { List gen = substitutions.unsubstitute(templateParser.parseAnnotations(getCursor(), substitutedTemplate)); J.MethodDeclaration m = method; - if (mode.equals(JavaCoordinates.Mode.REPLACEMENT)) { + if (mode == JavaCoordinates.Mode.REPLACEMENT) { m = method.withLeadingAnnotations(gen); if (m.getTypeParameters() != null) { m = m.withTypeParameters(ListUtils.map(m.getTypeParameters(), tp -> tp.withAnnotations(emptyList()))); @@ -384,9 +384,9 @@ public J visitMethodDeclaration(J.MethodDeclaration method, Integer p) { @Override public J visitMethodInvocation(J.MethodInvocation method, Integer integer) { - if ((loc.equals(METHOD_INVOCATION_ARGUMENTS) || loc.equals(METHOD_INVOCATION_NAME)) && method.isScope(insertionPoint)) { + if ((loc == METHOD_INVOCATION_ARGUMENTS || loc == METHOD_INVOCATION_NAME) && method.isScope(insertionPoint)) { J.MethodInvocation m; - if (loc.equals(METHOD_INVOCATION_ARGUMENTS)) { + if (loc == METHOD_INVOCATION_ARGUMENTS) { m = substitutions.unsubstitute(templateParser.parseMethodArguments(getCursor(), substitutedTemplate, loc)); m = autoFormat(m, 0); m = method.withArguments(m.getArguments()).withMethodType(m.getMethodType()); @@ -433,7 +433,7 @@ public J visitNewClass(J.NewClass newClass, Integer p) { @Override public J visitPackage(J.Package pkg, Integer integer) { - if (loc.equals(PACKAGE_PREFIX) && pkg.isScope(insertionPoint)) { + if (loc == PACKAGE_PREFIX && pkg.isScope(insertionPoint)) { return pkg.withExpression(substitutions.unsubstitute(templateParser.parsePackage(getCursor(), substitutedTemplate))); } return super.visitPackage(pkg, integer); @@ -445,8 +445,8 @@ public J visitStatement(Statement statement, Integer p) { } private J3 maybeReplaceStatement(Statement statement, Class expected, Integer p) { - if (loc.equals(STATEMENT_PREFIX) && statement.isScope(insertionPoint)) { - if (mode.equals(JavaCoordinates.Mode.REPLACEMENT)) { + if (loc == STATEMENT_PREFIX && statement.isScope(insertionPoint)) { + if (mode == JavaCoordinates.Mode.REPLACEMENT) { List gen = substitutions.unsubstitute(templateParser.parseBlockStatements(getCursor(), expected, substitutedTemplate, loc, mode)); if (gen.size() != 1) { @@ -481,7 +481,7 @@ public J visitVariableDeclarations(J.VariableDeclarations multiVariable, Integer if (loc == ANNOTATIONS) { J.VariableDeclarations v = multiVariable; final List gen = substitutions.unsubstitute(templateParser.parseAnnotations(getCursor(), substitutedTemplate)); - if (mode.equals(JavaCoordinates.Mode.REPLACEMENT)) { + if (mode == JavaCoordinates.Mode.REPLACEMENT) { v = v.withLeadingAnnotations(gen); if (v.getTypeExpression() instanceof J.AnnotatedType) { v = v.withTypeExpression(((J.AnnotatedType) v.getTypeExpression()).getTypeExpression()); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/Substitutions.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/Substitutions.java index 16a9a68438c..6331cc78d69 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/Substitutions.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/Substitutions.java @@ -146,7 +146,7 @@ private String substituteTypedPattern(String key, int index, TemplateParameterPa String fqn = getTypeName(type); JavaType.Primitive primitive = JavaType.Primitive.fromKeyword(fqn); - s = primitive == null || primitive.equals(JavaType.Primitive.String) ? + s = primitive == null || primitive == JavaType.Primitive.String ? newObjectParameter(fqn, index) : newPrimitiveParameter(fqn, index); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/style/Autodetect.java b/rewrite-java/src/main/java/org/openrewrite/java/style/Autodetect.java index 34a3a10abf5..d545053d8b8 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/style/Autodetect.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/style/Autodetect.java @@ -577,7 +577,7 @@ public ImportLayoutStyle getImportLayoutStyle() { List countOfBlocksInStaticGroups = new ArrayList<>(); for (Block block : longestBlocks) { - if (BlockType.ImportStatic.equals(block.type)) { + if (BlockType.ImportStatic == block.type) { staticBlocks.add(block); countOfBlocksInStaticGroups.add(0); countOfBlocksInStaticGroups.set(staticCountPos, countOfBlocksInStaticGroups.get(staticCountPos) + 1); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaCoordinates.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaCoordinates.java index 04bf5e5e1f5..482bf3cfe43 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaCoordinates.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaCoordinates.java @@ -34,7 +34,7 @@ public class JavaCoordinates implements Coordinates { Comparator comparator; public boolean isReplacement() { - return Mode.REPLACEMENT.equals(mode); + return Mode.REPLACEMENT == mode; } /** diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveDependency.java b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveDependency.java index 0d015f4417d..d60df379b3c 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveDependency.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveDependency.java @@ -70,7 +70,7 @@ public TreeVisitor getVisitor() { @Override public Validated validate() { return super.validate().and(Validated.test("scope", "Scope must be one of compile, runtime, test, or provided", - scope, s -> !Scope.Invalid.equals(Scope.fromName(s)))); + scope, s -> Scope.Invalid != Scope.fromName(s))); } private class RemoveDependencyVisitor extends MavenIsoVisitor { diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveManagedDependency.java b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveManagedDependency.java index f65fbf99269..2f1de67fc90 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveManagedDependency.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveManagedDependency.java @@ -69,7 +69,7 @@ public TreeVisitor getVisitor() { @Override public Validated validate() { return super.validate().and(Validated.test("scope", "Scope must be one of compile, runtime, test, or provided", - scope, s -> !Scope.Invalid.equals(Scope.fromName(s)))); + scope, s -> Scope.Invalid != Scope.fromName(s))); } private class RemoveManagedDependencyVisitor extends MavenIsoVisitor { diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantDependencyVersions.java b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantDependencyVersions.java index d4e94d99975..dbe5719624e 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantDependencyVersions.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveRedundantDependencyVersions.java @@ -167,7 +167,7 @@ public Xml.Document visitDocument(Xml.Document document, ExecutionContext ctx) { if (d != document) { d = (Xml.Document) new RemoveEmptyDependenciesTags().visitNonNull(d, ctx); d = (Xml.Document) new RemoveEmptyPluginsTags().visitNonNull(d, ctx); - if (!comparator.equals(Comparator.EQ)) { + if (comparator != Comparator.EQ) { maybeUpdateModel(); } } @@ -323,7 +323,7 @@ private boolean matchesComparator(@Nullable String managedVersion, String reques if (managedVersion == null) { return false; } - if (comparator.equals(Comparator.ANY)) { + if (comparator == Comparator.ANY) { return true; } if (!isExact(managedVersion)) { @@ -333,11 +333,11 @@ private boolean matchesComparator(@Nullable String managedVersion, String reques .compare(null, managedVersion, Objects.requireNonNull(getResolutionResult().getPom().getValue(requestedVersion))); if (comparison < 0) { - return comparator.equals(Comparator.LT) || comparator.equals(Comparator.LTE); + return comparator == Comparator.LT || comparator == Comparator.LTE; } else if (comparison > 0) { - return comparator.equals(Comparator.GT) || comparator.equals(Comparator.GTE); + return comparator == Comparator.GT || comparator == Comparator.GTE; } else { - return comparator.equals(Comparator.EQ) || comparator.equals(Comparator.LTE) || comparator.equals(Comparator.GTE); + return comparator == Comparator.EQ || comparator == Comparator.LTE || comparator == Comparator.GTE; } } diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/internal/InsertDependencyComparator.java b/rewrite-maven/src/main/java/org/openrewrite/maven/internal/InsertDependencyComparator.java index 6669c1321af..d439dcb0154 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/internal/InsertDependencyComparator.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/internal/InsertDependencyComparator.java @@ -71,7 +71,7 @@ public int compare(Content o1, Content o2) { private static final Comparator dependencyComparator = (d1, d2) -> { Scope scope1 = Scope.fromName(d1.getChildValue("scope").orElse(null)); Scope scope2 = Scope.fromName(d2.getChildValue("scope").orElse(null)); - if (!scope1.equals(scope2)) { + if (scope1 != scope2) { return scope1.compareTo(scope2); } diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java index cff46087276..57ae47a0905 100755 --- a/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java +++ b/rewrite-xml/src/test/java/org/openrewrite/xml/XmlParserTest.java @@ -146,8 +146,8 @@ void javaReferenceDocument() { """, spec -> spec.afterRecipe(doc -> { assertThat(doc.getReferences().getReferences().stream().anyMatch(typeRef -> typeRef.getValue().equals("java.lang.String"))).isTrue(); - assertThat(doc.getReferences().getReferences().stream().anyMatch(typeRef -> typeRef.getKind().equals(Reference.Kind.TYPE))).isTrue(); - assertThat(doc.getReferences().getReferences().stream().anyMatch(typeRef -> typeRef.getKind().equals(Reference.Kind.PACKAGE))).isTrue(); + assertThat(doc.getReferences().getReferences().stream().anyMatch(typeRef -> typeRef.getKind() == Reference.Kind.TYPE)).isTrue(); + assertThat(doc.getReferences().getReferences().stream().anyMatch(typeRef -> typeRef.getKind() == Reference.Kind.PACKAGE)).isTrue(); }) ) ); From 6dc9d5064071df4dac16c06a0c5a292a5dbcfa72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Schn=C3=A9ider?= Date: Wed, 25 Dec 2024 16:20:35 +0100 Subject: [PATCH 075/179] Keep the names of generic type variables defined by methods. (#4814) * Make the same performance improvement to parameter names allocations that we previously made to Java 17/21 in #3345. --- .../isolated/ReloadableJava11TypeMapping.java | 37 +++++++---- .../isolated/ReloadableJava17TypeMapping.java | 16 ++++- .../isolated/ReloadableJava21TypeMapping.java | 16 ++++- .../java/ReloadableJava8TypeMapping.java | 37 ++++++++--- .../openrewrite/java/JavaTypeMappingTest.java | 15 +++++ .../internal/JavaReflectionTypeMapping.java | 18 +++++- .../org/openrewrite/java/tree/JavaType.java | 61 +++++++++++++++++-- 7 files changed, 167 insertions(+), 33 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java index 00ba35afbd5..a37d73adf6e 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java @@ -470,12 +470,14 @@ public JavaType.Primitive primitive(TypeTag tag) { return existing; } - List paramNames = null; + String[] paramNames = null; if (!methodSymbol.params().isEmpty()) { - paramNames = new ArrayList<>(methodSymbol.params().size()); - for (Symbol.VarSymbol p : methodSymbol.params()) { + paramNames = new String[methodSymbol.params().size()]; + com.sun.tools.javac.util.List params = methodSymbol.params(); + for (int i = 0; i < params.size(); i++) { + Symbol.VarSymbol p = params.get(i); String s = p.name.toString(); - paramNames.add(s); + paramNames[i] = s; } } @@ -486,7 +488,7 @@ public JavaType.Primitive primitive(TypeTag tag) { methodSymbol.isConstructor() ? "" : methodSymbol.getSimpleName().toString(), null, paramNames, - null, null, null, null + null, null, null, null, null ); typeCache.put(signature, method); @@ -551,12 +553,14 @@ public JavaType.Primitive primitive(TypeTag tag) { return existing; } - List paramNames = null; + String[] paramNames = null; if (!methodSymbol.params().isEmpty()) { - paramNames = new ArrayList<>(methodSymbol.params().size()); - for (Symbol.VarSymbol p : methodSymbol.params()) { + paramNames = new String[methodSymbol.params().size()]; + com.sun.tools.javac.util.List params = methodSymbol.params(); + for (int i = 0; i < params.size(); i++) { + Symbol.VarSymbol p = params.get(i); String s = p.name.toString(); - paramNames.add(s); + paramNames[i] = s; } } @@ -574,6 +578,17 @@ public JavaType.Primitive primitive(TypeTag tag) { } } } + + List declaredFormalTypeNames = null; + for (Symbol.TypeVariableSymbol typeParam : methodSymbol.getTypeParameters()) { + if(typeParam.owner == methodSymbol) { + if (declaredFormalTypeNames == null) { + declaredFormalTypeNames = new ArrayList<>(); + } + declaredFormalTypeNames.add(typeParam.name.toString()); + } + } + JavaType.Method method = new JavaType.Method( null, methodSymbol.flags_field, @@ -582,8 +597,8 @@ public JavaType.Primitive primitive(TypeTag tag) { null, paramNames, null, null, null, - // TODO: Figure out the correct thing to put here based on methodSymbol.defaultValue.getValue() - defaultValues + defaultValues, + declaredFormalTypeNames == null ? null : declaredFormalTypeNames.toArray(new String[0]) ); typeCache.put(signature, method); diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java index d3a1ee1c9a7..d4252e1bc0e 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java @@ -494,7 +494,7 @@ public JavaType.Primitive primitive(TypeTag tag) { methodSymbol.isConstructor() ? "" : methodSymbol.getSimpleName().toString(), null, paramNames, - null, null, null, null + null, null, null, null, null ); typeCache.put(signature, method); @@ -583,6 +583,17 @@ public JavaType.Primitive primitive(TypeTag tag) { } } } + + List declaredFormalTypeNames = null; + for (Symbol.TypeVariableSymbol typeParam : methodSymbol.getTypeParameters()) { + if(typeParam.owner == methodSymbol) { + if (declaredFormalTypeNames == null) { + declaredFormalTypeNames = new ArrayList<>(); + } + declaredFormalTypeNames.add(typeParam.name.toString()); + } + } + JavaType.Method method = new JavaType.Method( null, methodSymbol.flags_field, @@ -591,7 +602,8 @@ public JavaType.Primitive primitive(TypeTag tag) { null, paramNames, null, null, null, - defaultValues + defaultValues, + declaredFormalTypeNames == null ? null : declaredFormalTypeNames.toArray(new String[0]) ); typeCache.put(signature, method); diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index bde8ecb7573..a7cbc01a00e 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -505,7 +505,7 @@ public JavaType.Primitive primitive(TypeTag tag) { methodSymbol.isConstructor() ? "" : methodSymbol.getSimpleName().toString(), null, paramNames, - null, null, null, null + null, null, null, null, null ); typeCache.put(signature, method); @@ -594,6 +594,17 @@ public JavaType.Primitive primitive(TypeTag tag) { } } } + + List declaredFormalTypeNames = null; + for (Symbol.TypeVariableSymbol typeParam : methodSymbol.getTypeParameters()) { + if(typeParam.owner == methodSymbol) { + if (declaredFormalTypeNames == null) { + declaredFormalTypeNames = new ArrayList<>(); + } + declaredFormalTypeNames.add(typeParam.name.toString()); + } + } + JavaType.Method method = new JavaType.Method( null, methodSymbol.flags_field, @@ -602,7 +613,8 @@ public JavaType.Primitive primitive(TypeTag tag) { null, paramNames, null, null, null, - defaultValues + defaultValues, + declaredFormalTypeNames == null ? null : declaredFormalTypeNames.toArray(new String[0]) ); typeCache.put(signature, method); diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java index 9beaba2727b..ca5db39ba80 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java @@ -472,12 +472,14 @@ public JavaType.Primitive primitive(TypeTag tag) { return existing; } - List paramNames = null; + String[] paramNames = null; if (!methodSymbol.params().isEmpty()) { - paramNames = new ArrayList<>(methodSymbol.params().size()); - for (Symbol.VarSymbol p : methodSymbol.params()) { + paramNames = new String[methodSymbol.params().size()]; + com.sun.tools.javac.util.List params = methodSymbol.params(); + for (int i = 0; i < params.size(); i++) { + Symbol.VarSymbol p = params.get(i); String s = p.name.toString(); - paramNames.add(s); + paramNames[i] = s; } } @@ -488,7 +490,7 @@ public JavaType.Primitive primitive(TypeTag tag) { methodSymbol.isConstructor() ? "" : methodSymbol.getSimpleName().toString(), null, paramNames, - null, null, null, null + null, null, null, null, null ); typeCache.put(signature, method); @@ -554,14 +556,17 @@ public JavaType.Primitive primitive(TypeTag tag) { return existing; } - List paramNames = null; + String[] paramNames = null; if (!methodSymbol.params().isEmpty()) { - paramNames = new ArrayList<>(methodSymbol.params().size()); - for (Symbol.VarSymbol p : methodSymbol.params()) { + paramNames = new String[methodSymbol.params().size()]; + com.sun.tools.javac.util.List params = methodSymbol.params(); + for (int i = 0; i < params.size(); i++) { + Symbol.VarSymbol p = params.get(i); String s = p.name.toString(); - paramNames.add(s); + paramNames[i] = s; } } + List defaultValues = null; if(methodSymbol.getDefaultValue() != null) { if(methodSymbol.getDefaultValue() instanceof Attribute.Array) { @@ -576,6 +581,17 @@ public JavaType.Primitive primitive(TypeTag tag) { } } } + + List declaredFormalTypeNames = null; + for (Symbol.TypeVariableSymbol typeParam : methodSymbol.getTypeParameters()) { + if(typeParam.owner == methodSymbol) { + if (declaredFormalTypeNames == null) { + declaredFormalTypeNames = new ArrayList<>(); + } + declaredFormalTypeNames.add(typeParam.name.toString()); + } + } + JavaType.Method method = new JavaType.Method( null, methodSymbol.flags_field, @@ -584,7 +600,8 @@ public JavaType.Primitive primitive(TypeTag tag) { null, paramNames, null, null, null, - defaultValues + defaultValues, + declaredFormalTypeNames == null ? null : declaredFormalTypeNames.toArray(new String[0]) ); typeCache.put(signature, method); diff --git a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java index 2eba1ba1e0f..2097273e1a2 100644 --- a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java +++ b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java @@ -63,6 +63,21 @@ default void declaringTypeRefersToParameterizedClass() { .isNotEmpty(); } + @Test + default void shadowedDeclaredFormalTypeParameters() { + // this method overrides the class definition of the type variable T + assertThat(methodType("nameShadow").getDeclaredFormalTypeNames()) + .containsExactly("T"); + + // this method provides an unshadowed definition of U + assertThat(methodType("genericUnbounded").getDeclaredFormalTypeNames()) + .containsExactly("U"); + + // this method uses the definition of T from the class level + assertThat(methodType("genericT").getDeclaredFormalTypeNames()) + .isEmpty(); + } + @Test default void javaLangObjectHasNoSupertype() { assertThat(goatType().getSupertype().getSupertype()).isNull(); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java index ef7ee8de348..860d259af24 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java @@ -341,7 +341,7 @@ private JavaType.Method method(Constructor method, JavaType.FullyQualified de "", null, paramNames, - null, null, null, null + null, null, null, null, null ); typeCache.put(signature, mappedMethod); @@ -439,6 +439,17 @@ private JavaType.Method method(Method method, JavaType.FullyQualified declaringT defaultValues = Collections.singletonList(method.getDefaultValue().toString()); } } + + List declaredFormalTypeNames = null; + for (TypeVariable typeVariable : method.getTypeParameters()) { + if (typeVariable.getGenericDeclaration() == method) { + if (declaredFormalTypeNames == null) { + declaredFormalTypeNames = new ArrayList<>(); + } + declaredFormalTypeNames.add(typeVariable.getName()); + } + } + JavaType.Method mappedMethod = new JavaType.Method( null, method.getModifiers(), @@ -447,7 +458,10 @@ private JavaType.Method method(Method method, JavaType.FullyQualified declaringT null, paramNames, null, null, null, - defaultValues + defaultValues, + declaredFormalTypeNames == null ? + null : + declaredFormalTypeNames.toArray(new String[0]) ); typeCache.put(signature, mappedMethod); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index 95d936ff2df..f4a0eac5195 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -1116,6 +1116,33 @@ class Method implements JavaType { @NonFinal List defaultValue; + /** + * The names of the generic type variables declared by this method. These names + * will occur as the name in a {@link GenericTypeVariable} parameter, + * return type, or thrown exception declaration elsewhere in the method definition. We + * keep track of the names of those variables that were defined by this method in order + * to be able to distinguish them from generic type variables, potentially of the same + * name, defined on a containing class. Some examples: + *

+ *
+         * {@code
+         * interface Test {
+         *    U m1();   // [U] used as return type
+         *    void m2(U); // [U] used as parameter
+         *    void m3() throws U; // [U]
+         *
+         *   T m4(T);      // ∅ since T refers to the class definition of T
+         *    T m3(T);  // [T] since it shadows the class definition of T
+         *    U m4(T);  // [U] but not T because T refers to the class
+         * }
+         * }
+         * 
+ */ + @With + @NonFinal + String @Nullable [] declaredFormalTypeNames; + + @Deprecated public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable FullyQualified declaringType, String name, @Nullable JavaType returnType, @Nullable List parameterNames, @Nullable List parameterTypes, @Nullable List thrownExceptions, @@ -1124,10 +1151,20 @@ public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable Fu thrownExceptions, annotations, null); } + @Deprecated public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable FullyQualified declaringType, String name, @Nullable JavaType returnType, @Nullable List parameterNames, @Nullable List parameterTypes, @Nullable List thrownExceptions, @Nullable List annotations, @Nullable List defaultValue) { + this(managedReference, flagsBitMap, declaringType, name, returnType, parameterNames, parameterTypes, + thrownExceptions, annotations, defaultValue, null); + } + + public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable FullyQualified declaringType, String name, + @Nullable JavaType returnType, @Nullable List parameterNames, + @Nullable List parameterTypes, @Nullable List thrownExceptions, + @Nullable List annotations, @Nullable List defaultValue, + @Nullable List declaredFormalTypeNames) { this( managedReference, flagsBitMap, @@ -1138,14 +1175,16 @@ public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable Fu arrayOrNullIfEmpty(parameterTypes, EMPTY_JAVA_TYPE_ARRAY), arrayOrNullIfEmpty(thrownExceptions, EMPTY_FULLY_QUALIFIED_ARRAY), arrayOrNullIfEmpty(annotations, EMPTY_FULLY_QUALIFIED_ARRAY), - defaultValue + defaultValue, + arrayOrNullIfEmpty(declaredFormalTypeNames, EMPTY_STRING_ARRAY) ); } public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable FullyQualified declaringType, String name, @Nullable JavaType returnType, String @Nullable [] parameterNames, JavaType @Nullable [] parameterTypes, JavaType @Nullable [] thrownExceptions, - FullyQualified @Nullable [] annotations, @Nullable List defaultValue) { + FullyQualified @Nullable [] annotations, @Nullable List defaultValue, + String @Nullable [] declaredFormalTypeNames) { this.managedReference = managedReference; this.flagsBitMap = flagsBitMap & Flag.VALID_FLAGS; this.declaringType = unknownIfNull(declaringType); @@ -1156,6 +1195,7 @@ public Method(@Nullable Integer managedReference, long flagsBitMap, @Nullable Fu this.thrownExceptions = nullIfEmpty(thrownExceptions); this.annotations = nullIfEmpty(annotations); this.defaultValue = nullIfEmpty(defaultValue); + this.declaredFormalTypeNames = nullIfEmpty(declaredFormalTypeNames); } @JsonCreator @@ -1191,6 +1231,7 @@ public Method unsafeSet(@Nullable FullyQualified declaringType, this.parameterTypes = ListUtils.nullIfEmpty(parameterTypes); this.thrownExceptions = ListUtils.nullIfEmpty(thrownExceptions); this.annotations = ListUtils.nullIfEmpty(annotations); + this.declaredFormalTypeNames = ListUtils.nullIfEmpty(declaredFormalTypeNames); return this; } @@ -1290,13 +1331,18 @@ public List getParameterNames() { return parameterNames == null ? emptyList() : Arrays.asList(parameterNames); } + public List getDeclaredFormalTypeNames() { + return declaredFormalTypeNames == null ? emptyList() : Arrays.asList(declaredFormalTypeNames); + } + public Method withParameterNames(@Nullable List parameterNames) { String[] parameterNamesArray = arrayOrNullIfEmpty(parameterNames, EMPTY_STRING_ARRAY); if (Arrays.equals(parameterNamesArray, this.parameterNames)) { return this; } return new Method(this.managedReference, this.flagsBitMap, this.declaringType, this.name, this.returnType, - parameterNamesArray, this.parameterTypes, this.thrownExceptions, this.annotations, this.defaultValue); + parameterNamesArray, this.parameterTypes, this.thrownExceptions, this.annotations, this.defaultValue, + this.declaredFormalTypeNames); } public List getParameterTypes() { @@ -1309,7 +1355,8 @@ public Method withParameterTypes(@Nullable List parameterTypes) { return this; } return new Method(this.managedReference, this.flagsBitMap, this.declaringType, this.name, this.returnType, - this.parameterNames, parameterTypesArray, this.thrownExceptions, this.annotations, this.defaultValue); + this.parameterNames, parameterTypesArray, this.thrownExceptions, this.annotations, this.defaultValue, + this.declaredFormalTypeNames); } public List getThrownExceptions() { @@ -1322,7 +1369,8 @@ public Method withThrownExceptions(@Nullable List thrownExceptions) { return this; } return new Method(this.managedReference, this.flagsBitMap, this.declaringType, this.name, this.returnType, - this.parameterNames, this.parameterTypes, thrownExceptionsArray, this.annotations, this.defaultValue); + this.parameterNames, this.parameterTypes, thrownExceptionsArray, this.annotations, this.defaultValue, + this.declaredFormalTypeNames); } public List getAnnotations() { @@ -1335,7 +1383,8 @@ public Method withAnnotations(@Nullable List annotations) { return this; } return new Method(this.managedReference, this.flagsBitMap, this.declaringType, this.name, this.returnType, - this.parameterNames, this.parameterTypes, this.thrownExceptions, annotationsArray, this.defaultValue); + this.parameterNames, this.parameterTypes, this.thrownExceptions, annotationsArray, this.defaultValue, + this.declaredFormalTypeNames); } public boolean hasFlags(Flag... test) { From f4038c23c528303df0ea9be52622539beac36cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Schn=C3=A9ider?= Date: Wed, 25 Dec 2024 16:44:39 +0100 Subject: [PATCH 076/179] Fix Java reflection mapping of generic typed fields. (#4815) --- .../java/org/openrewrite/java/JavaTypeGoat.java | 5 +++-- .../openrewrite/java/JavaTypeMappingTest.java | 16 +++++++++++++--- .../src/main/resources/JavaTypeGoat.java | 5 +++-- .../java/internal/JavaReflectionTypeMapping.java | 2 +- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeGoat.java b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeGoat.java index 8e8abd6fe37..64a1d90452f 100644 --- a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeGoat.java +++ b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeGoat.java @@ -26,8 +26,9 @@ public abstract class JavaTypeGoat & C> { public static final PT parameterizedField = new PT() { }; - public static final Double PI = 3.14; - public static final double PI_PRIMITIVE = 3.14; + + public static Double PI; + public static double PI_PRIMITIVE; public static abstract class InheritedJavaTypeGoat & C> extends JavaTypeGoat { public InheritedJavaTypeGoat() { diff --git a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java index 2097273e1a2..1c010267764 100644 --- a/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java +++ b/rewrite-java-test/src/main/java/org/openrewrite/java/JavaTypeMappingTest.java @@ -25,9 +25,7 @@ import static java.util.Objects.requireNonNull; import static org.assertj.core.api.Assertions.assertThat; -import static org.openrewrite.java.tree.JavaType.GenericTypeVariable.Variance.CONTRAVARIANT; -import static org.openrewrite.java.tree.JavaType.GenericTypeVariable.Variance.COVARIANT; -import static org.openrewrite.java.tree.JavaType.GenericTypeVariable.Variance.INVARIANT; +import static org.openrewrite.java.tree.JavaType.GenericTypeVariable.Variance.*; /** * Based on type attribution mappings of [JavaTypeGoat]. @@ -53,6 +51,18 @@ default JavaType firstMethodParameter(String methodName) { return methodType(methodName).getParameterTypes().get(0); } + @Test + default void declaredFields() { + JavaType.Parameterized goat = goatType(); + assertThat(goat.getMembers().stream().filter(m -> m.getName().equals("parameterizedField"))).anySatisfy(field -> + assertThat(field).isInstanceOfSatisfying(JavaType.Variable.class, variable -> + assertThat(variable.getType()).isInstanceOfSatisfying(JavaType.Parameterized.class, param -> + assertThat(param.getTypeParameters()).hasOnlyElementsOfType(JavaType.FullyQualified.class) + ) + ) + ); + } + @Test default void declaringTypeRefersToParameterizedClass() { JavaType.FullyQualified declaringType = methodType("nameShadow").getDeclaringType(); diff --git a/rewrite-java-test/src/main/resources/JavaTypeGoat.java b/rewrite-java-test/src/main/resources/JavaTypeGoat.java index 40e1696a15a..047fa6ada5e 100644 --- a/rewrite-java-test/src/main/resources/JavaTypeGoat.java +++ b/rewrite-java-test/src/main/resources/JavaTypeGoat.java @@ -26,8 +26,9 @@ public abstract class JavaTypeGoat & C> { public static final PT parameterizedField = new PT() { }; - public static final Double PI = 3.14; - public static final double PI_PRIMITIVE = 3.14; + + public static Double PI; + public static double PI_PRIMITIVE; public static abstract class InheritedJavaTypeGoat & C> extends JavaTypeGoat { public InheritedJavaTypeGoat() { diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java index 860d259af24..e242c73e335 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/JavaReflectionTypeMapping.java @@ -302,7 +302,7 @@ private JavaType.Variable field(Field field) { } } - mappedVariable.unsafeSet(type(field.getDeclaringClass()), type(field.getType()), annotations); + mappedVariable.unsafeSet(type(field.getDeclaringClass()), type(field.getGenericType()), annotations); return mappedVariable; } From b91499c728758cf6b52474707645bcf584a543b6 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Fri, 27 Dec 2024 11:48:54 +0100 Subject: [PATCH 077/179] Revert parenthesis changes (#4818) * Revert "Try alternative way of determining parenthesis level for `BinaryExpression` when AST doesn't provide `_INSIDE_PARENTHESES_LEVEL` flag (#4807)" This reverts commit e59e48b3a6e6be18ecb779ac329a243ed025da58. * Revert "Make Groovy Parser correctly handle nested parenthesis (#4801)" This reverts commit 91a031a3d517be1fe78656eb6b841141b336c085. --- .../org/openrewrite/internal/StringUtils.java | 10 -- .../groovy/GroovyParserVisitor.java | 146 ++++++------------ .../groovy/tree/AttributeTest.java | 25 ++- .../openrewrite/groovy/tree/BinaryTest.java | 31 +--- .../org/openrewrite/groovy/tree/CastTest.java | 17 +- .../org/openrewrite/groovy/tree/ListTest.java | 34 ---- .../openrewrite/groovy/tree/LiteralTest.java | 23 +++ .../openrewrite/groovy/tree/MapEntryTest.java | 7 - .../groovy/tree/MethodInvocationTest.java | 61 +------- .../openrewrite/groovy/tree/RangeTest.java | 2 + 10 files changed, 97 insertions(+), 259 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java b/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java index 4f0f76ae578..7cafdeb341a 100644 --- a/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java @@ -720,14 +720,4 @@ public static String formatUriForPropertiesFile(String uri) { public static boolean hasLineBreak(@Nullable String s) { return s != null && LINE_BREAK.matcher(s).find(); } - - public static boolean containsWhitespace(String s) { - for (int i = 0; i < s.length(); ++i) { - if (Character.isWhitespace(s.charAt(i))) { - return true; - } - } - - return false; - } } diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index af660485f32..c631e3998a1 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -34,7 +34,6 @@ import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; -import org.openrewrite.internal.StringUtils; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.ImplicitReturn; import org.openrewrite.java.marker.OmitParentheses; @@ -1351,20 +1350,20 @@ public void visitConstantExpression(ConstantExpression expression) { jType = JavaType.Primitive.Short; } else if (type == ClassHelper.STRING_TYPE) { jType = JavaType.Primitive.String; + // String literals value returned by getValue()/getText() has already processed sequences like "\\" -> "\" + int length = sourceLengthOfString(expression); // this is an attribute selector - boolean attributeSelector = source.startsWith("@" + value, cursor); - int length = lengthAccordingToAst(expression); - Integer insideParenthesesLevel = getInsideParenthesesLevel(expression); - if (insideParenthesesLevel != null) { - length = length - insideParenthesesLevel * 2; + if (source.startsWith("@" + value, cursor)) { + length += 1; } - String valueAccordingToAST = source.substring(cursor, cursor + length + (attributeSelector ? 1 : 0)); - int delimiterLength = getDelimiterLength(); - if (StringUtils.containsWhitespace(valueAccordingToAST)) { - length = delimiterLength + expression.getValue().toString().length() + delimiterLength; - text = source.substring(cursor, cursor + length + (attributeSelector ? 1 : 0)); - } else { - text = valueAccordingToAST; + text = source.substring(cursor, cursor + length); + int delimiterLength = 0; + if (text.startsWith("$/")) { + delimiterLength = 2; + } else if (text.startsWith("\"\"\"") || text.startsWith("'''")) { + delimiterLength = 3; + } else if (text.startsWith("/") || text.startsWith("\"") || text.startsWith("'")) { + delimiterLength = 1; } value = text.substring(delimiterLength, text.length() - delimiterLength); } else if (expression.isNullExpression()) { @@ -1691,18 +1690,15 @@ public void visitGStringExpression(GStringExpression gstring) { @Override public void visitListExpression(ListExpression list) { - queue.add(insideParentheses(list, fmt -> { - skip("["); - if (list.getExpressions().isEmpty()) { - return new G.ListLiteral(randomId(), fmt, Markers.EMPTY, - JContainer.build(singletonList(new JRightPadded<>(new J.Empty(randomId(), EMPTY, Markers.EMPTY), sourceBefore("]"), Markers.EMPTY))), - typeMapping.type(list.getType())); - } else { - return new G.ListLiteral(randomId(), fmt, Markers.EMPTY, - JContainer.build(visitRightPadded(list.getExpressions().toArray(new ASTNode[0]), "]")), - typeMapping.type(list.getType())); - } - })); + if (list.getExpressions().isEmpty()) { + queue.add(new G.ListLiteral(randomId(), sourceBefore("["), Markers.EMPTY, + JContainer.build(singletonList(new JRightPadded<>(new J.Empty(randomId(), EMPTY, Markers.EMPTY), sourceBefore("]"), Markers.EMPTY))), + typeMapping.type(list.getType()))); + } else { + queue.add(new G.ListLiteral(randomId(), sourceBefore("["), Markers.EMPTY, + JContainer.build(visitRightPadded(list.getExpressions().toArray(new ASTNode[0]), "]")), + typeMapping.type(list.getType()))); + } } @Override @@ -1717,19 +1713,17 @@ public void visitMapEntryExpression(MapEntryExpression expression) { @Override public void visitMapExpression(MapExpression map) { - queue.add(insideParentheses(map, fmt -> { - skip("["); - JContainer entries; - if (map.getMapEntryExpressions().isEmpty()) { - entries = JContainer.build(Collections.singletonList(JRightPadded.build( - new G.MapEntry(randomId(), whitespace(), Markers.EMPTY, - JRightPadded.build(new J.Empty(randomId(), sourceBefore(":"), Markers.EMPTY)), - new J.Empty(randomId(), sourceBefore("]"), Markers.EMPTY), null)))); - } else { - entries = JContainer.build(visitRightPadded(map.getMapEntryExpressions().toArray(new ASTNode[0]), "]")); - } - return new G.MapLiteral(randomId(), fmt, Markers.EMPTY, entries, typeMapping.type(map.getType())); - })); + Space prefix = sourceBefore("["); + JContainer entries; + if (map.getMapEntryExpressions().isEmpty()) { + entries = JContainer.build(Collections.singletonList(JRightPadded.build( + new G.MapEntry(randomId(), whitespace(), Markers.EMPTY, + JRightPadded.build(new J.Empty(randomId(), sourceBefore(":"), Markers.EMPTY)), + new J.Empty(randomId(), sourceBefore("]"), Markers.EMPTY), null)))); + } else { + entries = JContainer.build(visitRightPadded(map.getMapEntryExpressions().toArray(new ASTNode[0]), "]")); + } + queue.add(new G.MapLiteral(randomId(), prefix, Markers.EMPTY, entries, typeMapping.type(map.getType()))); } @Override @@ -1907,24 +1901,23 @@ public void visitStaticMethodCallExpression(StaticMethodCallExpression call) { @Override public void visitAttributeExpression(AttributeExpression attr) { - queue.add(insideParentheses(attr, fmt -> { - Expression target = visit(attr.getObjectExpression()); - Space beforeDot = attr.isSafe() ? sourceBefore("?.") : - sourceBefore(attr.isSpreadSafe() ? "*." : "."); - J name = visit(attr.getProperty()); - if (name instanceof J.Literal) { - String nameStr = ((J.Literal) name).getValueSource(); - assert nameStr != null; - name = new J.Identifier(randomId(), name.getPrefix(), Markers.EMPTY, emptyList(), nameStr, null, null); - } - if (attr.isSpreadSafe()) { - name = name.withMarkers(name.getMarkers().add(new StarDot(randomId()))); - } - if (attr.isSafe()) { - name = name.withMarkers(name.getMarkers().add(new NullSafe(randomId()))); - } - return new J.FieldAccess(randomId(), fmt, Markers.EMPTY, target, padLeft(beforeDot, (J.Identifier) name), null); - })); + Space fmt = whitespace(); + Expression target = visit(attr.getObjectExpression()); + Space beforeDot = attr.isSafe() ? sourceBefore("?.") : + sourceBefore(attr.isSpreadSafe() ? "*." : "."); + J name = visit(attr.getProperty()); + if (name instanceof J.Literal) { + String nameStr = ((J.Literal) name).getValueSource(); + assert nameStr != null; + name = new J.Identifier(randomId(), name.getPrefix(), Markers.EMPTY, emptyList(), nameStr, null, null); + } + if (attr.isSpreadSafe()) { + name = name.withMarkers(name.getMarkers().add(new StarDot(randomId()))); + } + if (attr.isSafe()) { + name = name.withMarkers(name.getMarkers().add(new NullSafe(randomId()))); + } + queue.add(new J.FieldAccess(randomId(), fmt, Markers.EMPTY, target, padLeft(beforeDot, (J.Identifier) name), null)); } @Override @@ -2529,52 +2522,15 @@ private int sourceLengthOfString(ConstantExpression expr) { return lengthAccordingToAst; } - private @Nullable Integer getInsideParenthesesLevel(ASTNode node) { + private static @Nullable Integer getInsideParenthesesLevel(ASTNode node) { Object rawIpl = node.getNodeMetaData("_INSIDE_PARENTHESES_LEVEL"); if (rawIpl instanceof AtomicInteger) { // On Java 11 and newer _INSIDE_PARENTHESES_LEVEL is an AtomicInteger return ((AtomicInteger) rawIpl).get(); - } else if (rawIpl instanceof Integer) { + } else { // On Java 8 _INSIDE_PARENTHESES_LEVEL is a regular Integer return (Integer) rawIpl; - } else if (node instanceof MethodCallExpression) { - MethodCallExpression expr = (MethodCallExpression) node; - return determineParenthesisLevel(expr.getObjectExpression().getLineNumber(), expr.getLineNumber(), expr.getObjectExpression().getColumnNumber(), expr.getColumnNumber()); - } else if (node instanceof BinaryExpression) { - BinaryExpression expr = (BinaryExpression) node; - return determineParenthesisLevel(expr.getLeftExpression().getLineNumber(), expr.getLineNumber(), expr.getLeftExpression().getColumnNumber(), expr.getColumnNumber()); - - } - return null; - } - - /** - * @param childLineNumber the beginning line number of the first sub node - * @param parentLineNumber the beginning line number of the parent node - * @param childColumn the column on the {@code childLineNumber} line where the sub node starts - * @param parentColumn the column on the {@code parentLineNumber} line where the parent node starts - * @return the level of parenthesis parsed from the source - */ - private int determineParenthesisLevel(int childLineNumber, int parentLineNumber, int childColumn, int parentColumn) { - int saveCursor = cursor; - whitespace(); - int childBeginCursor = cursor; - if (childLineNumber > parentLineNumber) { - for (int i = 0; i < (childColumn - parentLineNumber); i++) { - childBeginCursor = source.indexOf('\n', childBeginCursor); - } - childBeginCursor += childColumn; - } else { - childBeginCursor += childColumn - parentColumn; - } - int count = 0; - for (int i = cursor; i < childBeginCursor; i++) { - if (source.charAt(i) == '(') { - count++; - } } - cursor = saveCursor; - return count; } private int getDelimiterLength() { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java index 2b7d4c82756..bfbadb76655 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java @@ -20,26 +20,19 @@ import static org.openrewrite.groovy.Assertions.groovy; +@SuppressWarnings({"GroovyUnusedAssignment", "GrUnnecessarySemicolon"}) class AttributeTest implements RewriteTest { @Test - void attribute() { + void usingGroovyNode() { rewriteRun( - groovy("new User('Bob').@name") - ); - } - - @Test - void attributeInClosure() { - rewriteRun( - groovy("[new User('Bob')].collect { it.@name }") - ); - } - - @Test - void attributeWithParentheses() { - rewriteRun( - groovy("(new User('Bob').@name)") + groovy( + """ + def xml = new Node(null, "ivy") + def n = xml.dependencies.dependency.find { it.@name == 'test-module' } + n.@conf = 'runtime->default;docs->docs;sources->sources' + """ + ) ); } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java index aca502d3571..13239c0fc76 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java @@ -15,6 +15,7 @@ */ package org.openrewrite.groovy.tree; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -33,7 +34,6 @@ void insideParentheses() { // NOT inside parentheses, but verifies the parser's // test for "inside parentheses" condition - groovy("( 1 ) + 1"), groovy("(1) + 1"), // And combine the two cases groovy("((1) + 1)") @@ -216,35 +216,6 @@ void stringMultipliedInParentheses() { ); } - @Issue("https://github.com/openrewrite/rewrite/issues/4703") - @Test - void cxds() { - rewriteRun( - groovy( - """ - def differenceInDays(int time) { - return (int) ((time)/(1000*60*60*24)) - } - """ - ) - ); - } - - @Issue("https://github.com/openrewrite/rewrite/issues/4703") - @Test - void extraParensAroundInfixOxxxperator() { - rewriteRun( - groovy( - """ - def timestamp(int hours, int minutes, int seconds) { - 30 * (hours) - (((((hours))))) * 30 - } - """ - ) - ); - } - @Issue("https://github.com/openrewrite/rewrite/issues/4703") @Test void extraParensAroundInfixOperator() { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java index 4c009de95e3..5cf82ae85be 100755 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java @@ -16,6 +16,7 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -24,18 +25,6 @@ @SuppressWarnings({"UnnecessaryQualifiedReference", "GroovyUnusedAssignment", "GrUnnecessarySemicolon"}) class CastTest implements RewriteTest { - @Test - void cast() { - rewriteRun( - groovy( - """ - String foo = ( String ) "hallo" - String bar = "hallo" as String - """ - ) - ); - } - @Test void javaStyleCast() { rewriteRun( @@ -85,13 +74,14 @@ void groovyCastAndInvokeMethod() { rewriteRun( groovy( """ - ( "x" as String ).toString() + ( "" as String ).toString() """ ) ); } @Test + @ExpectedToFail("Parentheses with method invocation is not yet supported") void groovyCastAndInvokeMethodWithParentheses() { rewriteRun( groovy( @@ -113,6 +103,7 @@ void javaCastAndInvokeMethod() { ); } + @ExpectedToFail("Parentheses with method invocation is not yet supported") @Test void javaCastAndInvokeMethodWithParentheses() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java index d921377b661..b42f9579fd4 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java @@ -23,29 +23,6 @@ @SuppressWarnings("GroovyUnusedAssignment") class ListTest implements RewriteTest { - @Test - void emptyListLiteral() { - rewriteRun( - groovy( - """ - def a = [] - def b = [ ] - """ - ) - ); - } - - @Test - void emptyListLiteralWithParentheses() { - rewriteRun( - groovy( - """ - def y = ([]) - """ - ) - ); - } - @Test void listLiteral() { rewriteRun( @@ -56,15 +33,4 @@ void listLiteral() { ) ); } - - @Test - void listLiteralTrailingComma() { - rewriteRun( - groovy( - """ - def a = [ "foo" /* "foo" suffix */ , /* "]" prefix */ ] - """ - ) - ); - } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java index 12d638870d4..46851b2f65a 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java @@ -216,6 +216,18 @@ void literalValueAndTypeAgree() { ); } + @Test + void emptyListLiteral() { + rewriteRun( + groovy( + """ + def a = [] + def b = [ ] + """ + ) + ); + } + @Test void multilineStringWithApostrophes() { rewriteRun( @@ -242,6 +254,17 @@ void mapLiteralTrailingComma() { ); } + @Test + void listLiteralTrailingComma() { + rewriteRun( + groovy( + """ + def a = [ "foo" /* "foo" suffix */ , /* "]" prefix */ ] + """ + ) + ); + } + @Test void gStringThatHasEmptyValueExpressionForUnknownReason() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java index 67ee80177cd..65bb4a17492 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java @@ -55,13 +55,6 @@ void emptyMapLiteral() { ); } - @Test - void emptyMapLiteralWithParentheses() { - rewriteRun( - groovy("Map m = ([ : ])") - ); - } - @Test void mapAccess() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java index 42a73d160a0..a0714126901 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java @@ -16,6 +16,7 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -30,11 +31,11 @@ void gradle() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation 'org.hibernate:hibernate-core:3.6.7.Final' api 'com.google.guava:guava:23.0' @@ -45,6 +46,7 @@ void gradle() { ); } + @ExpectedToFail("Parentheses with method invocation is not yet supported") @Test @Issue("https://github.com/openrewrite/rewrite/issues/4615") void gradleWithParentheses() { @@ -347,7 +349,7 @@ class StringUtils { static boolean isEmpty(String value) { return value == null || value.isEmpty() } - + static void main(String[] args) { isEmpty("") } @@ -357,29 +359,7 @@ static void main(String[] args) { ); } - @Issue("https://github.com/openrewrite/rewrite/issues/4703") - @Test - void insideParenthesesSimple() { - rewriteRun( - groovy( - """ - ((a.invoke "b" )) - """ - ) - ); - } - - @Test - void lotOfSpacesAroundConstantWithParentheses() { - rewriteRun( - groovy( - """ - ( ( ( "x" ) ).toString() ) - """ - ) - ); - } - + @ExpectedToFail("Parentheses with method invocation is not yet supported") @Issue("https://github.com/openrewrite/rewrite/issues/4703") @Test void insideParentheses() { @@ -395,21 +375,7 @@ static def foo(Map map) { ); } - @Test - void insideParenthesesWithNewline() { - rewriteRun( - groovy( - """ - static def foo(Map map) { - (( - map.containsKey("foo")) - && ((map.get("foo")).equals("bar"))) - } - """ - ) - ); - } - + @ExpectedToFail("Parentheses with method invocation is not yet supported") @Issue("https://github.com/openrewrite/rewrite/issues/4703") @Test void insideParenthesesWithoutNewLineAndEscapedMethodName() { @@ -421,17 +387,4 @@ static def foo(Map someMap) {((((((someMap.get("(bar")))) ).'equals' "baz" ) ) ) ); } - - @Test - void insideFourParenthesesAndEnters() { - rewriteRun( - groovy( - """ - (((( - something(a) - )))) - """ - ) - ); - } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java index e0ff32f3d94..ac839e34d88 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java @@ -16,6 +16,7 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.test.RewriteTest; import static org.openrewrite.groovy.Assertions.groovy; @@ -47,6 +48,7 @@ void parenthesized() { ); } + @ExpectedToFail("Parentheses with method invocation is not yet supported") @Test void parenthesizedAndInvokeMethodWithParentheses() { rewriteRun( From 7444d1c3321b487d940894afecc1200822b0d1e8 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Fri, 27 Dec 2024 13:54:35 +0100 Subject: [PATCH 078/179] JavaTemplate bug when inserting `final var` into for-each (#4806) * JavaTemplate bug when inserting `final var` into for-each * Split variable declarations when they contain stop comment --- .../openrewrite/java/JavaTemplateTest.java | 47 ++++++++++++++++++- .../BlockStatementTemplateGenerator.java | 17 ++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateTest.java index 25e1e314f6f..cc2041f7236 100755 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateTest.java @@ -72,7 +72,7 @@ void assignmentWithinIfPredicate() { @Override public J.Assignment visitAssignment(J.Assignment assignment, ExecutionContext ctx) { if ((assignment.getAssignment() instanceof J.Literal) && - ((J.Literal) assignment.getAssignment()).getValue().equals(1)) { + ((J.Literal) assignment.getAssignment()).getValue().equals(1)) { return JavaTemplate.builder("value = 0") .contextSensitive() .build() @@ -1351,7 +1351,7 @@ void replaceMethodArgumentsInIfStatementWithoutBraces() { public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); if (new MethodMatcher("Foo bar(..)").matches(mi) && - mi.getArguments().get(0) instanceof J.Binary) { + mi.getArguments().get(0) instanceof J.Binary) { return JavaTemplate.builder("\"Hello, {}\", \"World!\"") .contextSensitive() .build() @@ -1382,4 +1382,47 @@ void foo(boolean condition) { ) ); } + + @Test + void replaceVariableDeclarationWithFinalVar() { + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new JavaIsoVisitor<>() { + @Override + public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) { + J.VariableDeclarations vd = super.visitVariableDeclarations(multiVariable, ctx); + if (TypeUtils.isString(vd.getType()) && "String".equals(((J.Identifier) vd.getTypeExpression()).getSimpleName())) { + JavaCoordinates coordinates = vd.getCoordinates().replace(); + return JavaTemplate.builder("final var #{}") + .contextSensitive() + .doBeforeParseTemplate(System.out::println) + .build() + .apply(getCursor(), coordinates, new Object[]{vd.getVariables().get(0).getSimpleName()}); + } + return vd; + } + })), + java( + """ + import java.util.List; + import java.util.ArrayList; + + class A { + void bar(List lst) { + for (String s : lst) {} + } + } + """, + """ + import java.util.List; + import java.util.ArrayList; + + class A { + void bar(List lst) { + for (final var s : lst) {} + } + } + """ + ) + ); + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java index f0f22eceff2..1dedaf9ea3d 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java @@ -25,6 +25,7 @@ import org.openrewrite.Cursor; import org.openrewrite.SourceFile; import org.openrewrite.Tree; +import org.openrewrite.internal.ListUtils; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.JavaVisitor; import org.openrewrite.java.tree.*; @@ -409,7 +410,7 @@ private void contextTemplate(Cursor cursor, J prior, StringBuilder before, Strin } else if (j instanceof J.ForEachLoop.Control) { J.ForEachLoop.Control c = (J.ForEachLoop.Control) j; if (referToSameElement(prior, c.getVariable())) { - after.append(" = /*" + STOP_COMMENT + "/*").append(c.getIterable().printTrimmed(cursor)); + after.append(" = /*" + STOP_COMMENT + "*/").append(c.getIterable().printTrimmed(cursor)); } else if (referToSameElement(prior, c.getIterable())) { before.insert(0, "Object __b" + cursor.getPathAsStream().count() + "__ ="); after.append(";"); @@ -818,6 +819,20 @@ public J visitMethodInvocation(J.MethodInvocation method, Integer integer) { } return mi; } + + @Override + public J visitVariableDeclarations(J.VariableDeclarations multiVariable, Integer integer) { + List variables = multiVariable.getVariables(); + for (J.VariableDeclarations.NamedVariable variable : variables) { + J.VariableDeclarations.NamedVariable.Padding padding = variable.getPadding(); + if (padding.getInitializer() != null && stopCommentExists(padding.getInitializer().getBefore().getComments())) { + // Split the variable declarations at the variable with the `STOP_COMMENT` & trim off initializer + List vars = variables.subList(0, variables.indexOf(variable) + 1); + return multiVariable.withVariables(ListUtils.mapLast(vars, v -> v.withInitializer(null))); + } + } + return super.visitVariableDeclarations(multiVariable, integer); + } } } } From 2375e311c1decf660598394f4e392d56a6cf1bbb Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sun, 29 Dec 2024 12:42:42 +0100 Subject: [PATCH 079/179] Fix StringIndexOutOfBoundsException for YamlReferences that end in a dot Fixes https://github.com/openrewrite/rewrite/issues/4817 --- .../openrewrite/yaml/trait/YamlReference.java | 2 +- .../yaml/trait/YamlReferenceTest.java | 67 +++++++++++++------ 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java index 23705fdae96..de2dce82039 100644 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java @@ -78,7 +78,7 @@ private static class Matcher extends SimpleTraitMatcher { } private Kind determineKind(String value) { - return Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Kind.TYPE : Kind.PACKAGE; + return !value.endsWith(".") && Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Kind.TYPE : Kind.PACKAGE; } } diff --git a/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java b/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java index a9bd71b35f4..956e6eb996c 100644 --- a/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java +++ b/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java @@ -16,8 +16,10 @@ package org.openrewrite.yaml.trait; import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; import org.openrewrite.trait.Reference; @@ -50,25 +52,24 @@ void findJavaReferencesInYamlProperties(String filename) { rewriteRun( yaml( YAML, - spec -> spec.path(filename).afterRecipe(doc -> { - assertThat(doc.getReferences().getReferences()).satisfiesExactlyInAnyOrder( - ref -> { - assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); - assertThat(ref.getValue()).isEqualTo("java.lang.String"); - }, - ref -> { - assertThat(ref.getKind()).isEqualTo(Reference.Kind.PACKAGE); - assertThat(ref.getValue()).isEqualTo("java.lang"); - }, - ref -> { - assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); - assertThat(ref.getValue()).isEqualTo("org.openrewrite.java.DoSomething"); - }, - ref -> { - assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); - assertThat(ref.getValue()).isEqualTo("org.foo.Bar"); - }); - })) + spec -> spec.path(filename).afterRecipe(doc -> + assertThat(doc.getReferences().getReferences()).satisfiesExactlyInAnyOrder( + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); + assertThat(ref.getValue()).isEqualTo("java.lang.String"); + }, + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.PACKAGE); + assertThat(ref.getValue()).isEqualTo("java.lang"); + }, + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); + assertThat(ref.getValue()).isEqualTo("org.openrewrite.java.DoSomething"); + }, + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); + assertThat(ref.getValue()).isEqualTo("org.foo.Bar"); + }))) ); } @@ -93,4 +94,32 @@ void noReferencesInMismatchedFilenames(String filename) { ) ); } + + @Issue("https://github.com/openrewrite/rewrite/issues/4817") + @Test + void endsWithDot() { + rewriteRun( + yaml( + """ + root: + recipelist: + - org.openrewrite.java.DoSomething: + option: 'org.foo.' + """, + spec -> spec + .path("application.yml") + .afterRecipe(doc -> assertThat(doc.getReferences().getReferences()) + .satisfiesExactlyInAnyOrder( + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); + assertThat(ref.getValue()).isEqualTo("org.openrewrite.java.DoSomething"); + }, + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.PACKAGE); + assertThat(ref.getValue()).isEqualTo("org.foo."); + }) + ) + ) + ); + } } From a8946ac9c7b6cbe0b6ac1c540d5e5cfc4e2d0919 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Mon, 30 Dec 2024 14:19:43 +0100 Subject: [PATCH 080/179] Add Docker Image reference, to be used for gitlab, docker, etc (#4793) * Basic implementation to find image over multiple sources * Formatting * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Improvement * Improvement * Add TODO removal comments * Add DockerImageReference * Add DockerImageReference * Add DockerImageReference * Introduce AbstractProvider * Improve DockerImageReference * work on it * first impl * Extra yaml test * working example * working example * working example * revert lost * Fix * Support --from and --platform and ignore comments for dockerfile * Merge branch 'main' into introduce-image-reference-and-recipe * Remove files (will be places in rewrite-docker) * Remove files (will be places in rewrite-docker) * Cleanup `findMatches` * Make SourceFileWithReferences `abstract`, so we can define `getReferences` once * Make SourceFileWithReferences `abstract`, so we can define `getReferences` once * Make SourceFileWithReferences `abstract`, so we can define `getReferences` once * Make SourceFileWithReferences `abstract`, so we can define `getReferences` once * Revert `SourceFileWithReferences` as interface * Make matchers static singletons in the provider classes * Update description * Fix tests * Revert implements of File class * Pattern.asPredicate() acts as `find`, not `matches()` --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tim te Beek --- .../openrewrite/SourceFileWithReferences.java | 24 +++--- .../main/java/org/openrewrite/text/Find.java | 10 ++- .../java/org/openrewrite/text/PlainText.java | 24 ++++-- .../org/openrewrite/text/PlainTextParser.java | 1 + .../java/org/openrewrite/trait/Reference.java | 18 ++++- .../java/org/openrewrite/text/FindTest.java | 35 +++++--- .../java/org/openrewrite/java/ChangeType.java | 2 +- .../openrewrite/java/search/FindTypes.java | 3 +- .../org/openrewrite/java/search/UsesType.java | 2 +- .../properties/trait/PropertiesReference.java | 50 +++++------- .../properties/tree/Properties.java | 17 +--- .../org/openrewrite/protobuf/ProtoParser.java | 1 + .../xml/trait/SpringXmlReference.java | 81 +++++++++---------- .../java/org/openrewrite/xml/tree/Xml.java | 22 +---- .../xml/trait/SpringXmlReferenceTest.java | 2 +- .../trait/YamlApplicationConfigReference.java | 69 ++++++++++++++++ .../openrewrite/yaml/trait/YamlReference.java | 57 +------------ .../java/org/openrewrite/yaml/tree/Yaml.java | 17 +--- .../org.openrewrite.trait.Reference$Provider | 2 +- .../yaml/trait/YamlReferenceTest.java | 15 ++-- 20 files changed, 234 insertions(+), 218 deletions(-) create mode 100644 rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlApplicationConfigReference.java diff --git a/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java b/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java index 0a8bb5faad8..bb1584aaabf 100644 --- a/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java +++ b/rewrite-core/src/main/java/org/openrewrite/SourceFileWithReferences.java @@ -21,6 +21,7 @@ import org.jspecify.annotations.Nullable; import org.openrewrite.trait.Reference; +import java.lang.ref.SoftReference; import java.util.*; @Incubating(since = "8.39.0") @@ -28,31 +29,32 @@ public interface SourceFileWithReferences extends SourceFile { References getReferences(); + default SoftReference build(@Nullable SoftReference<@Nullable References> references) { + References cache = references == null ? null : references.get(); + if (cache == null || cache.getSourceFile() != this) { + return new SoftReference<>(References.build(this)); + } + return references; + } + @RequiredArgsConstructor(access = AccessLevel.PRIVATE) - @Getter class References { + @Getter(AccessLevel.PRIVATE) private final SourceFile sourceFile; + @Getter private final Set references; public Collection findMatches(Reference.Matcher matcher) { - return findMatchesInternal(matcher, null); - } - - public Collection findMatches(Reference.Matcher matcher, Reference.Kind kind) { - return findMatchesInternal(matcher, kind); - } - - private List findMatchesInternal(Reference.Matcher matcher, Reference.@Nullable Kind kind) { List list = new ArrayList<>(); for (Reference ref : references) { - if ((kind == null || ref.getKind() == kind) && ref.matches(matcher) ) { + if (ref.matches(matcher)) { list.add(ref); } } return list; } - public static References build(SourceFile sourceFile) { + private static References build(SourceFile sourceFile) { Set references = new HashSet<>(); ServiceLoader loader = ServiceLoader.load(Reference.Provider.class); loader.forEach(provider -> { diff --git a/rewrite-core/src/main/java/org/openrewrite/text/Find.java b/rewrite-core/src/main/java/org/openrewrite/text/Find.java index eb8fb30c09a..ad25c20266c 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/Find.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/Find.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.Value; +import org.apache.commons.lang3.BooleanUtils; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.binary.Binary; @@ -91,6 +92,12 @@ public String getDescription() { @Nullable String filePattern; + @Option(displayName = "Description", + description = "Add the matched value(s) as description on the search result marker. Default `false`.", + required = false) + @Nullable + Boolean description; + @Override public TreeVisitor getVisitor() { @@ -135,7 +142,8 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { do { int matchStart = matcher.start(); snippets.add(snippet(rawText.substring(previousEnd, matchStart))); - snippets.add(SearchResult.found(snippet(rawText.substring(matchStart, matcher.end())))); + String text = rawText.substring(matchStart, matcher.end()); + snippets.add(SearchResult.found(snippet(text), BooleanUtils.isTrue(description) ? text : null)); previousEnd = matcher.end(); // For the first match, search backwards diff --git a/rewrite-core/src/main/java/org/openrewrite/text/PlainText.java b/rewrite-core/src/main/java/org/openrewrite/text/PlainText.java index 6ccab32adf8..cf538bca0ec 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/PlainText.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/PlainText.java @@ -16,14 +16,17 @@ package org.openrewrite.text; import lombok.*; +import lombok.experimental.NonFinal; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.marker.Markers; +import java.lang.ref.SoftReference; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.List; +import java.util.Objects; import java.util.UUID; import java.util.function.Predicate; @@ -36,7 +39,7 @@ @Value @Builder @AllArgsConstructor -public class PlainText implements SourceFile, Tree { +public class PlainText implements SourceFileWithReferences, Tree { @Builder.Default @With @@ -79,16 +82,27 @@ public SourceFile withCharset(Charset charset) { @Builder.Default String text = ""; + List snippets; + + @Nullable + @NonFinal + @ToString.Exclude + transient SoftReference references; + + @Override + public References getReferences() { + this.references = build(this.references); + return Objects.requireNonNull(this.references.get()); + } + public PlainText withText(String text) { if (!text.equals(this.text)) { return new PlainText(this.id, this.sourcePath, this.markers, this.charsetName, this.charsetBomMarked, - this.fileAttributes, this.checksum, text, this.snippets); + this.fileAttributes, this.checksum, text, this.snippets, this.references); } return this; } - List snippets; - @Override public

boolean isAcceptable(TreeVisitor v, P p) { return v.isAdaptableTo(PlainTextVisitor.class); @@ -123,7 +137,7 @@ public PlainText withSnippets(@Nullable List snippets) { if (this.snippets == snippets) { return this; } - return new PlainText(id, sourcePath, markers, charsetName, charsetBomMarked, fileAttributes, checksum, text, snippets); + return new PlainText(id, sourcePath, markers, charsetName, charsetBomMarked, fileAttributes, checksum, text, snippets, null); } @Value diff --git a/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java b/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java index d7da58e2be6..eb0d6281f0a 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java @@ -82,6 +82,7 @@ public Stream parseInputs(Iterable sources, @Nullable Path re input.getFileAttributes(), null, sourceStr, + null, null ); parsingListener.parsed(input, plainText); diff --git a/rewrite-core/src/main/java/org/openrewrite/trait/Reference.java b/rewrite-core/src/main/java/org/openrewrite/trait/Reference.java index df960a7b412..55cf9f63855 100644 --- a/rewrite-core/src/main/java/org/openrewrite/trait/Reference.java +++ b/rewrite-core/src/main/java/org/openrewrite/trait/Reference.java @@ -17,6 +17,7 @@ import org.openrewrite.*; +import java.util.HashSet; import java.util.Set; @Incubating(since = "8.39.0") @@ -24,7 +25,8 @@ public interface Reference extends Trait { enum Kind { TYPE, - PACKAGE + PACKAGE, + IMAGE } Kind getKind(); @@ -57,6 +59,20 @@ interface Provider { boolean isAcceptable(SourceFile sourceFile); } + abstract class AbstractProvider implements Provider { + protected abstract SimpleTraitMatcher getMatcher(); + + @Override + public Set getReferences(SourceFile sourceFile) { + Set references = new HashSet<>(); + getMatcher().asVisitor(reference -> { + references.add(reference); + return reference.getTree(); + }).visit(sourceFile, 0); + return references; + } + } + interface Matcher { boolean matchesReference(Reference value); diff --git a/rewrite-core/src/test/java/org/openrewrite/text/FindTest.java b/rewrite-core/src/test/java/org/openrewrite/text/FindTest.java index b887986efb1..1e628c1b681 100644 --- a/rewrite-core/src/test/java/org/openrewrite/text/FindTest.java +++ b/rewrite-core/src/test/java/org/openrewrite/text/FindTest.java @@ -29,7 +29,7 @@ class FindTest implements RewriteTest { @Test void dataTable() { rewriteRun( - spec -> spec.recipe(new Find("text", null, null, null, null, null)) + spec -> spec.recipe(new Find("text", null, null, null, null, null, null)) .dataTable(TextMatches.Row.class, rows -> { assertThat(rows).hasSize(1); assertThat(rows.get(0).getMatch()).isEqualTo("This is ~~>text."); @@ -53,7 +53,7 @@ void dataTable() { @Test void regex() { rewriteRun( - spec -> spec.recipe(new Find("[T\\s]", true, true, null, null, null)), + spec -> spec.recipe(new Find("[T\\s]", true, true, null, null, null, null)), text( """ This is\ttext. @@ -68,7 +68,7 @@ void regex() { @Test void plainText() { rewriteRun( - spec -> spec.recipe(new Find("\\s", null, null, null, null, null)), + spec -> spec.recipe(new Find("\\s", null, null, null, null, null, null)), text( """ This i\\s text. @@ -83,7 +83,7 @@ void plainText() { @Test void caseInsensitive() { rewriteRun( - spec -> spec.recipe(new Find("text", null, null, null, null, "**/foo/**;**/baz/**")), + spec -> spec.recipe(new Find("text", null, null, null, null, "**/foo/**;**/baz/**", null)), dir("foo", text( """ @@ -115,7 +115,7 @@ void caseInsensitive() { @Test void regexBasicMultiLine() { rewriteRun( - spec -> spec.recipe(new Find("[T\\s]", true, true, true, null, null)), + spec -> spec.recipe(new Find("[T\\s]", true, true, true, null, null, null)), text( """ This is\ttext. @@ -132,7 +132,7 @@ void regexBasicMultiLine() { @Test void regexWithoutMultilineAndDotall() { rewriteRun( - spec -> spec.recipe(new Find("^This.*below\\.$", true, true, false, false, null)), + spec -> spec.recipe(new Find("^This.*below\\.$", true, true, false, false, null, null)), text( """ This is text. @@ -148,7 +148,7 @@ void regexWithoutMultilineAndDotall() { @Test void regexMatchingWhitespaceWithoutMultilineWithDotall() { rewriteRun( - spec -> spec.recipe(new Find("One.Two$", true, true, false, true, null)), + spec -> spec.recipe(new Find("One.Two$", true, true, false, true, null, null)), //language=csv text( // the `.` above matches the space character on the same line """ @@ -163,7 +163,7 @@ void regexMatchingWhitespaceWithoutMultilineWithDotall() { @Test void regexWithoutMultilineAndWithDotAll() { rewriteRun( - spec -> spec.recipe(new Find("^This.*below\\.$", true, true, false, true, null)), + spec -> spec.recipe(new Find("^This.*below\\.$", true, true, false, true, null, null)), text( """ This is text. @@ -186,7 +186,7 @@ void regexWithoutMultilineAndWithDotAll() { @Test void regexWithMultilineAndWithoutDotall() { rewriteRun( - spec -> spec.recipe(new Find("^This.*below\\.$", true, true, true, false, null)), + spec -> spec.recipe(new Find("^This.*below\\.$", true, true, true, false, null, null)), text( """ This is text. @@ -209,7 +209,7 @@ void regexWithMultilineAndWithoutDotall() { @Test void regexWithBothMultilineAndDotAll() { rewriteRun( - spec -> spec.recipe(new Find("^This.*below\\.$", true, true, true, true, null)), + spec -> spec.recipe(new Find("^This.*below\\.$", true, true, true, true, null, null)), text( """ The first line. @@ -228,4 +228,19 @@ void regexWithBothMultilineAndDotAll() { ) ); } + + @Test + void description() { + rewriteRun( + spec -> spec.recipe(new Find("text", null, null, null, null, null, true)), + text( + """ + This is text. + """, + """ + This is ~~(text)~~>text. + """ + ) + ); + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java b/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java index 7dfbb7fed68..8cdb8cf4865 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/ChangeType.java @@ -114,7 +114,7 @@ public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) { SourceFileWithReferences.References references = sourceFile.getReferences(); TypeMatcher matcher = new TypeMatcher(oldFullyQualifiedTypeName); Map matches = new HashMap<>(); - for (Reference ref : references.findMatches(matcher, Reference.Kind.TYPE)) { + for (Reference ref : references.findMatches(matcher)) { matches.put(ref.getTree(), ref); } return new ReferenceChangeTypeVisitor(matches, matcher.createRenamer(newFullyQualifiedTypeName)).visit(tree, ctx, requireNonNull(getCursor().getParent())); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java b/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java index f9e4a051cf7..7a0dff047c5 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/FindTypes.java @@ -27,7 +27,6 @@ import org.openrewrite.java.table.TypeUses; import org.openrewrite.java.tree.*; import org.openrewrite.marker.SearchResult; -import org.openrewrite.trait.Reference; import org.openrewrite.trait.Trait; import java.util.HashSet; @@ -80,7 +79,7 @@ public boolean isAcceptable(SourceFile sourceFile, ExecutionContext ctx) { SourceFileWithReferences sourceFile = (SourceFileWithReferences) tree; SourceFileWithReferences.References references = sourceFile.getReferences(); TypeMatcher matcher = new TypeMatcher(fullyQualifiedTypeName); - Set matches = references.findMatches(matcher, Reference.Kind.TYPE).stream().map(Trait::getTree).collect(Collectors.toSet()); + Set matches = references.findMatches(matcher).stream().map(Trait::getTree).collect(Collectors.toSet()); return new ReferenceVisitor(matches).visit(tree, ctx); } return tree; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/UsesType.java b/rewrite-java/src/main/java/org/openrewrite/java/search/UsesType.java index 2e701f37491..4044dfcbc78 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/UsesType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/UsesType.java @@ -123,7 +123,7 @@ public boolean isAcceptable(SourceFile sourceFile, P p) { SourceFileWithReferences sourceFile = (SourceFileWithReferences) tree; SourceFileWithReferences.References references = sourceFile.getReferences(); TypeMatcher matcher = typeMatcher != null ? typeMatcher : new TypeMatcher(fullyQualifiedType); - for (Reference ignored : references.findMatches(matcher, Reference.Kind.TYPE)) { + for (Reference ignored : references.findMatches(matcher)) { return SearchResult.found(sourceFile); } } diff --git a/rewrite-properties/src/main/java/org/openrewrite/properties/trait/PropertiesReference.java b/rewrite-properties/src/main/java/org/openrewrite/properties/trait/PropertiesReference.java index 2d5fd55846a..f2ad9404f93 100644 --- a/rewrite-properties/src/main/java/org/openrewrite/properties/trait/PropertiesReference.java +++ b/rewrite-properties/src/main/java/org/openrewrite/properties/trait/PropertiesReference.java @@ -25,8 +25,6 @@ import org.openrewrite.trait.Reference; import org.openrewrite.trait.SimpleTraitMatcher; -import java.util.HashSet; -import java.util.Set; import java.util.function.Predicate; import java.util.regex.Pattern; @@ -64,29 +62,28 @@ public Tree rename(Renamer renamer, Cursor cursor, ExecutionContext ctx) { return tree; } - private static class Matcher extends SimpleTraitMatcher { - private static final Predicate javaFullyQualifiedTypeMatcher = Pattern.compile( - "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*(?:\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*").asPredicate(); + public static class Provider extends AbstractProvider { + private static final Predicate applicationPropertiesMatcher = Pattern.compile("^application(-\\w+)?\\.properties$").asPredicate(); + private static final SimpleTraitMatcher matcher = new SimpleTraitMatcher() { + private final Predicate javaFullyQualifiedTypeMatcher = Pattern.compile( + "^\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*" + + "\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*" + + "(?:\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*$").asPredicate(); - @Override - protected @Nullable PropertiesReference test(Cursor cursor) { - Object value = cursor.getValue(); - if (value instanceof Properties.Entry && - javaFullyQualifiedTypeMatcher.test(((Properties.Entry) value).getValue().getText())) { - return new PropertiesReference(cursor, determineKind(((Properties.Entry) value).getValue().getText())); + @Override + protected @Nullable PropertiesReference test(Cursor cursor) { + Object value = cursor.getValue(); + if (value instanceof Properties.Entry && + javaFullyQualifiedTypeMatcher.test(((Properties.Entry) value).getValue().getText())) { + return new PropertiesReference(cursor, determineKind(((Properties.Entry) value).getValue().getText())); + } + return null; } - return null; - } - private Kind determineKind(String value) { - return Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Kind.TYPE : Kind.PACKAGE; - } - } - - @SuppressWarnings("unused") - public static class Provider implements Reference.Provider { - - private static final Predicate applicationPropertiesMatcher = Pattern.compile("^application(-\\w+)?\\.properties$").asPredicate(); + private Kind determineKind(String value) { + return Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Kind.TYPE : Kind.PACKAGE; + } + }; @Override public boolean isAcceptable(SourceFile sourceFile) { @@ -94,13 +91,8 @@ public boolean isAcceptable(SourceFile sourceFile) { } @Override - public Set getReferences(SourceFile sourceFile) { - Set references = new HashSet<>(); - new Matcher().asVisitor(reference -> { - references.add(reference); - return reference.getTree(); - }).visit(sourceFile, 0); - return references; + public SimpleTraitMatcher getMatcher() { + return matcher; } } } diff --git a/rewrite-properties/src/main/java/org/openrewrite/properties/tree/Properties.java b/rewrite-properties/src/main/java/org/openrewrite/properties/tree/Properties.java index 098ea01dd35..d24b3706fa7 100755 --- a/rewrite-properties/src/main/java/org/openrewrite/properties/tree/Properties.java +++ b/rewrite-properties/src/main/java/org/openrewrite/properties/tree/Properties.java @@ -23,12 +23,12 @@ import org.openrewrite.properties.PropertiesVisitor; import org.openrewrite.properties.internal.PropertiesPrinter; -import java.beans.Transient; import java.lang.ref.SoftReference; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.List; +import java.util.Objects; import java.util.UUID; import java.util.regex.Pattern; @@ -117,21 +117,10 @@ public

TreeVisitor> printer(Cursor cursor) { @NonFinal transient SoftReference references; - @Transient @Override public References getReferences() { - References cache; - if (this.references == null) { - cache = References.build(this); - this.references = new SoftReference<>(cache); - } else { - cache = this.references.get(); - if (cache == null || cache.getSourceFile() != this) { - cache = References.build(this); - this.references = new SoftReference<>(cache); - } - } - return cache; + this.references = build(this.references); + return Objects.requireNonNull(this.references.get()); } } diff --git a/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java b/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java index 0bdb42ad260..d491f8506f4 100644 --- a/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java +++ b/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java @@ -66,6 +66,7 @@ public Stream parseInputs(Iterable sourceFiles, @Nullable Pat input.getFileAttributes(), null, sourceStr, + null, null ); } diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringXmlReference.java b/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringXmlReference.java index 41523a89b8a..0d0db0a51da 100644 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringXmlReference.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/trait/SpringXmlReference.java @@ -15,6 +15,7 @@ */ package org.openrewrite.xml.trait; +import lombok.EqualsAndHashCode; import lombok.Value; import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; @@ -24,12 +25,11 @@ import org.openrewrite.xml.XPathMatcher; import org.openrewrite.xml.tree.Xml; -import java.util.HashSet; import java.util.Optional; -import java.util.Set; import java.util.regex.Pattern; @Value +@EqualsAndHashCode(callSuper = false) public class SpringXmlReference extends XmlReference { Cursor cursor; @@ -40,54 +40,42 @@ public Kind getKind() { return kind; } - static class Matcher extends SimpleTraitMatcher { - private final Pattern referencePattern = Pattern.compile("\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*(?:\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*"); - private final XPathMatcher classXPath = new XPathMatcher("//@class"); - private final XPathMatcher typeXPath = new XPathMatcher("//@type"); - private final XPathMatcher keyTypeXPath = new XPathMatcher("//@key-type"); - private final XPathMatcher valueTypeXPath = new XPathMatcher("//@value-type"); - private final XPathMatcher tags = new XPathMatcher("//value"); + public static class Provider extends AbstractProvider { + private static final SimpleTraitMatcher matcher = new SimpleTraitMatcher() { + private final Pattern referencePattern = Pattern.compile("\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*(?:\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*"); + private final XPathMatcher classXPath = new XPathMatcher("//@class"); + private final XPathMatcher typeXPath = new XPathMatcher("//@type"); + private final XPathMatcher keyTypeXPath = new XPathMatcher("//@key-type"); + private final XPathMatcher valueTypeXPath = new XPathMatcher("//@value-type"); + private final XPathMatcher tags = new XPathMatcher("//value"); - @Override - protected @Nullable SpringXmlReference test(Cursor cursor) { - Object value = cursor.getValue(); - if (value instanceof Xml.Attribute) { - Xml.Attribute attrib = (Xml.Attribute) value; - if (classXPath.matches(cursor) || typeXPath.matches(cursor) || keyTypeXPath.matches(cursor) || valueTypeXPath.matches(cursor)) { - String stringVal = attrib.getValueAsString(); - if (referencePattern.matcher(stringVal).matches()) { - return new SpringXmlReference(cursor, determineKind(stringVal)); + @Override + protected @Nullable SpringXmlReference test(Cursor cursor) { + Object value = cursor.getValue(); + if (value instanceof Xml.Attribute) { + Xml.Attribute attrib = (Xml.Attribute) value; + if (classXPath.matches(cursor) || typeXPath.matches(cursor) || keyTypeXPath.matches(cursor) || valueTypeXPath.matches(cursor)) { + String stringVal = attrib.getValueAsString(); + if (referencePattern.matcher(stringVal).matches()) { + return new SpringXmlReference(cursor, determineKind(stringVal)); + } } - } - } else if (value instanceof Xml.Tag) { - Xml.Tag tag = (Xml.Tag) value; - if (tags.matches(cursor)) { - Optional stringVal = tag.getValue(); - if (stringVal.isPresent() && referencePattern.matcher(stringVal.get()).matches()) { - return new SpringXmlReference(cursor, determineKind(stringVal.get())); + } else if (value instanceof Xml.Tag) { + Xml.Tag tag = (Xml.Tag) value; + if (tags.matches(cursor)) { + Optional stringVal = tag.getValue(); + if (stringVal.isPresent() && referencePattern.matcher(stringVal.get()).matches()) { + return new SpringXmlReference(cursor, determineKind(stringVal.get())); + } } } + return null; } - return null; - } - - Reference.Kind determineKind(String value) { - return Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Reference.Kind.TYPE : Reference.Kind.PACKAGE; - } - } - @SuppressWarnings("unused") - public static class Provider implements Reference.Provider { - - @Override - public Set getReferences(SourceFile sourceFile) { - Set references = new HashSet<>(); - new Matcher().asVisitor(reference -> { - references.add(reference); - return reference.getTree(); - }).visit(sourceFile, 0); - return references; - } + Reference.Kind determineKind(String value) { + return Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Reference.Kind.TYPE : Reference.Kind.PACKAGE; + } + }; @Override public boolean isAcceptable(SourceFile sourceFile) { @@ -104,5 +92,10 @@ public boolean isAcceptable(SourceFile sourceFile) { } return false; } + + @Override + public SimpleTraitMatcher getMatcher() { + return matcher; + } } } diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java b/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java index 1fabf24388c..138f470ab7a 100755 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/tree/Xml.java @@ -31,15 +31,11 @@ import org.openrewrite.xml.internal.XmlPrinter; import org.openrewrite.xml.internal.XmlWhitespaceValidationService; -import java.beans.Transient; import java.lang.ref.SoftReference; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; import static java.util.Collections.emptyList; @@ -171,23 +167,11 @@ public T service(Class service) { @NonFinal transient SoftReference references; - @Transient @Override public References getReferences() { - References cache; - if (this.references == null) { - cache = References.build(this); - this.references = new SoftReference<>(cache); - } else { - cache = this.references.get(); - if (cache == null || cache.getSourceFile() != this) { - cache = References.build(this); - this.references = new SoftReference<>(cache); - } - } - return cache; + this.references = build(this.references); + return Objects.requireNonNull(this.references.get()); } - } @Value diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringXmlReferenceTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringXmlReferenceTest.java index 000d242b16e..1eec75fbb0a 100644 --- a/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringXmlReferenceTest.java +++ b/rewrite-xml/src/test/java/org/openrewrite/xml/trait/SpringXmlReferenceTest.java @@ -27,7 +27,7 @@ class SpringXmlReferenceTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.recipe(RewriteTest.toRecipe(() -> new SpringXmlReference.Matcher() + spec.recipe(RewriteTest.toRecipe(() -> new SpringXmlReference.Provider().getMatcher() .asVisitor(springJavaTypeReference -> SearchResult.found(springJavaTypeReference.getTree(), springJavaTypeReference.getValue())))); } diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlApplicationConfigReference.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlApplicationConfigReference.java new file mode 100644 index 00000000000..693f6bcdc77 --- /dev/null +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlApplicationConfigReference.java @@ -0,0 +1,69 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.yaml.trait; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Value; +import org.jspecify.annotations.Nullable; +import org.openrewrite.Cursor; +import org.openrewrite.SourceFile; +import org.openrewrite.trait.SimpleTraitMatcher; +import org.openrewrite.yaml.tree.Yaml; + +import java.util.function.Predicate; +import java.util.regex.Pattern; + +@Value +@EqualsAndHashCode(callSuper = false) +public class YamlApplicationConfigReference extends YamlReference { + Cursor cursor; + @Getter + Kind kind; + + public static class Provider extends YamlProvider { + private static final Predicate applicationPropertiesMatcher = Pattern.compile("^application(-\\w+)?\\.(yaml|yml)$").asPredicate(); + private static final SimpleTraitMatcher matcher = new SimpleTraitMatcher() { + private final Predicate javaFullyQualifiedTypePattern = Pattern.compile( + "^\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*" + + "\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*" + + "(?:\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*$").asPredicate(); + + @Override + protected @Nullable YamlReference test(Cursor cursor) { + Object value = cursor.getValue(); + if (value instanceof Yaml.Scalar && javaFullyQualifiedTypePattern.test(((Yaml.Scalar) value).getValue())) { + return new YamlApplicationConfigReference(cursor, determineKind(((Yaml.Scalar) value).getValue())); + } + return null; + } + + private Kind determineKind(String value) { + return Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Kind.TYPE : Kind.PACKAGE; + } + }; + + @Override + public boolean isAcceptable(SourceFile sourceFile) { + return super.isAcceptable(sourceFile) && applicationPropertiesMatcher.test(sourceFile.getSourcePath().getFileName().toString()); + } + + @Override + public SimpleTraitMatcher getMatcher() { + return matcher; + } + } +} diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java index de2dce82039..18ced348a74 100644 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/trait/YamlReference.java @@ -15,31 +15,14 @@ */ package org.openrewrite.yaml.trait; -import lombok.Value; -import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; import org.openrewrite.SourceFile; import org.openrewrite.Tree; import org.openrewrite.trait.Reference; -import org.openrewrite.trait.SimpleTraitMatcher; import org.openrewrite.yaml.tree.Yaml; -import java.util.HashSet; -import java.util.Set; -import java.util.function.Predicate; -import java.util.regex.Pattern; - -@Value -public class YamlReference implements Reference { - Cursor cursor; - Kind kind; - - @Override - public Kind getKind() { - return kind; - } - +public abstract class YamlReference implements Reference { @Override public String getValue() { if (getTree() instanceof Yaml.Scalar) { @@ -62,44 +45,10 @@ public Tree rename(Renamer renamer, Cursor cursor, ExecutionContext ctx) { throw new IllegalArgumentException("cursor.getValue() must be an Yaml.Scalar but is: " + tree.getClass()); } - private static class Matcher extends SimpleTraitMatcher { - private static final Predicate javaFullyQualifiedTypePattern = Pattern.compile( - "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*(?:\\.\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)*") - .asPredicate(); - - @Override - protected @Nullable YamlReference test(Cursor cursor) { - Object value = cursor.getValue(); - if (value instanceof Yaml.Scalar && - javaFullyQualifiedTypePattern.test(((Yaml.Scalar) value).getValue())) { - return new YamlReference(cursor, determineKind(((Yaml.Scalar) value).getValue())); - } - return null; - } - - private Kind determineKind(String value) { - return !value.endsWith(".") && Character.isUpperCase(value.charAt(value.lastIndexOf('.') + 1)) ? Kind.TYPE : Kind.PACKAGE; - } - } - - @SuppressWarnings("unused") - public static class Provider implements Reference.Provider { - - private static final Predicate applicationPropertiesMatcher = Pattern.compile("^application(-\\w+)?\\.(yaml|yml)$").asPredicate(); - + public static abstract class YamlProvider extends AbstractProvider { @Override public boolean isAcceptable(SourceFile sourceFile) { - return sourceFile instanceof Yaml.Documents && applicationPropertiesMatcher.test(sourceFile.getSourcePath().getFileName().toString()); - } - - @Override - public Set getReferences(SourceFile sourceFile) { - Set references = new HashSet<>(); - new Matcher().asVisitor(reference -> { - references.add(reference); - return reference.getTree(); - }).visit(sourceFile, 0); - return references; + return sourceFile instanceof Yaml.Documents; } } } diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/tree/Yaml.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/tree/Yaml.java index 4639bfbf40b..13ab313924b 100755 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/tree/Yaml.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/tree/Yaml.java @@ -24,12 +24,12 @@ import org.openrewrite.yaml.YamlVisitor; import org.openrewrite.yaml.internal.YamlPrinter; -import java.beans.Transient; import java.lang.ref.SoftReference; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.List; +import java.util.Objects; import java.util.UUID; import static java.util.stream.Collectors.toList; @@ -135,21 +135,10 @@ public

TreeVisitor> printer(Cursor cursor) { @NonFinal transient SoftReference references; - @Transient @Override public References getReferences() { - References cache; - if (this.references == null) { - cache = References.build(this); - this.references = new SoftReference<>(cache); - } else { - cache = this.references.get(); - if (cache == null || cache.getSourceFile() != this) { - cache = References.build(this); - this.references = new SoftReference<>(cache); - } - } - return cache; + this.references = build(this.references); + return Objects.requireNonNull(this.references.get()); } } diff --git a/rewrite-yaml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider b/rewrite-yaml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider index dd857df5564..a51673a11b4 100644 --- a/rewrite-yaml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider +++ b/rewrite-yaml/src/main/resources/META-INF/services/org.openrewrite.trait.Reference$Provider @@ -1 +1 @@ -org.openrewrite.yaml.trait.YamlReference$Provider \ No newline at end of file +org.openrewrite.yaml.trait.YamlApplicationConfigReference$Provider diff --git a/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java b/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java index 956e6eb996c..ddc9abdeff9 100644 --- a/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java +++ b/rewrite-yaml/src/test/java/org/openrewrite/yaml/trait/YamlReferenceTest.java @@ -108,16 +108,11 @@ void endsWithDot() { """, spec -> spec .path("application.yml") - .afterRecipe(doc -> assertThat(doc.getReferences().getReferences()) - .satisfiesExactlyInAnyOrder( - ref -> { - assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); - assertThat(ref.getValue()).isEqualTo("org.openrewrite.java.DoSomething"); - }, - ref -> { - assertThat(ref.getKind()).isEqualTo(Reference.Kind.PACKAGE); - assertThat(ref.getValue()).isEqualTo("org.foo."); - }) + .afterRecipe(doc -> assertThat(doc.getReferences().getReferences()).singleElement().satisfies( + ref -> { + assertThat(ref.getKind()).isEqualTo(Reference.Kind.TYPE); + assertThat(ref.getValue()).isEqualTo("org.openrewrite.java.DoSomething"); + }) ) ) ); From 9cfddab7dee4de929376839061b22c4e9a363de2 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Mon, 30 Dec 2024 15:59:06 +0100 Subject: [PATCH 081/179] Fix regression in `SimplifyBooleanExpressionVisitor` Fixes #4821 --- .../SimplifyBooleanExpressionVisitorTest.java | 16 ++++++++++++++++ .../SimplifyBooleanExpressionVisitor.java | 6 ++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java index 6030207335c..b5d90458706 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java @@ -766,4 +766,20 @@ class A { ) ); } + + @Issue("https://github.com/openrewrite/rewrite/issues/4821") + @Test + void stringComparisonInBinary() { + rewriteRun( + java( + """ + class A { + private boolean notNullAndNotEqual(String one, String other) { + return one != null && !one.equals(other); + } + } + """ + ) + ); + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java index 71bc99f825c..d1efe641755 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java @@ -255,10 +255,8 @@ public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext execu Expression arg = asMethod.getArguments().get(0); if (arg instanceof J.Literal && select instanceof J.Literal) { return booleanLiteral(method, ((J.Literal) select).getValue().equals(((J.Literal) arg).getValue())); - } else if (arg instanceof J.Identifier && select instanceof J.Identifier) { - return booleanLiteral(method, SemanticallyEqual.areEqual(select, arg)); - } if (arg instanceof J.FieldAccess && select instanceof J.FieldAccess) { - return booleanLiteral(method, SemanticallyEqual.areEqual(select, arg)); + } else if (SemanticallyEqual.areEqual(select, arg)) { + return booleanLiteral(method, true); } } return j; From af162a335c1c66b987427ab769514ca9c5584467 Mon Sep 17 00:00:00 2001 From: Anshuman Mishra <119983081+amishra-u@users.noreply.github.com> Date: Tue, 31 Dec 2024 01:48:17 -0800 Subject: [PATCH 082/179] Add support for lombok @Builder.Default Annotation (#4823) * Add support for lombok @Builder.Default Annotation * Update rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderHandler.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: Tim te Beek Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../lombok/BuilderDefaultNoOpHandler.java | 30 +++++ .../java/lombok/BuilderHandler.java | 112 ++++++++++++++++++ .../lombok.javac.JavacAnnotationHandler | 2 + .../org/openrewrite/java/tree/LombokTest.java | 24 ++++ 4 files changed, 168 insertions(+) create mode 100644 rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderDefaultNoOpHandler.java create mode 100644 rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderHandler.java diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderDefaultNoOpHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderDefaultNoOpHandler.java new file mode 100644 index 00000000000..7424fb33e39 --- /dev/null +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderDefaultNoOpHandler.java @@ -0,0 +1,30 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.lombok; + +import com.sun.tools.javac.tree.JCTree; +import lombok.Builder; +import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; + +@HandlerPriority(-1025) +public class BuilderDefaultNoOpHandler extends JavacAnnotationHandler { + @Override + public void handle(AnnotationValues annotationValues, JCTree.JCAnnotation jcAnnotation, JavacNode javacNode) { + } +} diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderHandler.java new file mode 100644 index 00000000000..ec23effd5f8 --- /dev/null +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderHandler.java @@ -0,0 +1,112 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.lombok; + +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import lombok.Builder; +import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; +import lombok.core.LombokImmutableList; +import lombok.core.LombokNode; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; +import lombok.javac.handlers.HandleBuilder; +import lombok.javac.handlers.HandleConstructor; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import static lombok.core.AST.Kind.ANNOTATION; + +@HandlerPriority(-1024) +public class BuilderHandler extends JavacAnnotationHandler { + @Override + public void handle(AnnotationValues annotationValues, JCTree.JCAnnotation jcAnnotation, JavacNode javacNode) { + JavacNode parent = javacNode.up(); + if (!(parent.get() instanceof JCTree.JCClassDecl)) { + new HandleBuilder().handle(annotationValues, jcAnnotation, javacNode); + return; + } + Map> modifiersAndOriginalAnnotationMap = new HashMap<>(); + Map> nodeToChildrenMap = new HashMap<>(); + Field childrenField = null; + try { + childrenField = LombokNode.class.getDeclaredField("children"); + childrenField.setAccessible(true); + // The Lombok handler for the @Builder annotation sets the init expression to null for fields annotated + // with @Builder.Default. Unlike typical Lombok behavior, which either creates new methods or fields, the + // handler for Builder annotation modifies the existing variable declaration. As a result, the AST-to-LST + // converter never encounters the init expression, causing it to behave unexpectedly. + // Additionally, the @Builder.Default annotation generates a private method named $default$, + // which is unlikely to be called in original code. Therefore, it is safe to temporarily remove the + // @Builder.Default annotation during processing. + for (JavacNode fieldNode : HandleConstructor.findAllFields(parent, true)) { + LombokImmutableList children = (LombokImmutableList) childrenField.get(fieldNode); + nodeToChildrenMap.put(fieldNode, children); + LombokImmutableList filtered = children; + for (int i : findBuilderDefaultIndexes(children)) { + filtered = filtered.removeElementAt(i); + } + childrenField.set(fieldNode, filtered); + JCTree.JCVariableDecl fd = (JCTree.JCVariableDecl) fieldNode.get(); + JCTree.JCModifiers modifiers = fd.getModifiers(); + List originalAnnotations = modifiers.getAnnotations(); + modifiersAndOriginalAnnotationMap.put(modifiers, originalAnnotations); + modifiers.annotations = removeBuilderDefault(originalAnnotations); + } + } catch (NoSuchFieldException | IllegalAccessException e) { + // On exception just continue with the original handler + } + new HandleBuilder().handle(annotationValues, jcAnnotation, javacNode); + + // restore values + for (Map.Entry> entry : modifiersAndOriginalAnnotationMap.entrySet()) { + entry.getKey().annotations = entry.getValue(); + } + for (Map.Entry> entry : nodeToChildrenMap.entrySet()) { + try { + childrenField.set(entry.getKey(), entry.getValue()); + } catch (IllegalAccessException e) { + // Not possible. + } + } + } + + private List removeBuilderDefault(List annotations) { + ListBuffer filteredAnnotations = new ListBuffer<>(); + for (JCTree.JCAnnotation annotation : annotations) { + if (annotation.getAnnotationType().toString().equals("lombok.Builder.Default")) { + continue; + } + filteredAnnotations = filteredAnnotations.append(annotation); + } + return filteredAnnotations.toList(); + } + + private List findBuilderDefaultIndexes(LombokImmutableList nodes) { + ListBuffer indexes = new ListBuffer<>(); + for (int i = 0; i < nodes.size(); i++) { + JavacNode node = nodes.get(i); + if (node.getKind() == ANNOTATION && "lombok.Builder.Default".equals(node.get().type.toString())) { + indexes.add(i); + } + } + return indexes.toList(); + } +} diff --git a/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler b/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler index cfecb22a205..322964dfb1b 100644 --- a/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler +++ b/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler @@ -14,6 +14,8 @@ # limitations under the License. # org.openrewrite.java.lombok.AllArgsConstructorHandler +org.openrewrite.java.lombok.BuilderHandler +org.openrewrite.java.lombok.BuilderDefaultNoOpHandler org.openrewrite.java.lombok.CleanupNoOpHandler org.openrewrite.java.lombok.ExtensionMethodHandler org.openrewrite.java.lombok.GetterHandler diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index 192c592e477..e6501675503 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -118,6 +118,30 @@ void test() { ); } + @Test + void builderWithDefault() { + rewriteRun( + java( + """ + import lombok.Builder; + + @Builder + class A { + @Builder.Default boolean b = false; + @Builder.Default int n = 0; + @Builder.Default String s = "Hello, Anshuman!"; + + void test() { + A x = A.builder().n(1).b(true).s("foo").build(); + A y = A.builder().n(1).b(true).build(); + A z = A.builder().n(1).build(); + } + } + """ + ) + ); + } + @Test void tostring() { rewriteRun( From 9fbda22328674e3ec6dad43ceb5e5433b6444928 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Tue, 31 Dec 2024 10:51:10 +0100 Subject: [PATCH 083/179] Put multiple parenthesis support back, fixes modifiers in for loop and support for varargs (#4819) * Revert "Revert parenthesis changes (#4818)" This reverts commit b91499c728758cf6b52474707645bcf584a543b6. * Add some real world tests * Add some real world tests * support method invocation called from object in object * ExpectedToFail "Anonymous inner class is not yet supported" * support modifiers in for loop * ExpectedToFail "Java style class argument is not yet supported" * Support varargs * Support varargs * Support varargs (improve test, show code breaking) * Support varargs * Add test for pattern operator * Format cleanup * Format cleanup * Varargs improvements * Varargs improvements * Varargs improvements * Update rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java Co-authored-by: Tim te Beek * Adjust other links as well * Small safety improvements * Small safety improvements * Small safety improvements * Cleanup --------- Co-authored-by: Tim te Beek --- .../org/openrewrite/internal/StringUtils.java | 10 + .../groovy/GroovyParserVisitor.java | 196 ++++---- .../groovy/tree/AttributeTest.java | 25 +- .../openrewrite/groovy/tree/BinaryTest.java | 45 +- .../org/openrewrite/groovy/tree/CastTest.java | 17 +- .../groovy/tree/ClassDeclarationTest.java | 50 +++ .../openrewrite/groovy/tree/ForLoopTest.java | 15 +- .../org/openrewrite/groovy/tree/ListTest.java | 34 ++ .../openrewrite/groovy/tree/LiteralTest.java | 23 - .../openrewrite/groovy/tree/MapEntryTest.java | 7 + .../groovy/tree/MethodDeclarationTest.java | 13 + .../groovy/tree/MethodInvocationTest.java | 77 +++- .../openrewrite/groovy/tree/RangeTest.java | 2 - .../groovy/tree/RealWorldGroovyTest.java | 422 ++++++++++++++++++ 14 files changed, 806 insertions(+), 130 deletions(-) create mode 100644 rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java b/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java index 7cafdeb341a..4f0f76ae578 100644 --- a/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java @@ -720,4 +720,14 @@ public static String formatUriForPropertiesFile(String uri) { public static boolean hasLineBreak(@Nullable String s) { return s != null && LINE_BREAK.matcher(s).find(); } + + public static boolean containsWhitespace(String s) { + for (int i = 0; i < s.length(); ++i) { + if (Character.isWhitespace(s.charAt(i))) { + return true; + } + } + + return false; + } } diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index c631e3998a1..0090130158b 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -34,6 +34,7 @@ import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.StringUtils; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.ImplicitReturn; import org.openrewrite.java.marker.OmitParentheses; @@ -557,6 +558,14 @@ public void visitMethod(MethodNode method) { } else { paramType = visitTypeTree(param.getOriginType()); } + + Space varargs = null; + if (paramType instanceof J.ArrayType && hasVarargs()) { + int varargStart = indexOfNextNonWhitespace(cursor, source); + varargs = format(source, cursor, varargStart); + cursor = varargStart + 3; + } + JRightPadded paramName = JRightPadded.build( new J.VariableDeclarations.NamedVariable(randomId(), EMPTY, Markers.EMPTY, new J.Identifier(randomId(), whitespace(), Markers.EMPTY, emptyList(), param.getName(), null, null), @@ -576,7 +585,7 @@ public void visitMethod(MethodNode method) { params.add(JRightPadded.build((Statement) new J.VariableDeclarations(randomId(), EMPTY, Markers.EMPTY, paramAnnotations, emptyList(), paramType, - null, emptyList(), + varargs, emptyList(), singletonList(paramName))).withAfter(rightPad)); } @@ -1350,20 +1359,20 @@ public void visitConstantExpression(ConstantExpression expression) { jType = JavaType.Primitive.Short; } else if (type == ClassHelper.STRING_TYPE) { jType = JavaType.Primitive.String; - // String literals value returned by getValue()/getText() has already processed sequences like "\\" -> "\" - int length = sourceLengthOfString(expression); // this is an attribute selector - if (source.startsWith("@" + value, cursor)) { - length += 1; + boolean attributeSelector = source.startsWith("@" + value, cursor); + int length = lengthAccordingToAst(expression); + Integer insideParenthesesLevel = getInsideParenthesesLevel(expression); + if (insideParenthesesLevel != null) { + length = length - insideParenthesesLevel * 2; } - text = source.substring(cursor, cursor + length); - int delimiterLength = 0; - if (text.startsWith("$/")) { - delimiterLength = 2; - } else if (text.startsWith("\"\"\"") || text.startsWith("'''")) { - delimiterLength = 3; - } else if (text.startsWith("/") || text.startsWith("\"") || text.startsWith("'")) { - delimiterLength = 1; + String valueAccordingToAST = source.substring(cursor, cursor + length + (attributeSelector ? 1 : 0)); + int delimiterLength = getDelimiterLength(); + if (StringUtils.containsWhitespace(valueAccordingToAST)) { + length = delimiterLength + expression.getValue().toString().length() + delimiterLength; + text = source.substring(cursor, cursor + length + (attributeSelector ? 1 : 0)); + } else { + text = valueAccordingToAST; } value = text.substring(delimiterLength, text.length() - delimiterLength); } else if (expression.isNullExpression()) { @@ -1574,8 +1583,8 @@ public void visitForLoop(ForStatement forLoop) { } else { Parameter param = forLoop.getVariable(); Space paramFmt = whitespace(); - TypeTree paramType = param.getOriginType().getColumnNumber() >= 0 ? - visitTypeTree(param.getOriginType()) : null; + List modifiers = getModifiers(); + TypeTree paramType = param.getOriginType().getColumnNumber() >= 0 ? visitTypeTree(param.getOriginType()) : null; JRightPadded paramName = JRightPadded.build( new J.VariableDeclarations.NamedVariable(randomId(), whitespace(), Markers.EMPTY, new J.Identifier(randomId(), EMPTY, Markers.EMPTY, emptyList(), param.getName(), null, null), @@ -1592,7 +1601,7 @@ public void visitForLoop(ForStatement forLoop) { } JRightPadded variable = JRightPadded.build(new J.VariableDeclarations(randomId(), paramFmt, - Markers.EMPTY, emptyList(), emptyList(), paramType, null, emptyList(), + Markers.EMPTY, emptyList(), modifiers, paramType, null, emptyList(), singletonList(paramName)) ).withAfter(rightPad); @@ -1690,15 +1699,18 @@ public void visitGStringExpression(GStringExpression gstring) { @Override public void visitListExpression(ListExpression list) { - if (list.getExpressions().isEmpty()) { - queue.add(new G.ListLiteral(randomId(), sourceBefore("["), Markers.EMPTY, - JContainer.build(singletonList(new JRightPadded<>(new J.Empty(randomId(), EMPTY, Markers.EMPTY), sourceBefore("]"), Markers.EMPTY))), - typeMapping.type(list.getType()))); - } else { - queue.add(new G.ListLiteral(randomId(), sourceBefore("["), Markers.EMPTY, - JContainer.build(visitRightPadded(list.getExpressions().toArray(new ASTNode[0]), "]")), - typeMapping.type(list.getType()))); - } + queue.add(insideParentheses(list, fmt -> { + skip("["); + if (list.getExpressions().isEmpty()) { + return new G.ListLiteral(randomId(), fmt, Markers.EMPTY, + JContainer.build(singletonList(new JRightPadded<>(new J.Empty(randomId(), EMPTY, Markers.EMPTY), sourceBefore("]"), Markers.EMPTY))), + typeMapping.type(list.getType())); + } else { + return new G.ListLiteral(randomId(), fmt, Markers.EMPTY, + JContainer.build(visitRightPadded(list.getExpressions().toArray(new ASTNode[0]), "]")), + typeMapping.type(list.getType())); + } + })); } @Override @@ -1713,17 +1725,19 @@ public void visitMapEntryExpression(MapEntryExpression expression) { @Override public void visitMapExpression(MapExpression map) { - Space prefix = sourceBefore("["); - JContainer entries; - if (map.getMapEntryExpressions().isEmpty()) { - entries = JContainer.build(Collections.singletonList(JRightPadded.build( - new G.MapEntry(randomId(), whitespace(), Markers.EMPTY, - JRightPadded.build(new J.Empty(randomId(), sourceBefore(":"), Markers.EMPTY)), - new J.Empty(randomId(), sourceBefore("]"), Markers.EMPTY), null)))); - } else { - entries = JContainer.build(visitRightPadded(map.getMapEntryExpressions().toArray(new ASTNode[0]), "]")); - } - queue.add(new G.MapLiteral(randomId(), prefix, Markers.EMPTY, entries, typeMapping.type(map.getType()))); + queue.add(insideParentheses(map, fmt -> { + skip("["); + JContainer entries; + if (map.getMapEntryExpressions().isEmpty()) { + entries = JContainer.build(Collections.singletonList(JRightPadded.build( + new G.MapEntry(randomId(), whitespace(), Markers.EMPTY, + JRightPadded.build(new J.Empty(randomId(), sourceBefore(":"), Markers.EMPTY)), + new J.Empty(randomId(), sourceBefore("]"), Markers.EMPTY), null)))); + } else { + entries = JContainer.build(visitRightPadded(map.getMapEntryExpressions().toArray(new ASTNode[0]), "]")); + } + return new G.MapLiteral(randomId(), fmt, Markers.EMPTY, entries, typeMapping.type(map.getType())); + })); } @Override @@ -1901,23 +1915,23 @@ public void visitStaticMethodCallExpression(StaticMethodCallExpression call) { @Override public void visitAttributeExpression(AttributeExpression attr) { - Space fmt = whitespace(); - Expression target = visit(attr.getObjectExpression()); - Space beforeDot = attr.isSafe() ? sourceBefore("?.") : - sourceBefore(attr.isSpreadSafe() ? "*." : "."); - J name = visit(attr.getProperty()); - if (name instanceof J.Literal) { - String nameStr = ((J.Literal) name).getValueSource(); - assert nameStr != null; - name = new J.Identifier(randomId(), name.getPrefix(), Markers.EMPTY, emptyList(), nameStr, null, null); - } - if (attr.isSpreadSafe()) { - name = name.withMarkers(name.getMarkers().add(new StarDot(randomId()))); - } - if (attr.isSafe()) { - name = name.withMarkers(name.getMarkers().add(new NullSafe(randomId()))); - } - queue.add(new J.FieldAccess(randomId(), fmt, Markers.EMPTY, target, padLeft(beforeDot, (J.Identifier) name), null)); + queue.add(insideParentheses(attr, fmt -> { + Expression target = visit(attr.getObjectExpression()); + Space beforeDot = attr.isSafe() ? sourceBefore("?.") : sourceBefore(attr.isSpreadSafe() ? "*." : "."); + J name = visit(attr.getProperty()); + if (name instanceof J.Literal) { + String nameStr = ((J.Literal) name).getValueSource(); + assert nameStr != null; + name = new J.Identifier(randomId(), name.getPrefix(), Markers.EMPTY, emptyList(), nameStr, null, null); + } + if (attr.isSpreadSafe()) { + name = name.withMarkers(name.getMarkers().add(new StarDot(randomId()))); + } + if (attr.isSafe()) { + name = name.withMarkers(name.getMarkers().add(new NullSafe(randomId()))); + } + return new J.FieldAccess(randomId(), fmt, Markers.EMPTY, target, padLeft(beforeDot, (J.Identifier) name), null); + })); } @Override @@ -2453,7 +2467,7 @@ private TypeTree arrayType(ClassNode classNode) { } Space prefix = whitespace(); TypeTree elemType = typeTree(typeTree); - JLeftPadded dimension = padLeft(sourceBefore("["), sourceBefore("]")); + JLeftPadded dimension = hasVarargs() ? null : padLeft(sourceBefore("["), sourceBefore("]")); return new J.ArrayType(randomId(), prefix, Markers.EMPTY, count == 1 ? elemType : mapDimensions(elemType, classNode.getComponentType()), null, @@ -2478,6 +2492,10 @@ private TypeTree mapDimensions(TypeTree baseType, ClassNode classNode) { return baseType; } + private boolean hasVarargs() { + return source.startsWith("...", indexOfNextNonWhitespace(cursor, source)); + } + /** * Get all characters of the source file between the cursor and the given delimiter. * The cursor will be moved past the delimiter. @@ -2498,39 +2516,54 @@ private Space sourceBefore(String untilDelim) { return space; } - /** - * Gets the length in characters of a String literal. - * Attempts to account for a number of different strange compiler behaviors, old bugs, and edge cases. - * cursor is presumed to point at the beginning of the node. - */ - private int sourceLengthOfString(ConstantExpression expr) { - // ConstantExpression.getValue() already has resolved escaped characters. So "\t" and a literal tab will look the same. - // Since we cannot differentiate between the two, use this alternate method only when an old version of groovy indicates risk - // and the literal doesn't contain any characters which might be from an escape sequence. e.g.: tabs, newlines, carriage returns - String value = (String) expr.getValue(); - if (isOlderThanGroovy3() && value.matches("[^\\t\\r\\n\\\\]*")) { - int delimiterLength = getDelimiterLength(); - return delimiterLength + value.length() + delimiterLength; - } - int lengthAccordingToAst = lengthAccordingToAst(expr); - // subtract any parentheses that were included with lengthAccordingToAst - Integer insideParenthesesLevel = getInsideParenthesesLevel(expr); - if (insideParenthesesLevel != null) { - return lengthAccordingToAst - insideParenthesesLevel * 2; - } - - return lengthAccordingToAst; - } - - private static @Nullable Integer getInsideParenthesesLevel(ASTNode node) { + private @Nullable Integer getInsideParenthesesLevel(ASTNode node) { Object rawIpl = node.getNodeMetaData("_INSIDE_PARENTHESES_LEVEL"); if (rawIpl instanceof AtomicInteger) { // On Java 11 and newer _INSIDE_PARENTHESES_LEVEL is an AtomicInteger return ((AtomicInteger) rawIpl).get(); - } else { + } else if (rawIpl instanceof Integer) { // On Java 8 _INSIDE_PARENTHESES_LEVEL is a regular Integer return (Integer) rawIpl; + } else if (node instanceof MethodCallExpression) { + MethodCallExpression expr = (MethodCallExpression) node; + return determineParenthesisLevel(expr.getObjectExpression().getLineNumber(), expr.getLineNumber(), expr.getObjectExpression().getColumnNumber(), expr.getColumnNumber()); + } else if (node instanceof BinaryExpression) { + BinaryExpression expr = (BinaryExpression) node; + return determineParenthesisLevel(expr.getLeftExpression().getLineNumber(), expr.getLineNumber(), expr.getLeftExpression().getColumnNumber(), expr.getColumnNumber()); + } + return null; + } + + /** + * @param childLineNumber the beginning line number of the first sub node + * @param parentLineNumber the beginning line number of the parent node + * @param childColumn the column on the {@code childLineNumber} line where the sub node starts + * @param parentColumn the column on the {@code parentLineNumber} line where the parent node starts + * @return the level of parenthesis parsed from the source + */ + private int determineParenthesisLevel(int childLineNumber, int parentLineNumber, int childColumn, int parentColumn) { + int saveCursor = cursor; + whitespace(); + int childBeginCursor = cursor; + if (childLineNumber > parentLineNumber) { + for (int i = 0; i < (childColumn - parentLineNumber); i++) { + childBeginCursor = source.indexOf('\n', childBeginCursor); + } + childBeginCursor += childColumn; + } else { + childBeginCursor += childColumn - parentColumn; } + int count = 0; + for (int i = cursor; i < childBeginCursor; i++) { + if (source.charAt(i) == '(') { + count++; + } + if (source.charAt(i) == ')') { + count--; + } + } + cursor = saveCursor; + return Math.max(count, 0); } private int getDelimiterLength() { @@ -2683,7 +2716,8 @@ private String name() { int i = cursor; for (; i < source.length(); i++) { char c = source.charAt(i); - if (!(Character.isJavaIdentifierPart(c) || c == '.' || c == '*')) { + boolean isVarargs = source.length() > (i + 2) && c == '.' && source.charAt(i + 1) == '.' && source.charAt(i + 2) == '.'; + if (!(Character.isJavaIdentifierPart(c) || c == '.' || c == '*') || isVarargs) { break; } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java index bfbadb76655..2b7d4c82756 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AttributeTest.java @@ -20,19 +20,26 @@ import static org.openrewrite.groovy.Assertions.groovy; -@SuppressWarnings({"GroovyUnusedAssignment", "GrUnnecessarySemicolon"}) class AttributeTest implements RewriteTest { @Test - void usingGroovyNode() { + void attribute() { rewriteRun( - groovy( - """ - def xml = new Node(null, "ivy") - def n = xml.dependencies.dependency.find { it.@name == 'test-module' } - n.@conf = 'runtime->default;docs->docs;sources->sources' - """ - ) + groovy("new User('Bob').@name") + ); + } + + @Test + void attributeInClosure() { + rewriteRun( + groovy("[new User('Bob')].collect { it.@name }") + ); + } + + @Test + void attributeWithParentheses() { + rewriteRun( + groovy("(new User('Bob').@name)") ); } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java index 13239c0fc76..1f9b86eba7b 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java @@ -15,8 +15,8 @@ */ package org.openrewrite.groovy.tree; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -34,6 +34,7 @@ void insideParentheses() { // NOT inside parentheses, but verifies the parser's // test for "inside parentheses" condition + groovy("( 1 ) + 1"), groovy("(1) + 1"), // And combine the two cases groovy("((1) + 1)") @@ -77,6 +78,19 @@ def foo(int a) { ); } + @Test + @ExpectedToFail("Pattern operator is not yet supported") // https://groovy-lang.org/operators.html#_pattern_operator + void regexPatternOperator() { + rewriteRun( + groovy( + """ + def PATTERN = ~/foo/ + def result = PATTERN.matcher('4711').matches() + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/1531") @Test void regexFindOperator() { @@ -216,6 +230,35 @@ void stringMultipliedInParentheses() { ); } + @Issue("https://github.com/openrewrite/rewrite/issues/4703") + @Test + void cxds() { + rewriteRun( + groovy( + """ + def differenceInDays(int time) { + return (int) ((time)/(1000*60*60*24)) + } + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite/issues/4703") + @Test + void extraParensAroundInfixOxxxperator() { + rewriteRun( + groovy( + """ + def timestamp(int hours, int minutes, int seconds) { + 30 * (hours) + (((((hours))))) * 30 + } + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/4703") @Test void extraParensAroundInfixOperator() { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java index 5cf82ae85be..4c009de95e3 100755 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/CastTest.java @@ -16,7 +16,6 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -25,6 +24,18 @@ @SuppressWarnings({"UnnecessaryQualifiedReference", "GroovyUnusedAssignment", "GrUnnecessarySemicolon"}) class CastTest implements RewriteTest { + @Test + void cast() { + rewriteRun( + groovy( + """ + String foo = ( String ) "hallo" + String bar = "hallo" as String + """ + ) + ); + } + @Test void javaStyleCast() { rewriteRun( @@ -74,14 +85,13 @@ void groovyCastAndInvokeMethod() { rewriteRun( groovy( """ - ( "" as String ).toString() + ( "x" as String ).toString() """ ) ); } @Test - @ExpectedToFail("Parentheses with method invocation is not yet supported") void groovyCastAndInvokeMethodWithParentheses() { rewriteRun( groovy( @@ -103,7 +113,6 @@ void javaCastAndInvokeMethod() { ); } - @ExpectedToFail("Parentheses with method invocation is not yet supported") @Test void javaCastAndInvokeMethodWithParentheses() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java index 99d937b3168..b478a9211ca 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; @@ -339,4 +340,53 @@ class RewriteSettings extends groovy.lang.Script { ) ); } + + @Test + void useClassAsArgument() { + rewriteRun( + groovy( + """ + class A {} + + def test(Class clazz) {} + + test(A) + """ + ) + ); + } + + @Test + @ExpectedToFail("Java style class argument is not yet supported") // https://groovy-lang.org/style-guide.html#_classes_as_first_class_citizens + void useClassAsArgumentJavaStyle() { + rewriteRun( + groovy( + """ + class A {} + + def test(Class clazz) {} + + test(A.class) + """ + ) + ); + } + + @Test + @ExpectedToFail("Anonymous inner class is not yet supported") // https://groovy-lang.org/objectorientation.html#_anonymous_inner_class + void anonymousInnerClass() { + rewriteRun( + groovy( + """ + interface Something {} + + class Test { + static def test() { + new Something() {} + } + } + """ + ) + ); + } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ForLoopTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ForLoopTest.java index a1432f73256..afb2445f900 100755 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ForLoopTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ForLoopTest.java @@ -162,6 +162,17 @@ void multiVariableInitialization() { @Test void forEachWithColon() { + rewriteRun( + groovy( + """ + for(def i : [1, 2, 3]) {} + """ + ) + ); + } + + @Test + void forEachTypedWithColon() { rewriteRun( groovy( """ @@ -176,9 +187,7 @@ void forIn() { rewriteRun( groovy( """ - def dependenciesType = ['implementation', 'testImplementation'] - for (type in dependenciesType) { - } + for (type in ['implementation', 'testImplementation']) {} """ ) ); diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java index b42f9579fd4..d921377b661 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ListTest.java @@ -23,6 +23,29 @@ @SuppressWarnings("GroovyUnusedAssignment") class ListTest implements RewriteTest { + @Test + void emptyListLiteral() { + rewriteRun( + groovy( + """ + def a = [] + def b = [ ] + """ + ) + ); + } + + @Test + void emptyListLiteralWithParentheses() { + rewriteRun( + groovy( + """ + def y = ([]) + """ + ) + ); + } + @Test void listLiteral() { rewriteRun( @@ -33,4 +56,15 @@ void listLiteral() { ) ); } + + @Test + void listLiteralTrailingComma() { + rewriteRun( + groovy( + """ + def a = [ "foo" /* "foo" suffix */ , /* "]" prefix */ ] + """ + ) + ); + } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java index 46851b2f65a..12d638870d4 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java @@ -216,18 +216,6 @@ void literalValueAndTypeAgree() { ); } - @Test - void emptyListLiteral() { - rewriteRun( - groovy( - """ - def a = [] - def b = [ ] - """ - ) - ); - } - @Test void multilineStringWithApostrophes() { rewriteRun( @@ -254,17 +242,6 @@ void mapLiteralTrailingComma() { ); } - @Test - void listLiteralTrailingComma() { - rewriteRun( - groovy( - """ - def a = [ "foo" /* "foo" suffix */ , /* "]" prefix */ ] - """ - ) - ); - } - @Test void gStringThatHasEmptyValueExpressionForUnknownReason() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java index 65bb4a17492..67ee80177cd 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MapEntryTest.java @@ -55,6 +55,13 @@ void emptyMapLiteral() { ); } + @Test + void emptyMapLiteralWithParentheses() { + rewriteRun( + groovy("Map m = ([ : ])") + ); + } + @Test void mapAccess() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java index ff2bf380095..3129c933afa 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java @@ -110,6 +110,19 @@ def foo(bar, baz) { ); } + @Test + void varargsArguments() { + rewriteRun( + groovy( + """ + def foo(String... messages) { + println(messages[0]) + } + """ + ) + ); + } + @Test void defaultArgumentValues() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java index a0714126901..86208e4943f 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java @@ -16,7 +16,6 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -31,11 +30,11 @@ void gradle() { plugins { id 'java-library' } - + repositories { mavenCentral() } - + dependencies { implementation 'org.hibernate:hibernate-core:3.6.7.Final' api 'com.google.guava:guava:23.0' @@ -46,7 +45,6 @@ void gradle() { ); } - @ExpectedToFail("Parentheses with method invocation is not yet supported") @Test @Issue("https://github.com/openrewrite/rewrite/issues/4615") void gradleWithParentheses() { @@ -193,6 +191,22 @@ def acceptsClosure(Closure cl) {} ); } + @Test + void closureInObjectInObject() { + rewriteRun( + groovy( + """ + class Test { + Test child = new Test() + def acceptsClosure(Closure cl) {} + } + + new Test().child.acceptsClosure {} + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/4766") @Test void gradleFileWithMultipleClosuresWithoutParentheses() { @@ -349,7 +363,7 @@ class StringUtils { static boolean isEmpty(String value) { return value == null || value.isEmpty() } - + static void main(String[] args) { isEmpty("") } @@ -359,7 +373,29 @@ static void main(String[] args) { ); } - @ExpectedToFail("Parentheses with method invocation is not yet supported") + @Issue("https://github.com/openrewrite/rewrite/issues/4703") + @Test + void insideParenthesesSimple() { + rewriteRun( + groovy( + """ + ((a.invoke "b" )) + """ + ) + ); + } + + @Test + void lotOfSpacesAroundConstantWithParentheses() { + rewriteRun( + groovy( + """ + ( ( ( "x" ) ).toString() ) + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/4703") @Test void insideParentheses() { @@ -375,7 +411,21 @@ static def foo(Map map) { ); } - @ExpectedToFail("Parentheses with method invocation is not yet supported") + @Test + void insideParenthesesWithNewline() { + rewriteRun( + groovy( + """ + static def foo(Map map) { + (( + map.containsKey("foo")) + && ((map.get("foo")).equals("bar"))) + } + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/4703") @Test void insideParenthesesWithoutNewLineAndEscapedMethodName() { @@ -387,4 +437,17 @@ static def foo(Map someMap) {((((((someMap.get("(bar")))) ).'equals' "baz" ) ) ) ); } + + @Test + void insideFourParenthesesAndEnters() { + rewriteRun( + groovy( + """ + (((( + something(a) + )))) + """ + ) + ); + } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java index ac839e34d88..e0ff32f3d94 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RangeTest.java @@ -16,7 +16,6 @@ package org.openrewrite.groovy.tree; import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.test.RewriteTest; import static org.openrewrite.groovy.Assertions.groovy; @@ -48,7 +47,6 @@ void parenthesized() { ); } - @ExpectedToFail("Parentheses with method invocation is not yet supported") @Test void parenthesizedAndInvokeMethodWithParentheses() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java new file mode 100644 index 00000000000..9277e585f68 --- /dev/null +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java @@ -0,0 +1,422 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.groovy.tree; + +import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ExpectedToFail; +import org.openrewrite.Issue; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.groovy.Assertions.groovy; + +/** + * A test with groovy examples picked from OSS repositories. + */ +class RealWorldGroovyTest implements RewriteTest { + + @Test + @ExpectedToFail("Pattern operator is not yet supported") // https://groovy-lang.org/operators.html#_pattern_operator + @Issue("https://github.com/spring-projects/spring-boot/blob/v3.4.1/settings.gradle") + void springBootSettingsGradle() { + rewriteRun( + groovy( + """ + pluginManagement { + evaluate(new File("${rootDir}/buildSrc/SpringRepositorySupport.groovy")).apply(this) + repositories { + mavenCentral() + gradlePluginPortal() + spring.mavenRepositories(); + } + resolutionStrategy { + eachPlugin { + if (requested.id.id == "org.jetbrains.kotlin.jvm") { + useVersion "${kotlinVersion}" + } + if (requested.id.id == "org.jetbrains.kotlin.plugin.spring") { + useVersion "${kotlinVersion}" + } + } + } + } + + plugins { + id "io.spring.develocity.conventions" version "0.0.22" + } + + rootProject.name="spring-boot-build" + + enableFeaturePreview("STABLE_CONFIGURATION_CACHE") + + settings.gradle.projectsLoaded { + develocity { + buildScan { + def toolchainVersion = settings.gradle.rootProject.findProperty('toolchainVersion') + if (toolchainVersion != null) { + value('Toolchain version', toolchainVersion) + tag("JDK-$toolchainVersion") + } + } + } + } + + include "spring-boot-system-tests:spring-boot-image-tests" + + file("${rootDir}/spring-boot-project/spring-boot-starters").eachDirMatch(~/spring-boot-starter.*/) { + include "spring-boot-project:spring-boot-starters:${it.name}" + } + + file("${rootDir}/spring-boot-tests/spring-boot-smoke-tests").eachDirMatch(~/spring-boot-smoke-test.*/) { + include "spring-boot-tests:spring-boot-smoke-tests:${it.name}" + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/spring-projects/spring-boot/blob/v3.4.1/spring-boot-project/spring-boot-tools/spring-boot-cli/src/test/resources/classloader-test-app.groovy") + void springBootClassloaderTestApp() { + rewriteRun( + groovy( + """ + import org.springframework.util.* + + @Component + public class Test implements CommandLineRunner { + + public void run(String... args) throws Exception { + println "HasClasses-" + ClassUtils.isPresent("missing", null) + "-" + + ClassUtils.isPresent("org.springframework.boot.SpringApplication", null) + "-" + + ClassUtils.isPresent(args[0], null) + } + + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/spring-projects/spring-ldap/blob/v3.4.1/buildSrc/src/main/groovy/io/spring/gradle/convention/JavadocOptionsPlugin.groovy") + void springLdapJavadocOptionsPlugin() { + rewriteRun( + groovy( + """ + import org.gradle.api.Plugin + import org.gradle.api.Project + import org.gradle.api.tasks.javadoc.Javadoc + + public class JavadocOptionsPlugin implements Plugin { + + @Override + public void apply(Project project) { + project.getTasks().withType(Javadoc).all { t-> + t.options.addStringOption('Xdoclint:none', '-quiet') + } + } + } + """ + ) + ); + } + + @Test + @ExpectedToFail("Anonymous inner class is not yet supported") // https://groovy-lang.org/objectorientation.html#_anonymous_inner_class + @Issue("https://github.com/spring-projects/spring-ldap/blob/v3.4.1/buildSrc/src/test/resources/samples/integrationtest/withgroovy/src/integration-test/groovy/sample/TheTest.groovy") + void springLdapTheTest() { + rewriteRun( + groovy( + """ + import org.springframework.core.Ordered + import spock.lang.Specification + + class TheTest extends Specification { + def "has Ordered"() { + expect: 'Loads Ordered fine' + Ordered ordered = new Ordered() { + @Override + int getOrder() { + return 0 + } + } + } + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/spring-projects/spring-session-data-geode/blob/v3.4.1/buildSrc/src/main/groovy/io/spring/gradle/convention/SchemaZipPlugin.groovy") + void springTestDataGeodeSchemaZipPlugin() { + rewriteRun( + groovy( + """ + import org.gradle.api.Plugin + import org.gradle.api.Project + import org.gradle.api.file.DuplicatesStrategy + import org.gradle.api.plugins.JavaPlugin + import org.gradle.api.tasks.bundling.Zip + + /** + * Zips all Spring XML schemas (XSD) files. + * + * @author Rob Winch + * @author John Blum + * @see org.gradle.api.Plugin + * @see org.gradle.api.Project + */ + class SchemaZipPlugin implements Plugin { + + @Override + void apply(Project project) { + + Zip schemaZip = project.tasks.create('schemaZip', Zip) + + schemaZip.archiveBaseName = project.rootProject.name + schemaZip.archiveClassifier = 'schema' + schemaZip.description = "Builds -${schemaZip.archiveClassifier} archive containing all XSDs" + + " for deployment to static.springframework.org/schema." + schemaZip.group = 'Distribution' + + project.rootProject.subprojects.each { module -> + + module.getPlugins().withType(JavaPlugin).all { + + Properties schemas = new Properties(); + + module.sourceSets.main.resources + .find { it.path.endsWith('META-INF/spring.schemas') } + ?.withInputStream { schemas.load(it) } + + for (def key : schemas.keySet()) { + + def zipEntryName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1') + + assert zipEntryName != key + + File xsdFile = module.sourceSets.main.resources.find { + it.path.endsWith(schemas.get(key)) + } + + assert xsdFile != null + + schemaZip.into(zipEntryName) { + duplicatesStrategy DuplicatesStrategy.EXCLUDE + from xsdFile.path + } + } + } + } + } + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/spring-projects/spring-webflow/blob/v3.4.1/gradle/docs.gradle") + void springWebflowGradleDocs() { + rewriteRun( + groovy( + """ + apply plugin: "maven-publish" + + configurations { + asciidoctorExtensions + } + + dependencies { + asciidoctorExtensions "io.spring.asciidoctor.backends:spring-asciidoctor-backends:0.0.7" + } + + asciidoctorPdf { + baseDirFollowsSourceFile() + asciidoctorj { + sources { + include 'index.adoc' + } + options doctype: 'book' + attributes 'icons': 'font', + 'sectanchors': '', + 'sectnums': '', + 'toc': '', + 'source-highlighter' : 'coderay', + revnumber: project.version, + 'project-version': project.version + } + } + + asciidoctor { + baseDirFollowsSourceFile() + configurations "asciidoctorExtensions" + outputOptions { + backends "spring-html" + } + sources { + include 'index.adoc' + } + options doctype: 'book' + + attributes 'docinfo': 'shared', + stylesdir: 'css/', + stylesheet: 'spring.css', + 'linkcss': true, + 'icons': 'font', + 'sectanchors': '', + 'source-highlighter': 'highlight.js', + 'highlightjsdir': 'js/highlight', + 'highlightjs-theme': 'github', + 'idprefix': '', + 'idseparator': '-', + 'spring-version': project.version, + 'allow-uri-read': '', + 'toc': 'left', + 'toclevels': '4', + revnumber: project.version, + 'project-version': project.version + } + + task api(type: Javadoc) { + group = "Documentation" + description = "Generates aggregated Javadoc API documentation." + title = "${rootProject.description} ${version} API" + options.memberLevel = JavadocMemberLevel.PROTECTED + options.author = true + options.header = rootProject.description + options.overview = "src/api/overview.html" + source subprojects.collect { project -> + project.sourceSets.main.allJava + } + destinationDir = new File(buildDir, "api") + classpath = files(subprojects.collect { project -> + project.sourceSets.main.compileClasspath + }) + maxMemory = "1024m" + } + + task docsZip(type: Zip) { + group = "Distribution" + archiveBaseName = "spring-webflow" + archiveClassifier = "docs" + description = "Builds -${archiveClassifier.get()} archive containing api and reference " + + "for deployment at static.springframework.org/spring-webflow/docs." + + from (api) { + into "api" + } + from (asciidoctor) { + into "reference" + } + from (asciidoctorPdf) { + into "reference" + } + } + + task schemaZip(type: Zip) { + group = "Distribution" + archiveBaseName = "spring-webflow" + archiveClassifier = "schema" + description = "Builds -${archiveClassifier.get()} archive containing all " + + "XSDs for deployment at static.springframework.org/schema." + + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + subprojects.each { subproject -> + Properties schemas = new Properties() + + subproject.sourceSets.main.resources.find { + it.path.endsWith("META-INF/spring.schemas") + }?.withInputStream { schemas.load(it) } + + for (def key : schemas.keySet()) { + def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1') + assert shortName != key + File xsdFile = subproject.sourceSets.main.allSource.find { + it.path.endsWith(schemas.get(key)) + } as File + assert xsdFile != null + into (shortName) { + from xsdFile.path + } + } + } + + project(":spring-webflow").sourceSets.main.resources.matching { + include '**/engine/model/builder/xml/*.xsd' + }.each { File file -> + into ('webflow') { + from file.path + } + } + } + + task distZip(type: Zip, dependsOn: [docsZip, schemaZip]) { + group = "Distribution" + archiveBaseName = "spring-webflow" + archiveClassifier = "dist" + description = "Builds -${archiveClassifier.get()} archive, containing all jars and docs, " + + "suitable for community download page." + + def baseDir = "${archiveBaseName.get()}-${project.version}" + + from("src/dist") { + include "notice.txt" + into "${baseDir}" + expand(copyright: new Date().format("yyyy"), version: project.version) + } + from("src/dist") { + include "readme.txt" + include "license.txt" + into "${baseDir}" + expand(version: project.version) + } + from(zipTree(docsZip.archiveFile)) { + into "${baseDir}/docs" + } + from(zipTree(schemaZip.archiveFile)) { + into "${baseDir}/schema" + } + + subprojects.each { subproject -> + into ("${baseDir}/libs") { + from subproject.jar + if (subproject.tasks.findByPath("sourcesJar")) { + from subproject.sourcesJar + } + if (subproject.tasks.findByPath("javadocJar")) { + from subproject.javadocJar + } + } + } + } + + publishing { + publications { + mavenJava(MavenPublication) { + artifact docsZip + artifact schemaZip + artifact distZip + } + } + } + """ + ) + ); + } +} From 2b8cdd0728c82d6437d9bd92b139d9e56c79351d Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Tue, 31 Dec 2024 12:12:56 +0100 Subject: [PATCH 084/179] Groovy parsers should be able to support `.class` (#4824) * Support `.class` as part of the ClassExpression * Support `.class` as part of the ClassExpression --- .../groovy/GroovyParserVisitor.java | 7 ++++- .../groovy/tree/AssignmentTest.java | 22 +++++++++++++ .../groovy/tree/ClassDeclarationTest.java | 31 ------------------- .../groovy/tree/MethodInvocationTest.java | 22 +++++++++++++ .../groovy/tree/RealWorldGroovyTest.java | 2 +- 5 files changed, 51 insertions(+), 33 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 0090130158b..598dd66f579 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -915,9 +915,14 @@ public boolean endsWithClosures(List li @Override public void visitClassExpression(ClassExpression clazz) { String unresolvedName = clazz.getType().getUnresolvedName().replace('$', '.'); + Space space = sourceBefore(unresolvedName); + if (source.substring(cursor).startsWith(".class")) { + unresolvedName += ".class"; + cursor += 6; + } queue.add(TypeTree.build(unresolvedName) .withType(typeMapping.type(clazz.getType())) - .withPrefix(sourceBefore(unresolvedName))); + .withPrefix(space)); } @Override diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java index e1421259a9d..3ccac493084 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java @@ -85,6 +85,28 @@ void assignment() { ); } + @Test + void classAssignment() { + rewriteRun( + groovy( + """ + def s = String + """ + ) + ); + } + + @Test + void classAssignmentJavaStyle() { + rewriteRun( + groovy( + """ + def s = String.class + """ + ) + ); + } + @Test void unaryMinus() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java index b478a9211ca..e3acb1f3d33 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java @@ -341,37 +341,6 @@ class RewriteSettings extends groovy.lang.Script { ); } - @Test - void useClassAsArgument() { - rewriteRun( - groovy( - """ - class A {} - - def test(Class clazz) {} - - test(A) - """ - ) - ); - } - - @Test - @ExpectedToFail("Java style class argument is not yet supported") // https://groovy-lang.org/style-guide.html#_classes_as_first_class_citizens - void useClassAsArgumentJavaStyle() { - rewriteRun( - groovy( - """ - class A {} - - def test(Class clazz) {} - - test(A.class) - """ - ) - ); - } - @Test @ExpectedToFail("Anonymous inner class is not yet supported") // https://groovy-lang.org/objectorientation.html#_anonymous_inner_class void anonymousInnerClass() { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java index 86208e4943f..31531c0d6ab 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java @@ -176,6 +176,28 @@ def acceptsNamedArguments(Map a, int n, int m) { } ); } + @Test + void useClassAsArgument() { + rewriteRun( + groovy( + """ + foo(String) + """ + ) + ); + } + + @Test + void useClassAsArgumentJavaStyle() { + rewriteRun( + groovy( + """ + foo(String.class) + """ + ) + ); + } + @Test @SuppressWarnings("GroovyAssignabilityCheck") void closureWithImplicitParameter() { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java index 9277e585f68..ea9da82cd73 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java @@ -195,7 +195,7 @@ void apply(Project project) { project.rootProject.subprojects.each { module -> - module.getPlugins().withType(JavaPlugin).all { + module.getPlugins().withType(JavaPlugin.class).all { Properties schemas = new Properties(); From 000a4f0832d05bf8191405277e7f3666a6673be5 Mon Sep 17 00:00:00 2001 From: Niels de Bruin Date: Tue, 31 Dec 2024 12:13:20 +0100 Subject: [PATCH 085/179] `AddAnnotationProcessor` should compare and update versions using a property (#4822) * Add test to reproduce issue with annotation processors * Add a second test and looking any variable version * Update version tag if possible --------- Co-authored-by: Tim te Beek --- .../maven/AddAnnotationProcessor.java | 36 ++++-- .../maven/AddAnnotationProcessorTest.java | 107 ++++++++++++++++++ 2 files changed, 132 insertions(+), 11 deletions(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/AddAnnotationProcessor.java b/rewrite-maven/src/main/java/org/openrewrite/maven/AddAnnotationProcessor.java index fbc2644eb39..6bcac007942 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/AddAnnotationProcessor.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/AddAnnotationProcessor.java @@ -28,6 +28,7 @@ import org.openrewrite.xml.tree.Xml; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import static org.openrewrite.maven.trait.Traits.mavenPlugin; @@ -49,7 +50,7 @@ public class AddAnnotationProcessor extends Recipe { @Option(displayName = "Version", description = "The third part of a coordinate 'org.projectlombok:lombok-mapstruct-binding:0.2.0' of the processor to add. " + - "Note that an exact version is expected", + "Note that an exact version is expected", example = "0.2.0") String version; @@ -61,8 +62,8 @@ public String getDisplayName() { @Override public String getDescription() { return "Add an annotation processor to the maven compiler plugin. Will not do anything if it already exists. " + - "Also doesn't add anything when no other annotation processors are defined yet. " + - "(Perhaps `ChangePluginConfiguration` can be used)."; + "Also doesn't add anything when no other annotation processors are defined yet. " + + "(Perhaps `ChangePluginConfiguration` can be used)."; } @Override @@ -73,8 +74,9 @@ public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) { Xml.Tag plugins = (Xml.Tag) super.visitTag(tag, ctx); plugins = (Xml.Tag) mavenPlugin().asVisitor(plugin -> { if (MAVEN_COMPILER_PLUGIN_GROUP_ID.equals(plugin.getGroupId()) && - MAVEN_COMPILER_PLUGIN_ARTIFACT_ID.equals(plugin.getArtifactId())) { - return new XmlIsoVisitor() { + MAVEN_COMPILER_PLUGIN_ARTIFACT_ID.equals(plugin.getArtifactId())) { + AtomicReference> afterVisitor = new AtomicReference<>(); + Xml.Tag modifiedPlugin = new XmlIsoVisitor() { @Override public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { Xml.Tag tg = super.visitTag(tag, ctx); @@ -82,14 +84,22 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { for (int i = 0; i < tg.getChildren().size(); i++) { Xml.Tag child = tg.getChildren().get(i); if (groupId.equals(child.getChildValue("groupId").orElse(null)) && - artifactId.equals(child.getChildValue("artifactId").orElse(null))) { + artifactId.equals(child.getChildValue("artifactId").orElse(null))) { if (!version.equals(child.getChildValue("version").orElse(null))) { String oldVersion = child.getChildValue("version").orElse(""); - VersionComparator comparator = Semver.validate(oldVersion, null).getValue(); - if (comparator.compare(version, oldVersion) > 0) { - List tags = tg.getChildren(); - tags.set(i, child.withChildValue("version", version)); - return tg.withContent(tags); + boolean oldVersionUsesProperty = oldVersion.startsWith("${"); + String lookupVersion = oldVersionUsesProperty ? + getResolutionResult().getPom().getValue(oldVersion.trim()) : + oldVersion; + VersionComparator comparator = Semver.validate(lookupVersion, null).getValue(); + if (comparator.compare(version, lookupVersion) > 0) { + if (oldVersionUsesProperty) { + afterVisitor.set(new ChangePropertyValue(oldVersion, version, null, null).getVisitor()); + } else { + List tags = tg.getChildren(); + tags.set(i, child.withChildValue("version", version)); + return tg.withContent(tags); + } } } return tg; @@ -102,6 +112,10 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { return tg; } }.visitTag(plugin.getTree(), ctx); + if (afterVisitor.get() != null) { + doAfterVisit(afterVisitor.get()); + } + return modifiedPlugin; } return plugin.getTree(); }).visitNonNull(plugins, 0); diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/AddAnnotationProcessorTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/AddAnnotationProcessorTest.java index b164cb28f98..851e394da5d 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/AddAnnotationProcessorTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/AddAnnotationProcessorTest.java @@ -178,4 +178,111 @@ void shouldUpdateProcessorVersionAlreadyPresent() { ) ); } + + @Test + void addAnnotationWithOlderVersionAsMavenProperty() { + rewriteRun( + spec -> spec.recipe(new AddAnnotationProcessor( + "org.projectlombok", + "lombok-mapstruct-binding", + "0.2.0" + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 0.1.0 + + + + + maven-compiler-plugin + + + + org.projectlombok + lombok-mapstruct-binding + ${version.lombok.mapstruct.binding} + + + + + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 0.2.0 + + + + + maven-compiler-plugin + + + + org.projectlombok + lombok-mapstruct-binding + ${version.lombok.mapstruct.binding} + + + + + + + + """ + ) + ); + } + + @Test + void addAnnotationWithSameVersionAsMavenProperty() { + rewriteRun( + spec -> spec.recipe(new AddAnnotationProcessor( + "org.projectlombok", + "lombok-mapstruct-binding", + "0.2.0" + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + 0.2.0 + + + + + maven-compiler-plugin + + + + org.projectlombok + lombok-mapstruct-binding + ${version.lombok.mapstruct.binding} + + + + + + + + """ + ) + ); + } } From 2a8bf2d7d3bad4f90b668e0304f10c68b159bbd6 Mon Sep 17 00:00:00 2001 From: Anshuman Mishra <119983081+amishra-u@users.noreply.github.com> Date: Tue, 31 Dec 2024 03:49:21 -0800 Subject: [PATCH 086/179] Add lombok support for java-11 (#4769) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add lombok support for java-11 * Handle erroneous nodes in open rewrite (#4412) * Handle erroneous nodes in a tree * Add visitErroneous to all java parser visitors * Override the visitVariable to handle erroneous identifier names set by JavacParser * retain name and suffix for erroneous varDecl * override the visitVariable to handle error identifiers in all java parser visitors * Remove sysout * Update rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * handle errors in method params, variable declarations, fix tests * Add missing license headers * fix compilation error * fix compilation error in Java8ParserVisitor * Apply code suggestions from bot * fix cases for statementDelim * fix block statement template generator to handle adding semicolon * fix ChangeStaticFieldToMethod recipe * Record compiler errors from erroneous LST nodes * Adjustments for comments * Java 17 parser adjustment alos in 8, 11 and 21 * Add `FindCompileErrorsTest` & move away from deprecated `print()` --------- Co-authored-by: Jonathan Schnéider Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tim te Beek Co-authored-by: aboyko * Make Groovy Parser correctly handle nested parenthesis (#4801) * WIP * Format * Format * Move grabbing of whitespace and resetting cursor to where it is actually required * Extra check is not required * Use toString * Add `emptyListLiteralWithParentheses` test * Add `insideFourParenthesesAndEnters` test * Move list tests all to ListTest * Add `emptyMapLiteralWithParentheses` * Review feedback and fix new testcases * Add `attributeWithParentheses` * Improve AttributeTest * Improve AttributeTest * Improve AttributeTest * Improve AttributeTest * Improve AttributeTest * Review fix new testcases * Revert edit to testcase * Add and fix testcase with newline * Add JavaDoc and move logic regarding whitespace and resetting cursor --------- Co-authored-by: lingenj * suppress javax.json (#4804) * suppress javax.json * Update suppressions.xml * Refactor SpringReference (#4805) * Separating and clearer naming * Add license header * Review feedback * refactor: Update Gradle wrapper (#4808) Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.gradle.UpdateGradleWrapper?organizationId=T3BlblJld3JpdGU%3D#defaults=W3sibmFtZSI6ImFkZElmTWlzc2luZyIsInZhbHVlIjoiRmFsc2UifV0= Co-authored-by: Moderne * Add recipe to remove Gradle Enterprise and Develocity (#4809) * Add recipe to remove Gradle Enterprise and Develocity * Remove left over java plugin * Add a UsesType precondition to ReplaceConstant * Allow file scheme in `RemoteArchive` to simplify testing (#4791) * Allow file scheme in `RemoteArchive` to simplify testing While it might look a bit controversial, the file scheme can also point to a remote (for instance a mounted network share) file. By allowing the `file://` scheme we can use `RemoteArchive` for those files. As a useful side effect, this makes testing RemoteArchive handling a lot easier. * fix test * Update rewrite-core/src/test/java/org/openrewrite/remote/RemoteArchiveTest.java Co-authored-by: Sam Snyder --------- Co-authored-by: Sam Snyder * Try alternative way of determining parenthesis level for `BinaryExpression` when AST doesn't provide `_INSIDE_PARENTHESES_LEVEL` flag (#4807) * Add a `isClassAvailable` method to the ReflectionUtils (#4810) * Add a `isClassAvailable` method to the ReflectionUtils * Add a `isClassAvailable` method to the ReflectionUtils * Add a `isClassAvailable` method to the ReflectionUtils * Update rewrite.yml to enforce CompareEnumsWithEqualityOperator * Correctly map generic return and parameter types in `JavaReflectionTypeMapping` (#4812) * Polish formatting * Add more scenarios to JavaTypeGoat for simply typed fields and methods that return exceptions. * Support mapping of generic thrown exception types (#4813) * refactor: Enum values should be compared with "==" (#4811) Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.staticanalysis.CompareEnumsWithEqualityOperator?organizationId=T3BlblJld3JpdGU%3D Co-authored-by: Moderne * Keep the names of generic type variables defined by methods. (#4814) * Make the same performance improvement to parameter names allocations that we previously made to Java 17/21 in #3345. * Fix Java reflection mapping of generic typed fields. (#4815) * Revert parenthesis changes (#4818) * Revert "Try alternative way of determining parenthesis level for `BinaryExpression` when AST doesn't provide `_INSIDE_PARENTHESES_LEVEL` flag (#4807)" This reverts commit e59e48b3a6e6be18ecb779ac329a243ed025da58. * Revert "Make Groovy Parser correctly handle nested parenthesis (#4801)" This reverts commit 91a031a3d517be1fe78656eb6b841141b336c085. * JavaTemplate bug when inserting `final var` into for-each (#4806) * JavaTemplate bug when inserting `final var` into for-each * Split variable declarations when they contain stop comment * Reduce accidental changes between Java 11 and 17 parsers * Add missing import --------- Co-authored-by: Udayani Vaka <79973862+vudayani@users.noreply.github.com> Co-authored-by: Jonathan Schnéider Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tim te Beek Co-authored-by: aboyko Co-authored-by: Laurens Westerlaken Co-authored-by: lingenj Co-authored-by: Peter Streef Co-authored-by: Shannon Pamperl Co-authored-by: Moderne Co-authored-by: Sam Snyder --- rewrite-java-11/build.gradle.kts | 1 + .../java/isolated/ReloadableJava11Parser.java | 158 ++++++++++++----- .../ReloadableJava11ParserVisitor.java | 167 +++++++++++++----- .../isolated/ReloadableJava11TypeMapping.java | 18 +- .../org/openrewrite/java/tree/LombokTest.java | 4 +- 5 files changed, 254 insertions(+), 94 deletions(-) diff --git a/rewrite-java-11/build.gradle.kts b/rewrite-java-11/build.gradle.kts index e897cf9f491..091f2016502 100644 --- a/rewrite-java-11/build.gradle.kts +++ b/rewrite-java-11/build.gradle.kts @@ -9,6 +9,7 @@ val javaTck = configurations.create("javaTck") { dependencies { api(project(":rewrite-core")) api(project(":rewrite-java")) + runtimeOnly(project(":rewrite-java-lombok")) compileOnly("org.slf4j:slf4j-api:1.7.+") diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java index 75a6e970757..43eeb24d8b8 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java @@ -18,12 +18,14 @@ import com.sun.tools.javac.comp.*; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.JavaCompiler; +import com.sun.tools.javac.main.Option; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Options; import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Timer; +import lombok.Getter; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import org.objectweb.asm.ClassReader; @@ -43,20 +45,28 @@ import org.openrewrite.tree.ParseError; import org.openrewrite.tree.ParsingEventListener; import org.openrewrite.tree.ParsingExecutionContextView; +import org.slf4j.LoggerFactory; +import javax.annotation.processing.Processor; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; import javax.tools.StandardLocation; import java.io.*; +import java.lang.reflect.Constructor; import java.net.URI; +import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; /** @@ -77,14 +87,16 @@ public class ReloadableJava11Parser implements JavaParser { private final JavaCompiler compiler; private final ResettableLog compilerLog; private final Collection styles; - - private ReloadableJava11Parser(boolean logCompilationWarningsAndErrors, - @Nullable Collection classpath, - Collection classBytesClasspath, - @Nullable Collection dependsOn, - Charset charset, - Collection styles, - JavaTypeCache typeCache) { + private final List annotationProcessors; + + private ReloadableJava11Parser( + boolean logCompilationWarningsAndErrors, + @Nullable Collection classpath, + Collection classBytesClasspath, + @Nullable Collection dependsOn, + Charset charset, + Collection styles, + JavaTypeCache typeCache) { this.classpath = classpath; this.dependsOn = dependsOn; this.styles = styles; @@ -106,6 +118,65 @@ private ReloadableJava11Parser(boolean logCompilationWarningsAndErrors, Options.instance(context).put("-g", "-g"); Options.instance(context).put("-proc", "none"); + LOMBOK: + if (System.getenv().getOrDefault("REWRITE_LOMBOK", System.getProperty("rewrite.lombok")) != null && + classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) { + Processor lombokProcessor = null; + try { + // https://projectlombok.org/contributing/lombok-execution-path + List overrideClasspath = new ArrayList<>(); + for (Path part : classpath) { + if (part.toString().contains("lombok")) { + overrideClasspath.add(part.toString()); + } + } + // make sure the rewrite-java-lombok dependency comes first + boolean found = false; + for (int i = 0; i < overrideClasspath.size(); i++) { + if (overrideClasspath.get(i).contains("rewrite-java-lombok")) { + overrideClasspath.add(0, overrideClasspath.remove(i)); + found = true; + } + } + if (!found) { + // try to find `rewrite-java-lombok` using class loader + URL resource = getClass().getClassLoader().getResource("org/openrewrite/java/lombok/OpenRewriteConfigurationKeysLoader.class"); + if (resource != null && resource.getProtocol().equals("jar") && resource.getPath().startsWith("file:")) { + String path = Paths.get(URI.create(resource.getPath().substring(0, resource.getPath().indexOf("!")))).toString(); + overrideClasspath.add(0, path); + } else { + break LOMBOK; + } + } + System.setProperty("shadow.override.lombok", String.join(File.pathSeparator, overrideClasspath)); + + Class shadowLoaderClass = Class.forName("lombok.launch.ShadowClassLoader", true, getClass().getClassLoader()); + Constructor shadowLoaderConstructor = shadowLoaderClass.getDeclaredConstructor( + Class.forName("java.lang.ClassLoader"), + Class.forName("java.lang.String"), + Class.forName("java.lang.String"), + Class.forName("java.util.List"), + Class.forName("java.util.List")); + shadowLoaderConstructor.setAccessible(true); + + ClassLoader lombokShadowLoader = (ClassLoader) shadowLoaderConstructor.newInstance( + getClass().getClassLoader(), + "lombok", + null, + emptyList(), + singletonList("lombok.patcher.Symbols") + ); + lombokProcessor = (Processor) lombokShadowLoader.loadClass("lombok.core.AnnotationProcessor").getDeclaredConstructor().newInstance(); + Options.instance(context).put(Option.PROCESSOR, "lombok.launch.AnnotationProcessorHider$AnnotationProcessor"); + } catch (ReflectiveOperationException ignore) { + // Lombok was not found or could not be initialized + } finally { + annotationProcessors = lombokProcessor != null ? singletonList(lombokProcessor) : emptyList(); + } + } else { + annotationProcessors = emptyList(); + } + // MUST be created ahead of compiler construction new TimedTodo(context); @@ -127,7 +198,7 @@ public void write(char[] cbuf, int off, int len) { if (logCompilationWarningsAndErrors) { String log = new String(Arrays.copyOfRange(cbuf, off, len)); if (!log.isBlank()) { - org.slf4j.LoggerFactory.getLogger(ReloadableJava11Parser.class).warn(log); + LoggerFactory.getLogger(ReloadableJava11Parser.class).warn(log); } } } @@ -191,37 +262,44 @@ LinkedHashMap parseInputsToCompilerAst(Iterable } LinkedHashMap cus = new LinkedHashMap<>(); - acceptedInputs(sourceFiles).forEach(input1 -> { + List inputFileObjects = acceptedInputs(sourceFiles) + .map(input -> new ReloadableJava11ParserInputFileObject(input, ctx)) + .collect(Collectors.toList()); + if (!annotationProcessors.isEmpty()) { + compiler.initProcessAnnotations(annotationProcessors, inputFileObjects, emptyList()); + } + try { + //noinspection unchecked + com.sun.tools.javac.util.List jcCompilationUnits = compiler.parseFiles((List) (List) inputFileObjects); + for (int i = 0; i < inputFileObjects.size(); i++) { + cus.put(inputFileObjects.get(i).getInput(), jcCompilationUnits.get(i)); + } try { - JCTree.JCCompilationUnit jcCompilationUnit = compiler.parse(new ReloadableJava11ParserInputFileObject(input1, ctx)); - cus.put(input1, jcCompilationUnit); - } catch (IllegalStateException e) { - if ("endPosTable already set".equals(e.getMessage())) { - throw new IllegalStateException( - "Call reset() on JavaParser before parsing another set of source files that " + - "have some of the same fully qualified names. Source file [" + - input1.getPath() + "]\n[\n" + StringUtils.readFully(input1.getSource(ctx), getCharset(ctx)) + "\n]", e); + initModules(cus.values()); + enterAll(cus.values()); + + // For some reason this is necessary in JDK 9+, where the internal block counter that + // annotationsBlocked() tests against remains >0 after attribution. + Annotate annotate = Annotate.instance(context); + while (annotate.annotationsBlocked()) { + annotate.unblockAnnotations(); // also flushes once unblocked + } + if (!annotationProcessors.isEmpty()) { + compiler.processAnnotations(jcCompilationUnits, emptyList()); } - throw e; + compiler.attribute(compiler.todo); + } catch (Throwable t) { + // when symbol entering fails on problems like missing types, attribution can often times proceed + // unhindered, but it sometimes cannot (so attribution is always best-effort in the presence of errors) + ctx.getOnError().accept(new JavaParsingException("Failed symbol entering or attribution", t)); } - }); - - try { - initModules(cus.values()); - enterAll(cus.values()); - - // For some reason this is necessary in JDK 9+, where the internal block counter that - // annotationsBlocked() tests against remains >0 after attribution. - Annotate annotate = Annotate.instance(context); - while (annotate.annotationsBlocked()) { - annotate.unblockAnnotations(); // also flushes once unblocked + } catch (IllegalStateException e) { + if ("endPosTable already set".equals(e.getMessage())) { + throw new IllegalStateException( + "Call reset() on JavaParser before parsing another set of source files that " + + "have some of the same fully qualified names.", e); } - - compiler.attribute(compiler.todo); - } catch (Throwable t) { - // when symbol entering fails on problems like missing types, attribution can often times proceed - // unhindered, but it sometimes cannot (so attribution is always a BEST EFFORT in the presence of errors) - ctx.getOnError().accept(new JavaParsingException("Failed symbol entering or attribution", t)); + throw e; } return cus; } @@ -361,8 +439,7 @@ public String inferBinaryName(Location location, JavaFileObject file) { public Iterable list(Location location, String packageName, Set kinds, boolean recurse) throws IOException { if (StandardLocation.CLASS_PATH.equals(location)) { Iterable listed = super.list(location, packageName, kinds, recurse); - return Stream.concat( - classByteClasspath.stream() + return Stream.concat(classByteClasspath.stream() .filter(jfo -> jfo.getPackage().equals(packageName)), StreamSupport.stream(listed.spliterator(), false) ).collect(toList()); @@ -373,6 +450,7 @@ public Iterable list(Location location, String packageName, Set< private static class PackageAwareJavaFileObject extends SimpleJavaFileObject { private final String pkg; + @Getter private final String className; private final byte[] classBytes; @@ -406,10 +484,6 @@ public String getPackage() { return pkg; } - public String getClassName() { - return className; - } - @Override public InputStream openInputStream() { return new ByteArrayInputStream(classBytes); diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index ac0714e55af..b8dd7a5d14f 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -18,6 +18,7 @@ import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; +import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DCTree; @@ -340,7 +341,7 @@ public J visitCase(CaseTree node, Space fmt) { node.getExpression() == null ? EMPTY : sourceBefore("case"), singletonList(node.getExpression() == null ? JRightPadded.build(new J.Identifier(randomId(), Space.EMPTY, Markers.EMPTY, emptyList(), skip("default"), null, null)) : - JRightPadded.build(convertOrNull(node.getExpression())) + JRightPadded.build(convert(node.getExpression())) ), Markers.EMPTY ), @@ -391,7 +392,7 @@ public J visitClass(ClassTree node, Space fmt) { Markers.EMPTY); JLeftPadded extendings = node.getExtendsClause() == null ? null : - padLeft(sourceBefore("extends"), convertOrNull(node.getExtendsClause())); + padLeft(sourceBefore("extends"), convert(node.getExtendsClause())); JContainer implementings = null; if (node.getImplementsClause() != null && !node.getImplementsClause().isEmpty()) { @@ -640,7 +641,7 @@ public J visitForLoop(ForLoopTree node, Space fmt) { commaDelim.apply(t) ); - JRightPadded condition = convertOrNull(node.getCondition(), semiDelim); + JRightPadded condition = convert(node.getCondition(), semiDelim); if (condition == null) { condition = padRight(new J.Empty(randomId(), sourceBefore(";"), Markers.EMPTY), EMPTY); } @@ -909,7 +910,7 @@ public J visitMethod(MethodTree node, Space fmt) { } List returnTypeAnnotations = collectAnnotations(annotationPosTable); - TypeTree returnType = convertOrNull(node.getReturnType()); + TypeTree returnType = convert(node.getReturnType()); if (returnType != null && !returnTypeAnnotations.isEmpty()) { returnType = new J.AnnotatedType(randomId(), Space.EMPTY, Markers.EMPTY, returnTypeAnnotations, returnType); @@ -952,7 +953,7 @@ public J visitMethod(MethodTree node, Space fmt) { JContainer.build(sourceBefore("throws"), convertAll(node.getThrows(), commaDelim, noDelim), Markers.EMPTY); - J.Block body = convertOrNull(node.getBody()); + J.Block body = convert(node.getBody()); JLeftPadded defaultValue = node.getDefaultValue() == null ? null : padLeft(sourceBefore("default"), convert(node.getDefaultValue())); @@ -976,9 +977,9 @@ public J visitNewArray(NewArrayTree node, Space fmt) { while (elementType instanceof JCArrayTypeTree) { elementType = ((JCArrayTypeTree) elementType).elemtype; } - typeExpr = convertOrNull(elementType); + typeExpr = convert(elementType); } else { - typeExpr = convertOrNull(jcVarType); + typeExpr = convert(jcVarType); } List nodeDimensions = node.getDimensions(); @@ -991,7 +992,7 @@ public J visitNewArray(NewArrayTree node, Space fmt) { convert(dim, t -> sourceBefore("]")))); } - while(true) { + while (true) { int beginBracket = indexOfNextNonWhitespace(cursor, source); if (source.charAt(beginBracket) == '[') { int endBracket = indexOfNextNonWhitespace(beginBracket + 1, source); @@ -1028,7 +1029,7 @@ public J visitNewClass(NewClassTree node, Space fmt) { } // for enum definitions with anonymous class initializers, endPos of node identifier will be -1 - TypeTree clazz = endPos(node.getIdentifier()) >= 0 ? convertOrNull(node.getIdentifier()) : null; + TypeTree clazz = endPos(node.getIdentifier()) >= 0 ? convert(node.getIdentifier()) : null; JContainer args; if (positionOfNext("(", '{') > -1) { @@ -1037,8 +1038,8 @@ public J visitNewClass(NewClassTree node, Space fmt) { singletonList(padRight(new J.Empty(randomId(), sourceBefore(")"), Markers.EMPTY), EMPTY)) : convertAll(node.getArguments(), commaDelim, t -> sourceBefore(")")), Markers.EMPTY); } else { - args = JContainer.empty(); - args = args.withMarkers(args.getMarkers().add(new OmitParentheses(randomId()))); + args = JContainer.empty() + .withMarkers(Markers.build(singletonList(new OmitParentheses(randomId())))); } J.Block body = null; @@ -1136,7 +1137,8 @@ public J visitPrimitiveType(PrimitiveTypeTree node, Space fmt) { @Override public J visitReturn(ReturnTree node, Space fmt) { skip("return"); - return new J.Return(randomId(), fmt, Markers.EMPTY, convertOrNull(node.getExpression())); + Expression expression = convert(node.getExpression()); + return new J.Return(randomId(), fmt, Markers.EMPTY, expression); } @Override @@ -1366,7 +1368,7 @@ private T buildName(String fullyQualifiedName) fullName += "." + part; int endOfPrefix = indexOfNextNonWhitespace(0, part); - Space identFmt = endOfPrefix > 0 ? format(part.substring(0, endOfPrefix)) : EMPTY; + Space identFmt = endOfPrefix > 0 ? format(part, 0, endOfPrefix) : EMPTY; Matcher whitespaceSuffix = whitespaceSuffixPattern.matcher(part); //noinspection ResultOfMethodCallIgnored @@ -1457,7 +1459,7 @@ public J visitVariable(VariableTree node, Space fmt) { int endPos = jcVariableDecl.getEndPosition(endPosTable); if (startPos == endPos) { - endPos = startPos + 1; + endPos = startPos + 1; // For cases where the error node is a single character like "/" } String erroneousNode = source.substring(startPos, endPos); return new J.Erroneous( @@ -1491,8 +1493,14 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm // this is a lambda parameter with an inferred type expression typeExpr = null; } else { - typeExpr = new J.Identifier(randomId(), sourceBefore("var"), Markers.EMPTY, emptyList(), "var", typeMapping.type(vartype), null); - typeExpr = typeExpr.withMarkers(typeExpr.getMarkers().add(JavaVarKeyword.build())); + boolean lombokVal = isLombokVal(node); + typeExpr = new J.Identifier(randomId(), + sourceBefore(lombokVal ? "val" : "var"), + Markers.build(singletonList(JavaVarKeyword.build())), + emptyList(), + lombokVal ? "val" : "var", + typeMapping.type(vartype), + null); } } else if (vartype instanceof JCArrayTypeTree) { JCExpression elementType = vartype; @@ -1512,6 +1520,10 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm typeExpr = convert(vartype); } + if (typeExpr == null && node.declaredUsingVar()) { + typeExpr = new J.Identifier(randomId(), sourceBefore("var"), Markers.build(singletonList(JavaVarKeyword.build())), emptyList(), "var", typeMapping.type(vartype), null); + } + if (typeExpr != null && !typeExprAnnotations.isEmpty()) { Space prefix = typeExprAnnotations.get(0).getPrefix(); typeExpr = new J.AnnotatedType(randomId(), prefix, Markers.EMPTY, ListUtils.mapFirst(typeExprAnnotations, a -> a.withPrefix(EMPTY)), typeExpr); @@ -1545,7 +1557,7 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm new J.VariableDeclarations.NamedVariable(randomId(), namedVarPrefix, Markers.EMPTY, name, dimensionsAfterName, - n.init != null ? padLeft(sourceBefore("="), convertOrNull(n.init)) : null, + n.init != null ? padLeft(sourceBefore("="), convert(n.init)) : null, (JavaType.Variable) typeMapping.type(n) ), i == nodes.size() - 1 ? EMPTY : sourceBefore(",") @@ -1558,15 +1570,15 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm private List> arrayDimensions() { List> dims = null; - while(true) { + while (true) { int beginBracket = indexOfNextNonWhitespace(cursor, source); if (source.charAt(beginBracket) == '[') { int endBracket = indexOfNextNonWhitespace(beginBracket + 1, source); - if(dims == null) { + if (dims == null) { dims = new ArrayList<>(2); } - dims.add(padLeft(format(source.substring(cursor, beginBracket)), - format(source.substring(beginBracket + 1, endBracket)))); + dims.add(padLeft(format(source, cursor, beginBracket), + format(source, beginBracket + 1, endBracket))); cursor = endBracket + 1; } else { break; @@ -1602,7 +1614,7 @@ public J visitWildcard(WildcardTree node, Space fmt) { bound = null; } - return new J.Wildcard(randomId(), fmt, Markers.EMPTY, bound, convertOrNull(wildcard.inner)); + return new J.Wildcard(randomId(), fmt, Markers.EMPTY, bound, convert(wildcard.inner)); } /** @@ -1611,9 +1623,12 @@ public J visitWildcard(WildcardTree node, Space fmt) { * -------------- */ - private J2 convert(Tree t) { + private @Nullable J2 convert(@Nullable Tree t) { + if (t == null) { + return null; + } try { - String prefix = source.substring(cursor, max(((JCTree) t).getStartPosition(), cursor)); + String prefix = source.substring(cursor, max(cursor, getActualStartPosition((JCTree) t))); cursor += prefix.length(); @SuppressWarnings("unchecked") J2 j = (J2) scan(t, formatWithCommentTree(prefix, (JCTree) t, docCommentTable.getCommentTree((JCTree) t))); return j; @@ -1643,7 +1658,18 @@ private J2 convert(Tree t) { } } - private JRightPadded convert(Tree t, Function suffix) { + private static int getActualStartPosition(JCTree t) { + // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation + if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { + return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); + } + return t.getStartPosition(); + } + + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix) { + if (t == null) { + return null; + } J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); @@ -1688,14 +1714,6 @@ private long lineNumber(Tree tree) { return source.substring(0, ((JCTree) tree).getStartPosition()).chars().filter(c -> c == '\n').count() + 1; } - private @Nullable T convertOrNull(@Nullable Tree t) { - return t == null ? null : convert(t); - } - - private @Nullable JRightPadded convertOrNull(@Nullable Tree t, Function suffix) { - return t == null ? null : convert(t, suffix); - } - private List convertAll(List trees) { List converted = new ArrayList<>(trees.size()); for (Tree tree : trees) { @@ -1759,7 +1777,7 @@ private Space statementDelim(@Nullable Tree t) { if (t instanceof JCExpressionStatement) { ExpressionTree expTree = ((ExpressionStatementTree) t).getExpression(); if (expTree instanceof ErroneousTree) { - return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable),((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); + return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable), ((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); } else { return sourceBefore(";"); } @@ -1807,6 +1825,9 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { + if (isLombokGenerated(t)) { + continue; + } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); } @@ -1836,6 +1857,53 @@ private List> convertStatements(@Nullable List JRightPadded padRight(T tree, Space right) { @@ -1894,7 +1962,7 @@ private int positionOfNext(String untilDelim, @Nullable Character stop) { char c2 = source.charAt(delimIndex + 1); switch (c1) { case '/': - switch(c2) { + switch (c2) { case '/': inSingleLineComment = true; delimIndex++; @@ -1906,7 +1974,7 @@ private int positionOfNext(String untilDelim, @Nullable Character stop) { } break; case '*': - if(c2 == '/') { + if (c2 == '/') { inMultiLineComment = false; delimIndex++; continue; @@ -1938,9 +2006,9 @@ private Space whitespace() { if (nextNonWhitespace == cursor) { return EMPTY; } - String prefix = source.substring(cursor, nextNonWhitespace); - cursor += prefix.length(); - return format(prefix); + Space space = format(source, cursor, nextNonWhitespace); + cursor = nextNonWhitespace; + return space; } private String skip(@Nullable String token) { @@ -2010,13 +2078,18 @@ private ReloadableJava11ModifierResults sortedModifiersAndAnnotations(ModifiersT int lastAnnotationPosition = cursor; for (int i = cursor; i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { - J.Annotation annotation = convert(annotationPosTable.get(i)); + JCAnnotation jcAnnotation = annotationPosTable.get(i); + // Skip over lombok's "@val" annotation which does not actually appear in source + if (isLombokGenerated(jcAnnotation.getAnnotationType())) { + continue; + } + J.Annotation annotation = convert(jcAnnotation); if (afterFirstModifier) { currentAnnotations.add(annotation); } else { leadingAnnotations.add(annotation); } - i = cursor -1; + i = cursor - 1; lastAnnotationPosition = cursor; continue; } @@ -2130,7 +2203,11 @@ private List collectAnnotations(Map annotat boolean inMultilineComment = false; for (int i = cursor; i <= maxAnnotationPosition && i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { - annotations.add(convert(annotationPosTable.get(i))); + JCAnnotation jcAnnotation = annotationPosTable.get(i); + if (isLombokGenerated(jcAnnotation)) { + continue; + } + annotations.add(convert(jcAnnotation)); i = cursor; continue; } diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java index a37d73adf6e..0fb15f638be 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java @@ -232,8 +232,9 @@ private JavaType generic(Type.TypeVar type, String signature) { private JavaType.FullyQualified classType(Type.ClassType classType, String signature) { Symbol.ClassSymbol sym = (Symbol.ClassSymbol) classType.tsym; Type.ClassType symType = (Type.ClassType) sym.type; + String fqn = sym.flatName().toString(); - JavaType.FullyQualified fq = typeCache.get(sym.flatName().toString()); + JavaType.FullyQualified fq = typeCache.get(fqn); JavaType.Class clazz = (JavaType.Class) (fq instanceof JavaType.Parameterized ? ((JavaType.Parameterized) fq).getType() : fq); if (clazz == null) { if (!sym.completer.isTerminal()) { @@ -243,12 +244,12 @@ private JavaType.FullyQualified classType(Type.ClassType classType, String signa clazz = new JavaType.Class( null, sym.flags_field, - sym.flatName().toString(), + fqn, getKind(sym), null, null, null, null, null, null, null ); - typeCache.put(sym.flatName().toString(), clazz); + typeCache.put(fqn, clazz); JavaType.FullyQualified supertype = TypeUtils.asFullyQualified(type(symType.supertype_field)); @@ -276,7 +277,7 @@ private JavaType.FullyQualified classType(Type.ClassType classType, String signa if (elem instanceof Symbol.VarSymbol && (elem.flags_field & (Flags.SYNTHETIC | Flags.BRIDGE | Flags.HYPOTHETICAL | Flags.GENERATEDCONSTR | Flags.ANONCONSTR)) == 0) { - if (sym.flatName().toString().equals("java.lang.String") && elem.name.toString().equals("serialPersistentFields")) { + if (fqn.equals("java.lang.String") && elem.name.toString().equals("serialPersistentFields")) { // there is a "serialPersistentFields" member within the String class which is used in normal Java // serialization to customize how the String field is serialized. This field is tripping up Jackson // serialization and is intentionally filtered to prevent errors. @@ -358,12 +359,19 @@ private JavaType.Class.Kind getKind(Symbol.ClassSymbol sym) { return variableType(((JCTree.JCVariableDecl) tree).sym); } else if (tree instanceof JCTree.JCAnnotatedType && ((JCTree.JCAnnotatedType) tree).getUnderlyingType() instanceof JCTree.JCArrayTypeTree) { return annotatedArray((JCTree.JCAnnotatedType) tree); + } else if (tree instanceof JCTree.JCClassDecl) { + symbol = ((JCTree.JCClassDecl) tree).sym; + } else if (tree instanceof JCTree.JCFieldAccess) { + symbol = ((JCTree.JCFieldAccess) tree).sym; } return type(((JCTree) tree).type, symbol); } - private @Nullable JavaType type(Type type, Symbol symbol) { + private @Nullable JavaType type(@Nullable Type type, @Nullable Symbol symbol) { + if (type == null && symbol != null) { + type = symbol.type; + } if (type instanceof Type.MethodType || type instanceof Type.ForAll) { return methodInvocationType(type, symbol); } diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index e6501675503..03daab50f46 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -33,7 +33,7 @@ import static org.openrewrite.java.Assertions.java; @SuppressWarnings({"CaughtExceptionImmediatelyRethrown", "LombokGetterMayBeUsed", "LombokSetterMayBeUsed", "DefaultAnnotationParam", "NotNullFieldNotInitialized", "ProtectedMemberInFinalClass", "WriteOnlyObject", "ConcatenationWithEmptyString"}) -@EnabledOnJre(JRE.JAVA_17) +@EnabledOnJre({JRE.JAVA_11, JRE.JAVA_17}) class LombokTest implements RewriteTest { @BeforeAll @@ -426,7 +426,7 @@ class A { Map map; void m() { log.info("string = " + string); - log.info(() -> "map = %s".formatted(map)); + log.info(() -> String.format("map = %s", map)); } } """ From 424575adff4fb920bac50ba68a74b031700ea175 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 2 Jan 2025 11:25:01 +0100 Subject: [PATCH 087/179] Add missing override annotation (#4828) --- rewrite-gradle/src/main/groovy/RewriteGradleProject.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/rewrite-gradle/src/main/groovy/RewriteGradleProject.groovy b/rewrite-gradle/src/main/groovy/RewriteGradleProject.groovy index e3283fd5733..ee780d3d430 100644 --- a/rewrite-gradle/src/main/groovy/RewriteGradleProject.groovy +++ b/rewrite-gradle/src/main/groovy/RewriteGradleProject.groovy @@ -78,6 +78,7 @@ interface DependencyHandlerSpec extends DependencyHandler { Dependency earlib(Object... dependencyNotation) Dependency earlib(Object dependencyNotation, @DelegatesTo(strategy=Closure.DELEGATE_ONLY, value= ExternalDependency) Closure closure) + @Override void constraints(Action configureAction) } From 0185820c78816dea92f7c06eb36be0bae1763903 Mon Sep 17 00:00:00 2001 From: Anshuman Mishra <119983081+amishra-u@users.noreply.github.com> Date: Thu, 2 Jan 2025 03:00:36 -0800 Subject: [PATCH 088/179] Don't skip type attribution on compilation error (#4826) --- .../java/isolated/ReloadableJava11Parser.java | 5 + .../java/isolated/ReloadableJava17Parser.java | 5 + .../org/openrewrite/java/tree/LombokTest.java | 122 +++++++++++------- .../java/org/openrewrite/java/Assertions.java | 1 + .../org/openrewrite/test/TypeValidation.java | 10 +- 5 files changed, 93 insertions(+), 50 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java index 43eeb24d8b8..51103226f9b 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11Parser.java @@ -118,6 +118,11 @@ private ReloadableJava11Parser( Options.instance(context).put("-g", "-g"); Options.instance(context).put("-proc", "none"); + // Ensure type attribution continues despite errors in individual files or nodes. + // If an error occurs in a single file or node, type attribution should still proceed + // for all other source files and unaffected nodes within the same file. + Options.instance(context).put("should-stop.ifError", "GENERATE"); + LOMBOK: if (System.getenv().getOrDefault("REWRITE_LOMBOK", System.getProperty("rewrite.lombok")) != null && classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) { diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17Parser.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17Parser.java index 8441177d969..72c579ed838 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17Parser.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17Parser.java @@ -116,6 +116,11 @@ private ReloadableJava17Parser( Options.instance(context).put("-g", "-g"); Options.instance(context).put("-proc", "none"); + // Ensure type attribution continues despite errors in individual files or nodes. + // If an error occurs in a single file or node, type attribution should still proceed + // for all other source files and unaffected nodes within the same file. + Options.instance(context).put("should-stop.ifError", "GENERATE"); + LOMBOK: if (System.getenv().getOrDefault("REWRITE_LOMBOK", System.getProperty("rewrite.lombok")) != null && classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) { diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index 03daab50f46..ad023f79ced 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.condition.EnabledOnJre; import org.junit.jupiter.api.condition.JRE; import org.openrewrite.java.JavaParser; +import org.openrewrite.java.search.FindMissingTypes; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; import org.openrewrite.test.TypeValidation; @@ -706,6 +707,78 @@ public class ExampleException extends Exception { ); } + @Test + void onConstructor() { + rewriteRun( + spec -> spec.typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { + assert o instanceof FindMissingTypes.MissingTypeResult; + FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; + // type attribution is missing for annotation args, as it was intentionally removed for processing. + return result.getPath().startsWith("Identifier->Annotation->"); + }).build()), + java( + """ + import lombok.AllArgsConstructor; + import lombok.Getter; + import lombok.Setter; + + import javax.inject.Inject; + import javax.persistence.Id; + import javax.persistence.Column; + import javax.validation.constraints.Max; + + @AllArgsConstructor(onConstructor=@__(@Inject)) + public class OnXExample { + @Getter(onMethod_={@Id, @Column(name="unique-id")}) //JDK8 + @Setter(onParam_=@Max(10000)) //JDK8 + private long unid; + + public void test() { + OnXExample x = new OnXExample(1L); + x.setUnid(2L); + System.out.println(x.getUnid()); + } + } + """ + ) + ); + } + + @Test + void onConstructorNoArgs() { + rewriteRun( + spec -> spec.typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { + assert o instanceof FindMissingTypes.MissingTypeResult; + FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; + if (result.getJ() instanceof J.Identifier identifier) { + // type attribution is missing for annotation args, as it was intentionally removed for processing. + return identifier.getSimpleName().equals("__") || identifier.getSimpleName().equals("Inject"); + } + return false; + }).build()), + java( + """ + import lombok.NoArgsConstructor; + import lombok.NonNull; + import lombok.RequiredArgsConstructor; + + import javax.inject.Inject; + + @NoArgsConstructor(onConstructor = @__(@Inject)) + @RequiredArgsConstructor(onConstructor = @__(@Inject)) + public class OnXExample { + @NonNull private Long unid; + + public void test() { + new OnXExample(); + new OnXExample(1L); + } + } + """ + ) + ); + } + /** * These test lombok features that we do not fully support. * Code should still parse and print back to its original source code but type information may be missing. @@ -745,55 +818,6 @@ public static String toTitleCase(String in) { ); } - @Test - void onConstructor() { - rewriteRun( - spec -> spec.typeValidationOptions(TypeValidation.none()), - java( - """ - import lombok.AllArgsConstructor; - import lombok.Getter; - import lombok.Setter; - - import javax.inject.Inject; - import javax.persistence.Id; - import javax.persistence.Column; - import javax.validation.constraints.Max; - - // @__ missing attribution - @AllArgsConstructor(onConstructor=@__(@Inject)) - public class OnXExample { - @Getter(onMethod_={@Id, @Column(name="unique-id")}) //JDK8 - @Setter(onParam_=@Max(10000)) //JDK8 - private long unid; - } - """ - ) - ); - } - - @Test - void onConstructorNoArgs() { - rewriteRun( - spec -> spec.typeValidationOptions(TypeValidation.none()), - java( - """ - import lombok.NoArgsConstructor; - import lombok.Getter; - import lombok.RequiredArgsConstructor;import lombok.Setter; - - import javax.inject.Inject; - // @__ missing attribution - @NoArgsConstructor(onConstructor = @__(@Inject)) - @RequiredArgsConstructor(onConstructor_ = @__(@Inject)) - public class OnXExample { - private long unid; - } - """ - ) - ); - } - @Test void helper() { rewriteRun( diff --git a/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java b/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java index 19142844e33..27ae9b4ec08 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java @@ -84,6 +84,7 @@ private static void assertValidTypes(TypeValidation typeValidation, J sf) { return true; } }) + .filter(missingType -> !typeValidation.allowMissingType().apply(missingType)) .collect(Collectors.toList()); if (!missingTypeResults.isEmpty()) { String missingTypes = missingTypeResults.stream() diff --git a/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java b/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java index 76abc5dfd6e..e4df172f017 100644 --- a/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java +++ b/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java @@ -21,6 +21,8 @@ import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +import java.util.function.Function; + /** * Controls the test framework's validation of invariants which are expected to hold true in an LST both before and * after the recipe run. Originally this applied only to validating the well-formedness of type metadata in Java LSTs @@ -88,6 +90,12 @@ public class TypeValidation { @Builder.Default private boolean cursorAcyclic = true; + /** + * Given finer control to client when they need to allow missing type metadata for a specific node. + */ + @Builder.Default + private Function allowMissingType = o -> false; + /** * Enable all invariant validation checks. */ @@ -99,7 +107,7 @@ public static TypeValidation all() { * Skip all invariant validation checks. */ public static TypeValidation none() { - return new TypeValidation(false, false, false, false, false, false, false, false); + return new TypeValidation(false, false, false, false, false, false, false, false, o -> false); } static TypeValidation before(RecipeSpec testMethodSpec, RecipeSpec testClassSpec) { From 1f83ea32fc5b807249a879ea2c0f9d3c0afd25fe Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Thu, 2 Jan 2025 12:10:11 +0100 Subject: [PATCH 089/179] UT for slash signs in string literals (#4829) Co-authored-by: Anshuman Mishra <119983081+amishra-u@users.noreply.github.com> --- .../org/openrewrite/hcl/tree/HclStringTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclStringTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclStringTest.java index 0c9262c4ab6..801dc3830d6 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclStringTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclStringTest.java @@ -66,4 +66,17 @@ void trailingDollarSign() { ) ); } + + @Test + void slashesInStrings() { + rewriteRun( + hcl( + """ + locals { + cidr = "192.168.0.0/24" + } + """ + ) + ); + } } From 1aee2af8245b444095d2e2abdf82330c68d9f024 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Thu, 2 Jan 2025 12:18:17 +0100 Subject: [PATCH 090/179] Support inner classes for groovy (#4825) * Support inner classes * Better text * Improvement * Support nested class without arguments * Improve test * Improvement * Improvement * Support anonymous inner classes --- .../groovy/GroovyParserVisitor.java | 140 +++++------------- .../groovy/tree/ClassDeclarationTest.java | 74 ++++++++- .../groovy/tree/RealWorldGroovyTest.java | 1 - 3 files changed, 111 insertions(+), 104 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 598dd66f579..783740c03c2 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -45,6 +45,7 @@ import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; +import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.nio.charset.Charset; import java.nio.file.Path; @@ -392,11 +393,11 @@ class A { JRightPadded.build(false), sortedByPosition.values().stream() .flatMap(asts -> asts.stream() + // anonymous classes will be visited as part of visiting the ConstructorCallExpression + .filter(ast -> !(ast instanceof InnerClassNode && ((InnerClassNode) ast).isAnonymous())) .map(ast -> { if (ast instanceof FieldNode) { visitField((FieldNode) ast); - } else if (ast instanceof ConstructorNode) { - visitConstructor((ConstructorNode) ast); } else if (ast instanceof MethodNode) { visitMethod((MethodNode) ast); } else if (ast instanceof ClassNode) { @@ -521,15 +522,34 @@ public void visitMethod(MethodNode method) { List annotations = visitAndGetAnnotations(method); List modifiers = visitModifiers(method.getModifiers()); - Optional redundantDef = maybeRedundantDef(method.getReturnType(), method.getName()); - TypeTree returnType = visitTypeTree(method.getReturnType()); + boolean isConstructor = method instanceof ConstructorNode; + boolean isConstructorOfInnerNonStaticClass = false; + Optional redundantDef = isConstructor ? Optional.empty() : maybeRedundantDef(method.getReturnType(), method.getName()); + TypeTree returnType = isConstructor ? null : visitTypeTree(method.getReturnType()); - // Method name might be in quotes Space namePrefix = whitespace(); String methodName; - if (source.startsWith(method.getName(), cursor)) { + if (isConstructor) { + /* + To support Java syntax for non-static inner classes, the groovy compiler uses an extra parameter with a reference to its parent class under the hood: + class A { class A { + class B { class B { + String s String s + B(String s) { => B(A $p$, String s) { + => new Object().this$0 = $p$ + this.s = s => this.s = s + } } + } } + } + In our LST, we don't need this internal logic, so we'll skip the first param + first two statements (ConstructorCallExpression and BlockStatement)} + See also: https://groovy-lang.org/differences.html#_creating_instances_of_non_static_inner_classes + */ + isConstructorOfInnerNonStaticClass = method.getDeclaringClass() instanceof InnerClassNode && (method.getDeclaringClass().getModifiers() & Modifier.STATIC) == 0; + methodName = method.getDeclaringClass().getName().replaceFirst(".*\\$", ""); + } else if (source.startsWith(method.getName(), cursor)) { methodName = method.getName(); } else { + // Method name might be in quotes char openingQuote = source.charAt(cursor); methodName = openingQuote + method.getName() + openingQuote; } @@ -547,7 +567,7 @@ public void visitMethod(MethodNode method) { Space beforeParen = sourceBefore("("); List> params = new ArrayList<>(method.getParameters().length); Parameter[] unparsedParams = method.getParameters(); - for (int i = 0; i < unparsedParams.length; i++) { + for (int i = (isConstructorOfInnerNonStaticClass ? 1 : 0); i < unparsedParams.length; i++) { Parameter param = unparsedParams[i]; List paramAnnotations = visitAndGetAnnotations(param); @@ -589,7 +609,7 @@ varargs, emptyList(), singletonList(paramName))).withAfter(rightPad)); } - if (unparsedParams.length == 0) { + if (unparsedParams.length == 0 || (isConstructorOfInnerNonStaticClass && unparsedParams.length == 1)) { params.add(JRightPadded.build(new J.Empty(randomId(), sourceBefore(")"), Markers.EMPTY))); } @@ -599,8 +619,16 @@ varargs, emptyList(), Markers.EMPTY ); - J.Block body = method.getCode() == null ? null : - bodyVisitor.visit(method.getCode()); + J.Block body = null; + if (method.getCode() != null) { + ASTNode code = isConstructorOfInnerNonStaticClass ? + new BlockStatement( + ((BlockStatement) method.getCode()).getStatements().subList(2, ((BlockStatement) method.getCode()).getStatements().size()), + ((BlockStatement) method.getCode()).getVariableScope() + ) + : method.getCode(); + body = bodyVisitor.visit(code); + } queue.add(new J.MethodDeclaration( randomId(), fmt, @@ -618,98 +646,6 @@ varargs, emptyList(), )); } - @Override - public void visitConstructor(ConstructorNode constructor) { - Space fmt = whitespace(); - - List annotations = visitAndGetAnnotations(constructor); - List modifiers = visitModifiers(constructor.getModifiers()); - - // Constructor name might be in quotes - Space namePrefix = whitespace(); - String constructorName; - if (source.startsWith(constructor.getDeclaringClass().getName(), cursor)) { - constructorName = constructor.getDeclaringClass().getName(); - } else { - char openingQuote = source.charAt(cursor); - constructorName = openingQuote + constructor.getName() + openingQuote; - } - cursor += constructorName.length(); - J.Identifier name = new J.Identifier(randomId(), - namePrefix, - Markers.EMPTY, - emptyList(), - constructorName, - null, null); - - RewriteGroovyVisitor bodyVisitor = new RewriteGroovyVisitor(constructor, this); - - // Parameter has no visit implementation, so we've got to do this by hand - Space beforeParen = sourceBefore("("); - List> params = new ArrayList<>(constructor.getParameters().length); - Parameter[] unparsedParams = constructor.getParameters(); - for (int i = 0; i < unparsedParams.length; i++) { - Parameter param = unparsedParams[i]; - - List paramAnnotations = visitAndGetAnnotations(param); - - TypeTree paramType; - if (param.isDynamicTyped()) { - paramType = new J.Identifier(randomId(), EMPTY, Markers.EMPTY, emptyList(), "", JavaType.ShallowClass.build("java.lang.Object"), null); - } else { - paramType = visitTypeTree(param.getOriginType()); - } - JRightPadded paramName = JRightPadded.build( - new J.VariableDeclarations.NamedVariable(randomId(), EMPTY, Markers.EMPTY, - new J.Identifier(randomId(), whitespace(), Markers.EMPTY, emptyList(), param.getName(), null, null), - emptyList(), null, null) - ); - cursor += param.getName().length(); - - org.codehaus.groovy.ast.expr.Expression defaultValue = param.getInitialExpression(); - if (defaultValue != null) { - paramName = paramName.withElement(paramName.getElement().getPadding() - .withInitializer(new JLeftPadded<>( - sourceBefore("="), - new RewriteGroovyVisitor(defaultValue, this).visit(defaultValue), - Markers.EMPTY))); - } - Space rightPad = sourceBefore(i == unparsedParams.length - 1 ? ")" : ","); - - params.add(JRightPadded.build((Statement) new J.VariableDeclarations(randomId(), EMPTY, - Markers.EMPTY, paramAnnotations, emptyList(), paramType, - null, emptyList(), - singletonList(paramName))).withAfter(rightPad)); - } - - if (unparsedParams.length == 0) { - params.add(JRightPadded.build(new J.Empty(randomId(), sourceBefore(")"), Markers.EMPTY))); - } - - JContainer throws_ = constructor.getExceptions().length == 0 ? null : JContainer.build( - sourceBefore("throws"), - bodyVisitor.visitRightPadded(constructor.getExceptions(), null), - Markers.EMPTY - ); - - J.Block body = constructor.getCode() == null ? null : - bodyVisitor.visit(constructor.getCode()); - - queue.add(new J.MethodDeclaration( - randomId(), fmt, Markers.EMPTY, - annotations, - modifiers, - null, - null, - new J.MethodDeclaration.IdentifierWithAnnotations(name, emptyList()), - JContainer.build(beforeParen, params, Markers.EMPTY), - throws_, - body, - null, - typeMapping.methodType(constructor) - )); - } - public List visitAndGetAnnotations(AnnotatedNode node) { if (node.getAnnotations().isEmpty()) { return emptyList(); diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java index e3acb1f3d33..c3991346c24 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java @@ -342,7 +342,6 @@ class RewriteSettings extends groovy.lang.Script { } @Test - @ExpectedToFail("Anonymous inner class is not yet supported") // https://groovy-lang.org/objectorientation.html#_anonymous_inner_class void anonymousInnerClass() { rewriteRun( groovy( @@ -350,6 +349,7 @@ void anonymousInnerClass() { interface Something {} class Test { + Something something = new Something() {} static def test() { new Something() {} } @@ -358,4 +358,76 @@ static def test() { ) ); } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4063") + void nestedClassWithoutParameters() { + rewriteRun( + groovy( + """ + class A { + class B { + B() {} + } + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4063") + void nestedClass() { + rewriteRun( + groovy( + """ + class A { + class B { + String a;String[] b + B(String $a, String... b) { + this.a = $a + this.b = b + } + } + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4063") + void nestedStaticClassWithoutParameters() { + rewriteRun( + groovy( + """ + class A { + static class B { + B() {} + } + } + """ + ) + ); + } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4063") + void nestedStaticClass() { + rewriteRun( + groovy( + """ + class A { + static class B { + String a;String[] b + B(String a, String... b) { + this.a = a + this.b = b + } + } + } + """ + ) + ); + } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java index ea9da82cd73..2f9998c197a 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java @@ -135,7 +135,6 @@ public void apply(Project project) { } @Test - @ExpectedToFail("Anonymous inner class is not yet supported") // https://groovy-lang.org/objectorientation.html#_anonymous_inner_class @Issue("https://github.com/spring-projects/spring-ldap/blob/v3.4.1/buildSrc/src/test/resources/samples/integrationtest/withgroovy/src/integration-test/groovy/sample/TheTest.groovy") void springLdapTheTest() { rewriteRun( From 30f171621b65aa9f53616420b00516549e9d6c6f Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Thu, 2 Jan 2025 15:50:19 +0100 Subject: [PATCH 091/179] Support nested annotations with properties and annotations with empty arguments (#4832) * Support nested annotations with properties * Support annotation with empty arguments --- .../groovy/GroovyParserVisitor.java | 53 +++++++++---------- .../groovy/tree/AnnotationTest.java | 44 +++++++++++++-- 2 files changed, 65 insertions(+), 32 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 783740c03c2..c34c258ee86 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -60,6 +60,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; +import static java.util.stream.Collectors.toList; import static org.openrewrite.Tree.randomId; import static org.openrewrite.internal.StringUtils.indexOfNextNonWhitespace; import static org.openrewrite.java.tree.Space.EMPTY; @@ -408,7 +409,7 @@ class A { Statement stat = pollQueue(); return maybeSemicolon(stat); })) - .collect(Collectors.toList()), + .collect(toList()), sourceBefore("}")); } @@ -483,36 +484,37 @@ protected void visitAnnotation(AnnotationNode annotation) { NameTree annotationType = visitTypeTree(annotation.getClassNode()); JContainer arguments = null; if (!annotation.getMembers().isEmpty()) { - // This doesn't handle the case where an annotation has empty arguments like @Foo(), but that is rare arguments = JContainer.build( sourceBefore("("), annotation.getMembers().entrySet().stream() .map(arg -> { - Space argPrefix; - if ("value".equals(arg.getKey())) { - // Determine whether the value is implicit or explicit - int saveCursor = cursor; - argPrefix = whitespace(); - if (!source.startsWith("value", cursor)) { - return new JRightPadded( - ((Expression) bodyVisitor.visit(arg.getValue())).withPrefix(argPrefix), - arg.getKey().equals(lastArgKey) ? sourceBefore(")") : sourceBefore(","), - Markers.EMPTY); - } - cursor = saveCursor; + boolean isImplicitValue = "value".equals(arg.getKey()) && !source.startsWith("value", indexOfNextNonWhitespace(cursor, source)); + Space argPrefix = isImplicitValue ? whitespace() : sourceBefore(arg.getKey()); + Space isSign = isImplicitValue ? null : sourceBefore("="); + Expression expression; + if (arg.getValue() instanceof AnnotationConstantExpression) { + visitAnnotation((AnnotationNode) ((AnnotationConstantExpression) arg.getValue()).getValue()); + expression = (J.Annotation) queue.poll(); + } else { + expression = bodyVisitor.visit(arg.getValue()); } - argPrefix = sourceBefore(arg.getKey()); - J.Identifier argName = new J.Identifier(randomId(), EMPTY, Markers.EMPTY, emptyList(), arg.getKey(), null, null); - J.Assignment assign = new J.Assignment(randomId(), argPrefix, Markers.EMPTY, - argName, padLeft(sourceBefore("="), bodyVisitor.visit(arg.getValue())), - null); - return JRightPadded.build((Expression) assign) + Expression element = isImplicitValue ? expression + : (new J.Assignment(randomId(), argPrefix, Markers.EMPTY, + new J.Identifier(randomId(), EMPTY, Markers.EMPTY, emptyList(), arg.getKey(), null, null), + padLeft(isSign, expression), null)); + return JRightPadded.build(element) .withAfter(arg.getKey().equals(lastArgKey) ? sourceBefore(")") : sourceBefore(",")); }) - .collect(Collectors.toList()), + .collect(toList()), Markers.EMPTY ); + } else if (source.startsWith("(", indexOfNextNonWhitespace(cursor, source))) { + // An annotation with empty arguments like @Foo() + arguments = JContainer.build(sourceBefore("("), + singletonList(JRightPadded.build(new J.Empty(randomId(), sourceBefore(")"), Markers.EMPTY))), + Markers.EMPTY); } + queue.add(new J.Annotation(randomId(), prefix, Markers.EMPTY, annotationType, arguments)); } @@ -761,7 +763,7 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { List unparsedArgs = expression.getExpressions().stream() .filter(GroovyParserVisitor::appearsInSource) - .collect(Collectors.toList()); + .collect(toList()); // If the first parameter to a function is a Map, then groovy allows "named parameters" style invocations, see: // https://docs.groovy-lang.org/latest/html/documentation/#_named_parameters_2 // When named parameters are in use they may appear before, after, or intermixed with any positional arguments @@ -778,7 +780,7 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { unparsedArgs.subList(1, unparsedArgs.size()).stream()) .sorted(Comparator.comparing(ASTNode::getLastLineNumber) .thenComparing(ASTNode::getLastColumnNumber)) - .collect(Collectors.toList()); + .collect(toList()); } else if (!unparsedArgs.isEmpty() && unparsedArgs.get(0) instanceof MapExpression) { // The map literal may or may not be wrapped in "[]" // If it is wrapped in "[]" then this isn't a named arguments situation, and we should not lift the parameters out of the enclosing MapExpression @@ -792,7 +794,7 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { Stream.concat( namedArgExpressions.getMapEntryExpressions().stream(), unparsedArgs.subList(1, unparsedArgs.size()).stream()) - .collect(Collectors.toList()); + .collect(toList()); } } @@ -1323,9 +1325,6 @@ public void visitConstantExpression(ConstantExpression expression) { text = ""; } jType = JavaType.Primitive.Null; - } else if (expression instanceof AnnotationConstantExpression) { - classVisitor.visitAnnotation((AnnotationNode) value); - return ((Expression) classVisitor.pollQueue()).withPrefix(fmt); } else { throw new IllegalStateException("Unexpected constant type " + type); } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AnnotationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AnnotationTest.java index a87695e7d71..b028da0dfa5 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AnnotationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AnnotationTest.java @@ -30,8 +30,43 @@ void simple() { groovy( """ @Foo - class Test { - } + class Test {} + """ + ) + ); + } + + @Test + void withParentheses() { + rewriteRun( + groovy( + """ + @Foo() + class Test {} + """ + ) + ); + } + + @Test + void withProperties() { + rewriteRun( + groovy( + """ + @Foo(value = "A", version = "1.0") + class Test {} + """ + ) + ); + } + + @Test + void withImplicitValueProperty() { + rewriteRun( + groovy( + """ + @Foo("A") + class Test {} """ ) ); @@ -43,9 +78,8 @@ void nested() { rewriteRun( groovy( """ - @Foo(bar = @Bar) - class Test { - } + @Foo(bar = @Bar(@Baz(baz = @Qux("1.0")))) + class Test {} """ ) ); From 1b1f1fe01daa00663cfae375068561615ce0be37 Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Thu, 2 Jan 2025 15:55:27 +0100 Subject: [PATCH 092/179] Hcl - allow for expression on LHS in objectelem (#4831) * Allowing for expressions on LHS of objectelem * Allowing for expressions on LHS of objectelem --------- Co-authored-by: Greg Oledzki --- rewrite-hcl/src/main/antlr/HCLParser.g4 | 2 +- .../hcl/internal/HclParserVisitor.java | 10 +- .../hcl/internal/grammar/HCLLexer.java | 68 +- .../hcl/internal/grammar/HCLParser.interp | 2 +- .../hcl/internal/grammar/HCLParser.java | 761 +++++++++--------- .../grammar/HCLParserBaseListener.java | 2 +- .../grammar/HCLParserBaseVisitor.java | 2 +- .../internal/grammar/HCLParserListener.java | 2 +- .../internal/grammar/HCLParserVisitor.java | 2 +- .../hcl/internal/grammar/JsonPathLexer.java | 51 +- .../hcl/internal/grammar/JsonPathParser.java | 80 +- .../grammar/JsonPathParserBaseListener.java | 2 +- .../grammar/JsonPathParserBaseVisitor.java | 2 +- .../grammar/JsonPathParserListener.java | 2 +- .../grammar/JsonPathParserVisitor.java | 2 +- .../openrewrite/hcl/tree/HclBlockTest.java | 18 + 16 files changed, 517 insertions(+), 491 deletions(-) diff --git a/rewrite-hcl/src/main/antlr/HCLParser.g4 b/rewrite-hcl/src/main/antlr/HCLParser.g4 index 9e8bebafb83..aa2618baa00 100644 --- a/rewrite-hcl/src/main/antlr/HCLParser.g4 +++ b/rewrite-hcl/src/main/antlr/HCLParser.g4 @@ -86,7 +86,7 @@ object ; objectelem - : (Identifier | LPAREN Identifier RPAREN | QUOTE quotedTemplatePart* QUOTE) (ASSIGN | COLON) expression COMMA? + : (Identifier | LPAREN Identifier RPAREN | QUOTE quotedTemplatePart* QUOTE | expression) (ASSIGN | COLON) expression COMMA? ; // For Expressions diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java index 9974ff15de1..40e9f9a2331 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java @@ -469,7 +469,13 @@ public Hcl visitObjectelem(HCLParser.ObjectelemContext ctx) { if (ctx.LPAREN() != null) { parenthesesPrefix = sourceBefore("("); } - name = visitIdentifier(ctx.Identifier()); + if (ctx.Identifier() != null) { + name = visitIdentifier(ctx.Identifier()); + } else if (ctx.expression(0) != null) { + name = (Expression) visit(ctx.expression(0)); + } else { + throw new IllegalStateException("Unsupported LHS in object element"); + } if (ctx.RPAREN() != null) { name = new Hcl.Parentheses(randomId(), parenthesesPrefix, Markers.EMPTY, HclRightPadded.build(name).withAfter(sourceBefore(")"))); @@ -486,7 +492,7 @@ public Hcl visitObjectelem(HCLParser.ObjectelemContext ctx) { c.ASSIGN() != null ? Hcl.Attribute.Type.Assignment : Hcl.Attribute.Type.ObjectElement, Markers.EMPTY ), - (Expression) visit(c.expression()), + (Expression) visit(c.expression().get(c.expression().size() - 1)), ctx.COMMA() == null ? null : new Hcl.Empty(randomId(), sourceBefore(","), Markers.EMPTY) diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java index 31598f56b7a..1a843f9b242 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,15 +15,15 @@ */ // Generated from java-escape by ANTLR 4.11.1 package org.openrewrite.hcl.internal.grammar; - +import java.util.Stack; +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.ATN; -import org.antlr.v4.runtime.atn.ATNDeserializer; -import org.antlr.v4.runtime.atn.LexerATNSimulator; -import org.antlr.v4.runtime.atn.PredictionContextCache; +import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; - -import java.util.Stack; +import org.antlr.v4.runtime.misc.*; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) public class HCLLexer extends Lexer { @@ -33,12 +33,12 @@ public class HCLLexer extends Lexer { protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int - FOR_BRACE=1, FOR_BRACK=2, IF=3, IN=4, LBRACE=5, RBRACE=6, ASSIGN=7, Identifier=8, - WS=9, COMMENT=10, LINE_COMMENT=11, NEWLINE=12, NumericLiteral=13, BooleanLiteral=14, - QUOTE=15, NULL=16, HEREDOC_START=17, PLUS=18, AND=19, EQ=20, LT=21, COLON=22, - LBRACK=23, LPAREN=24, MINUS=25, OR=26, NEQ=27, GT=28, QUESTION=29, RBRACK=30, - RPAREN=31, MUL=32, NOT=33, LEQ=34, DOT=35, DIV=36, GEQ=37, ARROW=38, COMMA=39, - MOD=40, ELLIPSIS=41, TILDE=42, TEMPLATE_INTERPOLATION_START=43, TemplateStringLiteral=44, + FOR_BRACE=1, FOR_BRACK=2, IF=3, IN=4, LBRACE=5, RBRACE=6, ASSIGN=7, Identifier=8, + WS=9, COMMENT=10, LINE_COMMENT=11, NEWLINE=12, NumericLiteral=13, BooleanLiteral=14, + QUOTE=15, NULL=16, HEREDOC_START=17, PLUS=18, AND=19, EQ=20, LT=21, COLON=22, + LBRACK=23, LPAREN=24, MINUS=25, OR=26, NEQ=27, GT=28, QUESTION=29, RBRACK=30, + RPAREN=31, MUL=32, NOT=33, LEQ=34, DOT=35, DIV=36, GEQ=37, ARROW=38, COMMA=39, + MOD=40, ELLIPSIS=41, TILDE=42, TEMPLATE_INTERPOLATION_START=43, TemplateStringLiteral=44, TemplateStringLiteralChar=45, HTemplateLiteral=46, HTemplateLiteralChar=47; public static final int TEMPLATE=1, HEREDOC_PREAMBLE=2, HEREDOC=3; @@ -52,15 +52,15 @@ public class HCLLexer extends Lexer { private static String[] makeRuleNames() { return new String[] { - "FOR_BRACE", "FOR_BRACK", "IF", "IN", "LBRACE", "RBRACE", "ASSIGN", "StringLiteralChar", - "Identifier", "WS", "COMMENT", "LINE_COMMENT", "NEWLINE", "LetterOrDigit", - "Letter", "EscapeSequence", "HexDigit", "NumericLiteral", "ExponentPart", - "BooleanLiteral", "QUOTE", "NULL", "HEREDOC_START", "PLUS", "AND", "EQ", - "LT", "COLON", "LBRACK", "LPAREN", "MINUS", "OR", "NEQ", "GT", "QUESTION", - "RBRACK", "RPAREN", "MUL", "NOT", "LEQ", "DOT", "DIV", "GEQ", "ARROW", - "COMMA", "MOD", "ELLIPSIS", "TILDE", "TEMPLATE_INTERPOLATION_START", - "TemplateStringLiteral", "TemplateStringLiteralChar", "END_QUOTE", "HP_NEWLINE", - "HPIdentifier", "H_NEWLINE", "H_TEMPLATE_INTERPOLATION_START", "HTemplateLiteral", + "FOR_BRACE", "FOR_BRACK", "IF", "IN", "LBRACE", "RBRACE", "ASSIGN", "StringLiteralChar", + "Identifier", "WS", "COMMENT", "LINE_COMMENT", "NEWLINE", "LetterOrDigit", + "Letter", "EscapeSequence", "HexDigit", "NumericLiteral", "ExponentPart", + "BooleanLiteral", "QUOTE", "NULL", "HEREDOC_START", "PLUS", "AND", "EQ", + "LT", "COLON", "LBRACK", "LPAREN", "MINUS", "OR", "NEQ", "GT", "QUESTION", + "RBRACK", "RPAREN", "MUL", "NOT", "LEQ", "DOT", "DIV", "GEQ", "ARROW", + "COMMA", "MOD", "ELLIPSIS", "TILDE", "TEMPLATE_INTERPOLATION_START", + "TemplateStringLiteral", "TemplateStringLiteralChar", "END_QUOTE", "HP_NEWLINE", + "HPIdentifier", "H_NEWLINE", "H_TEMPLATE_INTERPOLATION_START", "HTemplateLiteral", "HTemplateLiteralChar" }; } @@ -68,23 +68,23 @@ private static String[] makeRuleNames() { private static String[] makeLiteralNames() { return new String[] { - null, null, null, "'if'", "'in'", "'{'", "'}'", "'='", null, null, null, - null, null, null, null, null, "'null'", null, "'+'", "'&&'", "'=='", - "'<'", "':'", "'['", "'('", "'-'", "'||'", "'!='", "'>'", "'?'", "']'", - "')'", "'*'", "'!'", "'<='", "'.'", "'/'", "'>='", "'=>'", "','", "'%'", + null, null, null, "'if'", "'in'", "'{'", "'}'", "'='", null, null, null, + null, null, null, null, null, "'null'", null, "'+'", "'&&'", "'=='", + "'<'", "':'", "'['", "'('", "'-'", "'||'", "'!='", "'>'", "'?'", "']'", + "')'", "'*'", "'!'", "'<='", "'.'", "'/'", "'>='", "'=>'", "','", "'%'", "'...'", "'~'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { - null, "FOR_BRACE", "FOR_BRACK", "IF", "IN", "LBRACE", "RBRACE", "ASSIGN", - "Identifier", "WS", "COMMENT", "LINE_COMMENT", "NEWLINE", "NumericLiteral", - "BooleanLiteral", "QUOTE", "NULL", "HEREDOC_START", "PLUS", "AND", "EQ", - "LT", "COLON", "LBRACK", "LPAREN", "MINUS", "OR", "NEQ", "GT", "QUESTION", - "RBRACK", "RPAREN", "MUL", "NOT", "LEQ", "DOT", "DIV", "GEQ", "ARROW", - "COMMA", "MOD", "ELLIPSIS", "TILDE", "TEMPLATE_INTERPOLATION_START", - "TemplateStringLiteral", "TemplateStringLiteralChar", "HTemplateLiteral", + null, "FOR_BRACE", "FOR_BRACK", "IF", "IN", "LBRACE", "RBRACE", "ASSIGN", + "Identifier", "WS", "COMMENT", "LINE_COMMENT", "NEWLINE", "NumericLiteral", + "BooleanLiteral", "QUOTE", "NULL", "HEREDOC_START", "PLUS", "AND", "EQ", + "LT", "COLON", "LBRACK", "LPAREN", "MINUS", "OR", "NEQ", "GT", "QUESTION", + "RBRACK", "RPAREN", "MUL", "NOT", "LEQ", "DOT", "DIV", "GEQ", "ARROW", + "COMMA", "MOD", "ELLIPSIS", "TILDE", "TEMPLATE_INTERPOLATION_START", + "TemplateStringLiteral", "TemplateStringLiteralChar", "HTemplateLiteral", "HTemplateLiteralChar" }; } diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.interp b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.interp index dfee8f1641d..20b2b39e3b0 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.interp +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.interp @@ -142,4 +142,4 @@ templateInterpolation atn: -[4, 1, 47, 361, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 1, 0, 1, 0, 1, 1, 5, 1, 84, 8, 1, 10, 1, 12, 1, 87, 9, 1, 1, 2, 1, 2, 3, 2, 91, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 5, 4, 99, 8, 4, 10, 4, 12, 4, 102, 9, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 111, 8, 5, 1, 6, 1, 6, 1, 6, 3, 6, 116, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 5, 6, 124, 8, 6, 10, 6, 12, 6, 127, 9, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 140, 8, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 5, 7, 148, 8, 7, 10, 7, 12, 7, 151, 9, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 3, 10, 161, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 167, 8, 11, 10, 11, 12, 11, 170, 9, 11, 1, 11, 3, 11, 173, 8, 11, 3, 11, 175, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 5, 12, 181, 8, 12, 10, 12, 12, 12, 184, 9, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 194, 8, 13, 10, 13, 12, 13, 197, 9, 13, 1, 13, 3, 13, 200, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 205, 8, 13, 1, 14, 1, 14, 3, 14, 209, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 216, 8, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 227, 8, 16, 1, 16, 3, 16, 230, 8, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 3, 17, 237, 8, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 3, 20, 250, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 5, 21, 257, 8, 21, 10, 21, 12, 21, 260, 9, 21, 1, 21, 3, 21, 263, 8, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 3, 24, 274, 8, 24, 1, 25, 1, 25, 1, 25, 5, 25, 279, 8, 25, 10, 25, 12, 25, 282, 9, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 5, 26, 289, 8, 26, 10, 26, 12, 26, 292, 9, 26, 1, 27, 1, 27, 3, 27, 296, 8, 27, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 3, 29, 303, 8, 29, 1, 29, 1, 29, 1, 29, 3, 29, 308, 8, 29, 1, 30, 1, 30, 1, 30, 3, 30, 313, 8, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 325, 8, 34, 10, 34, 12, 34, 328, 9, 34, 4, 34, 330, 8, 34, 11, 34, 12, 34, 331, 1, 34, 1, 34, 1, 34, 5, 34, 337, 8, 34, 10, 34, 12, 34, 340, 9, 34, 1, 34, 3, 34, 343, 8, 34, 1, 35, 1, 35, 3, 35, 347, 8, 35, 1, 36, 1, 36, 1, 37, 1, 37, 3, 37, 353, 8, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 0, 2, 12, 14, 40, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 0, 7, 2, 0, 13, 14, 16, 16, 2, 0, 7, 7, 22, 22, 2, 0, 39, 39, 41, 41, 2, 0, 25, 25, 33, 33, 4, 0, 20, 21, 27, 28, 34, 34, 37, 37, 5, 0, 18, 18, 25, 25, 32, 32, 36, 36, 40, 40, 2, 0, 19, 19, 26, 26, 367, 0, 80, 1, 0, 0, 0, 2, 85, 1, 0, 0, 0, 4, 90, 1, 0, 0, 0, 6, 92, 1, 0, 0, 0, 8, 96, 1, 0, 0, 0, 10, 110, 1, 0, 0, 0, 12, 115, 1, 0, 0, 0, 14, 139, 1, 0, 0, 0, 16, 152, 1, 0, 0, 0, 18, 156, 1, 0, 0, 0, 20, 160, 1, 0, 0, 0, 22, 162, 1, 0, 0, 0, 24, 178, 1, 0, 0, 0, 26, 199, 1, 0, 0, 0, 28, 208, 1, 0, 0, 0, 30, 210, 1, 0, 0, 0, 32, 219, 1, 0, 0, 0, 34, 233, 1, 0, 0, 0, 36, 241, 1, 0, 0, 0, 38, 244, 1, 0, 0, 0, 40, 246, 1, 0, 0, 0, 42, 253, 1, 0, 0, 0, 44, 264, 1, 0, 0, 0, 46, 268, 1, 0, 0, 0, 48, 273, 1, 0, 0, 0, 50, 275, 1, 0, 0, 0, 52, 283, 1, 0, 0, 0, 54, 295, 1, 0, 0, 0, 56, 297, 1, 0, 0, 0, 58, 302, 1, 0, 0, 0, 60, 312, 1, 0, 0, 0, 62, 314, 1, 0, 0, 0, 64, 316, 1, 0, 0, 0, 66, 318, 1, 0, 0, 0, 68, 342, 1, 0, 0, 0, 70, 346, 1, 0, 0, 0, 72, 348, 1, 0, 0, 0, 74, 352, 1, 0, 0, 0, 76, 354, 1, 0, 0, 0, 78, 356, 1, 0, 0, 0, 80, 81, 3, 2, 1, 0, 81, 1, 1, 0, 0, 0, 82, 84, 3, 4, 2, 0, 83, 82, 1, 0, 0, 0, 84, 87, 1, 0, 0, 0, 85, 83, 1, 0, 0, 0, 85, 86, 1, 0, 0, 0, 86, 3, 1, 0, 0, 0, 87, 85, 1, 0, 0, 0, 88, 91, 3, 6, 3, 0, 89, 91, 3, 8, 4, 0, 90, 88, 1, 0, 0, 0, 90, 89, 1, 0, 0, 0, 91, 5, 1, 0, 0, 0, 92, 93, 5, 8, 0, 0, 93, 94, 5, 7, 0, 0, 94, 95, 3, 12, 6, 0, 95, 7, 1, 0, 0, 0, 96, 100, 5, 8, 0, 0, 97, 99, 3, 10, 5, 0, 98, 97, 1, 0, 0, 0, 99, 102, 1, 0, 0, 0, 100, 98, 1, 0, 0, 0, 100, 101, 1, 0, 0, 0, 101, 103, 1, 0, 0, 0, 102, 100, 1, 0, 0, 0, 103, 104, 3, 16, 8, 0, 104, 9, 1, 0, 0, 0, 105, 106, 5, 15, 0, 0, 106, 107, 3, 76, 38, 0, 107, 108, 5, 15, 0, 0, 108, 111, 1, 0, 0, 0, 109, 111, 5, 8, 0, 0, 110, 105, 1, 0, 0, 0, 110, 109, 1, 0, 0, 0, 111, 11, 1, 0, 0, 0, 112, 113, 6, 6, -1, 0, 113, 116, 3, 14, 7, 0, 114, 116, 3, 54, 27, 0, 115, 112, 1, 0, 0, 0, 115, 114, 1, 0, 0, 0, 116, 125, 1, 0, 0, 0, 117, 118, 10, 1, 0, 0, 118, 119, 5, 29, 0, 0, 119, 120, 3, 12, 6, 0, 120, 121, 5, 22, 0, 0, 121, 122, 3, 12, 6, 2, 122, 124, 1, 0, 0, 0, 123, 117, 1, 0, 0, 0, 124, 127, 1, 0, 0, 0, 125, 123, 1, 0, 0, 0, 125, 126, 1, 0, 0, 0, 126, 13, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 128, 129, 6, 7, -1, 0, 129, 140, 3, 68, 34, 0, 130, 140, 3, 18, 9, 0, 131, 140, 3, 28, 14, 0, 132, 140, 3, 20, 10, 0, 133, 140, 3, 38, 19, 0, 134, 140, 3, 40, 20, 0, 135, 136, 5, 24, 0, 0, 136, 137, 3, 12, 6, 0, 137, 138, 5, 31, 0, 0, 138, 140, 1, 0, 0, 0, 139, 128, 1, 0, 0, 0, 139, 130, 1, 0, 0, 0, 139, 131, 1, 0, 0, 0, 139, 132, 1, 0, 0, 0, 139, 133, 1, 0, 0, 0, 139, 134, 1, 0, 0, 0, 139, 135, 1, 0, 0, 0, 140, 149, 1, 0, 0, 0, 141, 142, 10, 4, 0, 0, 142, 148, 3, 44, 22, 0, 143, 144, 10, 3, 0, 0, 144, 148, 3, 46, 23, 0, 145, 146, 10, 2, 0, 0, 146, 148, 3, 48, 24, 0, 147, 141, 1, 0, 0, 0, 147, 143, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 148, 151, 1, 0, 0, 0, 149, 147, 1, 0, 0, 0, 149, 150, 1, 0, 0, 0, 150, 15, 1, 0, 0, 0, 151, 149, 1, 0, 0, 0, 152, 153, 5, 5, 0, 0, 153, 154, 3, 2, 1, 0, 154, 155, 5, 6, 0, 0, 155, 17, 1, 0, 0, 0, 156, 157, 7, 0, 0, 0, 157, 19, 1, 0, 0, 0, 158, 161, 3, 22, 11, 0, 159, 161, 3, 24, 12, 0, 160, 158, 1, 0, 0, 0, 160, 159, 1, 0, 0, 0, 161, 21, 1, 0, 0, 0, 162, 174, 5, 23, 0, 0, 163, 168, 3, 12, 6, 0, 164, 165, 5, 39, 0, 0, 165, 167, 3, 12, 6, 0, 166, 164, 1, 0, 0, 0, 167, 170, 1, 0, 0, 0, 168, 166, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 172, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 173, 5, 39, 0, 0, 172, 171, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, 173, 175, 1, 0, 0, 0, 174, 163, 1, 0, 0, 0, 174, 175, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 177, 5, 30, 0, 0, 177, 23, 1, 0, 0, 0, 178, 182, 5, 5, 0, 0, 179, 181, 3, 26, 13, 0, 180, 179, 1, 0, 0, 0, 181, 184, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 185, 1, 0, 0, 0, 184, 182, 1, 0, 0, 0, 185, 186, 5, 6, 0, 0, 186, 25, 1, 0, 0, 0, 187, 200, 5, 8, 0, 0, 188, 189, 5, 24, 0, 0, 189, 190, 5, 8, 0, 0, 190, 200, 5, 31, 0, 0, 191, 195, 5, 15, 0, 0, 192, 194, 3, 74, 37, 0, 193, 192, 1, 0, 0, 0, 194, 197, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 198, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 198, 200, 5, 15, 0, 0, 199, 187, 1, 0, 0, 0, 199, 188, 1, 0, 0, 0, 199, 191, 1, 0, 0, 0, 200, 201, 1, 0, 0, 0, 201, 202, 7, 1, 0, 0, 202, 204, 3, 12, 6, 0, 203, 205, 5, 39, 0, 0, 204, 203, 1, 0, 0, 0, 204, 205, 1, 0, 0, 0, 205, 27, 1, 0, 0, 0, 206, 209, 3, 30, 15, 0, 207, 209, 3, 32, 16, 0, 208, 206, 1, 0, 0, 0, 208, 207, 1, 0, 0, 0, 209, 29, 1, 0, 0, 0, 210, 211, 5, 2, 0, 0, 211, 212, 3, 34, 17, 0, 212, 213, 5, 22, 0, 0, 213, 215, 3, 12, 6, 0, 214, 216, 3, 36, 18, 0, 215, 214, 1, 0, 0, 0, 215, 216, 1, 0, 0, 0, 216, 217, 1, 0, 0, 0, 217, 218, 5, 30, 0, 0, 218, 31, 1, 0, 0, 0, 219, 220, 5, 1, 0, 0, 220, 221, 3, 34, 17, 0, 221, 222, 5, 22, 0, 0, 222, 223, 3, 12, 6, 0, 223, 224, 5, 38, 0, 0, 224, 226, 3, 12, 6, 0, 225, 227, 5, 41, 0, 0, 226, 225, 1, 0, 0, 0, 226, 227, 1, 0, 0, 0, 227, 229, 1, 0, 0, 0, 228, 230, 3, 36, 18, 0, 229, 228, 1, 0, 0, 0, 229, 230, 1, 0, 0, 0, 230, 231, 1, 0, 0, 0, 231, 232, 5, 6, 0, 0, 232, 33, 1, 0, 0, 0, 233, 236, 5, 8, 0, 0, 234, 235, 5, 39, 0, 0, 235, 237, 5, 8, 0, 0, 236, 234, 1, 0, 0, 0, 236, 237, 1, 0, 0, 0, 237, 238, 1, 0, 0, 0, 238, 239, 5, 4, 0, 0, 239, 240, 3, 12, 6, 0, 240, 35, 1, 0, 0, 0, 241, 242, 5, 3, 0, 0, 242, 243, 3, 12, 6, 0, 243, 37, 1, 0, 0, 0, 244, 245, 5, 8, 0, 0, 245, 39, 1, 0, 0, 0, 246, 247, 5, 8, 0, 0, 247, 249, 5, 24, 0, 0, 248, 250, 3, 42, 21, 0, 249, 248, 1, 0, 0, 0, 249, 250, 1, 0, 0, 0, 250, 251, 1, 0, 0, 0, 251, 252, 5, 31, 0, 0, 252, 41, 1, 0, 0, 0, 253, 258, 3, 12, 6, 0, 254, 255, 5, 39, 0, 0, 255, 257, 3, 12, 6, 0, 256, 254, 1, 0, 0, 0, 257, 260, 1, 0, 0, 0, 258, 256, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 262, 1, 0, 0, 0, 260, 258, 1, 0, 0, 0, 261, 263, 7, 2, 0, 0, 262, 261, 1, 0, 0, 0, 262, 263, 1, 0, 0, 0, 263, 43, 1, 0, 0, 0, 264, 265, 5, 23, 0, 0, 265, 266, 3, 12, 6, 0, 266, 267, 5, 30, 0, 0, 267, 45, 1, 0, 0, 0, 268, 269, 5, 35, 0, 0, 269, 270, 5, 8, 0, 0, 270, 47, 1, 0, 0, 0, 271, 274, 3, 50, 25, 0, 272, 274, 3, 52, 26, 0, 273, 271, 1, 0, 0, 0, 273, 272, 1, 0, 0, 0, 274, 49, 1, 0, 0, 0, 275, 276, 5, 35, 0, 0, 276, 280, 5, 32, 0, 0, 277, 279, 3, 46, 23, 0, 278, 277, 1, 0, 0, 0, 279, 282, 1, 0, 0, 0, 280, 278, 1, 0, 0, 0, 280, 281, 1, 0, 0, 0, 281, 51, 1, 0, 0, 0, 282, 280, 1, 0, 0, 0, 283, 284, 5, 23, 0, 0, 284, 285, 5, 32, 0, 0, 285, 290, 5, 30, 0, 0, 286, 289, 3, 46, 23, 0, 287, 289, 3, 44, 22, 0, 288, 286, 1, 0, 0, 0, 288, 287, 1, 0, 0, 0, 289, 292, 1, 0, 0, 0, 290, 288, 1, 0, 0, 0, 290, 291, 1, 0, 0, 0, 291, 53, 1, 0, 0, 0, 292, 290, 1, 0, 0, 0, 293, 296, 3, 56, 28, 0, 294, 296, 3, 58, 29, 0, 295, 293, 1, 0, 0, 0, 295, 294, 1, 0, 0, 0, 296, 55, 1, 0, 0, 0, 297, 298, 7, 3, 0, 0, 298, 299, 3, 14, 7, 0, 299, 57, 1, 0, 0, 0, 300, 303, 3, 14, 7, 0, 301, 303, 3, 56, 28, 0, 302, 300, 1, 0, 0, 0, 302, 301, 1, 0, 0, 0, 303, 304, 1, 0, 0, 0, 304, 307, 3, 60, 30, 0, 305, 308, 3, 14, 7, 0, 306, 308, 3, 54, 27, 0, 307, 305, 1, 0, 0, 0, 307, 306, 1, 0, 0, 0, 308, 59, 1, 0, 0, 0, 309, 313, 3, 62, 31, 0, 310, 313, 3, 64, 32, 0, 311, 313, 3, 66, 33, 0, 312, 309, 1, 0, 0, 0, 312, 310, 1, 0, 0, 0, 312, 311, 1, 0, 0, 0, 313, 61, 1, 0, 0, 0, 314, 315, 7, 4, 0, 0, 315, 63, 1, 0, 0, 0, 316, 317, 7, 5, 0, 0, 317, 65, 1, 0, 0, 0, 318, 319, 7, 6, 0, 0, 319, 67, 1, 0, 0, 0, 320, 321, 5, 17, 0, 0, 321, 329, 5, 8, 0, 0, 322, 326, 5, 12, 0, 0, 323, 325, 3, 70, 35, 0, 324, 323, 1, 0, 0, 0, 325, 328, 1, 0, 0, 0, 326, 324, 1, 0, 0, 0, 326, 327, 1, 0, 0, 0, 327, 330, 1, 0, 0, 0, 328, 326, 1, 0, 0, 0, 329, 322, 1, 0, 0, 0, 330, 331, 1, 0, 0, 0, 331, 329, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 333, 1, 0, 0, 0, 333, 343, 5, 8, 0, 0, 334, 338, 5, 15, 0, 0, 335, 337, 3, 74, 37, 0, 336, 335, 1, 0, 0, 0, 337, 340, 1, 0, 0, 0, 338, 336, 1, 0, 0, 0, 338, 339, 1, 0, 0, 0, 339, 341, 1, 0, 0, 0, 340, 338, 1, 0, 0, 0, 341, 343, 5, 15, 0, 0, 342, 320, 1, 0, 0, 0, 342, 334, 1, 0, 0, 0, 343, 69, 1, 0, 0, 0, 344, 347, 3, 78, 39, 0, 345, 347, 3, 72, 36, 0, 346, 344, 1, 0, 0, 0, 346, 345, 1, 0, 0, 0, 347, 71, 1, 0, 0, 0, 348, 349, 5, 46, 0, 0, 349, 73, 1, 0, 0, 0, 350, 353, 3, 78, 39, 0, 351, 353, 3, 76, 38, 0, 352, 350, 1, 0, 0, 0, 352, 351, 1, 0, 0, 0, 353, 75, 1, 0, 0, 0, 354, 355, 5, 44, 0, 0, 355, 77, 1, 0, 0, 0, 356, 357, 5, 43, 0, 0, 357, 358, 3, 12, 6, 0, 358, 359, 5, 6, 0, 0, 359, 79, 1, 0, 0, 0, 39, 85, 90, 100, 110, 115, 125, 139, 147, 149, 160, 168, 172, 174, 182, 195, 199, 204, 208, 215, 226, 229, 236, 249, 258, 262, 273, 280, 288, 290, 295, 302, 307, 312, 326, 331, 338, 342, 346, 352] \ No newline at end of file +[4, 1, 47, 362, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 1, 0, 1, 0, 1, 1, 5, 1, 84, 8, 1, 10, 1, 12, 1, 87, 9, 1, 1, 2, 1, 2, 3, 2, 91, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 5, 4, 99, 8, 4, 10, 4, 12, 4, 102, 9, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 111, 8, 5, 1, 6, 1, 6, 1, 6, 3, 6, 116, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 5, 6, 124, 8, 6, 10, 6, 12, 6, 127, 9, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 140, 8, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 5, 7, 148, 8, 7, 10, 7, 12, 7, 151, 9, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 3, 10, 161, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 167, 8, 11, 10, 11, 12, 11, 170, 9, 11, 1, 11, 3, 11, 173, 8, 11, 3, 11, 175, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 5, 12, 181, 8, 12, 10, 12, 12, 12, 184, 9, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 194, 8, 13, 10, 13, 12, 13, 197, 9, 13, 1, 13, 1, 13, 3, 13, 201, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 206, 8, 13, 1, 14, 1, 14, 3, 14, 210, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 217, 8, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 228, 8, 16, 1, 16, 3, 16, 231, 8, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 3, 17, 238, 8, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 3, 20, 251, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 5, 21, 258, 8, 21, 10, 21, 12, 21, 261, 9, 21, 1, 21, 3, 21, 264, 8, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 3, 24, 275, 8, 24, 1, 25, 1, 25, 1, 25, 5, 25, 280, 8, 25, 10, 25, 12, 25, 283, 9, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 5, 26, 290, 8, 26, 10, 26, 12, 26, 293, 9, 26, 1, 27, 1, 27, 3, 27, 297, 8, 27, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 3, 29, 304, 8, 29, 1, 29, 1, 29, 1, 29, 3, 29, 309, 8, 29, 1, 30, 1, 30, 1, 30, 3, 30, 314, 8, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 326, 8, 34, 10, 34, 12, 34, 329, 9, 34, 4, 34, 331, 8, 34, 11, 34, 12, 34, 332, 1, 34, 1, 34, 1, 34, 5, 34, 338, 8, 34, 10, 34, 12, 34, 341, 9, 34, 1, 34, 3, 34, 344, 8, 34, 1, 35, 1, 35, 3, 35, 348, 8, 35, 1, 36, 1, 36, 1, 37, 1, 37, 3, 37, 354, 8, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 0, 2, 12, 14, 40, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 0, 7, 2, 0, 13, 14, 16, 16, 2, 0, 7, 7, 22, 22, 2, 0, 39, 39, 41, 41, 2, 0, 25, 25, 33, 33, 4, 0, 20, 21, 27, 28, 34, 34, 37, 37, 5, 0, 18, 18, 25, 25, 32, 32, 36, 36, 40, 40, 2, 0, 19, 19, 26, 26, 369, 0, 80, 1, 0, 0, 0, 2, 85, 1, 0, 0, 0, 4, 90, 1, 0, 0, 0, 6, 92, 1, 0, 0, 0, 8, 96, 1, 0, 0, 0, 10, 110, 1, 0, 0, 0, 12, 115, 1, 0, 0, 0, 14, 139, 1, 0, 0, 0, 16, 152, 1, 0, 0, 0, 18, 156, 1, 0, 0, 0, 20, 160, 1, 0, 0, 0, 22, 162, 1, 0, 0, 0, 24, 178, 1, 0, 0, 0, 26, 200, 1, 0, 0, 0, 28, 209, 1, 0, 0, 0, 30, 211, 1, 0, 0, 0, 32, 220, 1, 0, 0, 0, 34, 234, 1, 0, 0, 0, 36, 242, 1, 0, 0, 0, 38, 245, 1, 0, 0, 0, 40, 247, 1, 0, 0, 0, 42, 254, 1, 0, 0, 0, 44, 265, 1, 0, 0, 0, 46, 269, 1, 0, 0, 0, 48, 274, 1, 0, 0, 0, 50, 276, 1, 0, 0, 0, 52, 284, 1, 0, 0, 0, 54, 296, 1, 0, 0, 0, 56, 298, 1, 0, 0, 0, 58, 303, 1, 0, 0, 0, 60, 313, 1, 0, 0, 0, 62, 315, 1, 0, 0, 0, 64, 317, 1, 0, 0, 0, 66, 319, 1, 0, 0, 0, 68, 343, 1, 0, 0, 0, 70, 347, 1, 0, 0, 0, 72, 349, 1, 0, 0, 0, 74, 353, 1, 0, 0, 0, 76, 355, 1, 0, 0, 0, 78, 357, 1, 0, 0, 0, 80, 81, 3, 2, 1, 0, 81, 1, 1, 0, 0, 0, 82, 84, 3, 4, 2, 0, 83, 82, 1, 0, 0, 0, 84, 87, 1, 0, 0, 0, 85, 83, 1, 0, 0, 0, 85, 86, 1, 0, 0, 0, 86, 3, 1, 0, 0, 0, 87, 85, 1, 0, 0, 0, 88, 91, 3, 6, 3, 0, 89, 91, 3, 8, 4, 0, 90, 88, 1, 0, 0, 0, 90, 89, 1, 0, 0, 0, 91, 5, 1, 0, 0, 0, 92, 93, 5, 8, 0, 0, 93, 94, 5, 7, 0, 0, 94, 95, 3, 12, 6, 0, 95, 7, 1, 0, 0, 0, 96, 100, 5, 8, 0, 0, 97, 99, 3, 10, 5, 0, 98, 97, 1, 0, 0, 0, 99, 102, 1, 0, 0, 0, 100, 98, 1, 0, 0, 0, 100, 101, 1, 0, 0, 0, 101, 103, 1, 0, 0, 0, 102, 100, 1, 0, 0, 0, 103, 104, 3, 16, 8, 0, 104, 9, 1, 0, 0, 0, 105, 106, 5, 15, 0, 0, 106, 107, 3, 76, 38, 0, 107, 108, 5, 15, 0, 0, 108, 111, 1, 0, 0, 0, 109, 111, 5, 8, 0, 0, 110, 105, 1, 0, 0, 0, 110, 109, 1, 0, 0, 0, 111, 11, 1, 0, 0, 0, 112, 113, 6, 6, -1, 0, 113, 116, 3, 14, 7, 0, 114, 116, 3, 54, 27, 0, 115, 112, 1, 0, 0, 0, 115, 114, 1, 0, 0, 0, 116, 125, 1, 0, 0, 0, 117, 118, 10, 1, 0, 0, 118, 119, 5, 29, 0, 0, 119, 120, 3, 12, 6, 0, 120, 121, 5, 22, 0, 0, 121, 122, 3, 12, 6, 2, 122, 124, 1, 0, 0, 0, 123, 117, 1, 0, 0, 0, 124, 127, 1, 0, 0, 0, 125, 123, 1, 0, 0, 0, 125, 126, 1, 0, 0, 0, 126, 13, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 128, 129, 6, 7, -1, 0, 129, 140, 3, 68, 34, 0, 130, 140, 3, 18, 9, 0, 131, 140, 3, 28, 14, 0, 132, 140, 3, 20, 10, 0, 133, 140, 3, 38, 19, 0, 134, 140, 3, 40, 20, 0, 135, 136, 5, 24, 0, 0, 136, 137, 3, 12, 6, 0, 137, 138, 5, 31, 0, 0, 138, 140, 1, 0, 0, 0, 139, 128, 1, 0, 0, 0, 139, 130, 1, 0, 0, 0, 139, 131, 1, 0, 0, 0, 139, 132, 1, 0, 0, 0, 139, 133, 1, 0, 0, 0, 139, 134, 1, 0, 0, 0, 139, 135, 1, 0, 0, 0, 140, 149, 1, 0, 0, 0, 141, 142, 10, 4, 0, 0, 142, 148, 3, 44, 22, 0, 143, 144, 10, 3, 0, 0, 144, 148, 3, 46, 23, 0, 145, 146, 10, 2, 0, 0, 146, 148, 3, 48, 24, 0, 147, 141, 1, 0, 0, 0, 147, 143, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 148, 151, 1, 0, 0, 0, 149, 147, 1, 0, 0, 0, 149, 150, 1, 0, 0, 0, 150, 15, 1, 0, 0, 0, 151, 149, 1, 0, 0, 0, 152, 153, 5, 5, 0, 0, 153, 154, 3, 2, 1, 0, 154, 155, 5, 6, 0, 0, 155, 17, 1, 0, 0, 0, 156, 157, 7, 0, 0, 0, 157, 19, 1, 0, 0, 0, 158, 161, 3, 22, 11, 0, 159, 161, 3, 24, 12, 0, 160, 158, 1, 0, 0, 0, 160, 159, 1, 0, 0, 0, 161, 21, 1, 0, 0, 0, 162, 174, 5, 23, 0, 0, 163, 168, 3, 12, 6, 0, 164, 165, 5, 39, 0, 0, 165, 167, 3, 12, 6, 0, 166, 164, 1, 0, 0, 0, 167, 170, 1, 0, 0, 0, 168, 166, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 172, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 173, 5, 39, 0, 0, 172, 171, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, 173, 175, 1, 0, 0, 0, 174, 163, 1, 0, 0, 0, 174, 175, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 177, 5, 30, 0, 0, 177, 23, 1, 0, 0, 0, 178, 182, 5, 5, 0, 0, 179, 181, 3, 26, 13, 0, 180, 179, 1, 0, 0, 0, 181, 184, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 185, 1, 0, 0, 0, 184, 182, 1, 0, 0, 0, 185, 186, 5, 6, 0, 0, 186, 25, 1, 0, 0, 0, 187, 201, 5, 8, 0, 0, 188, 189, 5, 24, 0, 0, 189, 190, 5, 8, 0, 0, 190, 201, 5, 31, 0, 0, 191, 195, 5, 15, 0, 0, 192, 194, 3, 74, 37, 0, 193, 192, 1, 0, 0, 0, 194, 197, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 198, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 198, 201, 5, 15, 0, 0, 199, 201, 3, 12, 6, 0, 200, 187, 1, 0, 0, 0, 200, 188, 1, 0, 0, 0, 200, 191, 1, 0, 0, 0, 200, 199, 1, 0, 0, 0, 201, 202, 1, 0, 0, 0, 202, 203, 7, 1, 0, 0, 203, 205, 3, 12, 6, 0, 204, 206, 5, 39, 0, 0, 205, 204, 1, 0, 0, 0, 205, 206, 1, 0, 0, 0, 206, 27, 1, 0, 0, 0, 207, 210, 3, 30, 15, 0, 208, 210, 3, 32, 16, 0, 209, 207, 1, 0, 0, 0, 209, 208, 1, 0, 0, 0, 210, 29, 1, 0, 0, 0, 211, 212, 5, 2, 0, 0, 212, 213, 3, 34, 17, 0, 213, 214, 5, 22, 0, 0, 214, 216, 3, 12, 6, 0, 215, 217, 3, 36, 18, 0, 216, 215, 1, 0, 0, 0, 216, 217, 1, 0, 0, 0, 217, 218, 1, 0, 0, 0, 218, 219, 5, 30, 0, 0, 219, 31, 1, 0, 0, 0, 220, 221, 5, 1, 0, 0, 221, 222, 3, 34, 17, 0, 222, 223, 5, 22, 0, 0, 223, 224, 3, 12, 6, 0, 224, 225, 5, 38, 0, 0, 225, 227, 3, 12, 6, 0, 226, 228, 5, 41, 0, 0, 227, 226, 1, 0, 0, 0, 227, 228, 1, 0, 0, 0, 228, 230, 1, 0, 0, 0, 229, 231, 3, 36, 18, 0, 230, 229, 1, 0, 0, 0, 230, 231, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 233, 5, 6, 0, 0, 233, 33, 1, 0, 0, 0, 234, 237, 5, 8, 0, 0, 235, 236, 5, 39, 0, 0, 236, 238, 5, 8, 0, 0, 237, 235, 1, 0, 0, 0, 237, 238, 1, 0, 0, 0, 238, 239, 1, 0, 0, 0, 239, 240, 5, 4, 0, 0, 240, 241, 3, 12, 6, 0, 241, 35, 1, 0, 0, 0, 242, 243, 5, 3, 0, 0, 243, 244, 3, 12, 6, 0, 244, 37, 1, 0, 0, 0, 245, 246, 5, 8, 0, 0, 246, 39, 1, 0, 0, 0, 247, 248, 5, 8, 0, 0, 248, 250, 5, 24, 0, 0, 249, 251, 3, 42, 21, 0, 250, 249, 1, 0, 0, 0, 250, 251, 1, 0, 0, 0, 251, 252, 1, 0, 0, 0, 252, 253, 5, 31, 0, 0, 253, 41, 1, 0, 0, 0, 254, 259, 3, 12, 6, 0, 255, 256, 5, 39, 0, 0, 256, 258, 3, 12, 6, 0, 257, 255, 1, 0, 0, 0, 258, 261, 1, 0, 0, 0, 259, 257, 1, 0, 0, 0, 259, 260, 1, 0, 0, 0, 260, 263, 1, 0, 0, 0, 261, 259, 1, 0, 0, 0, 262, 264, 7, 2, 0, 0, 263, 262, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 43, 1, 0, 0, 0, 265, 266, 5, 23, 0, 0, 266, 267, 3, 12, 6, 0, 267, 268, 5, 30, 0, 0, 268, 45, 1, 0, 0, 0, 269, 270, 5, 35, 0, 0, 270, 271, 5, 8, 0, 0, 271, 47, 1, 0, 0, 0, 272, 275, 3, 50, 25, 0, 273, 275, 3, 52, 26, 0, 274, 272, 1, 0, 0, 0, 274, 273, 1, 0, 0, 0, 275, 49, 1, 0, 0, 0, 276, 277, 5, 35, 0, 0, 277, 281, 5, 32, 0, 0, 278, 280, 3, 46, 23, 0, 279, 278, 1, 0, 0, 0, 280, 283, 1, 0, 0, 0, 281, 279, 1, 0, 0, 0, 281, 282, 1, 0, 0, 0, 282, 51, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 284, 285, 5, 23, 0, 0, 285, 286, 5, 32, 0, 0, 286, 291, 5, 30, 0, 0, 287, 290, 3, 46, 23, 0, 288, 290, 3, 44, 22, 0, 289, 287, 1, 0, 0, 0, 289, 288, 1, 0, 0, 0, 290, 293, 1, 0, 0, 0, 291, 289, 1, 0, 0, 0, 291, 292, 1, 0, 0, 0, 292, 53, 1, 0, 0, 0, 293, 291, 1, 0, 0, 0, 294, 297, 3, 56, 28, 0, 295, 297, 3, 58, 29, 0, 296, 294, 1, 0, 0, 0, 296, 295, 1, 0, 0, 0, 297, 55, 1, 0, 0, 0, 298, 299, 7, 3, 0, 0, 299, 300, 3, 14, 7, 0, 300, 57, 1, 0, 0, 0, 301, 304, 3, 14, 7, 0, 302, 304, 3, 56, 28, 0, 303, 301, 1, 0, 0, 0, 303, 302, 1, 0, 0, 0, 304, 305, 1, 0, 0, 0, 305, 308, 3, 60, 30, 0, 306, 309, 3, 14, 7, 0, 307, 309, 3, 54, 27, 0, 308, 306, 1, 0, 0, 0, 308, 307, 1, 0, 0, 0, 309, 59, 1, 0, 0, 0, 310, 314, 3, 62, 31, 0, 311, 314, 3, 64, 32, 0, 312, 314, 3, 66, 33, 0, 313, 310, 1, 0, 0, 0, 313, 311, 1, 0, 0, 0, 313, 312, 1, 0, 0, 0, 314, 61, 1, 0, 0, 0, 315, 316, 7, 4, 0, 0, 316, 63, 1, 0, 0, 0, 317, 318, 7, 5, 0, 0, 318, 65, 1, 0, 0, 0, 319, 320, 7, 6, 0, 0, 320, 67, 1, 0, 0, 0, 321, 322, 5, 17, 0, 0, 322, 330, 5, 8, 0, 0, 323, 327, 5, 12, 0, 0, 324, 326, 3, 70, 35, 0, 325, 324, 1, 0, 0, 0, 326, 329, 1, 0, 0, 0, 327, 325, 1, 0, 0, 0, 327, 328, 1, 0, 0, 0, 328, 331, 1, 0, 0, 0, 329, 327, 1, 0, 0, 0, 330, 323, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 330, 1, 0, 0, 0, 332, 333, 1, 0, 0, 0, 333, 334, 1, 0, 0, 0, 334, 344, 5, 8, 0, 0, 335, 339, 5, 15, 0, 0, 336, 338, 3, 74, 37, 0, 337, 336, 1, 0, 0, 0, 338, 341, 1, 0, 0, 0, 339, 337, 1, 0, 0, 0, 339, 340, 1, 0, 0, 0, 340, 342, 1, 0, 0, 0, 341, 339, 1, 0, 0, 0, 342, 344, 5, 15, 0, 0, 343, 321, 1, 0, 0, 0, 343, 335, 1, 0, 0, 0, 344, 69, 1, 0, 0, 0, 345, 348, 3, 78, 39, 0, 346, 348, 3, 72, 36, 0, 347, 345, 1, 0, 0, 0, 347, 346, 1, 0, 0, 0, 348, 71, 1, 0, 0, 0, 349, 350, 5, 46, 0, 0, 350, 73, 1, 0, 0, 0, 351, 354, 3, 78, 39, 0, 352, 354, 3, 76, 38, 0, 353, 351, 1, 0, 0, 0, 353, 352, 1, 0, 0, 0, 354, 75, 1, 0, 0, 0, 355, 356, 5, 44, 0, 0, 356, 77, 1, 0, 0, 0, 357, 358, 5, 43, 0, 0, 358, 359, 3, 12, 6, 0, 359, 360, 5, 6, 0, 0, 360, 79, 1, 0, 0, 0, 39, 85, 90, 100, 110, 115, 125, 139, 147, 149, 160, 168, 172, 174, 182, 195, 200, 205, 209, 216, 227, 230, 237, 250, 259, 263, 274, 281, 289, 291, 296, 303, 308, 313, 327, 332, 339, 343, 347, 353] \ No newline at end of file diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.java index 94796886905..5d5346463fb 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,18 +15,14 @@ */ // Generated from java-escape by ANTLR 4.11.1 package org.openrewrite.hcl.internal.grammar; - -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.ATN; -import org.antlr.v4.runtime.atn.ATNDeserializer; -import org.antlr.v4.runtime.atn.ParserATNSimulator; -import org.antlr.v4.runtime.atn.PredictionContextCache; +import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.tree.ParseTreeListener; -import org.antlr.v4.runtime.tree.ParseTreeVisitor; -import org.antlr.v4.runtime.tree.TerminalNode; - +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.misc.*; +import org.antlr.v4.runtime.tree.*; import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) public class HCLParser extends Parser { @@ -36,34 +32,34 @@ public class HCLParser extends Parser { protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int - FOR_BRACE=1, FOR_BRACK=2, IF=3, IN=4, LBRACE=5, RBRACE=6, ASSIGN=7, Identifier=8, - WS=9, COMMENT=10, LINE_COMMENT=11, NEWLINE=12, NumericLiteral=13, BooleanLiteral=14, - QUOTE=15, NULL=16, HEREDOC_START=17, PLUS=18, AND=19, EQ=20, LT=21, COLON=22, - LBRACK=23, LPAREN=24, MINUS=25, OR=26, NEQ=27, GT=28, QUESTION=29, RBRACK=30, - RPAREN=31, MUL=32, NOT=33, LEQ=34, DOT=35, DIV=36, GEQ=37, ARROW=38, COMMA=39, - MOD=40, ELLIPSIS=41, TILDE=42, TEMPLATE_INTERPOLATION_START=43, TemplateStringLiteral=44, + FOR_BRACE=1, FOR_BRACK=2, IF=3, IN=4, LBRACE=5, RBRACE=6, ASSIGN=7, Identifier=8, + WS=9, COMMENT=10, LINE_COMMENT=11, NEWLINE=12, NumericLiteral=13, BooleanLiteral=14, + QUOTE=15, NULL=16, HEREDOC_START=17, PLUS=18, AND=19, EQ=20, LT=21, COLON=22, + LBRACK=23, LPAREN=24, MINUS=25, OR=26, NEQ=27, GT=28, QUESTION=29, RBRACK=30, + RPAREN=31, MUL=32, NOT=33, LEQ=34, DOT=35, DIV=36, GEQ=37, ARROW=38, COMMA=39, + MOD=40, ELLIPSIS=41, TILDE=42, TEMPLATE_INTERPOLATION_START=43, TemplateStringLiteral=44, TemplateStringLiteralChar=45, HTemplateLiteral=46, HTemplateLiteralChar=47; public static final int - RULE_configFile = 0, RULE_body = 1, RULE_bodyContent = 2, RULE_attribute = 3, - RULE_block = 4, RULE_blockLabel = 5, RULE_expression = 6, RULE_exprTerm = 7, - RULE_blockExpr = 8, RULE_literalValue = 9, RULE_collectionValue = 10, - RULE_tuple = 11, RULE_object = 12, RULE_objectelem = 13, RULE_forExpr = 14, - RULE_forTupleExpr = 15, RULE_forObjectExpr = 16, RULE_forIntro = 17, RULE_forCond = 18, - RULE_variableExpr = 19, RULE_functionCall = 20, RULE_arguments = 21, RULE_index = 22, - RULE_getAttr = 23, RULE_splat = 24, RULE_attrSplat = 25, RULE_fullSplat = 26, - RULE_operation = 27, RULE_unaryOp = 28, RULE_binaryOp = 29, RULE_binaryOperator = 30, - RULE_compareOperator = 31, RULE_arithmeticOperator = 32, RULE_logicOperator = 33, - RULE_templateExpr = 34, RULE_heredocTemplatePart = 35, RULE_heredocLiteral = 36, + RULE_configFile = 0, RULE_body = 1, RULE_bodyContent = 2, RULE_attribute = 3, + RULE_block = 4, RULE_blockLabel = 5, RULE_expression = 6, RULE_exprTerm = 7, + RULE_blockExpr = 8, RULE_literalValue = 9, RULE_collectionValue = 10, + RULE_tuple = 11, RULE_object = 12, RULE_objectelem = 13, RULE_forExpr = 14, + RULE_forTupleExpr = 15, RULE_forObjectExpr = 16, RULE_forIntro = 17, RULE_forCond = 18, + RULE_variableExpr = 19, RULE_functionCall = 20, RULE_arguments = 21, RULE_index = 22, + RULE_getAttr = 23, RULE_splat = 24, RULE_attrSplat = 25, RULE_fullSplat = 26, + RULE_operation = 27, RULE_unaryOp = 28, RULE_binaryOp = 29, RULE_binaryOperator = 30, + RULE_compareOperator = 31, RULE_arithmeticOperator = 32, RULE_logicOperator = 33, + RULE_templateExpr = 34, RULE_heredocTemplatePart = 35, RULE_heredocLiteral = 36, RULE_quotedTemplatePart = 37, RULE_stringLiteral = 38, RULE_templateInterpolation = 39; private static String[] makeRuleNames() { return new String[] { - "configFile", "body", "bodyContent", "attribute", "block", "blockLabel", - "expression", "exprTerm", "blockExpr", "literalValue", "collectionValue", - "tuple", "object", "objectelem", "forExpr", "forTupleExpr", "forObjectExpr", - "forIntro", "forCond", "variableExpr", "functionCall", "arguments", "index", - "getAttr", "splat", "attrSplat", "fullSplat", "operation", "unaryOp", - "binaryOp", "binaryOperator", "compareOperator", "arithmeticOperator", - "logicOperator", "templateExpr", "heredocTemplatePart", "heredocLiteral", + "configFile", "body", "bodyContent", "attribute", "block", "blockLabel", + "expression", "exprTerm", "blockExpr", "literalValue", "collectionValue", + "tuple", "object", "objectelem", "forExpr", "forTupleExpr", "forObjectExpr", + "forIntro", "forCond", "variableExpr", "functionCall", "arguments", "index", + "getAttr", "splat", "attrSplat", "fullSplat", "operation", "unaryOp", + "binaryOp", "binaryOperator", "compareOperator", "arithmeticOperator", + "logicOperator", "templateExpr", "heredocTemplatePart", "heredocLiteral", "quotedTemplatePart", "stringLiteral", "templateInterpolation" }; } @@ -71,23 +67,23 @@ private static String[] makeRuleNames() { private static String[] makeLiteralNames() { return new String[] { - null, null, null, "'if'", "'in'", "'{'", "'}'", "'='", null, null, null, - null, null, null, null, null, "'null'", null, "'+'", "'&&'", "'=='", - "'<'", "':'", "'['", "'('", "'-'", "'||'", "'!='", "'>'", "'?'", "']'", - "')'", "'*'", "'!'", "'<='", "'.'", "'/'", "'>='", "'=>'", "','", "'%'", + null, null, null, "'if'", "'in'", "'{'", "'}'", "'='", null, null, null, + null, null, null, null, null, "'null'", null, "'+'", "'&&'", "'=='", + "'<'", "':'", "'['", "'('", "'-'", "'||'", "'!='", "'>'", "'?'", "']'", + "')'", "'*'", "'!'", "'<='", "'.'", "'/'", "'>='", "'=>'", "','", "'%'", "'...'", "'~'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { - null, "FOR_BRACE", "FOR_BRACK", "IF", "IN", "LBRACE", "RBRACE", "ASSIGN", - "Identifier", "WS", "COMMENT", "LINE_COMMENT", "NEWLINE", "NumericLiteral", - "BooleanLiteral", "QUOTE", "NULL", "HEREDOC_START", "PLUS", "AND", "EQ", - "LT", "COLON", "LBRACK", "LPAREN", "MINUS", "OR", "NEQ", "GT", "QUESTION", - "RBRACK", "RPAREN", "MUL", "NOT", "LEQ", "DOT", "DIV", "GEQ", "ARROW", - "COMMA", "MOD", "ELLIPSIS", "TILDE", "TEMPLATE_INTERPOLATION_START", - "TemplateStringLiteral", "TemplateStringLiteralChar", "HTemplateLiteral", + null, "FOR_BRACE", "FOR_BRACK", "IF", "IN", "LBRACE", "RBRACE", "ASSIGN", + "Identifier", "WS", "COMMENT", "LINE_COMMENT", "NEWLINE", "NumericLiteral", + "BooleanLiteral", "QUOTE", "NULL", "HEREDOC_START", "PLUS", "AND", "EQ", + "LT", "COLON", "LBRACK", "LPAREN", "MINUS", "OR", "NEQ", "GT", "QUESTION", + "RBRACK", "RPAREN", "MUL", "NOT", "LEQ", "DOT", "DIV", "GEQ", "ARROW", + "COMMA", "MOD", "ELLIPSIS", "TILDE", "TEMPLATE_INTERPOLATION_START", + "TemplateStringLiteral", "TemplateStringLiteralChar", "HTemplateLiteral", "HTemplateLiteralChar" }; } @@ -504,7 +500,7 @@ public ExpressionContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_expression; } - + public ExpressionContext() { } public void copyFrom(ExpressionContext ctx) { super.copyFrom(ctx); @@ -637,7 +633,7 @@ private ExpressionContext expression(int _p) throws RecognitionException { setState(121); expression(2); } - } + } } setState(127); _errHandler.sync(this); @@ -662,7 +658,7 @@ public ExprTermContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_exprTerm; } - + public ExprTermContext() { } public void copyFrom(ExprTermContext ctx) { super.copyFrom(ctx); @@ -1010,7 +1006,7 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { } break; } - } + } } setState(151); _errHandler.sync(this); @@ -1259,7 +1255,7 @@ public final TupleContext tuple() throws RecognitionException { setState(165); expression(0); } - } + } } setState(170); _errHandler.sync(this); @@ -1334,7 +1330,7 @@ public final ObjectContext object() throws RecognitionException { setState(182); _errHandler.sync(this); _la = _input.LA(1); - while (((_la) & ~0x3f) == 0 && ((1L << _la) & 16810240L) != 0) { + while (((_la) & ~0x3f) == 0 && ((1L << _la) & 8648909094L) != 0) { { { setState(179); @@ -1362,8 +1358,11 @@ public final ObjectContext object() throws RecognitionException { @SuppressWarnings("CheckReturnValue") public static class ObjectelemContext extends ParserRuleContext { - public ExpressionContext expression() { - return getRuleContext(ExpressionContext.class,0); + public List expression() { + return getRuleContexts(ExpressionContext.class); + } + public ExpressionContext expression(int i) { + return getRuleContext(ExpressionContext.class,i); } public TerminalNode ASSIGN() { return getToken(HCLParser.ASSIGN, 0); } public TerminalNode COLON() { return getToken(HCLParser.COLON, 0); } @@ -1407,16 +1406,16 @@ public final ObjectelemContext objectelem() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(199); + setState(200); _errHandler.sync(this); - switch (_input.LA(1)) { - case Identifier: + switch ( getInterpreter().adaptivePredict(_input,15,_ctx) ) { + case 1: { setState(187); match(Identifier); } break; - case LPAREN: + case 2: { setState(188); match(LPAREN); @@ -1426,7 +1425,7 @@ public final ObjectelemContext objectelem() throws RecognitionException { match(RPAREN); } break; - case QUOTE: + case 3: { setState(191); match(QUOTE); @@ -1448,10 +1447,14 @@ public final ObjectelemContext objectelem() throws RecognitionException { match(QUOTE); } break; - default: - throw new NoViableAltException(this); + case 4: + { + setState(199); + expression(0); + } + break; } - setState(201); + setState(202); _la = _input.LA(1); if ( !(_la==ASSIGN || _la==COLON) ) { _errHandler.recoverInline(this); @@ -1461,14 +1464,14 @@ public final ObjectelemContext objectelem() throws RecognitionException { _errHandler.reportMatch(this); consume(); } - setState(202); + setState(203); expression(0); - setState(204); + setState(205); _errHandler.sync(this); _la = _input.LA(1); if (_la==COMMA) { { - setState(203); + setState(204); match(COMMA); } } @@ -1517,20 +1520,20 @@ public final ForExprContext forExpr() throws RecognitionException { ForExprContext _localctx = new ForExprContext(_ctx, getState()); enterRule(_localctx, 28, RULE_forExpr); try { - setState(208); + setState(209); _errHandler.sync(this); switch (_input.LA(1)) { case FOR_BRACK: enterOuterAlt(_localctx, 1); { - setState(206); + setState(207); forTupleExpr(); } break; case FOR_BRACE: enterOuterAlt(_localctx, 2); { - setState(207); + setState(208); forObjectExpr(); } break; @@ -1589,25 +1592,25 @@ public final ForTupleExprContext forTupleExpr() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(210); - match(FOR_BRACK); setState(211); - forIntro(); + match(FOR_BRACK); setState(212); - match(COLON); + forIntro(); setState(213); + match(COLON); + setState(214); expression(0); - setState(215); + setState(216); _errHandler.sync(this); _la = _input.LA(1); if (_la==IF) { { - setState(214); + setState(215); forCond(); } } - setState(217); + setState(218); match(RBRACK); } } @@ -1667,39 +1670,39 @@ public final ForObjectExprContext forObjectExpr() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(219); - match(FOR_BRACE); setState(220); - forIntro(); + match(FOR_BRACE); setState(221); - match(COLON); + forIntro(); setState(222); - expression(0); + match(COLON); setState(223); - match(ARROW); + expression(0); setState(224); + match(ARROW); + setState(225); expression(0); - setState(226); + setState(227); _errHandler.sync(this); _la = _input.LA(1); if (_la==ELLIPSIS) { { - setState(225); + setState(226); match(ELLIPSIS); } } - setState(229); + setState(230); _errHandler.sync(this); _la = _input.LA(1); if (_la==IF) { { - setState(228); + setState(229); forCond(); } } - setState(231); + setState(232); match(RBRACE); } } @@ -1751,23 +1754,23 @@ public final ForIntroContext forIntro() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(233); + setState(234); match(Identifier); - setState(236); + setState(237); _errHandler.sync(this); _la = _input.LA(1); if (_la==COMMA) { { - setState(234); - match(COMMA); setState(235); + match(COMMA); + setState(236); match(Identifier); } } - setState(238); - match(IN); setState(239); + match(IN); + setState(240); expression(0); } } @@ -1813,9 +1816,9 @@ public final ForCondContext forCond() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(241); - match(IF); setState(242); + match(IF); + setState(243); expression(0); } } @@ -1858,7 +1861,7 @@ public final VariableExprContext variableExpr() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(244); + setState(245); match(Identifier); } } @@ -1907,21 +1910,21 @@ public final FunctionCallContext functionCall() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(246); - match(Identifier); setState(247); + match(Identifier); + setState(248); match(LPAREN); - setState(249); + setState(250); _errHandler.sync(this); _la = _input.LA(1); if (((_la) & ~0x3f) == 0 && ((1L << _la) & 8648909094L) != 0) { { - setState(248); + setState(249); arguments(); } } - setState(251); + setState(252); match(RPAREN); } } @@ -1976,32 +1979,32 @@ public final ArgumentsContext arguments() throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(253); + setState(254); expression(0); - setState(258); + setState(259); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,23,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(254); - match(COMMA); setState(255); + match(COMMA); + setState(256); expression(0); } - } + } } - setState(260); + setState(261); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,23,_ctx); } - setState(262); + setState(263); _errHandler.sync(this); _la = _input.LA(1); if (_la==COMMA || _la==ELLIPSIS) { { - setState(261); + setState(262); _la = _input.LA(1); if ( !(_la==COMMA || _la==ELLIPSIS) ) { _errHandler.recoverInline(this); @@ -2059,11 +2062,11 @@ public final IndexContext index() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(264); - match(LBRACK); setState(265); - expression(0); + match(LBRACK); setState(266); + expression(0); + setState(267); match(RBRACK); } } @@ -2107,9 +2110,9 @@ public final GetAttrContext getAttr() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(268); - match(DOT); setState(269); + match(DOT); + setState(270); match(Identifier); } } @@ -2155,20 +2158,20 @@ public final SplatContext splat() throws RecognitionException { SplatContext _localctx = new SplatContext(_ctx, getState()); enterRule(_localctx, 48, RULE_splat); try { - setState(273); + setState(274); _errHandler.sync(this); switch (_input.LA(1)) { case DOT: enterOuterAlt(_localctx, 1); { - setState(271); + setState(272); attrSplat(); } break; case LBRACK: enterOuterAlt(_localctx, 2); { - setState(272); + setState(273); fullSplat(); } break; @@ -2223,23 +2226,23 @@ public final AttrSplatContext attrSplat() throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(275); - match(DOT); setState(276); + match(DOT); + setState(277); match(MUL); - setState(280); + setState(281); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,26,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(277); + setState(278); getAttr(); } - } + } } - setState(282); + setState(283); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,26,_ctx); } @@ -2299,39 +2302,39 @@ public final FullSplatContext fullSplat() throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(283); - match(LBRACK); setState(284); - match(MUL); + match(LBRACK); setState(285); + match(MUL); + setState(286); match(RBRACK); - setState(290); + setState(291); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,28,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { - setState(288); + setState(289); _errHandler.sync(this); switch (_input.LA(1)) { case DOT: { - setState(286); + setState(287); getAttr(); } break; case LBRACK: { - setState(287); + setState(288); index(); } break; default: throw new NoViableAltException(this); } - } + } } - setState(292); + setState(293); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,28,_ctx); } @@ -2379,20 +2382,20 @@ public final OperationContext operation() throws RecognitionException { OperationContext _localctx = new OperationContext(_ctx, getState()); enterRule(_localctx, 54, RULE_operation); try { - setState(295); + setState(296); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,29,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(293); + setState(294); unaryOp(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(294); + setState(295); binaryOp(); } break; @@ -2442,7 +2445,7 @@ public final UnaryOpContext unaryOp() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(297); + setState(298); _la = _input.LA(1); if ( !(_la==MINUS || _la==NOT) ) { _errHandler.recoverInline(this); @@ -2452,7 +2455,7 @@ public final UnaryOpContext unaryOp() throws RecognitionException { _errHandler.reportMatch(this); consume(); } - setState(298); + setState(299); exprTerm(0); } } @@ -2509,7 +2512,7 @@ public final BinaryOpContext binaryOp() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(302); + setState(303); _errHandler.sync(this); switch (_input.LA(1)) { case FOR_BRACE: @@ -2524,34 +2527,34 @@ public final BinaryOpContext binaryOp() throws RecognitionException { case LBRACK: case LPAREN: { - setState(300); + setState(301); exprTerm(0); } break; case MINUS: case NOT: { - setState(301); + setState(302); unaryOp(); } break; default: throw new NoViableAltException(this); } - setState(304); + setState(305); binaryOperator(); - setState(307); + setState(308); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,31,_ctx) ) { case 1: { - setState(305); + setState(306); exprTerm(0); } break; case 2: { - setState(306); + setState(307); operation(); } break; @@ -2603,7 +2606,7 @@ public final BinaryOperatorContext binaryOperator() throws RecognitionException BinaryOperatorContext _localctx = new BinaryOperatorContext(_ctx, getState()); enterRule(_localctx, 60, RULE_binaryOperator); try { - setState(312); + setState(313); _errHandler.sync(this); switch (_input.LA(1)) { case EQ: @@ -2614,7 +2617,7 @@ public final BinaryOperatorContext binaryOperator() throws RecognitionException case GEQ: enterOuterAlt(_localctx, 1); { - setState(309); + setState(310); compareOperator(); } break; @@ -2625,7 +2628,7 @@ public final BinaryOperatorContext binaryOperator() throws RecognitionException case MOD: enterOuterAlt(_localctx, 2); { - setState(310); + setState(311); arithmeticOperator(); } break; @@ -2633,7 +2636,7 @@ public final BinaryOperatorContext binaryOperator() throws RecognitionException case OR: enterOuterAlt(_localctx, 3); { - setState(311); + setState(312); logicOperator(); } break; @@ -2686,7 +2689,7 @@ public final CompareOperatorContext compareOperator() throws RecognitionExceptio try { enterOuterAlt(_localctx, 1); { - setState(314); + setState(315); _la = _input.LA(1); if ( !(((_la) & ~0x3f) == 0 && ((1L << _la) & 155024621568L) != 0) ) { _errHandler.recoverInline(this); @@ -2742,7 +2745,7 @@ public final ArithmeticOperatorContext arithmeticOperator() throws RecognitionEx try { enterOuterAlt(_localctx, 1); { - setState(316); + setState(317); _la = _input.LA(1); if ( !(((_la) & ~0x3f) == 0 && ((1L << _la) & 1172559888384L) != 0) ) { _errHandler.recoverInline(this); @@ -2795,7 +2798,7 @@ public final LogicOperatorContext logicOperator() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(318); + setState(319); _la = _input.LA(1); if ( !(_la==AND || _la==OR) ) { _errHandler.recoverInline(this); @@ -2824,7 +2827,7 @@ public TemplateExprContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @Override public int getRuleIndex() { return RULE_templateExpr; } - + public TemplateExprContext() { } public void copyFrom(TemplateExprContext ctx) { super.copyFrom(ctx); @@ -2895,46 +2898,46 @@ public final TemplateExprContext templateExpr() throws RecognitionException { enterRule(_localctx, 68, RULE_templateExpr); int _la; try { - setState(342); + setState(343); _errHandler.sync(this); switch (_input.LA(1)) { case HEREDOC_START: _localctx = new HeredocContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(320); - match(HEREDOC_START); setState(321); + match(HEREDOC_START); + setState(322); match(Identifier); - setState(329); + setState(330); _errHandler.sync(this); _la = _input.LA(1); do { { { - setState(322); + setState(323); match(NEWLINE); - setState(326); + setState(327); _errHandler.sync(this); _la = _input.LA(1); while (_la==TEMPLATE_INTERPOLATION_START || _la==HTemplateLiteral) { { { - setState(323); + setState(324); heredocTemplatePart(); } } - setState(328); + setState(329); _errHandler.sync(this); _la = _input.LA(1); } } } - setState(331); + setState(332); _errHandler.sync(this); _la = _input.LA(1); } while ( _la==NEWLINE ); - setState(333); + setState(334); match(Identifier); } break; @@ -2942,23 +2945,23 @@ public final TemplateExprContext templateExpr() throws RecognitionException { _localctx = new QuotedTemplateContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(334); + setState(335); match(QUOTE); - setState(338); + setState(339); _errHandler.sync(this); _la = _input.LA(1); while (_la==TEMPLATE_INTERPOLATION_START || _la==TemplateStringLiteral) { { { - setState(335); + setState(336); quotedTemplatePart(); } } - setState(340); + setState(341); _errHandler.sync(this); _la = _input.LA(1); } - setState(341); + setState(342); match(QUOTE); } break; @@ -3008,20 +3011,20 @@ public final HeredocTemplatePartContext heredocTemplatePart() throws Recognition HeredocTemplatePartContext _localctx = new HeredocTemplatePartContext(_ctx, getState()); enterRule(_localctx, 70, RULE_heredocTemplatePart); try { - setState(346); + setState(347); _errHandler.sync(this); switch (_input.LA(1)) { case TEMPLATE_INTERPOLATION_START: enterOuterAlt(_localctx, 1); { - setState(344); + setState(345); templateInterpolation(); } break; case HTemplateLiteral: enterOuterAlt(_localctx, 2); { - setState(345); + setState(346); heredocLiteral(); } break; @@ -3068,7 +3071,7 @@ public final HeredocLiteralContext heredocLiteral() throws RecognitionException try { enterOuterAlt(_localctx, 1); { - setState(348); + setState(349); match(HTemplateLiteral); } } @@ -3114,20 +3117,20 @@ public final QuotedTemplatePartContext quotedTemplatePart() throws RecognitionEx QuotedTemplatePartContext _localctx = new QuotedTemplatePartContext(_ctx, getState()); enterRule(_localctx, 74, RULE_quotedTemplatePart); try { - setState(352); + setState(353); _errHandler.sync(this); switch (_input.LA(1)) { case TEMPLATE_INTERPOLATION_START: enterOuterAlt(_localctx, 1); { - setState(350); + setState(351); templateInterpolation(); } break; case TemplateStringLiteral: enterOuterAlt(_localctx, 2); { - setState(351); + setState(352); stringLiteral(); } break; @@ -3174,7 +3177,7 @@ public final StringLiteralContext stringLiteral() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(354); + setState(355); match(TemplateStringLiteral); } } @@ -3221,11 +3224,11 @@ public final TemplateInterpolationContext templateInterpolation() throws Recogni try { enterOuterAlt(_localctx, 1); { - setState(356); - match(TEMPLATE_INTERPOLATION_START); setState(357); - expression(0); + match(TEMPLATE_INTERPOLATION_START); setState(358); + expression(0); + setState(359); match(RBRACE); } } @@ -3240,8 +3243,8 @@ public final TemplateInterpolationContext templateInterpolation() throws Recogni return _localctx; } - @Override - public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { + @Override + public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { switch (ruleIndex) { case 6: return expression_sempred((ExpressionContext)_localctx, predIndex); @@ -3270,7 +3273,7 @@ private boolean exprTerm_sempred(ExprTermContext _localctx, int predIndex) { } public static final String _serializedATN = - "\u0004\u0001/\u0169\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0004\u0001/\u016a\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ "\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b\u0002"+ @@ -3299,205 +3302,207 @@ private boolean exprTerm_sempred(ExprTermContext _localctx, int predIndex) { "\u0001\u000b\u0003\u000b\u00ad\b\u000b\u0003\u000b\u00af\b\u000b\u0001"+ "\u000b\u0001\u000b\u0001\f\u0001\f\u0005\f\u00b5\b\f\n\f\f\f\u00b8\t\f"+ "\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0005"+ - "\r\u00c2\b\r\n\r\f\r\u00c5\t\r\u0001\r\u0003\r\u00c8\b\r\u0001\r\u0001"+ - "\r\u0001\r\u0003\r\u00cd\b\r\u0001\u000e\u0001\u000e\u0003\u000e\u00d1"+ - "\b\u000e\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0003"+ - "\u000f\u00d8\b\u000f\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010\u0001"+ - "\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0003\u0010\u00e3"+ - "\b\u0010\u0001\u0010\u0003\u0010\u00e6\b\u0010\u0001\u0010\u0001\u0010"+ - "\u0001\u0011\u0001\u0011\u0001\u0011\u0003\u0011\u00ed\b\u0011\u0001\u0011"+ - "\u0001\u0011\u0001\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0013"+ - "\u0001\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0003\u0014\u00fa\b\u0014"+ - "\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0015\u0005\u0015"+ - "\u0101\b\u0015\n\u0015\f\u0015\u0104\t\u0015\u0001\u0015\u0003\u0015\u0107"+ - "\b\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001"+ - "\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0003\u0018\u0112\b\u0018\u0001"+ - "\u0019\u0001\u0019\u0001\u0019\u0005\u0019\u0117\b\u0019\n\u0019\f\u0019"+ - "\u011a\t\u0019\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a"+ - "\u0005\u001a\u0121\b\u001a\n\u001a\f\u001a\u0124\t\u001a\u0001\u001b\u0001"+ - "\u001b\u0003\u001b\u0128\b\u001b\u0001\u001c\u0001\u001c\u0001\u001c\u0001"+ - "\u001d\u0001\u001d\u0003\u001d\u012f\b\u001d\u0001\u001d\u0001\u001d\u0001"+ - "\u001d\u0003\u001d\u0134\b\u001d\u0001\u001e\u0001\u001e\u0001\u001e\u0003"+ - "\u001e\u0139\b\u001e\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001!\u0001"+ - "!\u0001\"\u0001\"\u0001\"\u0001\"\u0005\"\u0145\b\"\n\"\f\"\u0148\t\""+ - "\u0004\"\u014a\b\"\u000b\"\f\"\u014b\u0001\"\u0001\"\u0001\"\u0005\"\u0151"+ - "\b\"\n\"\f\"\u0154\t\"\u0001\"\u0003\"\u0157\b\"\u0001#\u0001#\u0003#"+ - "\u015b\b#\u0001$\u0001$\u0001%\u0001%\u0003%\u0161\b%\u0001&\u0001&\u0001"+ - "\'\u0001\'\u0001\'\u0001\'\u0001\'\u0000\u0002\f\u000e(\u0000\u0002\u0004"+ - "\u0006\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u001a\u001c\u001e \""+ - "$&(*,.02468:<>@BDFHJLN\u0000\u0007\u0002\u0000\r\u000e\u0010\u0010\u0002"+ - "\u0000\u0007\u0007\u0016\u0016\u0002\u0000\'\'))\u0002\u0000\u0019\u0019"+ - "!!\u0004\u0000\u0014\u0015\u001b\u001c\"\"%%\u0005\u0000\u0012\u0012\u0019"+ - "\u0019 $$((\u0002\u0000\u0013\u0013\u001a\u001a\u016f\u0000P\u0001\u0000"+ - "\u0000\u0000\u0002U\u0001\u0000\u0000\u0000\u0004Z\u0001\u0000\u0000\u0000"+ - "\u0006\\\u0001\u0000\u0000\u0000\b`\u0001\u0000\u0000\u0000\nn\u0001\u0000"+ - "\u0000\u0000\fs\u0001\u0000\u0000\u0000\u000e\u008b\u0001\u0000\u0000"+ - "\u0000\u0010\u0098\u0001\u0000\u0000\u0000\u0012\u009c\u0001\u0000\u0000"+ - "\u0000\u0014\u00a0\u0001\u0000\u0000\u0000\u0016\u00a2\u0001\u0000\u0000"+ - "\u0000\u0018\u00b2\u0001\u0000\u0000\u0000\u001a\u00c7\u0001\u0000\u0000"+ - "\u0000\u001c\u00d0\u0001\u0000\u0000\u0000\u001e\u00d2\u0001\u0000\u0000"+ - "\u0000 \u00db\u0001\u0000\u0000\u0000\"\u00e9\u0001\u0000\u0000\u0000"+ - "$\u00f1\u0001\u0000\u0000\u0000&\u00f4\u0001\u0000\u0000\u0000(\u00f6"+ - "\u0001\u0000\u0000\u0000*\u00fd\u0001\u0000\u0000\u0000,\u0108\u0001\u0000"+ - "\u0000\u0000.\u010c\u0001\u0000\u0000\u00000\u0111\u0001\u0000\u0000\u0000"+ - "2\u0113\u0001\u0000\u0000\u00004\u011b\u0001\u0000\u0000\u00006\u0127"+ - "\u0001\u0000\u0000\u00008\u0129\u0001\u0000\u0000\u0000:\u012e\u0001\u0000"+ - "\u0000\u0000<\u0138\u0001\u0000\u0000\u0000>\u013a\u0001\u0000\u0000\u0000"+ - "@\u013c\u0001\u0000\u0000\u0000B\u013e\u0001\u0000\u0000\u0000D\u0156"+ - "\u0001\u0000\u0000\u0000F\u015a\u0001\u0000\u0000\u0000H\u015c\u0001\u0000"+ - "\u0000\u0000J\u0160\u0001\u0000\u0000\u0000L\u0162\u0001\u0000\u0000\u0000"+ - "N\u0164\u0001\u0000\u0000\u0000PQ\u0003\u0002\u0001\u0000Q\u0001\u0001"+ - "\u0000\u0000\u0000RT\u0003\u0004\u0002\u0000SR\u0001\u0000\u0000\u0000"+ - "TW\u0001\u0000\u0000\u0000US\u0001\u0000\u0000\u0000UV\u0001\u0000\u0000"+ - "\u0000V\u0003\u0001\u0000\u0000\u0000WU\u0001\u0000\u0000\u0000X[\u0003"+ - "\u0006\u0003\u0000Y[\u0003\b\u0004\u0000ZX\u0001\u0000\u0000\u0000ZY\u0001"+ - "\u0000\u0000\u0000[\u0005\u0001\u0000\u0000\u0000\\]\u0005\b\u0000\u0000"+ - "]^\u0005\u0007\u0000\u0000^_\u0003\f\u0006\u0000_\u0007\u0001\u0000\u0000"+ - "\u0000`d\u0005\b\u0000\u0000ac\u0003\n\u0005\u0000ba\u0001\u0000\u0000"+ - "\u0000cf\u0001\u0000\u0000\u0000db\u0001\u0000\u0000\u0000de\u0001\u0000"+ - "\u0000\u0000eg\u0001\u0000\u0000\u0000fd\u0001\u0000\u0000\u0000gh\u0003"+ - "\u0010\b\u0000h\t\u0001\u0000\u0000\u0000ij\u0005\u000f\u0000\u0000jk"+ - "\u0003L&\u0000kl\u0005\u000f\u0000\u0000lo\u0001\u0000\u0000\u0000mo\u0005"+ - "\b\u0000\u0000ni\u0001\u0000\u0000\u0000nm\u0001\u0000\u0000\u0000o\u000b"+ - "\u0001\u0000\u0000\u0000pq\u0006\u0006\uffff\uffff\u0000qt\u0003\u000e"+ - "\u0007\u0000rt\u00036\u001b\u0000sp\u0001\u0000\u0000\u0000sr\u0001\u0000"+ - "\u0000\u0000t}\u0001\u0000\u0000\u0000uv\n\u0001\u0000\u0000vw\u0005\u001d"+ - "\u0000\u0000wx\u0003\f\u0006\u0000xy\u0005\u0016\u0000\u0000yz\u0003\f"+ - "\u0006\u0002z|\u0001\u0000\u0000\u0000{u\u0001\u0000\u0000\u0000|\u007f"+ - "\u0001\u0000\u0000\u0000}{\u0001\u0000\u0000\u0000}~\u0001\u0000\u0000"+ - "\u0000~\r\u0001\u0000\u0000\u0000\u007f}\u0001\u0000\u0000\u0000\u0080"+ - "\u0081\u0006\u0007\uffff\uffff\u0000\u0081\u008c\u0003D\"\u0000\u0082"+ - "\u008c\u0003\u0012\t\u0000\u0083\u008c\u0003\u001c\u000e\u0000\u0084\u008c"+ - "\u0003\u0014\n\u0000\u0085\u008c\u0003&\u0013\u0000\u0086\u008c\u0003"+ - "(\u0014\u0000\u0087\u0088\u0005\u0018\u0000\u0000\u0088\u0089\u0003\f"+ - "\u0006\u0000\u0089\u008a\u0005\u001f\u0000\u0000\u008a\u008c\u0001\u0000"+ - "\u0000\u0000\u008b\u0080\u0001\u0000\u0000\u0000\u008b\u0082\u0001\u0000"+ - "\u0000\u0000\u008b\u0083\u0001\u0000\u0000\u0000\u008b\u0084\u0001\u0000"+ - "\u0000\u0000\u008b\u0085\u0001\u0000\u0000\u0000\u008b\u0086\u0001\u0000"+ - "\u0000\u0000\u008b\u0087\u0001\u0000\u0000\u0000\u008c\u0095\u0001\u0000"+ - "\u0000\u0000\u008d\u008e\n\u0004\u0000\u0000\u008e\u0094\u0003,\u0016"+ - "\u0000\u008f\u0090\n\u0003\u0000\u0000\u0090\u0094\u0003.\u0017\u0000"+ - "\u0091\u0092\n\u0002\u0000\u0000\u0092\u0094\u00030\u0018\u0000\u0093"+ - "\u008d\u0001\u0000\u0000\u0000\u0093\u008f\u0001\u0000\u0000\u0000\u0093"+ - "\u0091\u0001\u0000\u0000\u0000\u0094\u0097\u0001\u0000\u0000\u0000\u0095"+ - "\u0093\u0001\u0000\u0000\u0000\u0095\u0096\u0001\u0000\u0000\u0000\u0096"+ - "\u000f\u0001\u0000\u0000\u0000\u0097\u0095\u0001\u0000\u0000\u0000\u0098"+ - "\u0099\u0005\u0005\u0000\u0000\u0099\u009a\u0003\u0002\u0001\u0000\u009a"+ - "\u009b\u0005\u0006\u0000\u0000\u009b\u0011\u0001\u0000\u0000\u0000\u009c"+ - "\u009d\u0007\u0000\u0000\u0000\u009d\u0013\u0001\u0000\u0000\u0000\u009e"+ - "\u00a1\u0003\u0016\u000b\u0000\u009f\u00a1\u0003\u0018\f\u0000\u00a0\u009e"+ - "\u0001\u0000\u0000\u0000\u00a0\u009f\u0001\u0000\u0000\u0000\u00a1\u0015"+ - "\u0001\u0000\u0000\u0000\u00a2\u00ae\u0005\u0017\u0000\u0000\u00a3\u00a8"+ - "\u0003\f\u0006\u0000\u00a4\u00a5\u0005\'\u0000\u0000\u00a5\u00a7\u0003"+ - "\f\u0006\u0000\u00a6\u00a4\u0001\u0000\u0000\u0000\u00a7\u00aa\u0001\u0000"+ - "\u0000\u0000\u00a8\u00a6\u0001\u0000\u0000\u0000\u00a8\u00a9\u0001\u0000"+ - "\u0000\u0000\u00a9\u00ac\u0001\u0000\u0000\u0000\u00aa\u00a8\u0001\u0000"+ - "\u0000\u0000\u00ab\u00ad\u0005\'\u0000\u0000\u00ac\u00ab\u0001\u0000\u0000"+ - "\u0000\u00ac\u00ad\u0001\u0000\u0000\u0000\u00ad\u00af\u0001\u0000\u0000"+ - "\u0000\u00ae\u00a3\u0001\u0000\u0000\u0000\u00ae\u00af\u0001\u0000\u0000"+ - "\u0000\u00af\u00b0\u0001\u0000\u0000\u0000\u00b0\u00b1\u0005\u001e\u0000"+ - "\u0000\u00b1\u0017\u0001\u0000\u0000\u0000\u00b2\u00b6\u0005\u0005\u0000"+ - "\u0000\u00b3\u00b5\u0003\u001a\r\u0000\u00b4\u00b3\u0001\u0000\u0000\u0000"+ - "\u00b5\u00b8\u0001\u0000\u0000\u0000\u00b6\u00b4\u0001\u0000\u0000\u0000"+ - "\u00b6\u00b7\u0001\u0000\u0000\u0000\u00b7\u00b9\u0001\u0000\u0000\u0000"+ - "\u00b8\u00b6\u0001\u0000\u0000\u0000\u00b9\u00ba\u0005\u0006\u0000\u0000"+ - "\u00ba\u0019\u0001\u0000\u0000\u0000\u00bb\u00c8\u0005\b\u0000\u0000\u00bc"+ - "\u00bd\u0005\u0018\u0000\u0000\u00bd\u00be\u0005\b\u0000\u0000\u00be\u00c8"+ - "\u0005\u001f\u0000\u0000\u00bf\u00c3\u0005\u000f\u0000\u0000\u00c0\u00c2"+ - "\u0003J%\u0000\u00c1\u00c0\u0001\u0000\u0000\u0000\u00c2\u00c5\u0001\u0000"+ - "\u0000\u0000\u00c3\u00c1\u0001\u0000\u0000\u0000\u00c3\u00c4\u0001\u0000"+ - "\u0000\u0000\u00c4\u00c6\u0001\u0000\u0000\u0000\u00c5\u00c3\u0001\u0000"+ - "\u0000\u0000\u00c6\u00c8\u0005\u000f\u0000\u0000\u00c7\u00bb\u0001\u0000"+ - "\u0000\u0000\u00c7\u00bc\u0001\u0000\u0000\u0000\u00c7\u00bf\u0001\u0000"+ - "\u0000\u0000\u00c8\u00c9\u0001\u0000\u0000\u0000\u00c9\u00ca\u0007\u0001"+ - "\u0000\u0000\u00ca\u00cc\u0003\f\u0006\u0000\u00cb\u00cd\u0005\'\u0000"+ - "\u0000\u00cc\u00cb\u0001\u0000\u0000\u0000\u00cc\u00cd\u0001\u0000\u0000"+ - "\u0000\u00cd\u001b\u0001\u0000\u0000\u0000\u00ce\u00d1\u0003\u001e\u000f"+ - "\u0000\u00cf\u00d1\u0003 \u0010\u0000\u00d0\u00ce\u0001\u0000\u0000\u0000"+ - "\u00d0\u00cf\u0001\u0000\u0000\u0000\u00d1\u001d\u0001\u0000\u0000\u0000"+ - "\u00d2\u00d3\u0005\u0002\u0000\u0000\u00d3\u00d4\u0003\"\u0011\u0000\u00d4"+ - "\u00d5\u0005\u0016\u0000\u0000\u00d5\u00d7\u0003\f\u0006\u0000\u00d6\u00d8"+ - "\u0003$\u0012\u0000\u00d7\u00d6\u0001\u0000\u0000\u0000\u00d7\u00d8\u0001"+ - "\u0000\u0000\u0000\u00d8\u00d9\u0001\u0000\u0000\u0000\u00d9\u00da\u0005"+ - "\u001e\u0000\u0000\u00da\u001f\u0001\u0000\u0000\u0000\u00db\u00dc\u0005"+ - "\u0001\u0000\u0000\u00dc\u00dd\u0003\"\u0011\u0000\u00dd\u00de\u0005\u0016"+ - "\u0000\u0000\u00de\u00df\u0003\f\u0006\u0000\u00df\u00e0\u0005&\u0000"+ - "\u0000\u00e0\u00e2\u0003\f\u0006\u0000\u00e1\u00e3\u0005)\u0000\u0000"+ - "\u00e2\u00e1\u0001\u0000\u0000\u0000\u00e2\u00e3\u0001\u0000\u0000\u0000"+ - "\u00e3\u00e5\u0001\u0000\u0000\u0000\u00e4\u00e6\u0003$\u0012\u0000\u00e5"+ - "\u00e4\u0001\u0000\u0000\u0000\u00e5\u00e6\u0001\u0000\u0000\u0000\u00e6"+ - "\u00e7\u0001\u0000\u0000\u0000\u00e7\u00e8\u0005\u0006\u0000\u0000\u00e8"+ - "!\u0001\u0000\u0000\u0000\u00e9\u00ec\u0005\b\u0000\u0000\u00ea\u00eb"+ - "\u0005\'\u0000\u0000\u00eb\u00ed\u0005\b\u0000\u0000\u00ec\u00ea\u0001"+ - "\u0000\u0000\u0000\u00ec\u00ed\u0001\u0000\u0000\u0000\u00ed\u00ee\u0001"+ - "\u0000\u0000\u0000\u00ee\u00ef\u0005\u0004\u0000\u0000\u00ef\u00f0\u0003"+ - "\f\u0006\u0000\u00f0#\u0001\u0000\u0000\u0000\u00f1\u00f2\u0005\u0003"+ - "\u0000\u0000\u00f2\u00f3\u0003\f\u0006\u0000\u00f3%\u0001\u0000\u0000"+ - "\u0000\u00f4\u00f5\u0005\b\u0000\u0000\u00f5\'\u0001\u0000\u0000\u0000"+ - "\u00f6\u00f7\u0005\b\u0000\u0000\u00f7\u00f9\u0005\u0018\u0000\u0000\u00f8"+ - "\u00fa\u0003*\u0015\u0000\u00f9\u00f8\u0001\u0000\u0000\u0000\u00f9\u00fa"+ - "\u0001\u0000\u0000\u0000\u00fa\u00fb\u0001\u0000\u0000\u0000\u00fb\u00fc"+ - "\u0005\u001f\u0000\u0000\u00fc)\u0001\u0000\u0000\u0000\u00fd\u0102\u0003"+ - "\f\u0006\u0000\u00fe\u00ff\u0005\'\u0000\u0000\u00ff\u0101\u0003\f\u0006"+ - "\u0000\u0100\u00fe\u0001\u0000\u0000\u0000\u0101\u0104\u0001\u0000\u0000"+ - "\u0000\u0102\u0100\u0001\u0000\u0000\u0000\u0102\u0103\u0001\u0000\u0000"+ - "\u0000\u0103\u0106\u0001\u0000\u0000\u0000\u0104\u0102\u0001\u0000\u0000"+ - "\u0000\u0105\u0107\u0007\u0002\u0000\u0000\u0106\u0105\u0001\u0000\u0000"+ - "\u0000\u0106\u0107\u0001\u0000\u0000\u0000\u0107+\u0001\u0000\u0000\u0000"+ - "\u0108\u0109\u0005\u0017\u0000\u0000\u0109\u010a\u0003\f\u0006\u0000\u010a"+ - "\u010b\u0005\u001e\u0000\u0000\u010b-\u0001\u0000\u0000\u0000\u010c\u010d"+ - "\u0005#\u0000\u0000\u010d\u010e\u0005\b\u0000\u0000\u010e/\u0001\u0000"+ - "\u0000\u0000\u010f\u0112\u00032\u0019\u0000\u0110\u0112\u00034\u001a\u0000"+ - "\u0111\u010f\u0001\u0000\u0000\u0000\u0111\u0110\u0001\u0000\u0000\u0000"+ - "\u01121\u0001\u0000\u0000\u0000\u0113\u0114\u0005#\u0000\u0000\u0114\u0118"+ - "\u0005 \u0000\u0000\u0115\u0117\u0003.\u0017\u0000\u0116\u0115\u0001\u0000"+ - "\u0000\u0000\u0117\u011a\u0001\u0000\u0000\u0000\u0118\u0116\u0001\u0000"+ - "\u0000\u0000\u0118\u0119\u0001\u0000\u0000\u0000\u01193\u0001\u0000\u0000"+ - "\u0000\u011a\u0118\u0001\u0000\u0000\u0000\u011b\u011c\u0005\u0017\u0000"+ - "\u0000\u011c\u011d\u0005 \u0000\u0000\u011d\u0122\u0005\u001e\u0000\u0000"+ - "\u011e\u0121\u0003.\u0017\u0000\u011f\u0121\u0003,\u0016\u0000\u0120\u011e"+ - "\u0001\u0000\u0000\u0000\u0120\u011f\u0001\u0000\u0000\u0000\u0121\u0124"+ - "\u0001\u0000\u0000\u0000\u0122\u0120\u0001\u0000\u0000\u0000\u0122\u0123"+ - "\u0001\u0000\u0000\u0000\u01235\u0001\u0000\u0000\u0000\u0124\u0122\u0001"+ - "\u0000\u0000\u0000\u0125\u0128\u00038\u001c\u0000\u0126\u0128\u0003:\u001d"+ - "\u0000\u0127\u0125\u0001\u0000\u0000\u0000\u0127\u0126\u0001\u0000\u0000"+ - "\u0000\u01287\u0001\u0000\u0000\u0000\u0129\u012a\u0007\u0003\u0000\u0000"+ - "\u012a\u012b\u0003\u000e\u0007\u0000\u012b9\u0001\u0000\u0000\u0000\u012c"+ - "\u012f\u0003\u000e\u0007\u0000\u012d\u012f\u00038\u001c\u0000\u012e\u012c"+ - "\u0001\u0000\u0000\u0000\u012e\u012d\u0001\u0000\u0000\u0000\u012f\u0130"+ - "\u0001\u0000\u0000\u0000\u0130\u0133\u0003<\u001e\u0000\u0131\u0134\u0003"+ - "\u000e\u0007\u0000\u0132\u0134\u00036\u001b\u0000\u0133\u0131\u0001\u0000"+ - "\u0000\u0000\u0133\u0132\u0001\u0000\u0000\u0000\u0134;\u0001\u0000\u0000"+ - "\u0000\u0135\u0139\u0003>\u001f\u0000\u0136\u0139\u0003@ \u0000\u0137"+ - "\u0139\u0003B!\u0000\u0138\u0135\u0001\u0000\u0000\u0000\u0138\u0136\u0001"+ - "\u0000\u0000\u0000\u0138\u0137\u0001\u0000\u0000\u0000\u0139=\u0001\u0000"+ - "\u0000\u0000\u013a\u013b\u0007\u0004\u0000\u0000\u013b?\u0001\u0000\u0000"+ - "\u0000\u013c\u013d\u0007\u0005\u0000\u0000\u013dA\u0001\u0000\u0000\u0000"+ - "\u013e\u013f\u0007\u0006\u0000\u0000\u013fC\u0001\u0000\u0000\u0000\u0140"+ - "\u0141\u0005\u0011\u0000\u0000\u0141\u0149\u0005\b\u0000\u0000\u0142\u0146"+ - "\u0005\f\u0000\u0000\u0143\u0145\u0003F#\u0000\u0144\u0143\u0001\u0000"+ - "\u0000\u0000\u0145\u0148\u0001\u0000\u0000\u0000\u0146\u0144\u0001\u0000"+ - "\u0000\u0000\u0146\u0147\u0001\u0000\u0000\u0000\u0147\u014a\u0001\u0000"+ - "\u0000\u0000\u0148\u0146\u0001\u0000\u0000\u0000\u0149\u0142\u0001\u0000"+ - "\u0000\u0000\u014a\u014b\u0001\u0000\u0000\u0000\u014b\u0149\u0001\u0000"+ - "\u0000\u0000\u014b\u014c\u0001\u0000\u0000\u0000\u014c\u014d\u0001\u0000"+ - "\u0000\u0000\u014d\u0157\u0005\b\u0000\u0000\u014e\u0152\u0005\u000f\u0000"+ - "\u0000\u014f\u0151\u0003J%\u0000\u0150\u014f\u0001\u0000\u0000\u0000\u0151"+ - "\u0154\u0001\u0000\u0000\u0000\u0152\u0150\u0001\u0000\u0000\u0000\u0152"+ - "\u0153\u0001\u0000\u0000\u0000\u0153\u0155\u0001\u0000\u0000\u0000\u0154"+ - "\u0152\u0001\u0000\u0000\u0000\u0155\u0157\u0005\u000f\u0000\u0000\u0156"+ - "\u0140\u0001\u0000\u0000\u0000\u0156\u014e\u0001\u0000\u0000\u0000\u0157"+ - "E\u0001\u0000\u0000\u0000\u0158\u015b\u0003N\'\u0000\u0159\u015b\u0003"+ - "H$\u0000\u015a\u0158\u0001\u0000\u0000\u0000\u015a\u0159\u0001\u0000\u0000"+ - "\u0000\u015bG\u0001\u0000\u0000\u0000\u015c\u015d\u0005.\u0000\u0000\u015d"+ - "I\u0001\u0000\u0000\u0000\u015e\u0161\u0003N\'\u0000\u015f\u0161\u0003"+ - "L&\u0000\u0160\u015e\u0001\u0000\u0000\u0000\u0160\u015f\u0001\u0000\u0000"+ - "\u0000\u0161K\u0001\u0000\u0000\u0000\u0162\u0163\u0005,\u0000\u0000\u0163"+ - "M\u0001\u0000\u0000\u0000\u0164\u0165\u0005+\u0000\u0000\u0165\u0166\u0003"+ - "\f\u0006\u0000\u0166\u0167\u0005\u0006\u0000\u0000\u0167O\u0001\u0000"+ - "\u0000\u0000\'UZdns}\u008b\u0093\u0095\u00a0\u00a8\u00ac\u00ae\u00b6\u00c3"+ - "\u00c7\u00cc\u00d0\u00d7\u00e2\u00e5\u00ec\u00f9\u0102\u0106\u0111\u0118"+ - "\u0120\u0122\u0127\u012e\u0133\u0138\u0146\u014b\u0152\u0156\u015a\u0160"; + "\r\u00c2\b\r\n\r\f\r\u00c5\t\r\u0001\r\u0001\r\u0003\r\u00c9\b\r\u0001"+ + "\r\u0001\r\u0001\r\u0003\r\u00ce\b\r\u0001\u000e\u0001\u000e\u0003\u000e"+ + "\u00d2\b\u000e\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f"+ + "\u0003\u000f\u00d9\b\u000f\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010"+ + "\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0003\u0010"+ + "\u00e4\b\u0010\u0001\u0010\u0003\u0010\u00e7\b\u0010\u0001\u0010\u0001"+ + "\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0003\u0011\u00ee\b\u0011\u0001"+ + "\u0011\u0001\u0011\u0001\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+ + "\u0013\u0001\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0003\u0014\u00fb"+ + "\b\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0015\u0005"+ + "\u0015\u0102\b\u0015\n\u0015\f\u0015\u0105\t\u0015\u0001\u0015\u0003\u0015"+ + "\u0108\b\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0017"+ + "\u0001\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0003\u0018\u0113\b\u0018"+ + "\u0001\u0019\u0001\u0019\u0001\u0019\u0005\u0019\u0118\b\u0019\n\u0019"+ + "\f\u0019\u011b\t\u0019\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a"+ + "\u0001\u001a\u0005\u001a\u0122\b\u001a\n\u001a\f\u001a\u0125\t\u001a\u0001"+ + "\u001b\u0001\u001b\u0003\u001b\u0129\b\u001b\u0001\u001c\u0001\u001c\u0001"+ + "\u001c\u0001\u001d\u0001\u001d\u0003\u001d\u0130\b\u001d\u0001\u001d\u0001"+ + "\u001d\u0001\u001d\u0003\u001d\u0135\b\u001d\u0001\u001e\u0001\u001e\u0001"+ + "\u001e\u0003\u001e\u013a\b\u001e\u0001\u001f\u0001\u001f\u0001 \u0001"+ + " \u0001!\u0001!\u0001\"\u0001\"\u0001\"\u0001\"\u0005\"\u0146\b\"\n\""+ + "\f\"\u0149\t\"\u0004\"\u014b\b\"\u000b\"\f\"\u014c\u0001\"\u0001\"\u0001"+ + "\"\u0005\"\u0152\b\"\n\"\f\"\u0155\t\"\u0001\"\u0003\"\u0158\b\"\u0001"+ + "#\u0001#\u0003#\u015c\b#\u0001$\u0001$\u0001%\u0001%\u0003%\u0162\b%\u0001"+ + "&\u0001&\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0000\u0002\f\u000e("+ + "\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u001a"+ + "\u001c\u001e \"$&(*,.02468:<>@BDFHJLN\u0000\u0007\u0002\u0000\r\u000e"+ + "\u0010\u0010\u0002\u0000\u0007\u0007\u0016\u0016\u0002\u0000\'\'))\u0002"+ + "\u0000\u0019\u0019!!\u0004\u0000\u0014\u0015\u001b\u001c\"\"%%\u0005\u0000"+ + "\u0012\u0012\u0019\u0019 $$((\u0002\u0000\u0013\u0013\u001a\u001a\u0171"+ + "\u0000P\u0001\u0000\u0000\u0000\u0002U\u0001\u0000\u0000\u0000\u0004Z"+ + "\u0001\u0000\u0000\u0000\u0006\\\u0001\u0000\u0000\u0000\b`\u0001\u0000"+ + "\u0000\u0000\nn\u0001\u0000\u0000\u0000\fs\u0001\u0000\u0000\u0000\u000e"+ + "\u008b\u0001\u0000\u0000\u0000\u0010\u0098\u0001\u0000\u0000\u0000\u0012"+ + "\u009c\u0001\u0000\u0000\u0000\u0014\u00a0\u0001\u0000\u0000\u0000\u0016"+ + "\u00a2\u0001\u0000\u0000\u0000\u0018\u00b2\u0001\u0000\u0000\u0000\u001a"+ + "\u00c8\u0001\u0000\u0000\u0000\u001c\u00d1\u0001\u0000\u0000\u0000\u001e"+ + "\u00d3\u0001\u0000\u0000\u0000 \u00dc\u0001\u0000\u0000\u0000\"\u00ea"+ + "\u0001\u0000\u0000\u0000$\u00f2\u0001\u0000\u0000\u0000&\u00f5\u0001\u0000"+ + "\u0000\u0000(\u00f7\u0001\u0000\u0000\u0000*\u00fe\u0001\u0000\u0000\u0000"+ + ",\u0109\u0001\u0000\u0000\u0000.\u010d\u0001\u0000\u0000\u00000\u0112"+ + "\u0001\u0000\u0000\u00002\u0114\u0001\u0000\u0000\u00004\u011c\u0001\u0000"+ + "\u0000\u00006\u0128\u0001\u0000\u0000\u00008\u012a\u0001\u0000\u0000\u0000"+ + ":\u012f\u0001\u0000\u0000\u0000<\u0139\u0001\u0000\u0000\u0000>\u013b"+ + "\u0001\u0000\u0000\u0000@\u013d\u0001\u0000\u0000\u0000B\u013f\u0001\u0000"+ + "\u0000\u0000D\u0157\u0001\u0000\u0000\u0000F\u015b\u0001\u0000\u0000\u0000"+ + "H\u015d\u0001\u0000\u0000\u0000J\u0161\u0001\u0000\u0000\u0000L\u0163"+ + "\u0001\u0000\u0000\u0000N\u0165\u0001\u0000\u0000\u0000PQ\u0003\u0002"+ + "\u0001\u0000Q\u0001\u0001\u0000\u0000\u0000RT\u0003\u0004\u0002\u0000"+ + "SR\u0001\u0000\u0000\u0000TW\u0001\u0000\u0000\u0000US\u0001\u0000\u0000"+ + "\u0000UV\u0001\u0000\u0000\u0000V\u0003\u0001\u0000\u0000\u0000WU\u0001"+ + "\u0000\u0000\u0000X[\u0003\u0006\u0003\u0000Y[\u0003\b\u0004\u0000ZX\u0001"+ + "\u0000\u0000\u0000ZY\u0001\u0000\u0000\u0000[\u0005\u0001\u0000\u0000"+ + "\u0000\\]\u0005\b\u0000\u0000]^\u0005\u0007\u0000\u0000^_\u0003\f\u0006"+ + "\u0000_\u0007\u0001\u0000\u0000\u0000`d\u0005\b\u0000\u0000ac\u0003\n"+ + "\u0005\u0000ba\u0001\u0000\u0000\u0000cf\u0001\u0000\u0000\u0000db\u0001"+ + "\u0000\u0000\u0000de\u0001\u0000\u0000\u0000eg\u0001\u0000\u0000\u0000"+ + "fd\u0001\u0000\u0000\u0000gh\u0003\u0010\b\u0000h\t\u0001\u0000\u0000"+ + "\u0000ij\u0005\u000f\u0000\u0000jk\u0003L&\u0000kl\u0005\u000f\u0000\u0000"+ + "lo\u0001\u0000\u0000\u0000mo\u0005\b\u0000\u0000ni\u0001\u0000\u0000\u0000"+ + "nm\u0001\u0000\u0000\u0000o\u000b\u0001\u0000\u0000\u0000pq\u0006\u0006"+ + "\uffff\uffff\u0000qt\u0003\u000e\u0007\u0000rt\u00036\u001b\u0000sp\u0001"+ + "\u0000\u0000\u0000sr\u0001\u0000\u0000\u0000t}\u0001\u0000\u0000\u0000"+ + "uv\n\u0001\u0000\u0000vw\u0005\u001d\u0000\u0000wx\u0003\f\u0006\u0000"+ + "xy\u0005\u0016\u0000\u0000yz\u0003\f\u0006\u0002z|\u0001\u0000\u0000\u0000"+ + "{u\u0001\u0000\u0000\u0000|\u007f\u0001\u0000\u0000\u0000}{\u0001\u0000"+ + "\u0000\u0000}~\u0001\u0000\u0000\u0000~\r\u0001\u0000\u0000\u0000\u007f"+ + "}\u0001\u0000\u0000\u0000\u0080\u0081\u0006\u0007\uffff\uffff\u0000\u0081"+ + "\u008c\u0003D\"\u0000\u0082\u008c\u0003\u0012\t\u0000\u0083\u008c\u0003"+ + "\u001c\u000e\u0000\u0084\u008c\u0003\u0014\n\u0000\u0085\u008c\u0003&"+ + "\u0013\u0000\u0086\u008c\u0003(\u0014\u0000\u0087\u0088\u0005\u0018\u0000"+ + "\u0000\u0088\u0089\u0003\f\u0006\u0000\u0089\u008a\u0005\u001f\u0000\u0000"+ + "\u008a\u008c\u0001\u0000\u0000\u0000\u008b\u0080\u0001\u0000\u0000\u0000"+ + "\u008b\u0082\u0001\u0000\u0000\u0000\u008b\u0083\u0001\u0000\u0000\u0000"+ + "\u008b\u0084\u0001\u0000\u0000\u0000\u008b\u0085\u0001\u0000\u0000\u0000"+ + "\u008b\u0086\u0001\u0000\u0000\u0000\u008b\u0087\u0001\u0000\u0000\u0000"+ + "\u008c\u0095\u0001\u0000\u0000\u0000\u008d\u008e\n\u0004\u0000\u0000\u008e"+ + "\u0094\u0003,\u0016\u0000\u008f\u0090\n\u0003\u0000\u0000\u0090\u0094"+ + "\u0003.\u0017\u0000\u0091\u0092\n\u0002\u0000\u0000\u0092\u0094\u0003"+ + "0\u0018\u0000\u0093\u008d\u0001\u0000\u0000\u0000\u0093\u008f\u0001\u0000"+ + "\u0000\u0000\u0093\u0091\u0001\u0000\u0000\u0000\u0094\u0097\u0001\u0000"+ + "\u0000\u0000\u0095\u0093\u0001\u0000\u0000\u0000\u0095\u0096\u0001\u0000"+ + "\u0000\u0000\u0096\u000f\u0001\u0000\u0000\u0000\u0097\u0095\u0001\u0000"+ + "\u0000\u0000\u0098\u0099\u0005\u0005\u0000\u0000\u0099\u009a\u0003\u0002"+ + "\u0001\u0000\u009a\u009b\u0005\u0006\u0000\u0000\u009b\u0011\u0001\u0000"+ + "\u0000\u0000\u009c\u009d\u0007\u0000\u0000\u0000\u009d\u0013\u0001\u0000"+ + "\u0000\u0000\u009e\u00a1\u0003\u0016\u000b\u0000\u009f\u00a1\u0003\u0018"+ + "\f\u0000\u00a0\u009e\u0001\u0000\u0000\u0000\u00a0\u009f\u0001\u0000\u0000"+ + "\u0000\u00a1\u0015\u0001\u0000\u0000\u0000\u00a2\u00ae\u0005\u0017\u0000"+ + "\u0000\u00a3\u00a8\u0003\f\u0006\u0000\u00a4\u00a5\u0005\'\u0000\u0000"+ + "\u00a5\u00a7\u0003\f\u0006\u0000\u00a6\u00a4\u0001\u0000\u0000\u0000\u00a7"+ + "\u00aa\u0001\u0000\u0000\u0000\u00a8\u00a6\u0001\u0000\u0000\u0000\u00a8"+ + "\u00a9\u0001\u0000\u0000\u0000\u00a9\u00ac\u0001\u0000\u0000\u0000\u00aa"+ + "\u00a8\u0001\u0000\u0000\u0000\u00ab\u00ad\u0005\'\u0000\u0000\u00ac\u00ab"+ + "\u0001\u0000\u0000\u0000\u00ac\u00ad\u0001\u0000\u0000\u0000\u00ad\u00af"+ + "\u0001\u0000\u0000\u0000\u00ae\u00a3\u0001\u0000\u0000\u0000\u00ae\u00af"+ + "\u0001\u0000\u0000\u0000\u00af\u00b0\u0001\u0000\u0000\u0000\u00b0\u00b1"+ + "\u0005\u001e\u0000\u0000\u00b1\u0017\u0001\u0000\u0000\u0000\u00b2\u00b6"+ + "\u0005\u0005\u0000\u0000\u00b3\u00b5\u0003\u001a\r\u0000\u00b4\u00b3\u0001"+ + "\u0000\u0000\u0000\u00b5\u00b8\u0001\u0000\u0000\u0000\u00b6\u00b4\u0001"+ + "\u0000\u0000\u0000\u00b6\u00b7\u0001\u0000\u0000\u0000\u00b7\u00b9\u0001"+ + "\u0000\u0000\u0000\u00b8\u00b6\u0001\u0000\u0000\u0000\u00b9\u00ba\u0005"+ + "\u0006\u0000\u0000\u00ba\u0019\u0001\u0000\u0000\u0000\u00bb\u00c9\u0005"+ + "\b\u0000\u0000\u00bc\u00bd\u0005\u0018\u0000\u0000\u00bd\u00be\u0005\b"+ + "\u0000\u0000\u00be\u00c9\u0005\u001f\u0000\u0000\u00bf\u00c3\u0005\u000f"+ + "\u0000\u0000\u00c0\u00c2\u0003J%\u0000\u00c1\u00c0\u0001\u0000\u0000\u0000"+ + "\u00c2\u00c5\u0001\u0000\u0000\u0000\u00c3\u00c1\u0001\u0000\u0000\u0000"+ + "\u00c3\u00c4\u0001\u0000\u0000\u0000\u00c4\u00c6\u0001\u0000\u0000\u0000"+ + "\u00c5\u00c3\u0001\u0000\u0000\u0000\u00c6\u00c9\u0005\u000f\u0000\u0000"+ + "\u00c7\u00c9\u0003\f\u0006\u0000\u00c8\u00bb\u0001\u0000\u0000\u0000\u00c8"+ + "\u00bc\u0001\u0000\u0000\u0000\u00c8\u00bf\u0001\u0000\u0000\u0000\u00c8"+ + "\u00c7\u0001\u0000\u0000\u0000\u00c9\u00ca\u0001\u0000\u0000\u0000\u00ca"+ + "\u00cb\u0007\u0001\u0000\u0000\u00cb\u00cd\u0003\f\u0006\u0000\u00cc\u00ce"+ + "\u0005\'\u0000\u0000\u00cd\u00cc\u0001\u0000\u0000\u0000\u00cd\u00ce\u0001"+ + "\u0000\u0000\u0000\u00ce\u001b\u0001\u0000\u0000\u0000\u00cf\u00d2\u0003"+ + "\u001e\u000f\u0000\u00d0\u00d2\u0003 \u0010\u0000\u00d1\u00cf\u0001\u0000"+ + "\u0000\u0000\u00d1\u00d0\u0001\u0000\u0000\u0000\u00d2\u001d\u0001\u0000"+ + "\u0000\u0000\u00d3\u00d4\u0005\u0002\u0000\u0000\u00d4\u00d5\u0003\"\u0011"+ + "\u0000\u00d5\u00d6\u0005\u0016\u0000\u0000\u00d6\u00d8\u0003\f\u0006\u0000"+ + "\u00d7\u00d9\u0003$\u0012\u0000\u00d8\u00d7\u0001\u0000\u0000\u0000\u00d8"+ + "\u00d9\u0001\u0000\u0000\u0000\u00d9\u00da\u0001\u0000\u0000\u0000\u00da"+ + "\u00db\u0005\u001e\u0000\u0000\u00db\u001f\u0001\u0000\u0000\u0000\u00dc"+ + "\u00dd\u0005\u0001\u0000\u0000\u00dd\u00de\u0003\"\u0011\u0000\u00de\u00df"+ + "\u0005\u0016\u0000\u0000\u00df\u00e0\u0003\f\u0006\u0000\u00e0\u00e1\u0005"+ + "&\u0000\u0000\u00e1\u00e3\u0003\f\u0006\u0000\u00e2\u00e4\u0005)\u0000"+ + "\u0000\u00e3\u00e2\u0001\u0000\u0000\u0000\u00e3\u00e4\u0001\u0000\u0000"+ + "\u0000\u00e4\u00e6\u0001\u0000\u0000\u0000\u00e5\u00e7\u0003$\u0012\u0000"+ + "\u00e6\u00e5\u0001\u0000\u0000\u0000\u00e6\u00e7\u0001\u0000\u0000\u0000"+ + "\u00e7\u00e8\u0001\u0000\u0000\u0000\u00e8\u00e9\u0005\u0006\u0000\u0000"+ + "\u00e9!\u0001\u0000\u0000\u0000\u00ea\u00ed\u0005\b\u0000\u0000\u00eb"+ + "\u00ec\u0005\'\u0000\u0000\u00ec\u00ee\u0005\b\u0000\u0000\u00ed\u00eb"+ + "\u0001\u0000\u0000\u0000\u00ed\u00ee\u0001\u0000\u0000\u0000\u00ee\u00ef"+ + "\u0001\u0000\u0000\u0000\u00ef\u00f0\u0005\u0004\u0000\u0000\u00f0\u00f1"+ + "\u0003\f\u0006\u0000\u00f1#\u0001\u0000\u0000\u0000\u00f2\u00f3\u0005"+ + "\u0003\u0000\u0000\u00f3\u00f4\u0003\f\u0006\u0000\u00f4%\u0001\u0000"+ + "\u0000\u0000\u00f5\u00f6\u0005\b\u0000\u0000\u00f6\'\u0001\u0000\u0000"+ + "\u0000\u00f7\u00f8\u0005\b\u0000\u0000\u00f8\u00fa\u0005\u0018\u0000\u0000"+ + "\u00f9\u00fb\u0003*\u0015\u0000\u00fa\u00f9\u0001\u0000\u0000\u0000\u00fa"+ + "\u00fb\u0001\u0000\u0000\u0000\u00fb\u00fc\u0001\u0000\u0000\u0000\u00fc"+ + "\u00fd\u0005\u001f\u0000\u0000\u00fd)\u0001\u0000\u0000\u0000\u00fe\u0103"+ + "\u0003\f\u0006\u0000\u00ff\u0100\u0005\'\u0000\u0000\u0100\u0102\u0003"+ + "\f\u0006\u0000\u0101\u00ff\u0001\u0000\u0000\u0000\u0102\u0105\u0001\u0000"+ + "\u0000\u0000\u0103\u0101\u0001\u0000\u0000\u0000\u0103\u0104\u0001\u0000"+ + "\u0000\u0000\u0104\u0107\u0001\u0000\u0000\u0000\u0105\u0103\u0001\u0000"+ + "\u0000\u0000\u0106\u0108\u0007\u0002\u0000\u0000\u0107\u0106\u0001\u0000"+ + "\u0000\u0000\u0107\u0108\u0001\u0000\u0000\u0000\u0108+\u0001\u0000\u0000"+ + "\u0000\u0109\u010a\u0005\u0017\u0000\u0000\u010a\u010b\u0003\f\u0006\u0000"+ + "\u010b\u010c\u0005\u001e\u0000\u0000\u010c-\u0001\u0000\u0000\u0000\u010d"+ + "\u010e\u0005#\u0000\u0000\u010e\u010f\u0005\b\u0000\u0000\u010f/\u0001"+ + "\u0000\u0000\u0000\u0110\u0113\u00032\u0019\u0000\u0111\u0113\u00034\u001a"+ + "\u0000\u0112\u0110\u0001\u0000\u0000\u0000\u0112\u0111\u0001\u0000\u0000"+ + "\u0000\u01131\u0001\u0000\u0000\u0000\u0114\u0115\u0005#\u0000\u0000\u0115"+ + "\u0119\u0005 \u0000\u0000\u0116\u0118\u0003.\u0017\u0000\u0117\u0116\u0001"+ + "\u0000\u0000\u0000\u0118\u011b\u0001\u0000\u0000\u0000\u0119\u0117\u0001"+ + "\u0000\u0000\u0000\u0119\u011a\u0001\u0000\u0000\u0000\u011a3\u0001\u0000"+ + "\u0000\u0000\u011b\u0119\u0001\u0000\u0000\u0000\u011c\u011d\u0005\u0017"+ + "\u0000\u0000\u011d\u011e\u0005 \u0000\u0000\u011e\u0123\u0005\u001e\u0000"+ + "\u0000\u011f\u0122\u0003.\u0017\u0000\u0120\u0122\u0003,\u0016\u0000\u0121"+ + "\u011f\u0001\u0000\u0000\u0000\u0121\u0120\u0001\u0000\u0000\u0000\u0122"+ + "\u0125\u0001\u0000\u0000\u0000\u0123\u0121\u0001\u0000\u0000\u0000\u0123"+ + "\u0124\u0001\u0000\u0000\u0000\u01245\u0001\u0000\u0000\u0000\u0125\u0123"+ + "\u0001\u0000\u0000\u0000\u0126\u0129\u00038\u001c\u0000\u0127\u0129\u0003"+ + ":\u001d\u0000\u0128\u0126\u0001\u0000\u0000\u0000\u0128\u0127\u0001\u0000"+ + "\u0000\u0000\u01297\u0001\u0000\u0000\u0000\u012a\u012b\u0007\u0003\u0000"+ + "\u0000\u012b\u012c\u0003\u000e\u0007\u0000\u012c9\u0001\u0000\u0000\u0000"+ + "\u012d\u0130\u0003\u000e\u0007\u0000\u012e\u0130\u00038\u001c\u0000\u012f"+ + "\u012d\u0001\u0000\u0000\u0000\u012f\u012e\u0001\u0000\u0000\u0000\u0130"+ + "\u0131\u0001\u0000\u0000\u0000\u0131\u0134\u0003<\u001e\u0000\u0132\u0135"+ + "\u0003\u000e\u0007\u0000\u0133\u0135\u00036\u001b\u0000\u0134\u0132\u0001"+ + "\u0000\u0000\u0000\u0134\u0133\u0001\u0000\u0000\u0000\u0135;\u0001\u0000"+ + "\u0000\u0000\u0136\u013a\u0003>\u001f\u0000\u0137\u013a\u0003@ \u0000"+ + "\u0138\u013a\u0003B!\u0000\u0139\u0136\u0001\u0000\u0000\u0000\u0139\u0137"+ + "\u0001\u0000\u0000\u0000\u0139\u0138\u0001\u0000\u0000\u0000\u013a=\u0001"+ + "\u0000\u0000\u0000\u013b\u013c\u0007\u0004\u0000\u0000\u013c?\u0001\u0000"+ + "\u0000\u0000\u013d\u013e\u0007\u0005\u0000\u0000\u013eA\u0001\u0000\u0000"+ + "\u0000\u013f\u0140\u0007\u0006\u0000\u0000\u0140C\u0001\u0000\u0000\u0000"+ + "\u0141\u0142\u0005\u0011\u0000\u0000\u0142\u014a\u0005\b\u0000\u0000\u0143"+ + "\u0147\u0005\f\u0000\u0000\u0144\u0146\u0003F#\u0000\u0145\u0144\u0001"+ + "\u0000\u0000\u0000\u0146\u0149\u0001\u0000\u0000\u0000\u0147\u0145\u0001"+ + "\u0000\u0000\u0000\u0147\u0148\u0001\u0000\u0000\u0000\u0148\u014b\u0001"+ + "\u0000\u0000\u0000\u0149\u0147\u0001\u0000\u0000\u0000\u014a\u0143\u0001"+ + "\u0000\u0000\u0000\u014b\u014c\u0001\u0000\u0000\u0000\u014c\u014a\u0001"+ + "\u0000\u0000\u0000\u014c\u014d\u0001\u0000\u0000\u0000\u014d\u014e\u0001"+ + "\u0000\u0000\u0000\u014e\u0158\u0005\b\u0000\u0000\u014f\u0153\u0005\u000f"+ + "\u0000\u0000\u0150\u0152\u0003J%\u0000\u0151\u0150\u0001\u0000\u0000\u0000"+ + "\u0152\u0155\u0001\u0000\u0000\u0000\u0153\u0151\u0001\u0000\u0000\u0000"+ + "\u0153\u0154\u0001\u0000\u0000\u0000\u0154\u0156\u0001\u0000\u0000\u0000"+ + "\u0155\u0153\u0001\u0000\u0000\u0000\u0156\u0158\u0005\u000f\u0000\u0000"+ + "\u0157\u0141\u0001\u0000\u0000\u0000\u0157\u014f\u0001\u0000\u0000\u0000"+ + "\u0158E\u0001\u0000\u0000\u0000\u0159\u015c\u0003N\'\u0000\u015a\u015c"+ + "\u0003H$\u0000\u015b\u0159\u0001\u0000\u0000\u0000\u015b\u015a\u0001\u0000"+ + "\u0000\u0000\u015cG\u0001\u0000\u0000\u0000\u015d\u015e\u0005.\u0000\u0000"+ + "\u015eI\u0001\u0000\u0000\u0000\u015f\u0162\u0003N\'\u0000\u0160\u0162"+ + "\u0003L&\u0000\u0161\u015f\u0001\u0000\u0000\u0000\u0161\u0160\u0001\u0000"+ + "\u0000\u0000\u0162K\u0001\u0000\u0000\u0000\u0163\u0164\u0005,\u0000\u0000"+ + "\u0164M\u0001\u0000\u0000\u0000\u0165\u0166\u0005+\u0000\u0000\u0166\u0167"+ + "\u0003\f\u0006\u0000\u0167\u0168\u0005\u0006\u0000\u0000\u0168O\u0001"+ + "\u0000\u0000\u0000\'UZdns}\u008b\u0093\u0095\u00a0\u00a8\u00ac\u00ae\u00b6"+ + "\u00c3\u00c8\u00cd\u00d1\u00d8\u00e3\u00e6\u00ed\u00fa\u0103\u0107\u0112"+ + "\u0119\u0121\u0123\u0128\u012f\u0134\u0139\u0147\u014c\u0153\u0157\u015b"+ + "\u0161"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseListener.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseListener.java index dbdd45be121..955f095e365 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseListener.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseVisitor.java index fb7e701455a..5add2c1566f 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserListener.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserListener.java index fde58c5b522..c73e9f70565 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserListener.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserVisitor.java index 4d9f7ee6d32..531e35db3bc 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathLexer.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathLexer.java index e4ff51db26c..987668c563c 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathLexer.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathLexer.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,13 +15,14 @@ */ // Generated from java-escape by ANTLR 4.11.1 package org.openrewrite.hcl.internal.grammar; - +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.ATN; -import org.antlr.v4.runtime.atn.ATNDeserializer; -import org.antlr.v4.runtime.atn.LexerATNSimulator; -import org.antlr.v4.runtime.atn.PredictionContextCache; +import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) public class JsonPathLexer extends Lexer { @@ -31,11 +32,11 @@ public class JsonPathLexer extends Lexer { protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int - WS=1, UTF_8_BOM=2, MATCHES_REGEX_OPEN=3, LBRACE=4, RBRACE=5, LBRACK=6, - RBRACK=7, LPAREN=8, RPAREN=9, AT=10, DOT=11, DOT_DOT=12, ROOT=13, WILDCARD=14, - COLON=15, QUESTION=16, CONTAINS=17, Identifier=18, StringLiteral=19, PositiveNumber=20, - NegativeNumber=21, NumericLiteral=22, COMMA=23, TICK=24, QUOTE=25, MATCHES=26, - LOGICAL_OPERATOR=27, AND=28, OR=29, EQUALITY_OPERATOR=30, EQ=31, NE=32, + WS=1, UTF_8_BOM=2, MATCHES_REGEX_OPEN=3, LBRACE=4, RBRACE=5, LBRACK=6, + RBRACK=7, LPAREN=8, RPAREN=9, AT=10, DOT=11, DOT_DOT=12, ROOT=13, WILDCARD=14, + COLON=15, QUESTION=16, CONTAINS=17, Identifier=18, StringLiteral=19, PositiveNumber=20, + NegativeNumber=21, NumericLiteral=22, COMMA=23, TICK=24, QUOTE=25, MATCHES=26, + LOGICAL_OPERATOR=27, AND=28, OR=29, EQUALITY_OPERATOR=30, EQ=31, NE=32, TRUE=33, FALSE=34, NULL=35, MATCHES_REGEX_CLOSE=36, S=37, REGEX=38; public static final int MATCHES_REGEX=1; @@ -49,12 +50,12 @@ public class JsonPathLexer extends Lexer { private static String[] makeRuleNames() { return new String[] { - "WS", "UTF_8_BOM", "MATCHES_REGEX_OPEN", "LBRACE", "RBRACE", "LBRACK", - "RBRACK", "LPAREN", "RPAREN", "AT", "DOT", "DOT_DOT", "ROOT", "WILDCARD", - "COLON", "QUESTION", "CONTAINS", "Identifier", "StringLiteral", "PositiveNumber", - "NegativeNumber", "NumericLiteral", "COMMA", "TICK", "QUOTE", "MATCHES", - "LOGICAL_OPERATOR", "AND", "OR", "EQUALITY_OPERATOR", "EQ", "NE", "TRUE", - "FALSE", "NULL", "ESCAPE_SEQUENCE", "UNICODE", "HEX_DIGIT", "SAFE_CODE_POINT", + "WS", "UTF_8_BOM", "MATCHES_REGEX_OPEN", "LBRACE", "RBRACE", "LBRACK", + "RBRACK", "LPAREN", "RPAREN", "AT", "DOT", "DOT_DOT", "ROOT", "WILDCARD", + "COLON", "QUESTION", "CONTAINS", "Identifier", "StringLiteral", "PositiveNumber", + "NegativeNumber", "NumericLiteral", "COMMA", "TICK", "QUOTE", "MATCHES", + "LOGICAL_OPERATOR", "AND", "OR", "EQUALITY_OPERATOR", "EQ", "NE", "TRUE", + "FALSE", "NULL", "ESCAPE_SEQUENCE", "UNICODE", "HEX_DIGIT", "SAFE_CODE_POINT", "EXPONENT_PART", "MINUS", "MATCHES_REGEX_CLOSE", "S", "REGEX" }; } @@ -62,20 +63,20 @@ private static String[] makeRuleNames() { private static String[] makeLiteralNames() { return new String[] { - null, null, "'\\uFEFF'", null, "'{'", "'}'", "'['", "']'", "'('", "')'", - "'@'", "'.'", "'..'", "'$'", "'*'", "':'", "'?'", "'contains'", null, - null, null, null, null, "','", "'''", "'\"'", "'=~'", null, "'&&'", "'||'", + null, null, "'\\uFEFF'", null, "'{'", "'}'", "'['", "']'", "'('", "')'", + "'@'", "'.'", "'..'", "'$'", "'*'", "':'", "'?'", "'contains'", null, + null, null, null, null, "','", "'''", "'\"'", "'=~'", null, "'&&'", "'||'", null, "'=='", "'!='", "'true'", "'false'", "'null'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { - null, "WS", "UTF_8_BOM", "MATCHES_REGEX_OPEN", "LBRACE", "RBRACE", "LBRACK", - "RBRACK", "LPAREN", "RPAREN", "AT", "DOT", "DOT_DOT", "ROOT", "WILDCARD", - "COLON", "QUESTION", "CONTAINS", "Identifier", "StringLiteral", "PositiveNumber", - "NegativeNumber", "NumericLiteral", "COMMA", "TICK", "QUOTE", "MATCHES", - "LOGICAL_OPERATOR", "AND", "OR", "EQUALITY_OPERATOR", "EQ", "NE", "TRUE", + null, "WS", "UTF_8_BOM", "MATCHES_REGEX_OPEN", "LBRACE", "RBRACE", "LBRACK", + "RBRACK", "LPAREN", "RPAREN", "AT", "DOT", "DOT_DOT", "ROOT", "WILDCARD", + "COLON", "QUESTION", "CONTAINS", "Identifier", "StringLiteral", "PositiveNumber", + "NegativeNumber", "NumericLiteral", "COMMA", "TICK", "QUOTE", "MATCHES", + "LOGICAL_OPERATOR", "AND", "OR", "EQUALITY_OPERATOR", "EQ", "NE", "TRUE", "FALSE", "NULL", "MATCHES_REGEX_CLOSE", "S", "REGEX" }; } diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParser.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParser.java index 687e2a8d034..9303ee81d64 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParser.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,18 +15,14 @@ */ // Generated from java-escape by ANTLR 4.11.1 package org.openrewrite.hcl.internal.grammar; - -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.ATN; -import org.antlr.v4.runtime.atn.ATNDeserializer; -import org.antlr.v4.runtime.atn.ParserATNSimulator; -import org.antlr.v4.runtime.atn.PredictionContextCache; +import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.tree.ParseTreeListener; -import org.antlr.v4.runtime.tree.ParseTreeVisitor; -import org.antlr.v4.runtime.tree.TerminalNode; - +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.misc.*; +import org.antlr.v4.runtime.tree.*; import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) public class JsonPathParser extends Parser { @@ -36,23 +32,23 @@ public class JsonPathParser extends Parser { protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int - WS=1, UTF_8_BOM=2, MATCHES_REGEX_OPEN=3, LBRACE=4, RBRACE=5, LBRACK=6, - RBRACK=7, LPAREN=8, RPAREN=9, AT=10, DOT=11, DOT_DOT=12, ROOT=13, WILDCARD=14, - COLON=15, QUESTION=16, CONTAINS=17, Identifier=18, StringLiteral=19, PositiveNumber=20, - NegativeNumber=21, NumericLiteral=22, COMMA=23, TICK=24, QUOTE=25, MATCHES=26, - LOGICAL_OPERATOR=27, AND=28, OR=29, EQUALITY_OPERATOR=30, EQ=31, NE=32, + WS=1, UTF_8_BOM=2, MATCHES_REGEX_OPEN=3, LBRACE=4, RBRACE=5, LBRACK=6, + RBRACK=7, LPAREN=8, RPAREN=9, AT=10, DOT=11, DOT_DOT=12, ROOT=13, WILDCARD=14, + COLON=15, QUESTION=16, CONTAINS=17, Identifier=18, StringLiteral=19, PositiveNumber=20, + NegativeNumber=21, NumericLiteral=22, COMMA=23, TICK=24, QUOTE=25, MATCHES=26, + LOGICAL_OPERATOR=27, AND=28, OR=29, EQUALITY_OPERATOR=30, EQ=31, NE=32, TRUE=33, FALSE=34, NULL=35, MATCHES_REGEX_CLOSE=36, S=37, REGEX=38; public static final int - RULE_jsonPath = 0, RULE_expression = 1, RULE_dotOperator = 2, RULE_recursiveDecent = 3, - RULE_bracketOperator = 4, RULE_filter = 5, RULE_filterExpression = 6, - RULE_binaryExpression = 7, RULE_containsExpression = 8, RULE_regexExpression = 9, - RULE_unaryExpression = 10, RULE_literalExpression = 11, RULE_property = 12, + RULE_jsonPath = 0, RULE_expression = 1, RULE_dotOperator = 2, RULE_recursiveDecent = 3, + RULE_bracketOperator = 4, RULE_filter = 5, RULE_filterExpression = 6, + RULE_binaryExpression = 7, RULE_containsExpression = 8, RULE_regexExpression = 9, + RULE_unaryExpression = 10, RULE_literalExpression = 11, RULE_property = 12, RULE_wildcard = 13, RULE_slice = 14, RULE_start = 15, RULE_end = 16, RULE_indexes = 17; private static String[] makeRuleNames() { return new String[] { - "jsonPath", "expression", "dotOperator", "recursiveDecent", "bracketOperator", - "filter", "filterExpression", "binaryExpression", "containsExpression", - "regexExpression", "unaryExpression", "literalExpression", "property", + "jsonPath", "expression", "dotOperator", "recursiveDecent", "bracketOperator", + "filter", "filterExpression", "binaryExpression", "containsExpression", + "regexExpression", "unaryExpression", "literalExpression", "property", "wildcard", "slice", "start", "end", "indexes" }; } @@ -60,20 +56,20 @@ private static String[] makeRuleNames() { private static String[] makeLiteralNames() { return new String[] { - null, null, "'\\uFEFF'", null, "'{'", "'}'", "'['", "']'", "'('", "')'", - "'@'", "'.'", "'..'", "'$'", "'*'", "':'", "'?'", "'contains'", null, - null, null, null, null, "','", "'''", "'\"'", "'=~'", null, "'&&'", "'||'", + null, null, "'\\uFEFF'", null, "'{'", "'}'", "'['", "']'", "'('", "')'", + "'@'", "'.'", "'..'", "'$'", "'*'", "':'", "'?'", "'contains'", null, + null, null, null, null, "','", "'''", "'\"'", "'=~'", null, "'&&'", "'||'", null, "'=='", "'!='", "'true'", "'false'", "'null'" }; } private static final String[] _LITERAL_NAMES = makeLiteralNames(); private static String[] makeSymbolicNames() { return new String[] { - null, "WS", "UTF_8_BOM", "MATCHES_REGEX_OPEN", "LBRACE", "RBRACE", "LBRACK", - "RBRACK", "LPAREN", "RPAREN", "AT", "DOT", "DOT_DOT", "ROOT", "WILDCARD", - "COLON", "QUESTION", "CONTAINS", "Identifier", "StringLiteral", "PositiveNumber", - "NegativeNumber", "NumericLiteral", "COMMA", "TICK", "QUOTE", "MATCHES", - "LOGICAL_OPERATOR", "AND", "OR", "EQUALITY_OPERATOR", "EQ", "NE", "TRUE", + null, "WS", "UTF_8_BOM", "MATCHES_REGEX_OPEN", "LBRACE", "RBRACE", "LBRACK", + "RBRACK", "LPAREN", "RPAREN", "AT", "DOT", "DOT_DOT", "ROOT", "WILDCARD", + "COLON", "QUESTION", "CONTAINS", "Identifier", "StringLiteral", "PositiveNumber", + "NegativeNumber", "NumericLiteral", "COMMA", "TICK", "QUOTE", "MATCHES", + "LOGICAL_OPERATOR", "AND", "OR", "EQUALITY_OPERATOR", "EQ", "NE", "TRUE", "FALSE", "NULL", "MATCHES_REGEX_CLOSE", "S", "REGEX" }; } @@ -174,7 +170,7 @@ public final JsonPathContext jsonPath() throws RecognitionException { } } - setState(40); + setState(40); _errHandler.sync(this); _alt = 1; do { @@ -190,7 +186,7 @@ public final JsonPathContext jsonPath() throws RecognitionException { default: throw new NoViableAltException(this); } - setState(42); + setState(42); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,1,_ctx); } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ); @@ -475,7 +471,7 @@ public final BracketOperatorContext bracketOperator() throws RecognitionExceptio break; case 4: { - setState(63); + setState(63); _errHandler.sync(this); _la = _input.LA(1); do { @@ -485,7 +481,7 @@ public final BracketOperatorContext bracketOperator() throws RecognitionExceptio property(); } } - setState(65); + setState(65); _errHandler.sync(this); _la = _input.LA(1); } while ( _la==Identifier || _la==StringLiteral ); @@ -548,7 +544,7 @@ public final FilterContext filter() throws RecognitionException { match(QUESTION); setState(72); match(LPAREN); - setState(74); + setState(74); _errHandler.sync(this); _la = _input.LA(1); do { @@ -558,7 +554,7 @@ public final FilterContext filter() throws RecognitionException { filterExpression(); } } - setState(76); + setState(76); _errHandler.sync(this); _la = _input.LA(1); } while ( ((_la) & ~0x3f) == 0 && ((1L << _la) & 60137421888L) != 0 ); @@ -853,7 +849,7 @@ private BinaryExpressionContext binaryExpression(int _p) throws RecognitionExcep } break; } - } + } } setState(134); _errHandler.sync(this); @@ -1482,7 +1478,7 @@ public final IndexesContext indexes() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(187); + setState(187); _errHandler.sync(this); _la = _input.LA(1); do { @@ -1492,7 +1488,7 @@ public final IndexesContext indexes() throws RecognitionException { match(PositiveNumber); } } - setState(189); + setState(189); _errHandler.sync(this); _la = _input.LA(1); } while ( _la==PositiveNumber ); @@ -1509,8 +1505,8 @@ public final IndexesContext indexes() throws RecognitionException { return _localctx; } - @Override - public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { + @Override + public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { switch (ruleIndex) { case 7: return binaryExpression_sempred((BinaryExpressionContext)_localctx, predIndex); diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserBaseListener.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserBaseListener.java index 024b82f697e..66acfd555d7 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserBaseListener.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserBaseListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserBaseVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserBaseVisitor.java index b8de4dc8962..7b55bd30391 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserBaseVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserBaseVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserListener.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserListener.java index dac28047fb4..7764c87c616 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserListener.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserVisitor.java index c4d008aeacf..53fd9927b92 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/JsonPathParserVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 the original author or authors. *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclBlockTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclBlockTest.java index fff395d2ac6..281dcde77e9 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclBlockTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclBlockTest.java @@ -97,4 +97,22 @@ void oneLineBlock() { ) ); } + + @Test + void providersInModule() { + rewriteRun( + hcl( + """ + module "something" { + source = "./some/other/directory" + + providers = { + aws = aws + aws.dns = aws + } + } + """ + ) + ); + } } From 56be668c30808f66509b0e76c8ba152e51e5c129 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 2 Jan 2025 16:38:54 +0100 Subject: [PATCH 093/179] Prevent class cast exception on Unknown annotation type (#4833) --- .../internal/template/BlockStatementTemplateGenerator.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java index 1dedaf9ea3d..d8715d558d5 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/internal/template/BlockStatementTemplateGenerator.java @@ -309,7 +309,12 @@ private void contextTemplate(Cursor cursor, J prior, StringBuilder before, Strin Optional arg = annotation.getArguments().stream().filter(a -> a == prior).findFirst(); if (arg.isPresent()) { StringBuilder beforeBuffer = new StringBuilder(); - beforeBuffer.append('@').append(((JavaType.Class) annotation.getType()).getFullyQualifiedName()).append('('); + String name = annotation.getType() instanceof JavaType.Class ? + ((JavaType.Class) annotation.getType()).getFullyQualifiedName() : + annotation.getType() instanceof JavaType.FullyQualified ? + ((JavaType.FullyQualified) annotation.getType()).getFullyQualifiedName() : + annotation.getSimpleName(); + beforeBuffer.append('@').append(name).append('('); before.insert(0, beforeBuffer); after.append(')').append('\n'); From 2bf57b9c804bac61994dff7d4b29161a49c728c7 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Thu, 2 Jan 2025 17:32:40 +0100 Subject: [PATCH 094/179] Improve discovery of parentheses level for MethodCallExpression (#4834) --- .../groovy/GroovyParserVisitor.java | 12 ++++++------ .../groovy/tree/MethodInvocationTest.java | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index c34c258ee86..97855816ed0 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -2484,17 +2484,17 @@ private Space sourceBefore(String untilDelim) { private int determineParenthesisLevel(int childLineNumber, int parentLineNumber, int childColumn, int parentColumn) { int saveCursor = cursor; whitespace(); - int childBeginCursor = cursor; + int untilCursor = cursor; if (childLineNumber > parentLineNumber) { - for (int i = 0; i < (childColumn - parentLineNumber); i++) { - childBeginCursor = source.indexOf('\n', childBeginCursor); + for (int i = 0; i < (childLineNumber - parentLineNumber); i++) { + untilCursor = source.indexOf('\n', untilCursor) + 1; // +1; set cursor past `\n` } - childBeginCursor += childColumn; + untilCursor += childColumn - 1; // -1; skip previous `\n` } else { - childBeginCursor += childColumn - parentColumn; + untilCursor += childColumn - parentColumn; } int count = 0; - for (int i = cursor; i < childBeginCursor; i++) { + for (int i = cursor; i < untilCursor; i++) { if (source.charAt(i) == '(') { count++; } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java index 31531c0d6ab..4e893f7ffb0 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodInvocationTest.java @@ -362,6 +362,25 @@ void closureReturn() { ); } + @Issue("https://github.com/openrewrite/rewrite/issues/4055") + @Test + void chainOfMethodInvocations() { + rewriteRun( + groovy( + """ + Micronaut.build(args) + .banner(false) + .propertySources(PropertySource.of("my-config", [name: "MyApp"])) + .environments("prod") // Only prod + .overrideConfig("custom-config.yml") // Load custom config + .packages("com.company") + .mainClass(Application) + .start() + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/2552") @Test void closureInvocation() { From f9201dd0de15e2bc378eb5708bbcc6341fd82b88 Mon Sep 17 00:00:00 2001 From: Anshuman Mishra <119983081+amishra-u@users.noreply.github.com> Date: Thu, 2 Jan 2025 13:47:34 -0800 Subject: [PATCH 095/179] Add Support for Builder.Default annotation for final vars (#4835) --- .../java/lombok/BuilderHandler.java | 24 ++++++++++++++----- .../org/openrewrite/java/tree/LombokTest.java | 24 +++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderHandler.java index ec23effd5f8..73c8b434f30 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/BuilderHandler.java @@ -43,7 +43,7 @@ public void handle(AnnotationValues annotationValues, JCTree.JCAnnotati new HandleBuilder().handle(annotationValues, jcAnnotation, javacNode); return; } - Map> modifiersAndOriginalAnnotationMap = new HashMap<>(); + Map modifiersRestoreMap = new HashMap<>(); Map> nodeToChildrenMap = new HashMap<>(); Field childrenField = null; try { @@ -66,9 +66,10 @@ public void handle(AnnotationValues annotationValues, JCTree.JCAnnotati childrenField.set(fieldNode, filtered); JCTree.JCVariableDecl fd = (JCTree.JCVariableDecl) fieldNode.get(); JCTree.JCModifiers modifiers = fd.getModifiers(); - List originalAnnotations = modifiers.getAnnotations(); - modifiersAndOriginalAnnotationMap.put(modifiers, originalAnnotations); - modifiers.annotations = removeBuilderDefault(originalAnnotations); + + modifiersRestoreMap.put(modifiers, new FlagAndAnnotations(modifiers.flags, modifiers.annotations)); + modifiers.annotations = removeBuilderDefault(modifiers.annotations); + modifiers.flags = modifiers.flags & (~(1 << 4) /*final mask*/); } } catch (NoSuchFieldException | IllegalAccessException e) { // On exception just continue with the original handler @@ -76,8 +77,9 @@ public void handle(AnnotationValues annotationValues, JCTree.JCAnnotati new HandleBuilder().handle(annotationValues, jcAnnotation, javacNode); // restore values - for (Map.Entry> entry : modifiersAndOriginalAnnotationMap.entrySet()) { - entry.getKey().annotations = entry.getValue(); + for (Map.Entry entry : modifiersRestoreMap.entrySet()) { + entry.getKey().flags = entry.getValue().flags; + entry.getKey().annotations = entry.getValue().annotations; } for (Map.Entry> entry : nodeToChildrenMap.entrySet()) { try { @@ -109,4 +111,14 @@ private List findBuilderDefaultIndexes(LombokImmutableList n } return indexes.toList(); } + + private static class FlagAndAnnotations { + long flags; + List annotations; + + FlagAndAnnotations(long flags, List annotations) { + this.flags = flags; + this.annotations = annotations; + } + } } diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index ad023f79ced..3a7f7850365 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -143,6 +143,30 @@ void test() { ); } + @Test + void builderWithDefaultAndFinal() { + rewriteRun( + java( + """ + import lombok.Builder; + + @Builder + class A { + @Builder.Default private final boolean b = false; + @Builder.Default public final int n = 0; + @Builder.Default protected final String s = "Hello, Anshuman!"; + + void test() { + A x = A.builder().n(1).b(true).s("foo").build(); + A y = A.builder().n(1).b(true).build(); + A z = A.builder().n(1).build(); + } + } + """ + ) + ); + } + @Test void tostring() { rewriteRun( From e69e4130efe6fcd0dc64fd4a064112478fdcb04d Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Fri, 3 Jan 2025 12:57:43 +0100 Subject: [PATCH 096/179] Allow to add Maven test scoped dependency (#4837) - Fixes #4836 --- .../src/main/java/org/openrewrite/maven/AddDependency.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/AddDependency.java b/rewrite-maven/src/main/java/org/openrewrite/maven/AddDependency.java index 0dc1f33bd74..f9e4b4e8d9f 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/AddDependency.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/AddDependency.java @@ -78,7 +78,7 @@ public class AddDependency extends ScanningRecipe { description = "A scope to use when it is not what can be inferred from usage. Most of the time this will be left empty, but " + "is used when adding a runtime, provided, or import dependency.", example = "runtime", - valid = {"import", "runtime", "provided"}, + valid = {"import", "runtime", "provided", "test"}, required = false) @Nullable String scope; From 988390af2f8f8decf62df9196e52630c62b6eb6d Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Fri, 3 Jan 2025 13:10:16 +0100 Subject: [PATCH 097/179] UT for expressionOnLeftHandSideOfAMapLiteral (#4841) --- .../org/openrewrite/hcl/tree/HclBlockTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclBlockTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclBlockTest.java index 281dcde77e9..295bbac8585 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclBlockTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclBlockTest.java @@ -115,4 +115,19 @@ void providersInModule() { ) ); } + + @Test + void expressionOnLeftHandSideOfAMapLiteral() { + rewriteRun( + hcl( + """ + locals { + security_groups_to_create = { + (data.aws_security_group.default.id) : "the_default_one" + } + } + """ + ) + ); + } } From 38d92b078c4369c4ecdb47a3747c9a7ed5514180 Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Fri, 3 Jan 2025 13:11:13 +0100 Subject: [PATCH 098/179] HCL - Fixing handling of multi-line empty maps (#4839) * Fixing handling of multi-line empty maps * Apply formatter --------- Co-authored-by: Tim te Beek --- .../openrewrite/hcl/internal/HclParserVisitor.java | 13 +++++++++---- .../hcl/tree/HclCollectionValueTest.java | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java index 40e9f9a2331..d729bdffc15 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java @@ -444,10 +444,15 @@ public Hcl visitObject(HCLParser.ObjectContext ctx) { Space tuplePrefix = sourceBefore("{"); List> mappedValues = new ArrayList<>(); List values = ctx.objectelem(); - for (int i = 0; i < values.size(); i++) { - HCLParser.ObjectelemContext value = values.get(i); - mappedValues.add(HclRightPadded.build((Expression) visit(value)) - .withAfter(i == values.size() - 1 ? sourceBefore("}") : Space.EMPTY)); + if (values.isEmpty()) { + mappedValues.add( + HclRightPadded.build(new Hcl.Empty(randomId(), sourceBefore("}"), Markers.EMPTY))); + } else { + for (int i = 0; i < values.size(); i++) { + HCLParser.ObjectelemContext value = values.get(i); + mappedValues.add(HclRightPadded.build((Expression) visit(value)) + .withAfter(i == values.size() - 1 ? sourceBefore("}") : Space.EMPTY)); + } } return new Hcl.ObjectValue(randomId(), Space.format(prefix), Markers.EMPTY, diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCollectionValueTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCollectionValueTest.java index 2b877a4cc47..30e60b4f1b9 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCollectionValueTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCollectionValueTest.java @@ -54,4 +54,18 @@ void objectValue() { ) ); } + + @Test + void emptyMapInTwoLines() { + rewriteRun( + hcl( + """ + locals { + known_weird_cases = { + } + } + """ + ) + ); + } } From 10a16619ddeec70f72edfd62f7d6a1778ea75862 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Fri, 3 Jan 2025 13:23:23 +0100 Subject: [PATCH 099/179] Cleanup groovy parser (#4838) * Cleanup groovy parser - Remove `def` check for visitTypeTree - Remove unnecessary RedundantDef marker for DeclarationExpression - Made RedundantDef function more specific for MethodNodes - Use `skip` function as much as possible * Cleanup groovy parser - Remove `def` check for visitTypeTree - Remove unnecessary RedundantDef marker for DeclarationExpression - Made RedundantDef function more specific for MethodNodes - Use `skip` function as much as possible * Support for `def` keyword for constructors * Improvement --- .../groovy/GroovyParserVisitor.java | 256 +++++++----------- .../groovy/tree/ClassDeclarationTest.java | 14 + .../groovy/tree/MethodDeclarationTest.java | 2 +- 3 files changed, 115 insertions(+), 157 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 97855816ed0..2735ff269e6 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -45,6 +45,7 @@ import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; +import java.lang.annotation.Annotation; import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.nio.charset.Charset; @@ -55,7 +56,6 @@ import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; import static java.util.Collections.emptyList; @@ -115,35 +115,6 @@ private static boolean isOlderThanGroovy3() { return olderThanGroovy3; } - /** - * Groovy methods can be declared with "def" AND a return type - * In these cases the "def" is semantically meaningless but needs to be preserved for source code accuracy - * If there is both a def and a return type, this method returns a RedundantDef object and advances the cursor - * position past the "def" keyword, leaving the return type to be parsed as normal. - * In any other situation an empty Optional is returned and the cursor is not advanced. - */ - private Optional maybeRedundantDef(ClassNode type, String name) { - int saveCursor = cursor; - Space defPrefix = whitespace(); - if (source.startsWith("def", cursor)) { - skip("def"); - // The def is redundant only when it is followed by the method's return type - // I hope no one puts an annotation between "def" and the return type - int cursorBeforeReturnType = cursor; - int lengthOfTypePrefix = indexOfNextNonWhitespace(cursorBeforeReturnType, source) - cursorBeforeReturnType; - // Differentiate between the next token being the method/variable name and it being the return type - if (!source.startsWith(name, cursorBeforeReturnType + lengthOfTypePrefix)) { - TypeTree returnType = visitTypeTree(type); - if (source.startsWith(returnType.toString(), cursorBeforeReturnType + lengthOfTypePrefix)) { - cursor = cursorBeforeReturnType; - return Optional.of(new RedundantDef(randomId(), defPrefix)); - } - } - } - cursor = saveCursor; - return Optional.empty(); - } - public G.CompilationUnit visit(SourceUnit unit, ModuleNode ast) throws GroovyParsingException { NavigableMap> sortedByPosition = new TreeMap<>(); for (org.codehaus.groovy.ast.stmt.Statement s : ast.getStatementBlock().getStatements()) { @@ -259,16 +230,16 @@ public void visitClass(ClassNode clazz) { J.ClassDeclaration.Kind.Type kindType = null; if (source.startsWith("class", cursor)) { kindType = J.ClassDeclaration.Kind.Type.Class; - cursor += "class".length(); + skip("class"); } else if (source.startsWith("interface", cursor)) { kindType = J.ClassDeclaration.Kind.Type.Interface; - cursor += "interface".length(); + skip("interface"); } else if (source.startsWith("@interface", cursor)) { kindType = J.ClassDeclaration.Kind.Type.Annotation; - cursor += "@interface".length(); + skip("@interface"); } else if (source.startsWith("enum", cursor)) { kindType = J.ClassDeclaration.Kind.Type.Enum; - cursor += "enum".length(); + skip("enum"); } assert kindType != null; J.ClassDeclaration.Kind kind = new J.ClassDeclaration.Kind(randomId(), kindPrefix, Markers.EMPTY, emptyList(), kindType); @@ -298,7 +269,7 @@ public void visitClass(ClassNode clazz) { for (int i = 0; i < interfaces.length; i++) { ClassNode anInterface = interfaces[i]; // Any annotation @interface is listed as extending java.lang.annotation.Annotation, although it doesn't appear in source - if (kindType == J.ClassDeclaration.Kind.Type.Annotation && "java.lang.annotation.Annotation".equals(anInterface.getName())) { + if (kindType == J.ClassDeclaration.Kind.Type.Annotation && Annotation.class.getName().equals(anInterface.getName())) { continue; } implTypes.add(JRightPadded.build(visitTypeTree(anInterface)) @@ -524,14 +495,13 @@ public void visitMethod(MethodNode method) { List annotations = visitAndGetAnnotations(method); List modifiers = visitModifiers(method.getModifiers()); - boolean isConstructor = method instanceof ConstructorNode; boolean isConstructorOfInnerNonStaticClass = false; - Optional redundantDef = isConstructor ? Optional.empty() : maybeRedundantDef(method.getReturnType(), method.getName()); - TypeTree returnType = isConstructor ? null : visitTypeTree(method.getReturnType()); + RedundantDef redundantDef = getRedundantDefMarker(method); + TypeTree returnType = method instanceof ConstructorNode ? null : visitTypeTree(method.getReturnType()); Space namePrefix = whitespace(); String methodName; - if (isConstructor) { + if (method instanceof ConstructorNode) { /* To support Java syntax for non-static inner classes, the groovy compiler uses an extra parameter with a reference to its parent class under the hood: class A { class A { @@ -593,7 +563,7 @@ class B { class B { new J.Identifier(randomId(), whitespace(), Markers.EMPTY, emptyList(), param.getName(), null, null), emptyList(), null, null) ); - cursor += param.getName().length(); + skip(param.getName()); org.codehaus.groovy.ast.expr.Expression defaultValue = param.getInitialExpression(); if (defaultValue != null) { @@ -634,7 +604,7 @@ varargs, emptyList(), queue.add(new J.MethodDeclaration( randomId(), fmt, - redundantDef.map(Markers.EMPTY::add).orElse(Markers.EMPTY), + redundantDef == null ? Markers.EMPTY : Markers.EMPTY.add(redundantDef), annotations, modifiers, null, @@ -648,6 +618,24 @@ varargs, emptyList(), )); } + /** + * Methods can be declared with "def" AND a return type (or constructors with "def"). + * In these cases the "def" is semantically meaningless but needs to be preserved for source code accuracy. + * If there is both a def and a return type, this method returns a RedundantDef object and advances the cursor + * position past the "def" keyword, leaving the return type to be parsed as normal. + */ + private @Nullable RedundantDef getRedundantDefMarker(MethodNode method) { + int saveCursor = cursor; + Space defPrefix = whitespace(); + if (source.startsWith("def", cursor) && (method.getReturnType().isRedirectNode() || !Object.class.getName().equals(method.getReturnType().getName()))) { + skip("def"); + return new RedundantDef(randomId(), defPrefix); + } + + cursor = saveCursor; + return null; + } + public List visitAndGetAnnotations(AnnotatedNode node) { if (node.getAnnotations().isEmpty()) { return emptyList(); @@ -694,13 +682,11 @@ private List> visitRightPadded(ASTNode[] nodes, @Nullable St converted = converted.withAfter(whitespace()); if (',' == source.charAt(cursor)) { // In Groovy trailing "," are allowed - cursor += 1; + skip(","); converted = converted.withMarkers(Markers.EMPTY.add(new TrailingComma(randomId(), whitespace()))); } ts.add(converted); - if (afterLast != null && source.startsWith(afterLast, cursor)) { - cursor += afterLast.length(); - } + skip(afterLast); } else { ts.add(converted.withAfter(sourceBefore(","))); } @@ -754,7 +740,7 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { boolean hasParentheses = true; if (source.charAt(cursor) == '(') { - cursor++; + skip("("); } else { hasParentheses = false; beforeOpenParen = EMPTY; @@ -775,11 +761,8 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { // Figure out the source-code ordering of the expressions MapExpression namedArgExpressions = (MapExpression) unparsedArgs.get(0); unparsedArgs = - Stream.concat( - namedArgExpressions.getMapEntryExpressions().stream(), - unparsedArgs.subList(1, unparsedArgs.size()).stream()) - .sorted(Comparator.comparing(ASTNode::getLastLineNumber) - .thenComparing(ASTNode::getLastColumnNumber)) + ListUtils.concatAll(unparsedArgs.subList(1, unparsedArgs.size()), namedArgExpressions.getMapEntryExpressions()).stream() + .sorted(Comparator.comparing(ASTNode::getLastLineNumber).thenComparing(ASTNode::getLastColumnNumber)) .collect(toList()); } else if (!unparsedArgs.isEmpty() && unparsedArgs.get(0) instanceof MapExpression) { // The map literal may or may not be wrapped in "[]" @@ -856,7 +839,7 @@ public void visitClassExpression(ClassExpression clazz) { Space space = sourceBefore(unresolvedName); if (source.substring(cursor).startsWith(".class")) { unresolvedName += ".class"; - cursor += 6; + skip(".class"); } queue.add(TypeTree.build(unresolvedName) .withType(typeMapping.type(clazz.getType())) @@ -1061,11 +1044,11 @@ public void visitBlockStatement(BlockStatement block) { JRightPadded stat = JRightPadded.build((Statement) expr); int saveCursor = cursor; Space beforeSemicolon = whitespace(); - if (cursor < source.length() && source.charAt(cursor) == ';') { + if (source.charAt(cursor) == ';') { stat = stat .withMarkers(stat.getMarkers().add(new Semicolon(randomId()))) .withAfter(beforeSemicolon); - cursor++; + skip(";"); } else { cursor = saveCursor; } @@ -1090,11 +1073,11 @@ public void visitCatchStatement(CatchStatement node) { Space paramPrefix = whitespace(); // Groovy allows catch variables to omit their type, shorthand for being of type java.lang.Exception // Can't use isSynthetic() here because groovy doesn't record the line number on the Parameter - if ("java.lang.Exception".equals(param.getType().getName()) && + if (Exception.class.getName().equals(param.getType().getName()) && !source.startsWith("Exception", cursor) && !source.startsWith("java.lang.Exception", cursor)) { paramType = new J.Identifier(randomId(), paramPrefix, Markers.EMPTY, emptyList(), "", - JavaType.ShallowClass.build("java.lang.Exception"), null); + JavaType.ShallowClass.build(Exception.class.getName()), null); } else { paramType = visitTypeTree(param.getOriginType()).withPrefix(paramPrefix); } @@ -1106,7 +1089,7 @@ public void visitCatchStatement(CatchStatement node) { ); cursor += param.getName().length(); Space rightPad = whitespace(); - cursor += 1; // skip ) + skip(")"); JRightPadded variable = JRightPadded.build(new J.VariableDeclarations(randomId(), paramType.getPrefix(), Markers.EMPTY, emptyList(), emptyList(), paramType.withPrefix(EMPTY), null, emptyList(), @@ -1151,9 +1134,8 @@ private J.Case visitDefaultCaseStatement(BlockStatement statement) { Markers.EMPTY, J.Case.Type.Statement, null, - JContainer.build(singletonList(JRightPadded.build(new J.Identifier(randomId(), Space.EMPTY, Markers.EMPTY, emptyList(), skip("default"), null, null)))), - JContainer.build(sourceBefore(":"), - convertStatements(statement.getStatements()), Markers.EMPTY), + JContainer.build(singletonList(JRightPadded.build(new J.Identifier(randomId(), EMPTY, Markers.EMPTY, emptyList(), skip("default"), null, null)))), + JContainer.build(sourceBefore(":"), convertStatements(statement.getStatements()), Markers.EMPTY), null ); } @@ -1163,7 +1145,7 @@ public void visitCastExpression(CastExpression cast) { queue.add(insideParentheses(cast, prefix -> { // Might be looking at a Java-style cast "(type)object" or a groovy-style cast "object as type" if (source.charAt(cursor) == '(') { - cursor++; // skip '(' + skip("("); return new J.TypeCast(randomId(), prefix, Markers.EMPTY, new J.ControlParentheses<>(randomId(), EMPTY, Markers.EMPTY, new JRightPadded<>(visitTypeTree(cast.getType()), sourceBefore(")"), Markers.EMPTY) @@ -1254,7 +1236,7 @@ public void visitClosureListExpression(ClosureListExpression closureListExpressi for (int i = 0, expressionsSize = expressions.size(); i < expressionsSize; i++) { results.add(JRightPadded.build(visit(expressions.get(i))).withAfter(whitespace())); if (i < expressionsSize - 1) { - cursor++; // "," + cursor++; // "," or ";" (a for-loop uses a ClosureListExpression) } } queue.add(results); @@ -1278,27 +1260,27 @@ public void visitConstantExpression(ConstantExpression expression) { jType = JavaType.Primitive.Byte; } else if (type == ClassHelper.char_TYPE) { jType = JavaType.Primitive.Char; - } else if (type == ClassHelper.double_TYPE || "java.lang.Double".equals(type.getName())) { + } else if (type == ClassHelper.double_TYPE || Double.class.getName().equals(type.getName())) { jType = JavaType.Primitive.Double; if (expression.getNodeMetaData().get("_FLOATING_POINT_LITERAL_TEXT") instanceof String) { text = (String) expression.getNodeMetaData().get("_FLOATING_POINT_LITERAL_TEXT"); } - } else if (type == ClassHelper.float_TYPE || "java.lang.Float".equals(type.getName())) { + } else if (type == ClassHelper.float_TYPE || Float.class.getName().equals(type.getName())) { jType = JavaType.Primitive.Float; if (expression.getNodeMetaData().get("_FLOATING_POINT_LITERAL_TEXT") instanceof String) { text = (String) expression.getNodeMetaData().get("_FLOATING_POINT_LITERAL_TEXT"); } - } else if (type == ClassHelper.int_TYPE || "java.lang.Integer".equals(type.getName())) { + } else if (type == ClassHelper.int_TYPE || Integer.class.getName().equals(type.getName())) { jType = JavaType.Primitive.Int; if (expression.getNodeMetaData().get("_INTEGER_LITERAL_TEXT") instanceof String) { text = (String) expression.getNodeMetaData().get("_INTEGER_LITERAL_TEXT"); } - } else if (type == ClassHelper.long_TYPE || "java.lang.Long".equals(type.getName())) { + } else if (type == ClassHelper.long_TYPE || Long.class.getName().equals(type.getName())) { if (expression.getNodeMetaData().get("_INTEGER_LITERAL_TEXT") instanceof String) { text = (String) expression.getNodeMetaData().get("_INTEGER_LITERAL_TEXT"); } jType = JavaType.Primitive.Long; - } else if (type == ClassHelper.short_TYPE || "java.lang.Short".equals(type.getName())) { + } else if (type == ClassHelper.short_TYPE || Short.class.getName().equals(type.getName())) { jType = JavaType.Primitive.Short; } else if (type == ClassHelper.STRING_TYPE) { jType = JavaType.Primitive.String; @@ -1349,7 +1331,7 @@ public void visitConstantExpression(ConstantExpression expression) { @Override public void visitConstructorCallExpression(ConstructorCallExpression ctor) { queue.add(insideParentheses(ctor, fmt -> { - cursor += 3; // skip "new" + skip("new"); TypeTree clazz = visitTypeTree(ctor.getType(), ctor.getNodeMetaData().containsKey(StaticTypesMarker.INFERRED_TYPE)); JContainer args = visit(ctor.getArguments()); J.Block body = null; @@ -1388,7 +1370,6 @@ public void visitNotExpression(NotExpression expression) { @Override public void visitDeclarationExpression(DeclarationExpression expression) { Space prefix = whitespace(); - Optional redundantDef = maybeRedundantDef(expression.getVariableExpression().getType(), expression.getVariableExpression().getName()); Optional multiVariable = maybeMultiVariable(); List modifiers = getModifiers(); TypeTree typeExpr = visitVariableExpressionType(expression.getVariableExpression()); @@ -1427,9 +1408,6 @@ public void visitDeclarationExpression(DeclarationExpression expression) { emptyList(), singletonList(JRightPadded.build(namedVariable)) ); - if (redundantDef.isPresent()) { - variableDeclarations = variableDeclarations.withMarkers(variableDeclarations.getMarkers().add(redundantDef.get())); - } if (multiVariable.isPresent()) { variableDeclarations = variableDeclarations.withMarkers(variableDeclarations.getMarkers().add(multiVariable.get())); } @@ -1455,13 +1433,13 @@ private List getModifiers() { while (source.startsWith("def", cursor) || source.startsWith("var", cursor) || source.startsWith("final", cursor)) { if (source.startsWith("var", cursor)) { modifiers.add(new J.Modifier(randomId(), prefix, Markers.EMPTY, "var", J.Modifier.Type.LanguageExtension, emptyList())); - cursor += 3; + skip("var"); } else if (source.startsWith("def", cursor)) { modifiers.add(new J.Modifier(randomId(), prefix, Markers.EMPTY, "def", J.Modifier.Type.LanguageExtension, emptyList())); - cursor += 3; + skip("def"); } else if (source.startsWith("final", cursor)) { modifiers.add(new J.Modifier(randomId(), prefix, Markers.EMPTY, "final", J.Modifier.Type.LanguageExtension, emptyList())); - cursor += 5; + skip("final"); } else { break; } @@ -1514,7 +1492,7 @@ public void visitForLoop(ForStatement forLoop) { List> update = controls.get(2).getElement() instanceof List ? (List>) controls.get(2).getElement() : singletonList((JRightPadded) controls.get(2)); - cursor++; // skip ')' + skip(")"); return new J.ForLoop(randomId(), prefix, Markers.EMPTY, new J.ForLoop.Control(randomId(), controlFmt, @@ -1534,9 +1512,9 @@ public void visitForLoop(ForStatement forLoop) { Space rightPad = whitespace(); Markers forEachMarkers = Markers.EMPTY; if (source.charAt(cursor) == ':') { - cursor++; // Skip ":" + skip(":"); } else { - cursor += 2; // Skip "in" + skip("in"); forEachMarkers = forEachMarkers.add(new InStyleForEachLoop(randomId())); } @@ -1580,7 +1558,7 @@ public void visitGStringExpression(GStringExpression gstring) { } else { delimiter = "\""; } - cursor += delimiter.length(); + skip(delimiter); // Opening delim for GString NavigableMap sortedByPosition = new TreeMap<>(); for (org.codehaus.groovy.ast.expr.ConstantExpression e : gstring.getStrings()) { @@ -1598,14 +1576,14 @@ public void visitGStringExpression(GStringExpression gstring) { for (int i = 0; i < rawExprs.size(); i++) { org.codehaus.groovy.ast.expr.Expression e = rawExprs.get(i); if (source.charAt(cursor) == '$') { - cursor++; + skip("$"); boolean inCurlies = source.charAt(cursor) == '{'; if (inCurlies) { - cursor++; + skip("{"); } else { columnOffset--; } - strings.add(new G.GString.Value(randomId(), Markers.EMPTY, visit(e), inCurlies ? sourceBefore("}") : Space.EMPTY, inCurlies)); + strings.add(new G.GString.Value(randomId(), Markers.EMPTY, visit(e), inCurlies ? sourceBefore("}") : EMPTY, inCurlies)); if (!inCurlies) { columnOffset++; } @@ -1625,16 +1603,15 @@ public void visitGStringExpression(GStringExpression gstring) { } String value = source.substring(cursor, cursor + length); strings.add(new J.Literal(randomId(), EMPTY, Markers.EMPTY, value, value, null, JavaType.Primitive.String)); - cursor += value.length(); + skip(value); } else { // Everything should be handled already by the other two code paths, but just in case strings.add(visit(e)); } } - queue.add(new G.GString(randomId(), fmt, Markers.EMPTY, delimiter, strings, - typeMapping.type(gstring.getType()))); - cursor += delimiter.length(); + queue.add(new G.GString(randomId(), fmt, Markers.EMPTY, delimiter, strings,typeMapping.type(gstring.getType()))); + skip(delimiter); // Closing delim for GString } @Override @@ -1711,10 +1688,8 @@ public void visitMethodCallExpression(MethodCallExpression call) { Space prefix = whitespace(); if (methodNameExpression.equals(source.substring(cursor, cursor + methodNameExpression.length()))) { - cursor += methodNameExpression.length(); - name = new J.Identifier(randomId(), prefix, Markers.EMPTY, - emptyList(), methodNameExpression, null, null); - + skip(methodNameExpression); + name = new J.Identifier(randomId(), prefix, Markers.EMPTY, emptyList(), methodNameExpression, null, null); } else if (select != null && select.getElement() instanceof J.Identifier) { name = (J.Identifier) select.getElement(); select = null; @@ -1805,8 +1780,7 @@ public void visitMethodCallExpression(MethodCallExpression call) { } else { methodType = typeMapping.methodType(methodNode); } - return new J.MethodInvocation(randomId(), fmt, markers, - select, null, name, args, methodType); + return new J.MethodInvocation(randomId(), fmt, markers, select, null, name, args, methodType); })); } @@ -1849,8 +1823,7 @@ public void visitStaticMethodCallExpression(StaticMethodCallExpression call) { } JContainer args = visit(call.getArguments()); - queue.add(new J.MethodInvocation(randomId(), fmt, markers, - null, null, name, args, methodType)); + queue.add(new J.MethodInvocation(randomId(), fmt, markers, null, null, name, args, methodType)); } @Override @@ -1878,8 +1851,7 @@ public void visitAttributeExpression(AttributeExpression attr) { public void visitPropertyExpression(PropertyExpression prop) { queue.add(insideParentheses(prop, fmt -> { Expression target = visit(prop.getObjectExpression()); - Space beforeDot = prop.isSpreadSafe() ? sourceBefore("*.") : - sourceBefore(prop.isSafe() ? "?." : "."); + Space beforeDot = prop.isSpreadSafe() ? sourceBefore("*.") : sourceBefore(prop.isSafe() ? "?." : "."); J name = visit(prop.getProperty()); if (name instanceof J.Literal) { J.Literal nameLiteral = ((J.Literal) name); @@ -1938,7 +1910,7 @@ public void visitSwitch(SwitchStatement statement) { randomId(), sourceBefore("{"), Markers.EMPTY, JRightPadded.build(false), ListUtils.concat( - convertAll(statement.getCaseStatements(), t -> Space.EMPTY, t -> Space.EMPTY), + convertAll(statement.getCaseStatements(), t -> EMPTY, t -> EMPTY), statement.getDefaultStatement().isEmpty() ? null : JRightPadded.build(visitDefaultCaseStatement((BlockStatement) statement.getDefaultStatement())) ), sourceBefore("}")))); @@ -1978,7 +1950,7 @@ public void visitTupleExpression(TupleExpression tuple) { OmitParentheses omitParentheses = null; if (source.charAt(cursor) == '(') { - cursor++; + skip("("); } else { omitParentheses = new OmitParentheses(randomId()); beforeOpenParen = EMPTY; @@ -2071,7 +2043,7 @@ public void visitPostfixExpression(PostfixExpression unary) { public void visitPrefixExpression(PrefixExpression unary) { Space fmt = whitespace(); String typeToken = unary.getOperation().getText(); - cursor += typeToken.length(); + skip(typeToken); J.Unary.Type operator = null; switch (typeToken) { @@ -2100,7 +2072,7 @@ public TypeTree visitVariableExpressionType(VariableExpression expression) { if (!expression.isDynamicTyped() && source.startsWith(expression.getOriginType().getUnresolvedName(), cursor)) { typeName = expression.getOriginType().getUnresolvedName(); - cursor += typeName.length(); + skip(typeName); } J.Identifier ident = new J.Identifier(randomId(), EMPTY, @@ -2189,10 +2161,10 @@ private Markers handlesCaseWhereEmptyParensAheadOfClosure(ArgumentListExpression int saveCursor = cursor; Space argPrefix = whitespace(); if (source.charAt(cursor) == '(') { - cursor += 1; + skip("("); Space infix = whitespace(); if (source.charAt(cursor) == ')') { - cursor += 1; + skip(")"); markers = markers.add(new EmptyArgumentListPrecedesArgument(randomId(), argPrefix, infix)); } else { cursor = saveCursor; @@ -2324,12 +2296,19 @@ private int positionOfNext(String untilDelim) { return delimIndex > source.length() - untilDelim.length() ? -1 : delimIndex; } + /** + * Get all whitespace characters of the source file between the cursor and the first non-whitespace character. + * The cursor will be moved before first non-whitespace character. + */ private Space whitespace() { String prefix = source.substring(cursor, indexOfNextNonWhitespace(cursor, source)); cursor += prefix.length(); return format(prefix); } + /** + * Move the cursor after the token. + */ private String skip(@Nullable String token) { if (token == null) { //noinspection ConstantConditions @@ -2366,12 +2345,12 @@ private T typeTree(@Nullable ClassNode classNo fullName += "." + part; Matcher whitespacePrefix = whitespacePrefixPattern.matcher(part); - Space identFmt = whitespacePrefix.matches() ? format(whitespacePrefix.group(0)) : Space.EMPTY; + Space identFmt = whitespacePrefix.matches() ? format(whitespacePrefix.group(0)) : EMPTY; Matcher whitespaceSuffix = whitespaceSuffixPattern.matcher(part); //noinspection ResultOfMethodCallIgnored whitespaceSuffix.matches(); - Space namePrefix = i == parts.length - 1 ? Space.EMPTY : format(whitespaceSuffix.group(1)); + Space namePrefix = i == parts.length - 1 ? EMPTY : format(whitespaceSuffix.group(1)); expr = new J.FieldAccess( randomId(), @@ -2565,17 +2544,6 @@ private TypeTree visitTypeTree(ClassNode classNode, boolean inferredType) { if (primitiveType != null) { return new J.Primitive(randomId(), sourceBefore(classNode.getUnresolvedName()), Markers.EMPTY, primitiveType); } - - int saveCursor = cursor; - Space fmt = whitespace(); - if (cursor < source.length() && source.startsWith("def", cursor)) { - cursor += 3; - return new J.Identifier(randomId(), fmt, Markers.EMPTY, emptyList(), "def", - JavaType.ShallowClass.build("java.lang.Object"), null); - } else { - cursor = saveCursor; - } - return typeTree(classNode, inferredType); } @@ -2695,7 +2663,7 @@ private JContainer visitTypeParameterizations(GenericsType @Nullable Space suffix = whitespace(); parameters.add(JRightPadded.build(param).withAfter(suffix)); if (source.charAt(cursor) == '>') { - cursor++; + skip(">"); break; } cursor++; @@ -2706,15 +2674,10 @@ private JContainer visitTypeParameterizations(GenericsType @Nullable parameters = new ArrayList<>(genericsTypes.length); for (int i = 0; i < genericsTypes.length; i++) { parameters.add(JRightPadded.build(visitTypeParameterization(genericsTypes[i])) - .withAfter( - i < genericsTypes.length - 1 ? - sourceBefore(",") : - sourceBefore(">") - )); + .withAfter(i < genericsTypes.length - 1 ? sourceBefore(",") : sourceBefore(">"))); } } - return JContainer.build(prefix, parameters, Markers.EMPTY); } @@ -2722,10 +2685,19 @@ private Expression visitTypeParameterization(GenericsType genericsType) { int saveCursor = cursor; Space prefix = whitespace(); if (source.charAt(cursor) == '?') { - cursor = saveCursor; - return visitWildcard(genericsType); + skip("?"); + JLeftPadded bound = null; + NameTree boundedType = null; + if (genericsType.getUpperBounds() != null) { + bound = padLeft(sourceBefore("extends"), J.Wildcard.Bound.Extends); + boundedType = visitTypeTree(genericsType.getUpperBounds()[0]); + } else if (genericsType.getLowerBound() != null) { + bound = padLeft(sourceBefore("super"), J.Wildcard.Bound.Super); + boundedType = visitTypeTree(genericsType.getLowerBound()); + } + return new J.Wildcard(randomId(), prefix, Markers.EMPTY, bound, boundedType); } else if (source.charAt(cursor) == '>') { - cursor++; + skip(">"); return new J.Empty(randomId(), prefix, Markers.EMPTY); } cursor = saveCursor; @@ -2741,19 +2713,14 @@ private JContainer visitTypeParameters(GenericsType[] genericsT List> typeParameters = new ArrayList<>(genericsTypes.length); for (int i = 0; i < genericsTypes.length; i++) { typeParameters.add(JRightPadded.build(visitTypeParameter(genericsTypes[i])) - .withAfter( - i < genericsTypes.length - 1 ? - sourceBefore(",") : - sourceBefore(">") - )); + .withAfter(i < genericsTypes.length - 1 ? sourceBefore(",") : sourceBefore(">"))); } return JContainer.build(prefix, typeParameters, Markers.EMPTY); } private J.TypeParameter visitTypeParameter(GenericsType genericType) { Space prefix = whitespace(); - Expression name = typeTree(null) - .withType(typeMapping.type(genericType)); + Expression name = typeTree(null).withType(typeMapping.type(genericType)); JContainer bounds = null; if (genericType.getUpperBounds() != null) { Space boundsPrefix = sourceBefore("extends"); @@ -2761,11 +2728,7 @@ private J.TypeParameter visitTypeParameter(GenericsType genericType) { List> convertedBounds = new ArrayList<>(upperBounds.length); for (int i = 0; i < upperBounds.length; i++) { convertedBounds.add(JRightPadded.build(visitTypeTree(upperBounds[i])) - .withAfter( - i < upperBounds.length - 1 ? - sourceBefore("&") : - EMPTY - )); + .withAfter(i < upperBounds.length - 1 ? sourceBefore("&") : EMPTY)); } bounds = JContainer.build(boundsPrefix, convertedBounds, Markers.EMPTY); } else if (genericType.getLowerBound() != null) { @@ -2779,25 +2742,6 @@ private J.TypeParameter visitTypeParameter(GenericsType genericType) { return new J.TypeParameter(randomId(), prefix, Markers.EMPTY, emptyList(), emptyList(), name, bounds); } - private J.Wildcard visitWildcard(GenericsType genericType) { - Space namePrefix = sourceBefore("?"); - - JLeftPadded bound; - NameTree boundedType; - if (genericType.getUpperBounds() != null) { - bound = padLeft(sourceBefore("extends"), J.Wildcard.Bound.Extends); - boundedType = visitTypeTree(genericType.getUpperBounds()[0]); - } else if (genericType.getLowerBound() != null) { - bound = padLeft(sourceBefore("super"), J.Wildcard.Bound.Super); - boundedType = visitTypeTree(genericType.getLowerBound()); - } else { - bound = null; - boundedType = null; - } - - return new J.Wildcard(randomId(), namePrefix, Markers.EMPTY, bound, boundedType); - } - /** * Sometimes the groovy compiler inserts phantom elements into argument lists and class bodies, * presumably to pass type information around. These elements do not appear in source code and should not diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java index c3991346c24..6399b556685 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java @@ -228,6 +228,20 @@ class Inner { ); } + @Issue("https://github.com/openrewrite/rewrite/issues/4705") + @Test + void constructorWithDef() { + rewriteRun( + groovy( + """ + class A { + def A() {} + } + """ + ) + ); + } + @Test void newParameterizedConstructor() { rewriteRun( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java index 3129c933afa..f55d8b5c133 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/MethodDeclarationTest.java @@ -201,7 +201,7 @@ void functionWithDefAndExplicitReturnType() { """ class A { def /*int*/ int one() { 1 } - def /*Object*/ Object two() { 2 } + @Foo def /*Object*/ Object two() { 2 } } """ ) From 8a9a44939f0cbf45f53da33bee5de0c7e7dd71e1 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Fri, 3 Jan 2025 19:27:42 +0100 Subject: [PATCH 100/179] Fix parsing string literal with line breaks and spaces (#4843) * Fix parsing of string literals with linebreaks and spaces * Use `getDelimiter` for GStringExpression * Improve stringLiteralInParentheses test * Remove temporary moreParenthesesStuff test * Revert escapeCharacters test * Remove `lengthAccordingToAst`, use same trick for ConstantExpression in GString * Fix typo --- .../groovy/GroovyParserVisitor.java | 126 ++++++------------ .../groovy/tree/AssignmentTest.java | 2 +- .../openrewrite/groovy/tree/LiteralTest.java | 26 +++- 3 files changed, 68 insertions(+), 86 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 2735ff269e6..c745fbffdc7 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -34,7 +34,6 @@ import org.openrewrite.groovy.tree.G; import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; -import org.openrewrite.internal.StringUtils; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.ImplicitReturn; import org.openrewrite.java.marker.OmitParentheses; @@ -1284,22 +1283,18 @@ public void visitConstantExpression(ConstantExpression expression) { jType = JavaType.Primitive.Short; } else if (type == ClassHelper.STRING_TYPE) { jType = JavaType.Primitive.String; - // this is an attribute selector - boolean attributeSelector = source.startsWith("@" + value, cursor); - int length = lengthAccordingToAst(expression); - Integer insideParenthesesLevel = getInsideParenthesesLevel(expression); - if (insideParenthesesLevel != null) { - length = length - insideParenthesesLevel * 2; - } - String valueAccordingToAST = source.substring(cursor, cursor + length + (attributeSelector ? 1 : 0)); - int delimiterLength = getDelimiterLength(); - if (StringUtils.containsWhitespace(valueAccordingToAST)) { - length = delimiterLength + expression.getValue().toString().length() + delimiterLength; - text = source.substring(cursor, cursor + length + (attributeSelector ? 1 : 0)); + // an attribute selector is modeled as a String ConstantExpression + if (source.startsWith("@" + value, cursor)) { + value = "@" + value; + text = "@" + text; } else { - text = valueAccordingToAST; + String delimiter = getDelimiter(); + if (delimiter != null) { + // Get the string literal from the source, so escaping of newlines and the like works out of the box + value = sourceSubstring(cursor + delimiter.length(), delimiter); + text = delimiter + value + delimiter; + } } - value = text.substring(delimiterLength, text.length() - delimiterLength); } else if (expression.isNullExpression()) { if (source.startsWith("null", cursor)) { text = "null"; @@ -1548,16 +1543,7 @@ public void visitIfElse(IfStatement ifElse) { @Override public void visitGStringExpression(GStringExpression gstring) { Space fmt = whitespace(); - String delimiter; - if (source.startsWith("\"\"\"", cursor)) { - delimiter = "\"\"\""; - } else if (source.startsWith("/", cursor)) { - delimiter = "/"; - } else if (source.startsWith("$/", cursor)) { - delimiter = "$/"; - } else { - delimiter = "\""; - } + String delimiter = getDelimiter(); skip(delimiter); // Opening delim for GString NavigableMap sortedByPosition = new TreeMap<>(); @@ -1588,20 +1574,13 @@ public void visitGStringExpression(GStringExpression gstring) { columnOffset++; } } else if (e instanceof ConstantExpression) { - ConstantExpression cs = (ConstantExpression) e; - // The sub-strings within a GString have no delimiters of their own, confusing visitConstantExpression() - // ConstantExpression.getValue() cannot be trusted for strings as its values don't match source code because sequences like "\\" have already been replaced with a single "\" - // Use the AST element's line/column positions to figure out its extent, but those numbers need tweaks to be correct - int length = lengthAccordingToAst(cs); - if (i == 0 || i == rawExprs.size() - 1) { - // The first and last constants within a GString have line/column position which incorrectly include the GString's delimiters - length -= delimiter.length(); - } - // The line/column numbers incorrectly indicate that the following expression's opening "$" is part of this expression - if (i < rawExprs.size() - 1) { - length--; + // Get the string literal from the source, so escaping of newlines and the like works out of the box + String value = sourceSubstring(cursor, delimiter); + // There could be a closer GString before the end of the closing delimiter, so shorten the string if needs be + int indexNextSign = source.indexOf("$", cursor); + if (indexNextSign != -1 && indexNextSign < (cursor + value.length())) { + value = source.substring(cursor, indexNextSign); } - String value = source.substring(cursor, cursor + length); strings.add(new J.Literal(randomId(), EMPTY, Markers.EMPTY, value, value, null, JavaType.Primitive.String)); skip(value); } else { @@ -2435,6 +2414,19 @@ private Space sourceBefore(String untilDelim) { return space; } + /** + * Returns a string that is a part of this source. The substring begins at the specified beginIndex and extends until delimiter. + * The cursor will not be moved. + */ + private String sourceSubstring(int beginIndex, String untilDelim) { + int endIndex = source.indexOf(untilDelim, cursor + untilDelim.length()); + // don't stop if last char is escaped. + while (source.charAt(endIndex - 1) == '\\') { + endIndex = source.indexOf(untilDelim, endIndex + 1); + } + return source.substring(beginIndex, endIndex); + } + private @Nullable Integer getInsideParenthesesLevel(ASTNode node) { Object rawIpl = node.getNodeMetaData("_INSIDE_PARENTHESES_LEVEL"); if (rawIpl instanceof AtomicInteger) { @@ -2485,54 +2477,22 @@ private int determineParenthesisLevel(int childLineNumber, int parentLineNumber, return Math.max(count, 0); } - private int getDelimiterLength() { + private @Nullable String getDelimiter() { String maybeDelimiter = source.substring(cursor, Math.min(cursor + 3, source.length())); - int delimiterLength = 0; if (maybeDelimiter.startsWith("$/")) { - delimiterLength = 2; - } else if (maybeDelimiter.startsWith("\"\"\"") || maybeDelimiter.startsWith("'''")) { - delimiterLength = 3; - } else if (maybeDelimiter.startsWith("/") || maybeDelimiter.startsWith("\"") || maybeDelimiter.startsWith("'")) { - delimiterLength = 1; - } - return delimiterLength; - } - - /** - * Gets the length according to the Groovy compiler's attestation of starting/ending line and column numbers. - * On older versions of the JDK/Groovy compiler string literals with following whitespace sometimes erroneously include - * the length of the whitespace in the length of the AST node. - * So in this method invocation: - * foo( 'a' ) - * the correct source length for the AST node representing 'a' is 3, but in affected groovy versions the length - * on the node is '4' because it is also counting the trailing whitespace. - */ - private int lengthAccordingToAst(ConstantExpression node) { - if (!appearsInSource(node)) { - return 0; - } - int lineCount = node.getLastLineNumber() - node.getLineNumber(); - if (lineCount == 0) { - return node.getLastColumnNumber() - node.getColumnNumber() + columnOffset; - } - int linesSoFar = 0; - int length = 0; - int finalLineChars = 0; - while (true) { - char c = source.charAt(cursor + length); - if (c == '\n') { - linesSoFar++; - } - if (linesSoFar == lineCount) { - finalLineChars++; - } - - length++; - - if (finalLineChars == node.getLastColumnNumber() + columnOffset) { - return length; - } + return "$/"; + } else if (maybeDelimiter.startsWith("\"\"\"")) { + return "\"\"\""; + } else if (maybeDelimiter.startsWith("'''")) { + return "'''"; + } else if (maybeDelimiter.startsWith("/")) { + return "/"; + } else if (maybeDelimiter.startsWith("\"")) { + return "\""; + } else if (maybeDelimiter.startsWith("'")) { + return "'"; } + return null; } private TypeTree visitTypeTree(ClassNode classNode) { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java index 3ccac493084..1d04f9bd706 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AssignmentTest.java @@ -156,7 +156,7 @@ void multipleAssignmentsAtOneLine() { """ def startItem = '| ', endItem = ' |' def repeatLength = startItem.length() + output.length() + endItem.length() - println("\\n" + ("-" * repeatLength) + "\\n" + startItem + output + endItem + "\\n" + ("-" * repeatLength)) + println("\\n" + ("-" * repeatLength) + "\\n| " + startItem + output + endItem + " |\\n" + ("-" * repeatLength)) """ ) ); diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java index 12d638870d4..0bc2ac3535d 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/LiteralTest.java @@ -84,6 +84,17 @@ void slashString() { ); } + @Test + void escapedString() { + rewriteRun( + groovy( + """ + "f\\"o\\\\\\"o" + """ + ) + ); + } + @Test void gString() { rewriteRun( @@ -169,6 +180,17 @@ void gStringWithSpace() { ); } + @Test + void gStringWithEscapedDelimiter() { + rewriteRun( + groovy( + """ + String s = "${displayName}" + """ + ) + ); + } + @Test void mapLiteral() { rewriteRun( @@ -259,7 +281,7 @@ void escapeCharacters() { rewriteRun( groovy( """ - "\\\\n\\t" + "\\\\\\\\n\\\\t" '\\\\n\\t' ///\\\\n\\t/// """ @@ -284,7 +306,7 @@ void stringLiteralInParentheses() { rewriteRun( groovy( """ - def a = ("-") + def a = ( "-" ) """ ), groovy( From 02411bd6e386f793b8c8af2c49f2154b528f6144 Mon Sep 17 00:00:00 2001 From: Shannon Pamperl Date: Fri, 3 Jan 2025 14:49:33 -0600 Subject: [PATCH 101/179] Add TOML language parser (#4845) * Add TOML language parser * Polish and address bot review comments * Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserVisitor.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: Tim te Beek Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- rewrite-toml/build.gradle.kts | 25 + rewrite-toml/src/main/antlr/TomlLexer.g4 | 149 ++ rewrite-toml/src/main/antlr/TomlParser.g4 | 137 ++ .../java/org/openrewrite/toml/Assertions.java | 52 + .../org/openrewrite/toml/TomlIsoVisitor.java | 46 + .../java/org/openrewrite/toml/TomlParser.java | 117 + .../toml/TomlParsingException.java | 31 + .../org/openrewrite/toml/TomlVisitor.java | 119 ++ .../toml/internal/TomlParserVisitor.java | 517 +++++ .../toml/internal/TomlPrinter.java | 157 ++ .../toml/internal/grammar/TomlLexer.interp | 176 ++ .../toml/internal/grammar/TomlLexer.java | 585 +++++ .../toml/internal/grammar/TomlLexer.tokens | 41 + .../toml/internal/grammar/TomlParser.interp | 96 + .../toml/internal/grammar/TomlParser.java | 1886 +++++++++++++++++ .../toml/internal/grammar/TomlParser.tokens | 41 + .../grammar/TomlParserBaseListener.java | 307 +++ .../grammar/TomlParserBaseVisitor.java | 177 ++ .../internal/grammar/TomlParserListener.java | 235 ++ .../internal/grammar/TomlParserVisitor.java | 154 ++ .../toml/internal/package-info.java | 21 + .../openrewrite/toml/marker/ArrayTable.java | 28 + .../openrewrite/toml/marker/InlineTable.java | 28 + .../openrewrite/toml/marker/package-info.java | 21 + .../org/openrewrite/toml/package-info.java | 21 + .../org/openrewrite/toml/tree/Comment.java | 28 + .../java/org/openrewrite/toml/tree/Space.java | 270 +++ .../java/org/openrewrite/toml/tree/Toml.java | 358 ++++ .../org/openrewrite/toml/tree/TomlKey.java | 19 + .../toml/tree/TomlRightPadded.java | 117 + .../org/openrewrite/toml/tree/TomlType.java | 29 + .../org/openrewrite/toml/tree/TomlValue.java | 19 + .../openrewrite/toml/tree/package-info.java | 21 + .../org/openrewrite/toml/TomlParserTest.java | 341 +++ settings.gradle.kts | 1 + 35 files changed, 6370 insertions(+) create mode 100644 rewrite-toml/build.gradle.kts create mode 100644 rewrite-toml/src/main/antlr/TomlLexer.g4 create mode 100644 rewrite-toml/src/main/antlr/TomlParser.g4 create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/Assertions.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/TomlIsoVisitor.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/TomlParser.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/TomlParsingException.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/TomlVisitor.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlParserVisitor.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlPrinter.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.interp create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.tokens create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.interp create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.tokens create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserBaseListener.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserBaseVisitor.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserListener.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserVisitor.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/internal/package-info.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/marker/ArrayTable.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/marker/InlineTable.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/marker/package-info.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/package-info.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/tree/Comment.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/tree/Space.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/tree/Toml.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlKey.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlRightPadded.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlType.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlValue.java create mode 100644 rewrite-toml/src/main/java/org/openrewrite/toml/tree/package-info.java create mode 100644 rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java diff --git a/rewrite-toml/build.gradle.kts b/rewrite-toml/build.gradle.kts new file mode 100644 index 00000000000..13534f609c6 --- /dev/null +++ b/rewrite-toml/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + id("org.openrewrite.build.language-library") +} + +tasks.register("generateAntlrSources") { + mainClass.set("org.antlr.v4.Tool") + + args = listOf( + "-o", "src/main/java/org/openrewrite/toml/internal/grammar", + "-package", "org.openrewrite.toml.internal.grammar", + "-visitor" + ) + fileTree("src/main/antlr").matching { include("**/*.g4") }.map { it.path } + + classpath = sourceSets["main"].runtimeClasspath +} + +dependencies { + implementation(project(":rewrite-core")) + implementation("org.antlr:antlr4-runtime:4.11.1") + implementation("io.micrometer:micrometer-core:1.9.+") + + compileOnly(project(":rewrite-test")) + + testImplementation(project(":rewrite-test")) +} diff --git a/rewrite-toml/src/main/antlr/TomlLexer.g4 b/rewrite-toml/src/main/antlr/TomlLexer.g4 new file mode 100644 index 00000000000..2c698f64e75 --- /dev/null +++ b/rewrite-toml/src/main/antlr/TomlLexer.g4 @@ -0,0 +1,149 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +// $antlr-format alignTrailingComments true, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments false, useTab false +// $antlr-format allowShortRulesOnASingleLine true, allowShortBlocksOnASingleLine true, minEmptyLines 0, alignSemicolons ownLine +// $antlr-format alignColons trailing, singleLineOverrulesHangingColon true, alignLexerCommands true, alignLabels true, alignTrailers true + +lexer grammar TomlLexer; + +WS : [ \t]+ -> skip; +NL : ('\r'? '\n')+; +COMMENT : '#' (~[\r\n])*; +L_BRACKET : '['; +DOUBLE_L_BRACKET : '[['; +R_BRACKET : ']'; +DOUBLE_R_BRACKET : ']]'; +EQUALS : '=' -> pushMode(SIMPLE_VALUE_MODE); +DOT : '.'; +COMMA : ',' -> skip; + +fragment DIGIT : [0-9]; +fragment ALPHA : [A-Za-z]; + +// strings +fragment ESC : '\\' (["\\/bfnrt] | UNICODE | EX_UNICODE); +fragment UNICODE : 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT; +fragment EX_UNICODE: + 'U' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT +; +BASIC_STRING : '"' (ESC | ~["\\\n])*? '"'; +LITERAL_STRING : '\'' (~['\n])*? '\''; + +// keys +UNQUOTED_KEY: (ALPHA | DIGIT | '-' | '_')+; + +mode SIMPLE_VALUE_MODE; + +VALUE_WS: WS -> skip; + +L_BRACE : '{' -> mode(INLINE_TABLE_MODE); +ARRAY_START : L_BRACKET -> type(L_BRACKET), mode(ARRAY_MODE); + +// booleans +BOOLEAN: ('true' | 'false') -> popMode; + +// strings +fragment ML_ESC : '\\' '\r'? '\n' | ESC; +VALUE_BASIC_STRING : BASIC_STRING -> type(BASIC_STRING), popMode; +ML_BASIC_STRING : '"""' (ML_ESC | ~["\\])*? '"""' -> popMode; +VALUE_LITERAL_STRING : LITERAL_STRING -> type(LITERAL_STRING), popMode; +ML_LITERAL_STRING : '\'\'\'' (.)*? '\'\'\'' -> popMode; + +// floating point numbers +fragment EXP : ('e' | 'E') [+-]? ZERO_PREFIXABLE_INT; +fragment ZERO_PREFIXABLE_INT : DIGIT (DIGIT | '_' DIGIT)*; +fragment FRAC : '.' ZERO_PREFIXABLE_INT; +FLOAT : DEC_INT ( EXP | FRAC EXP?) -> popMode; +INF : [+-]? 'inf' -> popMode; +NAN : [+-]? 'nan' -> popMode; + +// integers +fragment HEX_DIGIT : [A-Fa-f] | DIGIT; +fragment DIGIT_1_9 : [1-9]; +fragment DIGIT_0_7 : [0-7]; +fragment DIGIT_0_1 : [0-1]; +DEC_INT : [+-]? (DIGIT | (DIGIT_1_9 (DIGIT | '_' DIGIT)+)) -> popMode; +HEX_INT : '0x' HEX_DIGIT (HEX_DIGIT | '_' HEX_DIGIT)* -> popMode; +OCT_INT : '0o' DIGIT_0_7 (DIGIT_0_7 | '_' DIGIT_0_7)* -> popMode; +BIN_INT : '0b' DIGIT_0_1 (DIGIT_0_1 | '_' DIGIT_0_1)* -> popMode; + +// dates +fragment YEAR : DIGIT DIGIT DIGIT DIGIT; +fragment MONTH : DIGIT DIGIT; +fragment DAY : DIGIT DIGIT; +fragment DELIM : 'T' | 't' | ' '; +fragment HOUR : DIGIT DIGIT; +fragment MINUTE : DIGIT DIGIT; +fragment SECOND : DIGIT DIGIT; +fragment SECFRAC : '.' DIGIT+; +fragment NUMOFFSET : ('+' | '-') HOUR ':' MINUTE; +fragment OFFSET : 'Z' | NUMOFFSET; +fragment PARTIAL_TIME : HOUR ':' MINUTE ':' SECOND SECFRAC?; +fragment FULL_DATE : YEAR '-' MONTH '-' DAY; +fragment FULL_TIME : PARTIAL_TIME OFFSET; +OFFSET_DATE_TIME : FULL_DATE DELIM FULL_TIME -> popMode; +LOCAL_DATE_TIME : FULL_DATE DELIM PARTIAL_TIME -> popMode; +LOCAL_DATE : FULL_DATE -> popMode; +LOCAL_TIME : PARTIAL_TIME -> popMode; + +mode INLINE_TABLE_MODE; + +INLINE_TABLE_WS : WS -> skip; +INLINE_TABLE_KEY_DOT : DOT -> type(DOT); +INLINE_TABLE_COMMA : COMMA -> type(COMMA); +R_BRACE : '}' -> popMode; + +INLINE_TABLE_KEY_BASIC_STRING : BASIC_STRING -> type(BASIC_STRING); +INLINE_TABLE_KEY_LITERAL_STRING : LITERAL_STRING -> type(LITERAL_STRING); +INLINE_TABLE_KEY_UNQUOTED : UNQUOTED_KEY -> type(UNQUOTED_KEY); + +INLINE_TABLE_EQUALS: EQUALS -> type(EQUALS), pushMode(SIMPLE_VALUE_MODE); + +mode ARRAY_MODE; + +ARRAY_WS : WS -> skip; +ARRAY_NL : NL -> type(NL); +ARRAY_COMMENT : COMMENT -> type(COMMENT); +ARRAY_COMMA : COMMA -> type(COMMA); + +ARRAY_INLINE_TABLE_START : L_BRACE -> type(L_BRACE), pushMode(INLINE_TABLE_MODE); +NESTED_ARRAY_START : L_BRACKET -> type(L_BRACKET), pushMode(ARRAY_MODE); +ARRAY_END : R_BRACKET -> type(R_BRACKET), popMode; + +ARRAY_BOOLEAN: BOOLEAN -> type(BOOLEAN); + +ARRAY_BASIC_STRING : BASIC_STRING -> type(BASIC_STRING); +ARRAY_ML_BASIC_STRING : ML_BASIC_STRING -> type(ML_BASIC_STRING); +ARRAY_LITERAL_STRING : LITERAL_STRING -> type(LITERAL_STRING); +ARRAY_ML_LITERAL_STRING : ML_LITERAL_STRING -> type(ML_LITERAL_STRING); + +ARRAY_FLOAT : FLOAT -> type(FLOAT); +ARRAY_INF : INF -> type(INF); +ARRAY_NAN : NAN -> type(NAN); + +ARRAY_DEC_INT : DEC_INT -> type(DEC_INT); +ARRAY_HEX_INT : HEX_INT -> type(HEX_INT); +ARRAY_OCT_INT : OCT_INT -> type(OCT_INT); +ARRAY_BIN_INT : BIN_INT -> type(BIN_INT); + +ARRAY_OFFSET_DATE_TIME : OFFSET_DATE_TIME -> type(OFFSET_DATE_TIME); +ARRAY_LOCAL_DATE_TIME : LOCAL_DATE_TIME -> type(LOCAL_DATE_TIME); +ARRAY_LOCAL_DATE : LOCAL_DATE -> type(LOCAL_DATE); +ARRAY_LOCAL_TIME : LOCAL_TIME -> type(LOCAL_TIME); diff --git a/rewrite-toml/src/main/antlr/TomlParser.g4 b/rewrite-toml/src/main/antlr/TomlParser.g4 new file mode 100644 index 00000000000..46e51369ef8 --- /dev/null +++ b/rewrite-toml/src/main/antlr/TomlParser.g4 @@ -0,0 +1,137 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false +// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging + +parser grammar TomlParser; + +options { + tokenVocab = TomlLexer; +} + +document + : expression? (NL expression?)* EOF + ; + +expression + : keyValue comment? + | table comment? + | comment + ; + +comment + : COMMENT + ; + +keyValue + : key EQUALS value + ; + +key + : simpleKey + | dottedKey + ; + +simpleKey + : quotedKey + | unquotedKey + ; + +unquotedKey + : UNQUOTED_KEY + ; + +quotedKey + : BASIC_STRING + | LITERAL_STRING + ; + +dottedKey + : simpleKey (DOT simpleKey)+ + ; + +value + : string + | integer + | floatingPoint + | bool + | dateTime + | array + | inlineTable + ; + +string + : BASIC_STRING + | ML_BASIC_STRING + | LITERAL_STRING + | ML_LITERAL_STRING + ; + +integer + : DEC_INT + | HEX_INT + | OCT_INT + | BIN_INT + ; + +floatingPoint + : FLOAT + | INF + | NAN + ; + +bool + : BOOLEAN + ; + +dateTime + : OFFSET_DATE_TIME + | LOCAL_DATE_TIME + | LOCAL_DATE + | LOCAL_TIME + ; + +commentOrNl + : COMMENT NL + | NL + ; + +array + : L_BRACKET commentOrNl* R_BRACKET + | L_BRACKET commentOrNl* value (COMMA commentOrNl* value COMMA?)* commentOrNl* R_BRACKET + ; + +table + : standardTable + | arrayTable + ; + +standardTable + : L_BRACKET key R_BRACKET (commentOrNl* expression)* + ; + +inlineTable + : L_BRACE commentOrNl* R_BRACE + | L_BRACE commentOrNl* keyValue (COMMA commentOrNl* keyValue COMMA?)* commentOrNl* R_BRACE + ; + +arrayTable + : DOUBLE_L_BRACKET key DOUBLE_R_BRACKET (commentOrNl* expression)* + ; diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/Assertions.java b/rewrite-toml/src/main/java/org/openrewrite/toml/Assertions.java new file mode 100644 index 00000000000..85de7b6d79c --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/Assertions.java @@ -0,0 +1,52 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml; + +import org.intellij.lang.annotations.Language; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.test.SourceSpec; +import org.openrewrite.test.SourceSpecs; +import org.openrewrite.toml.tree.Toml; + +import java.util.function.Consumer; + +public class Assertions { + private Assertions() { + } + + public static SourceSpecs toml(@Language("toml") @Nullable String before) { + return Assertions.toml(before, s -> { + }); + } + + public static SourceSpecs toml(@Language("toml") @Nullable String before, Consumer> spec) { + SourceSpec toml = new SourceSpec<>(Toml.Document.class, null, TomlParser.builder(), before, null); + spec.accept(toml); + return toml; + } + + public static SourceSpecs toml(@Language("toml") @Nullable String before, @Language("toml") @Nullable String after) { + return toml(before, after, s -> { + }); + } + + public static SourceSpecs toml(@Language("toml") @Nullable String before, @Language("toml") @Nullable String after, + Consumer> spec) { + SourceSpec toml = new SourceSpec<>(Toml.Document.class, null, TomlParser.builder(), before, s -> after); + spec.accept(toml); + return toml; + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/TomlIsoVisitor.java b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlIsoVisitor.java new file mode 100644 index 00000000000..fff819fd1af --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlIsoVisitor.java @@ -0,0 +1,46 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml; + +import org.openrewrite.toml.tree.Toml; + +public class TomlIsoVisitor

extends TomlVisitor

{ + + @Override + public Toml.Array visitArray(Toml.Array array, P p) { + return (Toml.Array) super.visitArray(array, p); + } + + @Override + public Toml.Document visitDocument(Toml.Document document, P p) { + return (Toml.Document) super.visitDocument(document, p); + } + + @Override + public Toml.Identifier visitIdentifier(Toml.Identifier identifier, P p) { + return (Toml.Identifier) super.visitIdentifier(identifier, p); + } + + @Override + public Toml.KeyValue visitKeyValue(Toml.KeyValue keyValue, P p) { + return (Toml.KeyValue) super.visitKeyValue(keyValue, p); + } + + @Override + public Toml.Literal visitLiteral(Toml.Literal literal, P p) { + return (Toml.Literal) super.visitLiteral(literal, p); + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/TomlParser.java b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlParser.java new file mode 100644 index 00000000000..37b2ac6f826 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlParser.java @@ -0,0 +1,117 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml; + +import org.antlr.v4.runtime.*; +import org.intellij.lang.annotations.Language; +import org.openrewrite.ExecutionContext; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.Parser; +import org.openrewrite.SourceFile; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.toml.internal.TomlParserVisitor; +import org.openrewrite.toml.internal.grammar.TomlLexer; +import org.openrewrite.toml.tree.Toml; +import org.openrewrite.tree.ParseError; +import org.openrewrite.tree.ParsingEventListener; +import org.openrewrite.tree.ParsingExecutionContextView; + +import java.io.InputStream; +import java.nio.file.Path; +import java.util.stream.Stream; + +public class TomlParser implements Parser { + @Override + public Stream parseInputs(Iterable sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); + return acceptedInputs(sourceFiles).map(input -> { + parsingListener.startedParsing(input); + try (InputStream sourceStream = input.getSource(ctx)) { + TomlLexer lexer = new TomlLexer(CharStreams.fromStream(sourceStream)); + lexer.removeErrorListeners(); + lexer.addErrorListener(new ForwardingErrorListener(input.getPath(), ctx)); + + org.openrewrite.toml.internal.grammar.TomlParser parser = new org.openrewrite.toml.internal.grammar.TomlParser(new CommonTokenStream(lexer)); + parser.removeErrorListeners(); + parser.addErrorListener(new ForwardingErrorListener(input.getPath(), ctx)); + + Toml.Document document = new TomlParserVisitor( + input.getRelativePath(relativeTo), + input.getFileAttributes(), + input.getSource(ctx) + ).visitDocument(parser.document()); + parsingListener.parsed(input, document); + return requirePrintEqualsInput(document, input, relativeTo, ctx); + } catch (Throwable t) { + ctx.getOnError().accept(t); + return ParseError.build(this, input, relativeTo, ctx, t); + } + }); + } + + @Override + public Stream parse(@Language("toml") String... sources) { + return parse(new InMemoryExecutionContext(), sources); + } + + @Override + public boolean accept(Path path) { + return path.toString().endsWith(".toml"); + } + + @Override + public Path sourcePathFromSourceText(Path prefix, String sourceCode) { + return prefix.resolve("file.toml"); + } + + private static class ForwardingErrorListener extends BaseErrorListener { + private final Path sourcePath; + private final ExecutionContext ctx; + + private ForwardingErrorListener(Path sourcePath, ExecutionContext ctx) { + this.sourcePath = sourcePath; + this.ctx = ctx; + } + + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, + int line, int charPositionInLine, String msg, RecognitionException e) { + ctx.getOnError().accept(new TomlParsingException(sourcePath, + String.format("Syntax error in %s at line %d:%d %s.", sourcePath, line, charPositionInLine, msg), e)); + } + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends Parser.Builder { + + public Builder() { + super(Toml.Document.class); + } + + @Override + public TomlParser build() { + return new TomlParser(); + } + + @Override + public String getDslName() { + return "toml"; + } + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/TomlParsingException.java b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlParsingException.java new file mode 100644 index 00000000000..2de5c34fafe --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlParsingException.java @@ -0,0 +1,31 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml; + +import java.nio.file.Path; + +public class TomlParsingException extends Exception { + private final Path sourcePath; + + public TomlParsingException(Path sourcePath, String message, Throwable t) { + super(message, t); + this.sourcePath = sourcePath; + } + + public Path getSourcePath() { + return sourcePath; + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/TomlVisitor.java b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlVisitor.java new file mode 100644 index 00000000000..b3707132e10 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlVisitor.java @@ -0,0 +1,119 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml; + +import org.openrewrite.Cursor; +import org.openrewrite.SourceFile; +import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.toml.tree.*; + +public class TomlVisitor

extends TreeVisitor { + + @Override + public boolean isAcceptable(SourceFile sourceFile, P p) { + return sourceFile instanceof Toml.Document; + } + + @Override + public String getLanguage() { + return "toml"; + } + + public Toml visitArray(Toml.Array array, P p) { + Toml.Array a = array; + a = a.withPrefix(visitSpace(a.getPrefix(), p)); + a = a.withMarkers(visitMarkers(a.getMarkers(), p)); + a = a.withValues(ListUtils.map(a.getValues(), v -> (TomlValue) visit(v, p))); + return a; + } + + public Toml visitDocument(Toml.Document document, P p) { + Toml.Document d = document; + d = d.withPrefix(visitSpace(d.getPrefix(), p)); + d = d.withMarkers(visitMarkers(d.getMarkers(), p)); + d = d.withValues(ListUtils.map(d.getValues(), v -> (TomlValue) visit(v, p))); + d = d.withEof(visitSpace(d.getEof(), p)); + return d; + } + + public Toml visitEmpty(Toml.Empty empty, P p) { + Toml.Empty e = empty; + e = e.withPrefix(visitSpace(e.getPrefix(), p)); + e = e.withMarkers(visitMarkers(e.getMarkers(), p)); + return e; + } + + public Toml visitIdentifier(Toml.Identifier identifier, P p) { + Toml.Identifier i = identifier; + i = i.withPrefix(visitSpace(i.getPrefix(), p)); + i = i.withMarkers(visitMarkers(i.getMarkers(), p)); + return i; + } + + public Toml visitKeyValue(Toml.KeyValue keyValue, P p) { + Toml.KeyValue kv = keyValue; + kv = kv.withPrefix(visitSpace(kv.getPrefix(), p)); + kv = kv.withMarkers(visitMarkers(kv.getMarkers(), p)); + kv = kv.getPadding().withKey(visitRightPadded(kv.getPadding().getKey(), p)); + kv = kv.withValue(visit(kv.getValue(), p)); + return kv; + } + + public Toml visitLiteral(Toml.Literal literal, P p) { + Toml.Literal l = literal; + l = l.withPrefix(visitSpace(l.getPrefix(), p)); + l = l.withMarkers(visitMarkers(l.getMarkers(), p)); + return l; + } + + public Space visitSpace(Space space, P p) { + return space; + } + + public Toml visitTable(Toml.Table table, P p) { + Toml.Table t = table; + t = t.withPrefix(visitSpace(t.getPrefix(), p)); + t = t.withMarkers(visitMarkers(t.getMarkers(), p)); + t = t.withValues(ListUtils.map(t.getValues(), v -> visit(v, p))); + return t; + } + + public TomlRightPadded visitRightPadded(@Nullable TomlRightPadded right, P p) { + if (right == null) { + //noinspection ConstantConditions + return null; + } + + setCursor(new Cursor(getCursor(), right)); + + T t = right.getElement(); + if (t instanceof Toml) { + //noinspection unchecked + t = visitAndCast((Toml) right.getElement(), p); + } + + setCursor(getCursor().getParent()); + if (t == null) { + //noinspection ConstantConditions + return null; + } + + Space after = visitSpace(right.getAfter(), p); + return (after == right.getAfter() && t == right.getElement()) ? right : new TomlRightPadded<>(t, after, right.getMarkers()); + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlParserVisitor.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlParserVisitor.java new file mode 100644 index 00000000000..e72c3f29f44 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlParserVisitor.java @@ -0,0 +1,517 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.internal; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.RuleNode; +import org.antlr.v4.runtime.tree.TerminalNode; +import org.jspecify.annotations.Nullable; +import org.openrewrite.FileAttributes; +import org.openrewrite.internal.EncodingDetectingInputStream; +import org.openrewrite.marker.Markers; +import org.openrewrite.toml.internal.grammar.TomlParser; +import org.openrewrite.toml.internal.grammar.TomlParserBaseVisitor; +import org.openrewrite.toml.marker.ArrayTable; +import org.openrewrite.toml.marker.InlineTable; +import org.openrewrite.toml.tree.*; + +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.BiFunction; + +import static org.openrewrite.Tree.randomId; + +public class TomlParserVisitor extends TomlParserBaseVisitor { + private final Path path; + private final String source; + private final Charset charset; + private final boolean charsetBomMarked; + + @Nullable + private final FileAttributes fileAttributes; + + private int cursor = 0; + private int codePointCursor = 0; + + public TomlParserVisitor(Path path, @Nullable FileAttributes fileAttributes, EncodingDetectingInputStream source) { + this.path = path; + this.fileAttributes = fileAttributes; + this.source = source.readFully(); + this.charset = source.getCharset(); + this.charsetBomMarked = source.isCharsetBomMarked(); + } + + @Override + public Toml visitChildren(RuleNode node) { + Toml result = defaultResult(); + int n = node.getChildCount(); + for (int i = 0; i < n; i++) { + if (!shouldVisitNextChild(node, result)) { + break; + } + + ParseTree c = node.getChild(i); + if (c instanceof TomlParser.CommentContext) { + continue; + } + + Toml childResult = c.accept(this); + result = aggregateResult(result, childResult); + } + + return result; + } + + @Override + public Toml.Document visitDocument(TomlParser.DocumentContext ctx) { + if (!ctx.children.isEmpty() && ctx.children.get(0) instanceof TerminalNode && ((TerminalNode) ctx.children.get(0)).getSymbol().getType() == TomlParser.EOF) { + new Toml.Document( + randomId(), + path, + Space.EMPTY, + Markers.EMPTY, + charset.name(), + charsetBomMarked, + null, + fileAttributes, + Collections.emptyList(), + Space.EMPTY + ); + } + + List elements = new ArrayList<>(); + // The last element is a "TerminalNode" which we are uninterested in + for (int i = 0; i < ctx.children.size() - 1; i++) { + TomlValue element = (TomlValue) visit(ctx.children.get(i)); + if (element != null) { + elements.add(element); + } + } + + return new Toml.Document( + randomId(), + path, + Space.EMPTY, + Markers.EMPTY, + charset.name(), + charsetBomMarked, + null, + fileAttributes, + elements, + Space.format(source, cursor, source.length()) + ); + } + + @Override + public Toml.Identifier visitKey(TomlParser.KeyContext ctx) { + return (Toml.Identifier) super.visitKey(ctx); + } + + @Override + public Toml.Identifier visitSimpleKey(TomlParser.SimpleKeyContext ctx) { + return convert(ctx, (c, prefix) -> new Toml.Identifier( + randomId(), + prefix, + Markers.EMPTY, + c.getText(), + c.getText() + )); + } + + @Override + public Toml.Identifier visitDottedKey(TomlParser.DottedKeyContext ctx) { + Space prefix = prefix(ctx); + StringBuilder text = new StringBuilder(); + StringBuilder key = new StringBuilder(); + for (ParseTree child : ctx.children) { + Space space = sourceBefore(child.getText()); + text.append(space.getWhitespace()).append(child.getText()); + key.append(child.getText()); + } + return new Toml.Identifier( + randomId(), + prefix, + Markers.EMPTY, + text.toString(), + key.toString() + ); + } + + @Override + public Toml.KeyValue visitKeyValue(TomlParser.KeyValueContext ctx) { + return convert(ctx, (c, prefix) -> new Toml.KeyValue( + randomId(), + prefix, + Markers.EMPTY, + TomlRightPadded.build((TomlKey) visitKey(c.key())).withAfter(sourceBefore("=")), + visitValue(c.value()) + )); + } + + @Override + public Toml visitString(TomlParser.StringContext ctx) { + return convert(ctx, (c, prefix) -> { + String string = c.getText(); + return new Toml.Literal( + randomId(), + prefix, + Markers.EMPTY, + TomlType.Primitive.String, + string, + string.substring(1, string.length() - 1) + ); + }); + } + + @Override + public Toml visitInteger(TomlParser.IntegerContext ctx) { + return convert(ctx, (c, prefix) -> { + String rawNumber = c.getText(); + String number = rawNumber.replace("_", ""); + Long numberValue = rawNumber.startsWith("0x") ? Long.parseLong(number.substring(2), 16) : + rawNumber.startsWith("0o") ? Long.parseLong(number.substring(2), 8) : + rawNumber.startsWith("0b") ? Long.parseLong(number.substring(2), 2) : + Long.parseLong(number); + return new Toml.Literal( + randomId(), + prefix, + Markers.EMPTY, + TomlType.Primitive.Integer, + rawNumber, + numberValue + ); + }); + } + + @Override + public Toml visitFloatingPoint(TomlParser.FloatingPointContext ctx) { + return convert(ctx, (c, prefix) -> { + String rawNumber = c.getText(); + if (c.NAN() != null) { + return new Toml.Literal( + randomId(), + prefix, + Markers.EMPTY, + TomlType.Primitive.Float, + rawNumber, + Double.NaN + ); + } else if (c.INF() != null) { + return new Toml.Literal( + randomId(), + prefix, + Markers.EMPTY, + TomlType.Primitive.Float, + rawNumber, + source.charAt(cursor) == '-' ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY + ); + } + + String number = rawNumber.replace("_", ""); + Double numberValue = Double.parseDouble(number); + return new Toml.Literal( + randomId(), + prefix, + Markers.EMPTY, + TomlType.Primitive.Float, + rawNumber, + numberValue + ); + }); + } + + @Override + public Toml visitBool(TomlParser.BoolContext ctx) { + return convert(ctx, (c, prefix) -> { + String bool = c.getText(); + Boolean boolValue = Boolean.parseBoolean(bool); + return new Toml.Literal( + randomId(), + prefix, + Markers.EMPTY, + TomlType.Primitive.Boolean, + bool, + boolValue + ); + }); + } + + private static final DateTimeFormatter RFC3339_OFFSET_DATE_TIME; + + static { + RFC3339_OFFSET_DATE_TIME = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .append(DateTimeFormatter.ISO_LOCAL_DATE) + .appendLiteral(' ') + .append(DateTimeFormatter.ISO_LOCAL_TIME) + .parseLenient() + .appendOffsetId() + .parseStrict() + .toFormatter(); + } + + @Override + public Toml visitDateTime(TomlParser.DateTimeContext ctx) { + return convert(ctx, (c, prefix) -> { + String dateTime = c.getText(); + if (c.OFFSET_DATE_TIME() != null) { + return new Toml.Literal( + randomId(), + prefix, + Markers.EMPTY, + TomlType.Primitive.OffsetDateTime, + dateTime, + dateTime.contains("T") ? OffsetDateTime.parse(dateTime) : OffsetDateTime.parse(dateTime, RFC3339_OFFSET_DATE_TIME) + ); + } else if (c.LOCAL_DATE_TIME() != null) { + return new Toml.Literal( + randomId(), + prefix, + Markers.EMPTY, + TomlType.Primitive.LocalDateTime, + dateTime, + LocalDateTime.parse(dateTime) + ); + } else if (c.LOCAL_DATE() != null) { + return new Toml.Literal( + randomId(), + prefix, + Markers.EMPTY, + TomlType.Primitive.LocalDate, + dateTime, + LocalDate.parse(dateTime) + ); + } + + return new Toml.Literal( + randomId(), + prefix, + Markers.EMPTY, + TomlType.Primitive.LocalTime, + dateTime, + LocalTime.parse(dateTime) + ); + }); + } + + @Override + public Toml visitArray(TomlParser.ArrayContext ctx) { + return convert(ctx, (c, prefix) -> { + sourceBefore("["); + List values = c.value(); + List> elements = new ArrayList<>(); + for (int i = 0; i < values.size(); i++) { + Toml element = visit(values.get(i)); + if (i == values.size() - 1) { + if (positionOfNext(",", ']') >= 0) { + elements.add(TomlRightPadded.build(element).withAfter(sourceBefore(","))); + elements.add(TomlRightPadded.build((Toml) new Toml.Empty(randomId(), Space.EMPTY, Markers.EMPTY)).withAfter(sourceBefore("]"))); + } else { + elements.add(TomlRightPadded.build(element).withAfter(sourceBefore("]"))); + } + } else { + elements.add(TomlRightPadded.build(element).withAfter(sourceBefore(","))); + } + } + + return new Toml.Array( + randomId(), + prefix, + Markers.EMPTY, + elements + ); + }); + } + + @Override + public Toml visitInlineTable(TomlParser.InlineTableContext ctx) { + return convert(ctx, (c, prefix) -> { + sourceBefore("{"); + List values = c.keyValue(); + List> elements = new ArrayList<>(); + for (int i = 0; i < values.size(); i++) { + Toml element = visit(values.get(i)); + if (i == values.size() - 1) { + if (positionOfNext(",", '}') >= 0) { + elements.add(TomlRightPadded.build(element).withAfter(sourceBefore(","))); + elements.add(TomlRightPadded.build((Toml) new Toml.Empty(randomId(), Space.EMPTY, Markers.EMPTY)).withAfter(sourceBefore("}"))); + } else { + elements.add(TomlRightPadded.build(element).withAfter(sourceBefore("}"))); + } + } else { + elements.add(TomlRightPadded.build(element).withAfter(sourceBefore(","))); + } + } + + return new Toml.Table( + randomId(), + prefix, + Markers.build(Collections.singletonList(new InlineTable(randomId()))), + null, + elements + ); + }); + } + + @Override + public Toml visitStandardTable(TomlParser.StandardTableContext ctx) { + return convert(ctx, (c, prefix) -> { + sourceBefore("["); + Toml.Identifier tableName = visitKey(c.key()); + TomlRightPadded nameRightPadded = TomlRightPadded.build(tableName).withAfter(sourceBefore("]")); + + List values = c.expression(); + List> elements = new ArrayList<>(); + for (int i = 0; i < values.size(); i++) { + elements.add(TomlRightPadded.build(visit(values.get(i)))); + } + + return new Toml.Table( + randomId(), + prefix, + Markers.EMPTY, + nameRightPadded, + elements + ); + }); + } + + @Override + public Toml visitArrayTable(TomlParser.ArrayTableContext ctx) { + return convert(ctx, (c, prefix) -> { + sourceBefore("[["); + Toml.Identifier tableName = visitKey(c.key()); + TomlRightPadded nameRightPadded = TomlRightPadded.build(tableName).withAfter(sourceBefore("]]")); + + List values = c.expression(); + List> elements = new ArrayList<>(); + for (int i = 0; i < values.size(); i++) { + elements.add(TomlRightPadded.build(visit(values.get(i)))); + } + + return new Toml.Table( + randomId(), + prefix, + Markers.build(Collections.singletonList(new ArrayTable(randomId()))), + nameRightPadded, + elements + ); + }); + } + + private Space prefix(ParserRuleContext ctx) { + return prefix(ctx.getStart()); + } + + private Space prefix(@Nullable TerminalNode terminalNode) { + return terminalNode == null ? Space.EMPTY : prefix(terminalNode.getSymbol()); + } + + private Space prefix(Token token) { + int start = token.getStartIndex(); + if (start < codePointCursor) { + return Space.EMPTY; + } + return Space.format(source, cursor, advanceCursor(start)); + } + + public int advanceCursor(int newCodePointIndex) { + for (; codePointCursor < newCodePointIndex; codePointCursor++) { + cursor = source.offsetByCodePoints(cursor, 1); + } + return cursor; + } + + private @Nullable T convert(C ctx, BiFunction conversion) { + if (ctx == null) { + return null; + } + + T t = conversion.apply(ctx, prefix(ctx)); + if (ctx.getStop() != null) { + advanceCursor(ctx.getStop().getStopIndex() + 1); + } + + return t; + } + + private T convert(TerminalNode node, BiFunction conversion) { + T t = conversion.apply(node, prefix(node)); + advanceCursor(node.getSymbol().getStopIndex() + 1); + return t; + } + + private void skip(TerminalNode node) { + advanceCursor(node.getSymbol().getStopIndex() + 1); + } + + /** + * @return Source from cursor to next occurrence of untilDelim, + * and if not found in the remaining source, the empty String. If stop is reached before + * untilDelim return the empty String. + */ + private Space sourceBefore(String untilDelim) { + int delimIndex = positionOfNext(untilDelim, null); + if (delimIndex < 0) { + return Space.EMPTY; // unable to find this delimiter + } + + Space space = Space.format(source, cursor, delimIndex); + advanceCursor(codePointCursor + Character.codePointCount(source, cursor, delimIndex) + untilDelim.length()); + return space; + } + + private int positionOfNext(String untilDelim, @Nullable Character stop) { + boolean inSingleLineComment = false; + + int delimIndex = cursor; + for (; delimIndex < source.length() - untilDelim.length() + 1; delimIndex++) { + if (inSingleLineComment) { + if (source.charAt(delimIndex) == '\n') { + inSingleLineComment = false; + } + } else { + if (source.charAt(delimIndex) == '#') { + inSingleLineComment = true; + delimIndex++; + } + + if (!inSingleLineComment) { + if (stop != null && source.charAt(delimIndex) == stop) { + return -1; // reached stop word before finding the delimiter + } + + if (source.startsWith(untilDelim, delimIndex)) { + break; // found it! + } + } + } + } + + return delimIndex > source.length() - untilDelim.length() ? -1 : delimIndex; + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlPrinter.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlPrinter.java new file mode 100644 index 00000000000..af61c294a17 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlPrinter.java @@ -0,0 +1,157 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.internal; + +import org.openrewrite.Cursor; +import org.openrewrite.PrintOutputCapture; +import org.openrewrite.marker.Marker; +import org.openrewrite.marker.Markers; +import org.openrewrite.toml.TomlVisitor; +import org.openrewrite.toml.marker.ArrayTable; +import org.openrewrite.toml.marker.InlineTable; +import org.openrewrite.toml.tree.Comment; +import org.openrewrite.toml.tree.Space; +import org.openrewrite.toml.tree.Toml; +import org.openrewrite.toml.tree.TomlRightPadded; + +import java.util.List; +import java.util.function.UnaryOperator; + +public class TomlPrinter

extends TomlVisitor> { + + @Override + public Toml visitArray(Toml.Array array, PrintOutputCapture

p) { + beforeSyntax(array, p); + p.append("["); + visitRightPadded(array.getPadding().getValues(), ",", p); + p.append("]"); + afterSyntax(array, p); + return array; + } + + @Override + public Toml visitDocument(Toml.Document document, PrintOutputCapture

p) { + beforeSyntax(document, p); + visit(document.getValues(), p); + visitSpace(document.getEof(), p); + afterSyntax(document, p); + return document; + } + + @Override + public Toml visitEmpty(Toml.Empty empty, PrintOutputCapture

p) { + beforeSyntax(empty, p); + afterSyntax(empty, p); + return empty; + } + + @Override + public Toml visitIdentifier(Toml.Identifier identifier, PrintOutputCapture

p) { + beforeSyntax(identifier, p); + p.append(identifier.getSource()); + afterSyntax(identifier, p); + return identifier; + } + + @Override + public Toml visitKeyValue(Toml.KeyValue keyValue, PrintOutputCapture

p) { + beforeSyntax(keyValue, p); + visitRightPadded(keyValue.getPadding().getKey(), p); + p.append("="); + visit(keyValue.getValue(), p); + afterSyntax(keyValue, p); + return keyValue; + } + + @Override + public Toml visitLiteral(Toml.Literal literal, PrintOutputCapture

p) { + beforeSyntax(literal, p); + p.append(literal.getSource()); + afterSyntax(literal, p); + return literal; + } + + @Override + public Space visitSpace(Space space, PrintOutputCapture

p) { + p.append(space.getWhitespace()); + for (Comment comment : space.getComments()) { + visitMarkers(comment.getMarkers(), p); + p.append("#").append(comment.getText()).append(comment.getSuffix()); + } + return space; + } + + @Override + public Toml visitTable(Toml.Table table, PrintOutputCapture

p) { + beforeSyntax(table, p); + if (table.getMarkers().findFirst(InlineTable.class).isPresent()) { + p.append("{"); + visitRightPadded(table.getPadding().getValues(), ",", p); + p.append("}"); + } else if (table.getMarkers().findFirst(ArrayTable.class).isPresent()) { + p.append("[["); + visitRightPadded(table.getName(), p); + p.append("]]"); + visitRightPadded(table.getPadding().getValues(), "", p); + } else { + p.append("["); + visitRightPadded(table.getName(), p); + p.append("]"); + visitRightPadded(table.getPadding().getValues(), "", p); + } + afterSyntax(table, p); + return table; + } + + protected void visitRightPadded(List> nodes, String suffixBetween, PrintOutputCapture

p) { + for (int i = 0; i < nodes.size(); i++) { + TomlRightPadded node = nodes.get(i); + visit(node.getElement(), p); + visitSpace(node.getAfter(), p); + if (i < nodes.size() - 1) { + p.append(suffixBetween); + } + } + } + + private static final UnaryOperator TOML_MARKER_WRAPPER = + out -> "~~" + out + (out.isEmpty() ? "" : "~~") + ">"; + + protected void beforeSyntax(Toml t, PrintOutputCapture

p) { + beforeSyntax(t.getPrefix(), t.getMarkers(), p); + } + + protected void beforeSyntax(Space prefix, Markers markers, PrintOutputCapture

p) { + for (Marker marker : markers.getMarkers()) { + p.append(p.getMarkerPrinter().beforePrefix(marker, new Cursor(getCursor(), marker), TOML_MARKER_WRAPPER)); + } + visitSpace(prefix, p); + visitMarkers(markers, p); + for (Marker marker : markers.getMarkers()) { + p.append(p.getMarkerPrinter().beforeSyntax(marker, new Cursor(getCursor(), marker), TOML_MARKER_WRAPPER)); + } + } + + protected void afterSyntax(Toml t, PrintOutputCapture

p) { + afterSyntax(t.getMarkers(), p); + } + + protected void afterSyntax(Markers markers, PrintOutputCapture

p) { + for (Marker marker : markers.getMarkers()) { + p.append(p.getMarkerPrinter().afterSyntax(marker, new Cursor(getCursor(), marker), TOML_MARKER_WRAPPER)); + } + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.interp b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.interp new file mode 100644 index 00000000000..e1b1838c219 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.interp @@ -0,0 +1,176 @@ +token literal names: +null +null +null +null +'[' +'[[' +']' +']]' +'=' +'.' +',' +null +null +null +null +'{' +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +'}' +null + +token symbolic names: +null +WS +NL +COMMENT +L_BRACKET +DOUBLE_L_BRACKET +R_BRACKET +DOUBLE_R_BRACKET +EQUALS +DOT +COMMA +BASIC_STRING +LITERAL_STRING +UNQUOTED_KEY +VALUE_WS +L_BRACE +BOOLEAN +ML_BASIC_STRING +ML_LITERAL_STRING +FLOAT +INF +NAN +DEC_INT +HEX_INT +OCT_INT +BIN_INT +OFFSET_DATE_TIME +LOCAL_DATE_TIME +LOCAL_DATE +LOCAL_TIME +INLINE_TABLE_WS +R_BRACE +ARRAY_WS + +rule names: +WS +NL +COMMENT +L_BRACKET +DOUBLE_L_BRACKET +R_BRACKET +DOUBLE_R_BRACKET +EQUALS +DOT +COMMA +DIGIT +ALPHA +ESC +UNICODE +EX_UNICODE +BASIC_STRING +LITERAL_STRING +UNQUOTED_KEY +VALUE_WS +L_BRACE +ARRAY_START +BOOLEAN +ML_ESC +VALUE_BASIC_STRING +ML_BASIC_STRING +VALUE_LITERAL_STRING +ML_LITERAL_STRING +EXP +ZERO_PREFIXABLE_INT +FRAC +FLOAT +INF +NAN +HEX_DIGIT +DIGIT_1_9 +DIGIT_0_7 +DIGIT_0_1 +DEC_INT +HEX_INT +OCT_INT +BIN_INT +YEAR +MONTH +DAY +DELIM +HOUR +MINUTE +SECOND +SECFRAC +NUMOFFSET +OFFSET +PARTIAL_TIME +FULL_DATE +FULL_TIME +OFFSET_DATE_TIME +LOCAL_DATE_TIME +LOCAL_DATE +LOCAL_TIME +INLINE_TABLE_WS +INLINE_TABLE_KEY_DOT +INLINE_TABLE_COMMA +R_BRACE +INLINE_TABLE_KEY_BASIC_STRING +INLINE_TABLE_KEY_LITERAL_STRING +INLINE_TABLE_KEY_UNQUOTED +INLINE_TABLE_EQUALS +ARRAY_WS +ARRAY_NL +ARRAY_COMMENT +ARRAY_COMMA +ARRAY_INLINE_TABLE_START +NESTED_ARRAY_START +ARRAY_END +ARRAY_BOOLEAN +ARRAY_BASIC_STRING +ARRAY_ML_BASIC_STRING +ARRAY_LITERAL_STRING +ARRAY_ML_LITERAL_STRING +ARRAY_FLOAT +ARRAY_INF +ARRAY_NAN +ARRAY_DEC_INT +ARRAY_HEX_INT +ARRAY_OCT_INT +ARRAY_BIN_INT +ARRAY_OFFSET_DATE_TIME +ARRAY_LOCAL_DATE_TIME +ARRAY_LOCAL_DATE +ARRAY_LOCAL_TIME + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN +null +null +COMMENTS_CHANNEL + +mode names: +DEFAULT_MODE +SIMPLE_VALUE_MODE +INLINE_TABLE_MODE +ARRAY_MODE + +atn: +[4, 0, 32, 671, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 1, 0, 4, 0, 184, 8, 0, 11, 0, 12, 0, 185, 1, 0, 1, 0, 1, 1, 3, 1, 191, 8, 1, 1, 1, 4, 1, 194, 8, 1, 11, 1, 12, 1, 195, 1, 2, 1, 2, 5, 2, 200, 8, 2, 10, 2, 12, 2, 203, 9, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 235, 8, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 5, 15, 256, 8, 15, 10, 15, 12, 15, 259, 9, 15, 1, 15, 1, 15, 1, 16, 1, 16, 5, 16, 265, 8, 16, 10, 16, 12, 16, 268, 9, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 4, 17, 275, 8, 17, 11, 17, 12, 17, 276, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 3, 21, 301, 8, 21, 1, 21, 1, 21, 1, 22, 1, 22, 3, 22, 307, 8, 22, 1, 22, 1, 22, 3, 22, 311, 8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 324, 8, 24, 10, 24, 12, 24, 327, 9, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 5, 26, 345, 8, 26, 10, 26, 12, 26, 348, 9, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 3, 27, 358, 8, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 5, 28, 366, 8, 28, 10, 28, 12, 28, 369, 9, 28, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 3, 30, 378, 8, 30, 3, 30, 380, 8, 30, 1, 30, 1, 30, 1, 31, 3, 31, 385, 8, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 3, 32, 394, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 3, 33, 404, 8, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 3, 37, 413, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 4, 37, 420, 8, 37, 11, 37, 12, 37, 421, 3, 37, 424, 8, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 435, 8, 38, 10, 38, 12, 38, 438, 9, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 5, 39, 449, 8, 39, 10, 39, 12, 39, 452, 9, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 463, 8, 40, 10, 40, 12, 40, 466, 9, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 4, 48, 494, 8, 48, 11, 48, 12, 48, 495, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 3, 50, 505, 8, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 3, 51, 513, 8, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 4, 257, 266, 325, 346, 0, 89, 4, 1, 6, 2, 8, 3, 10, 4, 12, 5, 14, 6, 16, 7, 18, 8, 20, 9, 22, 10, 24, 0, 26, 0, 28, 0, 30, 0, 32, 0, 34, 11, 36, 12, 38, 13, 40, 14, 42, 15, 44, 0, 46, 16, 48, 0, 50, 0, 52, 17, 54, 0, 56, 18, 58, 0, 60, 0, 62, 0, 64, 19, 66, 20, 68, 21, 70, 0, 72, 0, 74, 0, 76, 0, 78, 22, 80, 23, 82, 24, 84, 25, 86, 0, 88, 0, 90, 0, 92, 0, 94, 0, 96, 0, 98, 0, 100, 0, 102, 0, 104, 0, 106, 0, 108, 0, 110, 0, 112, 26, 114, 27, 116, 28, 118, 29, 120, 30, 122, 0, 124, 0, 126, 31, 128, 0, 130, 0, 132, 0, 134, 0, 136, 32, 138, 0, 140, 0, 142, 0, 144, 0, 146, 0, 148, 0, 150, 0, 152, 0, 154, 0, 156, 0, 158, 0, 160, 0, 162, 0, 164, 0, 166, 0, 168, 0, 170, 0, 172, 0, 174, 0, 176, 0, 178, 0, 180, 0, 4, 0, 1, 2, 3, 16, 2, 0, 9, 9, 32, 32, 2, 0, 10, 10, 13, 13, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 47, 47, 92, 92, 98, 98, 102, 102, 110, 110, 114, 114, 116, 116, 3, 0, 10, 10, 34, 34, 92, 92, 2, 0, 10, 10, 39, 39, 2, 0, 45, 45, 95, 95, 2, 0, 34, 34, 92, 92, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 2, 0, 65, 70, 97, 102, 1, 0, 49, 57, 1, 0, 48, 55, 1, 0, 48, 49, 3, 0, 32, 32, 84, 84, 116, 116, 680, 0, 4, 1, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 10, 1, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 14, 1, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 18, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 34, 1, 0, 0, 0, 0, 36, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 1, 40, 1, 0, 0, 0, 1, 42, 1, 0, 0, 0, 1, 44, 1, 0, 0, 0, 1, 46, 1, 0, 0, 0, 1, 50, 1, 0, 0, 0, 1, 52, 1, 0, 0, 0, 1, 54, 1, 0, 0, 0, 1, 56, 1, 0, 0, 0, 1, 64, 1, 0, 0, 0, 1, 66, 1, 0, 0, 0, 1, 68, 1, 0, 0, 0, 1, 78, 1, 0, 0, 0, 1, 80, 1, 0, 0, 0, 1, 82, 1, 0, 0, 0, 1, 84, 1, 0, 0, 0, 1, 112, 1, 0, 0, 0, 1, 114, 1, 0, 0, 0, 1, 116, 1, 0, 0, 0, 1, 118, 1, 0, 0, 0, 2, 120, 1, 0, 0, 0, 2, 122, 1, 0, 0, 0, 2, 124, 1, 0, 0, 0, 2, 126, 1, 0, 0, 0, 2, 128, 1, 0, 0, 0, 2, 130, 1, 0, 0, 0, 2, 132, 1, 0, 0, 0, 2, 134, 1, 0, 0, 0, 3, 136, 1, 0, 0, 0, 3, 138, 1, 0, 0, 0, 3, 140, 1, 0, 0, 0, 3, 142, 1, 0, 0, 0, 3, 144, 1, 0, 0, 0, 3, 146, 1, 0, 0, 0, 3, 148, 1, 0, 0, 0, 3, 150, 1, 0, 0, 0, 3, 152, 1, 0, 0, 0, 3, 154, 1, 0, 0, 0, 3, 156, 1, 0, 0, 0, 3, 158, 1, 0, 0, 0, 3, 160, 1, 0, 0, 0, 3, 162, 1, 0, 0, 0, 3, 164, 1, 0, 0, 0, 3, 166, 1, 0, 0, 0, 3, 168, 1, 0, 0, 0, 3, 170, 1, 0, 0, 0, 3, 172, 1, 0, 0, 0, 3, 174, 1, 0, 0, 0, 3, 176, 1, 0, 0, 0, 3, 178, 1, 0, 0, 0, 3, 180, 1, 0, 0, 0, 4, 183, 1, 0, 0, 0, 6, 193, 1, 0, 0, 0, 8, 197, 1, 0, 0, 0, 10, 206, 1, 0, 0, 0, 12, 208, 1, 0, 0, 0, 14, 211, 1, 0, 0, 0, 16, 213, 1, 0, 0, 0, 18, 216, 1, 0, 0, 0, 20, 220, 1, 0, 0, 0, 22, 222, 1, 0, 0, 0, 24, 226, 1, 0, 0, 0, 26, 228, 1, 0, 0, 0, 28, 230, 1, 0, 0, 0, 30, 236, 1, 0, 0, 0, 32, 242, 1, 0, 0, 0, 34, 252, 1, 0, 0, 0, 36, 262, 1, 0, 0, 0, 38, 274, 1, 0, 0, 0, 40, 278, 1, 0, 0, 0, 42, 282, 1, 0, 0, 0, 44, 286, 1, 0, 0, 0, 46, 300, 1, 0, 0, 0, 48, 310, 1, 0, 0, 0, 50, 312, 1, 0, 0, 0, 52, 317, 1, 0, 0, 0, 54, 334, 1, 0, 0, 0, 56, 339, 1, 0, 0, 0, 58, 355, 1, 0, 0, 0, 60, 361, 1, 0, 0, 0, 62, 370, 1, 0, 0, 0, 64, 373, 1, 0, 0, 0, 66, 384, 1, 0, 0, 0, 68, 393, 1, 0, 0, 0, 70, 403, 1, 0, 0, 0, 72, 405, 1, 0, 0, 0, 74, 407, 1, 0, 0, 0, 76, 409, 1, 0, 0, 0, 78, 412, 1, 0, 0, 0, 80, 427, 1, 0, 0, 0, 82, 441, 1, 0, 0, 0, 84, 455, 1, 0, 0, 0, 86, 469, 1, 0, 0, 0, 88, 474, 1, 0, 0, 0, 90, 477, 1, 0, 0, 0, 92, 480, 1, 0, 0, 0, 94, 482, 1, 0, 0, 0, 96, 485, 1, 0, 0, 0, 98, 488, 1, 0, 0, 0, 100, 491, 1, 0, 0, 0, 102, 497, 1, 0, 0, 0, 104, 504, 1, 0, 0, 0, 106, 506, 1, 0, 0, 0, 108, 514, 1, 0, 0, 0, 110, 520, 1, 0, 0, 0, 112, 523, 1, 0, 0, 0, 114, 529, 1, 0, 0, 0, 116, 535, 1, 0, 0, 0, 118, 539, 1, 0, 0, 0, 120, 543, 1, 0, 0, 0, 122, 547, 1, 0, 0, 0, 124, 551, 1, 0, 0, 0, 126, 555, 1, 0, 0, 0, 128, 559, 1, 0, 0, 0, 130, 563, 1, 0, 0, 0, 132, 567, 1, 0, 0, 0, 134, 571, 1, 0, 0, 0, 136, 576, 1, 0, 0, 0, 138, 580, 1, 0, 0, 0, 140, 584, 1, 0, 0, 0, 142, 588, 1, 0, 0, 0, 144, 592, 1, 0, 0, 0, 146, 597, 1, 0, 0, 0, 148, 602, 1, 0, 0, 0, 150, 607, 1, 0, 0, 0, 152, 611, 1, 0, 0, 0, 154, 615, 1, 0, 0, 0, 156, 619, 1, 0, 0, 0, 158, 623, 1, 0, 0, 0, 160, 627, 1, 0, 0, 0, 162, 631, 1, 0, 0, 0, 164, 635, 1, 0, 0, 0, 166, 639, 1, 0, 0, 0, 168, 643, 1, 0, 0, 0, 170, 647, 1, 0, 0, 0, 172, 651, 1, 0, 0, 0, 174, 655, 1, 0, 0, 0, 176, 659, 1, 0, 0, 0, 178, 663, 1, 0, 0, 0, 180, 667, 1, 0, 0, 0, 182, 184, 7, 0, 0, 0, 183, 182, 1, 0, 0, 0, 184, 185, 1, 0, 0, 0, 185, 183, 1, 0, 0, 0, 185, 186, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 187, 188, 6, 0, 0, 0, 188, 5, 1, 0, 0, 0, 189, 191, 5, 13, 0, 0, 190, 189, 1, 0, 0, 0, 190, 191, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 192, 194, 5, 10, 0, 0, 193, 190, 1, 0, 0, 0, 194, 195, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 7, 1, 0, 0, 0, 197, 201, 5, 35, 0, 0, 198, 200, 8, 1, 0, 0, 199, 198, 1, 0, 0, 0, 200, 203, 1, 0, 0, 0, 201, 199, 1, 0, 0, 0, 201, 202, 1, 0, 0, 0, 202, 204, 1, 0, 0, 0, 203, 201, 1, 0, 0, 0, 204, 205, 6, 2, 1, 0, 205, 9, 1, 0, 0, 0, 206, 207, 5, 91, 0, 0, 207, 11, 1, 0, 0, 0, 208, 209, 5, 91, 0, 0, 209, 210, 5, 91, 0, 0, 210, 13, 1, 0, 0, 0, 211, 212, 5, 93, 0, 0, 212, 15, 1, 0, 0, 0, 213, 214, 5, 93, 0, 0, 214, 215, 5, 93, 0, 0, 215, 17, 1, 0, 0, 0, 216, 217, 5, 61, 0, 0, 217, 218, 1, 0, 0, 0, 218, 219, 6, 7, 2, 0, 219, 19, 1, 0, 0, 0, 220, 221, 5, 46, 0, 0, 221, 21, 1, 0, 0, 0, 222, 223, 5, 44, 0, 0, 223, 224, 1, 0, 0, 0, 224, 225, 6, 9, 0, 0, 225, 23, 1, 0, 0, 0, 226, 227, 7, 2, 0, 0, 227, 25, 1, 0, 0, 0, 228, 229, 7, 3, 0, 0, 229, 27, 1, 0, 0, 0, 230, 234, 5, 92, 0, 0, 231, 235, 7, 4, 0, 0, 232, 235, 3, 30, 13, 0, 233, 235, 3, 32, 14, 0, 234, 231, 1, 0, 0, 0, 234, 232, 1, 0, 0, 0, 234, 233, 1, 0, 0, 0, 235, 29, 1, 0, 0, 0, 236, 237, 5, 117, 0, 0, 237, 238, 3, 70, 33, 0, 238, 239, 3, 70, 33, 0, 239, 240, 3, 70, 33, 0, 240, 241, 3, 70, 33, 0, 241, 31, 1, 0, 0, 0, 242, 243, 5, 85, 0, 0, 243, 244, 3, 70, 33, 0, 244, 245, 3, 70, 33, 0, 245, 246, 3, 70, 33, 0, 246, 247, 3, 70, 33, 0, 247, 248, 3, 70, 33, 0, 248, 249, 3, 70, 33, 0, 249, 250, 3, 70, 33, 0, 250, 251, 3, 70, 33, 0, 251, 33, 1, 0, 0, 0, 252, 257, 5, 34, 0, 0, 253, 256, 3, 28, 12, 0, 254, 256, 8, 5, 0, 0, 255, 253, 1, 0, 0, 0, 255, 254, 1, 0, 0, 0, 256, 259, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 257, 255, 1, 0, 0, 0, 258, 260, 1, 0, 0, 0, 259, 257, 1, 0, 0, 0, 260, 261, 5, 34, 0, 0, 261, 35, 1, 0, 0, 0, 262, 266, 5, 39, 0, 0, 263, 265, 8, 6, 0, 0, 264, 263, 1, 0, 0, 0, 265, 268, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 266, 264, 1, 0, 0, 0, 267, 269, 1, 0, 0, 0, 268, 266, 1, 0, 0, 0, 269, 270, 5, 39, 0, 0, 270, 37, 1, 0, 0, 0, 271, 275, 3, 26, 11, 0, 272, 275, 3, 24, 10, 0, 273, 275, 7, 7, 0, 0, 274, 271, 1, 0, 0, 0, 274, 272, 1, 0, 0, 0, 274, 273, 1, 0, 0, 0, 275, 276, 1, 0, 0, 0, 276, 274, 1, 0, 0, 0, 276, 277, 1, 0, 0, 0, 277, 39, 1, 0, 0, 0, 278, 279, 3, 4, 0, 0, 279, 280, 1, 0, 0, 0, 280, 281, 6, 18, 0, 0, 281, 41, 1, 0, 0, 0, 282, 283, 5, 123, 0, 0, 283, 284, 1, 0, 0, 0, 284, 285, 6, 19, 3, 0, 285, 43, 1, 0, 0, 0, 286, 287, 3, 10, 3, 0, 287, 288, 1, 0, 0, 0, 288, 289, 6, 20, 4, 0, 289, 290, 6, 20, 5, 0, 290, 45, 1, 0, 0, 0, 291, 292, 5, 116, 0, 0, 292, 293, 5, 114, 0, 0, 293, 294, 5, 117, 0, 0, 294, 301, 5, 101, 0, 0, 295, 296, 5, 102, 0, 0, 296, 297, 5, 97, 0, 0, 297, 298, 5, 108, 0, 0, 298, 299, 5, 115, 0, 0, 299, 301, 5, 101, 0, 0, 300, 291, 1, 0, 0, 0, 300, 295, 1, 0, 0, 0, 301, 302, 1, 0, 0, 0, 302, 303, 6, 21, 6, 0, 303, 47, 1, 0, 0, 0, 304, 306, 5, 92, 0, 0, 305, 307, 5, 13, 0, 0, 306, 305, 1, 0, 0, 0, 306, 307, 1, 0, 0, 0, 307, 308, 1, 0, 0, 0, 308, 311, 5, 10, 0, 0, 309, 311, 3, 28, 12, 0, 310, 304, 1, 0, 0, 0, 310, 309, 1, 0, 0, 0, 311, 49, 1, 0, 0, 0, 312, 313, 3, 34, 15, 0, 313, 314, 1, 0, 0, 0, 314, 315, 6, 23, 7, 0, 315, 316, 6, 23, 6, 0, 316, 51, 1, 0, 0, 0, 317, 318, 5, 34, 0, 0, 318, 319, 5, 34, 0, 0, 319, 320, 5, 34, 0, 0, 320, 325, 1, 0, 0, 0, 321, 324, 3, 48, 22, 0, 322, 324, 8, 8, 0, 0, 323, 321, 1, 0, 0, 0, 323, 322, 1, 0, 0, 0, 324, 327, 1, 0, 0, 0, 325, 326, 1, 0, 0, 0, 325, 323, 1, 0, 0, 0, 326, 328, 1, 0, 0, 0, 327, 325, 1, 0, 0, 0, 328, 329, 5, 34, 0, 0, 329, 330, 5, 34, 0, 0, 330, 331, 5, 34, 0, 0, 331, 332, 1, 0, 0, 0, 332, 333, 6, 24, 6, 0, 333, 53, 1, 0, 0, 0, 334, 335, 3, 36, 16, 0, 335, 336, 1, 0, 0, 0, 336, 337, 6, 25, 8, 0, 337, 338, 6, 25, 6, 0, 338, 55, 1, 0, 0, 0, 339, 340, 5, 39, 0, 0, 340, 341, 5, 39, 0, 0, 341, 342, 5, 39, 0, 0, 342, 346, 1, 0, 0, 0, 343, 345, 9, 0, 0, 0, 344, 343, 1, 0, 0, 0, 345, 348, 1, 0, 0, 0, 346, 347, 1, 0, 0, 0, 346, 344, 1, 0, 0, 0, 347, 349, 1, 0, 0, 0, 348, 346, 1, 0, 0, 0, 349, 350, 5, 39, 0, 0, 350, 351, 5, 39, 0, 0, 351, 352, 5, 39, 0, 0, 352, 353, 1, 0, 0, 0, 353, 354, 6, 26, 6, 0, 354, 57, 1, 0, 0, 0, 355, 357, 7, 9, 0, 0, 356, 358, 7, 10, 0, 0, 357, 356, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 359, 1, 0, 0, 0, 359, 360, 3, 60, 28, 0, 360, 59, 1, 0, 0, 0, 361, 367, 3, 24, 10, 0, 362, 366, 3, 24, 10, 0, 363, 364, 5, 95, 0, 0, 364, 366, 3, 24, 10, 0, 365, 362, 1, 0, 0, 0, 365, 363, 1, 0, 0, 0, 366, 369, 1, 0, 0, 0, 367, 365, 1, 0, 0, 0, 367, 368, 1, 0, 0, 0, 368, 61, 1, 0, 0, 0, 369, 367, 1, 0, 0, 0, 370, 371, 5, 46, 0, 0, 371, 372, 3, 60, 28, 0, 372, 63, 1, 0, 0, 0, 373, 379, 3, 78, 37, 0, 374, 380, 3, 58, 27, 0, 375, 377, 3, 62, 29, 0, 376, 378, 3, 58, 27, 0, 377, 376, 1, 0, 0, 0, 377, 378, 1, 0, 0, 0, 378, 380, 1, 0, 0, 0, 379, 374, 1, 0, 0, 0, 379, 375, 1, 0, 0, 0, 380, 381, 1, 0, 0, 0, 381, 382, 6, 30, 6, 0, 382, 65, 1, 0, 0, 0, 383, 385, 7, 10, 0, 0, 384, 383, 1, 0, 0, 0, 384, 385, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 387, 5, 105, 0, 0, 387, 388, 5, 110, 0, 0, 388, 389, 5, 102, 0, 0, 389, 390, 1, 0, 0, 0, 390, 391, 6, 31, 6, 0, 391, 67, 1, 0, 0, 0, 392, 394, 7, 10, 0, 0, 393, 392, 1, 0, 0, 0, 393, 394, 1, 0, 0, 0, 394, 395, 1, 0, 0, 0, 395, 396, 5, 110, 0, 0, 396, 397, 5, 97, 0, 0, 397, 398, 5, 110, 0, 0, 398, 399, 1, 0, 0, 0, 399, 400, 6, 32, 6, 0, 400, 69, 1, 0, 0, 0, 401, 404, 7, 11, 0, 0, 402, 404, 3, 24, 10, 0, 403, 401, 1, 0, 0, 0, 403, 402, 1, 0, 0, 0, 404, 71, 1, 0, 0, 0, 405, 406, 7, 12, 0, 0, 406, 73, 1, 0, 0, 0, 407, 408, 7, 13, 0, 0, 408, 75, 1, 0, 0, 0, 409, 410, 7, 14, 0, 0, 410, 77, 1, 0, 0, 0, 411, 413, 7, 10, 0, 0, 412, 411, 1, 0, 0, 0, 412, 413, 1, 0, 0, 0, 413, 423, 1, 0, 0, 0, 414, 424, 3, 24, 10, 0, 415, 419, 3, 72, 34, 0, 416, 420, 3, 24, 10, 0, 417, 418, 5, 95, 0, 0, 418, 420, 3, 24, 10, 0, 419, 416, 1, 0, 0, 0, 419, 417, 1, 0, 0, 0, 420, 421, 1, 0, 0, 0, 421, 419, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 424, 1, 0, 0, 0, 423, 414, 1, 0, 0, 0, 423, 415, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 426, 6, 37, 6, 0, 426, 79, 1, 0, 0, 0, 427, 428, 5, 48, 0, 0, 428, 429, 5, 120, 0, 0, 429, 430, 1, 0, 0, 0, 430, 436, 3, 70, 33, 0, 431, 435, 3, 70, 33, 0, 432, 433, 5, 95, 0, 0, 433, 435, 3, 70, 33, 0, 434, 431, 1, 0, 0, 0, 434, 432, 1, 0, 0, 0, 435, 438, 1, 0, 0, 0, 436, 434, 1, 0, 0, 0, 436, 437, 1, 0, 0, 0, 437, 439, 1, 0, 0, 0, 438, 436, 1, 0, 0, 0, 439, 440, 6, 38, 6, 0, 440, 81, 1, 0, 0, 0, 441, 442, 5, 48, 0, 0, 442, 443, 5, 111, 0, 0, 443, 444, 1, 0, 0, 0, 444, 450, 3, 74, 35, 0, 445, 449, 3, 74, 35, 0, 446, 447, 5, 95, 0, 0, 447, 449, 3, 74, 35, 0, 448, 445, 1, 0, 0, 0, 448, 446, 1, 0, 0, 0, 449, 452, 1, 0, 0, 0, 450, 448, 1, 0, 0, 0, 450, 451, 1, 0, 0, 0, 451, 453, 1, 0, 0, 0, 452, 450, 1, 0, 0, 0, 453, 454, 6, 39, 6, 0, 454, 83, 1, 0, 0, 0, 455, 456, 5, 48, 0, 0, 456, 457, 5, 98, 0, 0, 457, 458, 1, 0, 0, 0, 458, 464, 3, 76, 36, 0, 459, 463, 3, 76, 36, 0, 460, 461, 5, 95, 0, 0, 461, 463, 3, 76, 36, 0, 462, 459, 1, 0, 0, 0, 462, 460, 1, 0, 0, 0, 463, 466, 1, 0, 0, 0, 464, 462, 1, 0, 0, 0, 464, 465, 1, 0, 0, 0, 465, 467, 1, 0, 0, 0, 466, 464, 1, 0, 0, 0, 467, 468, 6, 40, 6, 0, 468, 85, 1, 0, 0, 0, 469, 470, 3, 24, 10, 0, 470, 471, 3, 24, 10, 0, 471, 472, 3, 24, 10, 0, 472, 473, 3, 24, 10, 0, 473, 87, 1, 0, 0, 0, 474, 475, 3, 24, 10, 0, 475, 476, 3, 24, 10, 0, 476, 89, 1, 0, 0, 0, 477, 478, 3, 24, 10, 0, 478, 479, 3, 24, 10, 0, 479, 91, 1, 0, 0, 0, 480, 481, 7, 15, 0, 0, 481, 93, 1, 0, 0, 0, 482, 483, 3, 24, 10, 0, 483, 484, 3, 24, 10, 0, 484, 95, 1, 0, 0, 0, 485, 486, 3, 24, 10, 0, 486, 487, 3, 24, 10, 0, 487, 97, 1, 0, 0, 0, 488, 489, 3, 24, 10, 0, 489, 490, 3, 24, 10, 0, 490, 99, 1, 0, 0, 0, 491, 493, 5, 46, 0, 0, 492, 494, 3, 24, 10, 0, 493, 492, 1, 0, 0, 0, 494, 495, 1, 0, 0, 0, 495, 493, 1, 0, 0, 0, 495, 496, 1, 0, 0, 0, 496, 101, 1, 0, 0, 0, 497, 498, 7, 10, 0, 0, 498, 499, 3, 94, 45, 0, 499, 500, 5, 58, 0, 0, 500, 501, 3, 96, 46, 0, 501, 103, 1, 0, 0, 0, 502, 505, 5, 90, 0, 0, 503, 505, 3, 102, 49, 0, 504, 502, 1, 0, 0, 0, 504, 503, 1, 0, 0, 0, 505, 105, 1, 0, 0, 0, 506, 507, 3, 94, 45, 0, 507, 508, 5, 58, 0, 0, 508, 509, 3, 96, 46, 0, 509, 510, 5, 58, 0, 0, 510, 512, 3, 98, 47, 0, 511, 513, 3, 100, 48, 0, 512, 511, 1, 0, 0, 0, 512, 513, 1, 0, 0, 0, 513, 107, 1, 0, 0, 0, 514, 515, 3, 86, 41, 0, 515, 516, 5, 45, 0, 0, 516, 517, 3, 88, 42, 0, 517, 518, 5, 45, 0, 0, 518, 519, 3, 90, 43, 0, 519, 109, 1, 0, 0, 0, 520, 521, 3, 106, 51, 0, 521, 522, 3, 104, 50, 0, 522, 111, 1, 0, 0, 0, 523, 524, 3, 108, 52, 0, 524, 525, 3, 92, 44, 0, 525, 526, 3, 110, 53, 0, 526, 527, 1, 0, 0, 0, 527, 528, 6, 54, 6, 0, 528, 113, 1, 0, 0, 0, 529, 530, 3, 108, 52, 0, 530, 531, 3, 92, 44, 0, 531, 532, 3, 106, 51, 0, 532, 533, 1, 0, 0, 0, 533, 534, 6, 55, 6, 0, 534, 115, 1, 0, 0, 0, 535, 536, 3, 108, 52, 0, 536, 537, 1, 0, 0, 0, 537, 538, 6, 56, 6, 0, 538, 117, 1, 0, 0, 0, 539, 540, 3, 106, 51, 0, 540, 541, 1, 0, 0, 0, 541, 542, 6, 57, 6, 0, 542, 119, 1, 0, 0, 0, 543, 544, 3, 4, 0, 0, 544, 545, 1, 0, 0, 0, 545, 546, 6, 58, 0, 0, 546, 121, 1, 0, 0, 0, 547, 548, 3, 20, 8, 0, 548, 549, 1, 0, 0, 0, 549, 550, 6, 59, 9, 0, 550, 123, 1, 0, 0, 0, 551, 552, 3, 22, 9, 0, 552, 553, 1, 0, 0, 0, 553, 554, 6, 60, 10, 0, 554, 125, 1, 0, 0, 0, 555, 556, 5, 125, 0, 0, 556, 557, 1, 0, 0, 0, 557, 558, 6, 61, 6, 0, 558, 127, 1, 0, 0, 0, 559, 560, 3, 34, 15, 0, 560, 561, 1, 0, 0, 0, 561, 562, 6, 62, 7, 0, 562, 129, 1, 0, 0, 0, 563, 564, 3, 36, 16, 0, 564, 565, 1, 0, 0, 0, 565, 566, 6, 63, 8, 0, 566, 131, 1, 0, 0, 0, 567, 568, 3, 38, 17, 0, 568, 569, 1, 0, 0, 0, 569, 570, 6, 64, 11, 0, 570, 133, 1, 0, 0, 0, 571, 572, 3, 18, 7, 0, 572, 573, 1, 0, 0, 0, 573, 574, 6, 65, 12, 0, 574, 575, 6, 65, 2, 0, 575, 135, 1, 0, 0, 0, 576, 577, 3, 4, 0, 0, 577, 578, 1, 0, 0, 0, 578, 579, 6, 66, 0, 0, 579, 137, 1, 0, 0, 0, 580, 581, 3, 6, 1, 0, 581, 582, 1, 0, 0, 0, 582, 583, 6, 67, 13, 0, 583, 139, 1, 0, 0, 0, 584, 585, 3, 8, 2, 0, 585, 586, 1, 0, 0, 0, 586, 587, 6, 68, 14, 0, 587, 141, 1, 0, 0, 0, 588, 589, 3, 22, 9, 0, 589, 590, 1, 0, 0, 0, 590, 591, 6, 69, 10, 0, 591, 143, 1, 0, 0, 0, 592, 593, 3, 42, 19, 0, 593, 594, 1, 0, 0, 0, 594, 595, 6, 70, 15, 0, 595, 596, 6, 70, 16, 0, 596, 145, 1, 0, 0, 0, 597, 598, 3, 10, 3, 0, 598, 599, 1, 0, 0, 0, 599, 600, 6, 71, 4, 0, 600, 601, 6, 71, 17, 0, 601, 147, 1, 0, 0, 0, 602, 603, 3, 14, 5, 0, 603, 604, 1, 0, 0, 0, 604, 605, 6, 72, 18, 0, 605, 606, 6, 72, 6, 0, 606, 149, 1, 0, 0, 0, 607, 608, 3, 46, 21, 0, 608, 609, 1, 0, 0, 0, 609, 610, 6, 73, 19, 0, 610, 151, 1, 0, 0, 0, 611, 612, 3, 34, 15, 0, 612, 613, 1, 0, 0, 0, 613, 614, 6, 74, 7, 0, 614, 153, 1, 0, 0, 0, 615, 616, 3, 52, 24, 0, 616, 617, 1, 0, 0, 0, 617, 618, 6, 75, 20, 0, 618, 155, 1, 0, 0, 0, 619, 620, 3, 36, 16, 0, 620, 621, 1, 0, 0, 0, 621, 622, 6, 76, 8, 0, 622, 157, 1, 0, 0, 0, 623, 624, 3, 56, 26, 0, 624, 625, 1, 0, 0, 0, 625, 626, 6, 77, 21, 0, 626, 159, 1, 0, 0, 0, 627, 628, 3, 64, 30, 0, 628, 629, 1, 0, 0, 0, 629, 630, 6, 78, 22, 0, 630, 161, 1, 0, 0, 0, 631, 632, 3, 66, 31, 0, 632, 633, 1, 0, 0, 0, 633, 634, 6, 79, 23, 0, 634, 163, 1, 0, 0, 0, 635, 636, 3, 68, 32, 0, 636, 637, 1, 0, 0, 0, 637, 638, 6, 80, 24, 0, 638, 165, 1, 0, 0, 0, 639, 640, 3, 78, 37, 0, 640, 641, 1, 0, 0, 0, 641, 642, 6, 81, 25, 0, 642, 167, 1, 0, 0, 0, 643, 644, 3, 80, 38, 0, 644, 645, 1, 0, 0, 0, 645, 646, 6, 82, 26, 0, 646, 169, 1, 0, 0, 0, 647, 648, 3, 82, 39, 0, 648, 649, 1, 0, 0, 0, 649, 650, 6, 83, 27, 0, 650, 171, 1, 0, 0, 0, 651, 652, 3, 84, 40, 0, 652, 653, 1, 0, 0, 0, 653, 654, 6, 84, 28, 0, 654, 173, 1, 0, 0, 0, 655, 656, 3, 112, 54, 0, 656, 657, 1, 0, 0, 0, 657, 658, 6, 85, 29, 0, 658, 175, 1, 0, 0, 0, 659, 660, 3, 114, 55, 0, 660, 661, 1, 0, 0, 0, 661, 662, 6, 86, 30, 0, 662, 177, 1, 0, 0, 0, 663, 664, 3, 116, 56, 0, 664, 665, 1, 0, 0, 0, 665, 666, 6, 87, 31, 0, 666, 179, 1, 0, 0, 0, 667, 668, 3, 118, 57, 0, 668, 669, 1, 0, 0, 0, 669, 670, 6, 88, 32, 0, 670, 181, 1, 0, 0, 0, 41, 0, 1, 2, 3, 185, 190, 195, 201, 234, 255, 257, 266, 274, 276, 300, 306, 310, 323, 325, 346, 357, 365, 367, 377, 379, 384, 393, 403, 412, 419, 421, 423, 434, 436, 448, 450, 462, 464, 495, 504, 512, 33, 6, 0, 0, 0, 2, 0, 5, 1, 0, 2, 2, 0, 7, 4, 0, 2, 3, 0, 4, 0, 0, 7, 11, 0, 7, 12, 0, 7, 9, 0, 7, 10, 0, 7, 13, 0, 7, 8, 0, 7, 2, 0, 7, 3, 0, 7, 15, 0, 5, 2, 0, 5, 3, 0, 7, 6, 0, 7, 16, 0, 7, 17, 0, 7, 18, 0, 7, 19, 0, 7, 20, 0, 7, 21, 0, 7, 22, 0, 7, 23, 0, 7, 24, 0, 7, 25, 0, 7, 26, 0, 7, 27, 0, 7, 28, 0, 7, 29, 0] \ No newline at end of file diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.java new file mode 100644 index 00000000000..2a739910ab1 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.java @@ -0,0 +1,585 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Generated from java-escape by ANTLR 4.11.1 +package org.openrewrite.toml.internal.grammar; + +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.ATN; +import org.antlr.v4.runtime.atn.ATNDeserializer; +import org.antlr.v4.runtime.atn.LexerATNSimulator; +import org.antlr.v4.runtime.atn.PredictionContextCache; +import org.antlr.v4.runtime.dfa.DFA; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) +public class TomlLexer extends Lexer { + static { RuntimeMetaData.checkVersion("4.11.1", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + WS=1, NL=2, COMMENT=3, L_BRACKET=4, DOUBLE_L_BRACKET=5, R_BRACKET=6, DOUBLE_R_BRACKET=7, + EQUALS=8, DOT=9, COMMA=10, BASIC_STRING=11, LITERAL_STRING=12, UNQUOTED_KEY=13, + VALUE_WS=14, L_BRACE=15, BOOLEAN=16, ML_BASIC_STRING=17, ML_LITERAL_STRING=18, + FLOAT=19, INF=20, NAN=21, DEC_INT=22, HEX_INT=23, OCT_INT=24, BIN_INT=25, + OFFSET_DATE_TIME=26, LOCAL_DATE_TIME=27, LOCAL_DATE=28, LOCAL_TIME=29, + INLINE_TABLE_WS=30, R_BRACE=31, ARRAY_WS=32; + public static final int + COMMENTS_CHANNEL=2; + public static final int + SIMPLE_VALUE_MODE=1, INLINE_TABLE_MODE=2, ARRAY_MODE=3; + public static String[] channelNames = { + "DEFAULT_TOKEN_CHANNEL", "HIDDEN", "COMMENTS_CHANNEL" + }; + + public static String[] modeNames = { + "DEFAULT_MODE", "SIMPLE_VALUE_MODE", "INLINE_TABLE_MODE", "ARRAY_MODE" + }; + + private static String[] makeRuleNames() { + return new String[] { + "WS", "NL", "COMMENT", "L_BRACKET", "DOUBLE_L_BRACKET", "R_BRACKET", + "DOUBLE_R_BRACKET", "EQUALS", "DOT", "COMMA", "DIGIT", "ALPHA", "ESC", + "UNICODE", "EX_UNICODE", "BASIC_STRING", "LITERAL_STRING", "UNQUOTED_KEY", + "VALUE_WS", "L_BRACE", "ARRAY_START", "BOOLEAN", "ML_ESC", "VALUE_BASIC_STRING", + "ML_BASIC_STRING", "VALUE_LITERAL_STRING", "ML_LITERAL_STRING", "EXP", + "ZERO_PREFIXABLE_INT", "FRAC", "FLOAT", "INF", "NAN", "HEX_DIGIT", "DIGIT_1_9", + "DIGIT_0_7", "DIGIT_0_1", "DEC_INT", "HEX_INT", "OCT_INT", "BIN_INT", + "YEAR", "MONTH", "DAY", "DELIM", "HOUR", "MINUTE", "SECOND", "SECFRAC", + "NUMOFFSET", "OFFSET", "PARTIAL_TIME", "FULL_DATE", "FULL_TIME", "OFFSET_DATE_TIME", + "LOCAL_DATE_TIME", "LOCAL_DATE", "LOCAL_TIME", "INLINE_TABLE_WS", "INLINE_TABLE_KEY_DOT", + "INLINE_TABLE_COMMA", "R_BRACE", "INLINE_TABLE_KEY_BASIC_STRING", "INLINE_TABLE_KEY_LITERAL_STRING", + "INLINE_TABLE_KEY_UNQUOTED", "INLINE_TABLE_EQUALS", "ARRAY_WS", "ARRAY_NL", + "ARRAY_COMMENT", "ARRAY_COMMA", "ARRAY_INLINE_TABLE_START", "NESTED_ARRAY_START", + "ARRAY_END", "ARRAY_BOOLEAN", "ARRAY_BASIC_STRING", "ARRAY_ML_BASIC_STRING", + "ARRAY_LITERAL_STRING", "ARRAY_ML_LITERAL_STRING", "ARRAY_FLOAT", "ARRAY_INF", + "ARRAY_NAN", "ARRAY_DEC_INT", "ARRAY_HEX_INT", "ARRAY_OCT_INT", "ARRAY_BIN_INT", + "ARRAY_OFFSET_DATE_TIME", "ARRAY_LOCAL_DATE_TIME", "ARRAY_LOCAL_DATE", + "ARRAY_LOCAL_TIME" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, null, null, null, "'['", "'[['", "']'", "']]'", "'='", "'.'", "','", + null, null, null, null, "'{'", null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, "'}'" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, "WS", "NL", "COMMENT", "L_BRACKET", "DOUBLE_L_BRACKET", "R_BRACKET", + "DOUBLE_R_BRACKET", "EQUALS", "DOT", "COMMA", "BASIC_STRING", "LITERAL_STRING", + "UNQUOTED_KEY", "VALUE_WS", "L_BRACE", "BOOLEAN", "ML_BASIC_STRING", + "ML_LITERAL_STRING", "FLOAT", "INF", "NAN", "DEC_INT", "HEX_INT", "OCT_INT", + "BIN_INT", "OFFSET_DATE_TIME", "LOCAL_DATE_TIME", "LOCAL_DATE", "LOCAL_TIME", + "INLINE_TABLE_WS", "R_BRACE", "ARRAY_WS" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + + public TomlLexer(CharStream input) { + super(input); + _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + @Override + public String getGrammarFileName() { return "TomlLexer.g4"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public String[] getChannelNames() { return channelNames; } + + @Override + public String[] getModeNames() { return modeNames; } + + @Override + public ATN getATN() { return _ATN; } + + public static final String _serializedATN = + "\u0004\u0000 \u029f\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ + "\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ + "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ + "\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b\u0002"+ + "\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002\u000f\u0007\u000f"+ + "\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002\u0012\u0007\u0012"+ + "\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002\u0015\u0007\u0015"+ + "\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0002\u0018\u0007\u0018"+ + "\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002\u001b\u0007\u001b"+ + "\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002\u001e\u0007\u001e"+ + "\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007!\u0002\"\u0007\"\u0002"+ + "#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007&\u0002\'\u0007\'\u0002"+ + "(\u0007(\u0002)\u0007)\u0002*\u0007*\u0002+\u0007+\u0002,\u0007,\u0002"+ + "-\u0007-\u0002.\u0007.\u0002/\u0007/\u00020\u00070\u00021\u00071\u0002"+ + "2\u00072\u00023\u00073\u00024\u00074\u00025\u00075\u00026\u00076\u0002"+ + "7\u00077\u00028\u00078\u00029\u00079\u0002:\u0007:\u0002;\u0007;\u0002"+ + "<\u0007<\u0002=\u0007=\u0002>\u0007>\u0002?\u0007?\u0002@\u0007@\u0002"+ + "A\u0007A\u0002B\u0007B\u0002C\u0007C\u0002D\u0007D\u0002E\u0007E\u0002"+ + "F\u0007F\u0002G\u0007G\u0002H\u0007H\u0002I\u0007I\u0002J\u0007J\u0002"+ + "K\u0007K\u0002L\u0007L\u0002M\u0007M\u0002N\u0007N\u0002O\u0007O\u0002"+ + "P\u0007P\u0002Q\u0007Q\u0002R\u0007R\u0002S\u0007S\u0002T\u0007T\u0002"+ + "U\u0007U\u0002V\u0007V\u0002W\u0007W\u0002X\u0007X\u0001\u0000\u0004\u0000"+ + "\u00b8\b\u0000\u000b\u0000\f\u0000\u00b9\u0001\u0000\u0001\u0000\u0001"+ + "\u0001\u0003\u0001\u00bf\b\u0001\u0001\u0001\u0004\u0001\u00c2\b\u0001"+ + "\u000b\u0001\f\u0001\u00c3\u0001\u0002\u0001\u0002\u0005\u0002\u00c8\b"+ + "\u0002\n\u0002\f\u0002\u00cb\t\u0002\u0001\u0002\u0001\u0002\u0001\u0003"+ + "\u0001\u0003\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005"+ + "\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007"+ + "\u0001\u0007\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\n\u0001"+ + "\n\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001\f\u0003\f\u00eb"+ + "\b\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\u000e\u0001"+ + "\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001"+ + "\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001\u000f\u0005"+ + "\u000f\u0100\b\u000f\n\u000f\f\u000f\u0103\t\u000f\u0001\u000f\u0001\u000f"+ + "\u0001\u0010\u0001\u0010\u0005\u0010\u0109\b\u0010\n\u0010\f\u0010\u010c"+ + "\t\u0010\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0004"+ + "\u0011\u0113\b\u0011\u000b\u0011\f\u0011\u0114\u0001\u0012\u0001\u0012"+ + "\u0001\u0012\u0001\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013"+ + "\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015"+ + "\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015"+ + "\u0001\u0015\u0001\u0015\u0003\u0015\u012d\b\u0015\u0001\u0015\u0001\u0015"+ + "\u0001\u0016\u0001\u0016\u0003\u0016\u0133\b\u0016\u0001\u0016\u0001\u0016"+ + "\u0003\u0016\u0137\b\u0016\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017"+ + "\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018"+ + "\u0001\u0018\u0005\u0018\u0144\b\u0018\n\u0018\f\u0018\u0147\t\u0018\u0001"+ + "\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001"+ + "\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u001a\u0001"+ + "\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0005\u001a\u0159\b\u001a\n"+ + "\u001a\f\u001a\u015c\t\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001"+ + "\u001a\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0003\u001b\u0166"+ + "\b\u001b\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001\u001c\u0001"+ + "\u001c\u0005\u001c\u016e\b\u001c\n\u001c\f\u001c\u0171\t\u001c\u0001\u001d"+ + "\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e"+ + "\u0003\u001e\u017a\b\u001e\u0003\u001e\u017c\b\u001e\u0001\u001e\u0001"+ + "\u001e\u0001\u001f\u0003\u001f\u0181\b\u001f\u0001\u001f\u0001\u001f\u0001"+ + "\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001 \u0003 \u018a\b \u0001"+ + " \u0001 \u0001 \u0001 \u0001 \u0001 \u0001!\u0001!\u0003!\u0194\b!\u0001"+ + "\"\u0001\"\u0001#\u0001#\u0001$\u0001$\u0001%\u0003%\u019d\b%\u0001%\u0001"+ + "%\u0001%\u0001%\u0001%\u0004%\u01a4\b%\u000b%\f%\u01a5\u0003%\u01a8\b"+ + "%\u0001%\u0001%\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0005"+ + "&\u01b3\b&\n&\f&\u01b6\t&\u0001&\u0001&\u0001\'\u0001\'\u0001\'\u0001"+ + "\'\u0001\'\u0001\'\u0001\'\u0005\'\u01c1\b\'\n\'\f\'\u01c4\t\'\u0001\'"+ + "\u0001\'\u0001(\u0001(\u0001(\u0001(\u0001(\u0001(\u0001(\u0005(\u01cf"+ + "\b(\n(\f(\u01d2\t(\u0001(\u0001(\u0001)\u0001)\u0001)\u0001)\u0001)\u0001"+ + "*\u0001*\u0001*\u0001+\u0001+\u0001+\u0001,\u0001,\u0001-\u0001-\u0001"+ + "-\u0001.\u0001.\u0001.\u0001/\u0001/\u0001/\u00010\u00010\u00040\u01ee"+ + "\b0\u000b0\f0\u01ef\u00011\u00011\u00011\u00011\u00011\u00012\u00012\u0003"+ + "2\u01f9\b2\u00013\u00013\u00013\u00013\u00013\u00013\u00033\u0201\b3\u0001"+ + "4\u00014\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u00016\u0001"+ + "6\u00016\u00016\u00016\u00016\u00017\u00017\u00017\u00017\u00017\u0001"+ + "7\u00018\u00018\u00018\u00018\u00019\u00019\u00019\u00019\u0001:\u0001"+ + ":\u0001:\u0001:\u0001;\u0001;\u0001;\u0001;\u0001<\u0001<\u0001<\u0001"+ + "<\u0001=\u0001=\u0001=\u0001=\u0001>\u0001>\u0001>\u0001>\u0001?\u0001"+ + "?\u0001?\u0001?\u0001@\u0001@\u0001@\u0001@\u0001A\u0001A\u0001A\u0001"+ + "A\u0001A\u0001B\u0001B\u0001B\u0001B\u0001C\u0001C\u0001C\u0001C\u0001"+ + "D\u0001D\u0001D\u0001D\u0001E\u0001E\u0001E\u0001E\u0001F\u0001F\u0001"+ + "F\u0001F\u0001F\u0001G\u0001G\u0001G\u0001G\u0001G\u0001H\u0001H\u0001"+ + "H\u0001H\u0001H\u0001I\u0001I\u0001I\u0001I\u0001J\u0001J\u0001J\u0001"+ + "J\u0001K\u0001K\u0001K\u0001K\u0001L\u0001L\u0001L\u0001L\u0001M\u0001"+ + "M\u0001M\u0001M\u0001N\u0001N\u0001N\u0001N\u0001O\u0001O\u0001O\u0001"+ + "O\u0001P\u0001P\u0001P\u0001P\u0001Q\u0001Q\u0001Q\u0001Q\u0001R\u0001"+ + "R\u0001R\u0001R\u0001S\u0001S\u0001S\u0001S\u0001T\u0001T\u0001T\u0001"+ + "T\u0001U\u0001U\u0001U\u0001U\u0001V\u0001V\u0001V\u0001V\u0001W\u0001"+ + "W\u0001W\u0001W\u0001X\u0001X\u0001X\u0001X\u0004\u0101\u010a\u0145\u015a"+ + "\u0000Y\u0004\u0001\u0006\u0002\b\u0003\n\u0004\f\u0005\u000e\u0006\u0010"+ + "\u0007\u0012\b\u0014\t\u0016\n\u0018\u0000\u001a\u0000\u001c\u0000\u001e"+ + "\u0000 \u0000\"\u000b$\f&\r(\u000e*\u000f,\u0000.\u00100\u00002\u0000"+ + "4\u00116\u00008\u0012:\u0000<\u0000>\u0000@\u0013B\u0014D\u0015F\u0000"+ + "H\u0000J\u0000L\u0000N\u0016P\u0017R\u0018T\u0019V\u0000X\u0000Z\u0000"+ + "\\\u0000^\u0000`\u0000b\u0000d\u0000f\u0000h\u0000j\u0000l\u0000n\u0000"+ + "p\u001ar\u001bt\u001cv\u001dx\u001ez\u0000|\u0000~\u001f\u0080\u0000\u0082"+ + "\u0000\u0084\u0000\u0086\u0000\u0088 \u008a\u0000\u008c\u0000\u008e\u0000"+ + "\u0090\u0000\u0092\u0000\u0094\u0000\u0096\u0000\u0098\u0000\u009a\u0000"+ + "\u009c\u0000\u009e\u0000\u00a0\u0000\u00a2\u0000\u00a4\u0000\u00a6\u0000"+ + "\u00a8\u0000\u00aa\u0000\u00ac\u0000\u00ae\u0000\u00b0\u0000\u00b2\u0000"+ + "\u00b4\u0000\u0004\u0000\u0001\u0002\u0003\u0010\u0002\u0000\t\t \u0002"+ + "\u0000\n\n\r\r\u0001\u000009\u0002\u0000AZaz\b\u0000\"\"//\\\\bbffnnr"+ + "rtt\u0003\u0000\n\n\"\"\\\\\u0002\u0000\n\n\'\'\u0002\u0000--__\u0002"+ + "\u0000\"\"\\\\\u0002\u0000EEee\u0002\u0000++--\u0002\u0000AFaf\u0001\u0000"+ + "19\u0001\u000007\u0001\u000001\u0003\u0000 TTtt\u02a8\u0000\u0004\u0001"+ + "\u0000\u0000\u0000\u0000\u0006\u0001\u0000\u0000\u0000\u0000\b\u0001\u0000"+ + "\u0000\u0000\u0000\n\u0001\u0000\u0000\u0000\u0000\f\u0001\u0000\u0000"+ + "\u0000\u0000\u000e\u0001\u0000\u0000\u0000\u0000\u0010\u0001\u0000\u0000"+ + "\u0000\u0000\u0012\u0001\u0000\u0000\u0000\u0000\u0014\u0001\u0000\u0000"+ + "\u0000\u0000\u0016\u0001\u0000\u0000\u0000\u0000\"\u0001\u0000\u0000\u0000"+ + "\u0000$\u0001\u0000\u0000\u0000\u0000&\u0001\u0000\u0000\u0000\u0001("+ + "\u0001\u0000\u0000\u0000\u0001*\u0001\u0000\u0000\u0000\u0001,\u0001\u0000"+ + "\u0000\u0000\u0001.\u0001\u0000\u0000\u0000\u00012\u0001\u0000\u0000\u0000"+ + "\u00014\u0001\u0000\u0000\u0000\u00016\u0001\u0000\u0000\u0000\u00018"+ + "\u0001\u0000\u0000\u0000\u0001@\u0001\u0000\u0000\u0000\u0001B\u0001\u0000"+ + "\u0000\u0000\u0001D\u0001\u0000\u0000\u0000\u0001N\u0001\u0000\u0000\u0000"+ + "\u0001P\u0001\u0000\u0000\u0000\u0001R\u0001\u0000\u0000\u0000\u0001T"+ + "\u0001\u0000\u0000\u0000\u0001p\u0001\u0000\u0000\u0000\u0001r\u0001\u0000"+ + "\u0000\u0000\u0001t\u0001\u0000\u0000\u0000\u0001v\u0001\u0000\u0000\u0000"+ + "\u0002x\u0001\u0000\u0000\u0000\u0002z\u0001\u0000\u0000\u0000\u0002|"+ + "\u0001\u0000\u0000\u0000\u0002~\u0001\u0000\u0000\u0000\u0002\u0080\u0001"+ + "\u0000\u0000\u0000\u0002\u0082\u0001\u0000\u0000\u0000\u0002\u0084\u0001"+ + "\u0000\u0000\u0000\u0002\u0086\u0001\u0000\u0000\u0000\u0003\u0088\u0001"+ + "\u0000\u0000\u0000\u0003\u008a\u0001\u0000\u0000\u0000\u0003\u008c\u0001"+ + "\u0000\u0000\u0000\u0003\u008e\u0001\u0000\u0000\u0000\u0003\u0090\u0001"+ + "\u0000\u0000\u0000\u0003\u0092\u0001\u0000\u0000\u0000\u0003\u0094\u0001"+ + "\u0000\u0000\u0000\u0003\u0096\u0001\u0000\u0000\u0000\u0003\u0098\u0001"+ + "\u0000\u0000\u0000\u0003\u009a\u0001\u0000\u0000\u0000\u0003\u009c\u0001"+ + "\u0000\u0000\u0000\u0003\u009e\u0001\u0000\u0000\u0000\u0003\u00a0\u0001"+ + "\u0000\u0000\u0000\u0003\u00a2\u0001\u0000\u0000\u0000\u0003\u00a4\u0001"+ + "\u0000\u0000\u0000\u0003\u00a6\u0001\u0000\u0000\u0000\u0003\u00a8\u0001"+ + "\u0000\u0000\u0000\u0003\u00aa\u0001\u0000\u0000\u0000\u0003\u00ac\u0001"+ + "\u0000\u0000\u0000\u0003\u00ae\u0001\u0000\u0000\u0000\u0003\u00b0\u0001"+ + "\u0000\u0000\u0000\u0003\u00b2\u0001\u0000\u0000\u0000\u0003\u00b4\u0001"+ + "\u0000\u0000\u0000\u0004\u00b7\u0001\u0000\u0000\u0000\u0006\u00c1\u0001"+ + "\u0000\u0000\u0000\b\u00c5\u0001\u0000\u0000\u0000\n\u00ce\u0001\u0000"+ + "\u0000\u0000\f\u00d0\u0001\u0000\u0000\u0000\u000e\u00d3\u0001\u0000\u0000"+ + "\u0000\u0010\u00d5\u0001\u0000\u0000\u0000\u0012\u00d8\u0001\u0000\u0000"+ + "\u0000\u0014\u00dc\u0001\u0000\u0000\u0000\u0016\u00de\u0001\u0000\u0000"+ + "\u0000\u0018\u00e2\u0001\u0000\u0000\u0000\u001a\u00e4\u0001\u0000\u0000"+ + "\u0000\u001c\u00e6\u0001\u0000\u0000\u0000\u001e\u00ec\u0001\u0000\u0000"+ + "\u0000 \u00f2\u0001\u0000\u0000\u0000\"\u00fc\u0001\u0000\u0000\u0000"+ + "$\u0106\u0001\u0000\u0000\u0000&\u0112\u0001\u0000\u0000\u0000(\u0116"+ + "\u0001\u0000\u0000\u0000*\u011a\u0001\u0000\u0000\u0000,\u011e\u0001\u0000"+ + "\u0000\u0000.\u012c\u0001\u0000\u0000\u00000\u0136\u0001\u0000\u0000\u0000"+ + "2\u0138\u0001\u0000\u0000\u00004\u013d\u0001\u0000\u0000\u00006\u014e"+ + "\u0001\u0000\u0000\u00008\u0153\u0001\u0000\u0000\u0000:\u0163\u0001\u0000"+ + "\u0000\u0000<\u0169\u0001\u0000\u0000\u0000>\u0172\u0001\u0000\u0000\u0000"+ + "@\u0175\u0001\u0000\u0000\u0000B\u0180\u0001\u0000\u0000\u0000D\u0189"+ + "\u0001\u0000\u0000\u0000F\u0193\u0001\u0000\u0000\u0000H\u0195\u0001\u0000"+ + "\u0000\u0000J\u0197\u0001\u0000\u0000\u0000L\u0199\u0001\u0000\u0000\u0000"+ + "N\u019c\u0001\u0000\u0000\u0000P\u01ab\u0001\u0000\u0000\u0000R\u01b9"+ + "\u0001\u0000\u0000\u0000T\u01c7\u0001\u0000\u0000\u0000V\u01d5\u0001\u0000"+ + "\u0000\u0000X\u01da\u0001\u0000\u0000\u0000Z\u01dd\u0001\u0000\u0000\u0000"+ + "\\\u01e0\u0001\u0000\u0000\u0000^\u01e2\u0001\u0000\u0000\u0000`\u01e5"+ + "\u0001\u0000\u0000\u0000b\u01e8\u0001\u0000\u0000\u0000d\u01eb\u0001\u0000"+ + "\u0000\u0000f\u01f1\u0001\u0000\u0000\u0000h\u01f8\u0001\u0000\u0000\u0000"+ + "j\u01fa\u0001\u0000\u0000\u0000l\u0202\u0001\u0000\u0000\u0000n\u0208"+ + "\u0001\u0000\u0000\u0000p\u020b\u0001\u0000\u0000\u0000r\u0211\u0001\u0000"+ + "\u0000\u0000t\u0217\u0001\u0000\u0000\u0000v\u021b\u0001\u0000\u0000\u0000"+ + "x\u021f\u0001\u0000\u0000\u0000z\u0223\u0001\u0000\u0000\u0000|\u0227"+ + "\u0001\u0000\u0000\u0000~\u022b\u0001\u0000\u0000\u0000\u0080\u022f\u0001"+ + "\u0000\u0000\u0000\u0082\u0233\u0001\u0000\u0000\u0000\u0084\u0237\u0001"+ + "\u0000\u0000\u0000\u0086\u023b\u0001\u0000\u0000\u0000\u0088\u0240\u0001"+ + "\u0000\u0000\u0000\u008a\u0244\u0001\u0000\u0000\u0000\u008c\u0248\u0001"+ + "\u0000\u0000\u0000\u008e\u024c\u0001\u0000\u0000\u0000\u0090\u0250\u0001"+ + "\u0000\u0000\u0000\u0092\u0255\u0001\u0000\u0000\u0000\u0094\u025a\u0001"+ + "\u0000\u0000\u0000\u0096\u025f\u0001\u0000\u0000\u0000\u0098\u0263\u0001"+ + "\u0000\u0000\u0000\u009a\u0267\u0001\u0000\u0000\u0000\u009c\u026b\u0001"+ + "\u0000\u0000\u0000\u009e\u026f\u0001\u0000\u0000\u0000\u00a0\u0273\u0001"+ + "\u0000\u0000\u0000\u00a2\u0277\u0001\u0000\u0000\u0000\u00a4\u027b\u0001"+ + "\u0000\u0000\u0000\u00a6\u027f\u0001\u0000\u0000\u0000\u00a8\u0283\u0001"+ + "\u0000\u0000\u0000\u00aa\u0287\u0001\u0000\u0000\u0000\u00ac\u028b\u0001"+ + "\u0000\u0000\u0000\u00ae\u028f\u0001\u0000\u0000\u0000\u00b0\u0293\u0001"+ + "\u0000\u0000\u0000\u00b2\u0297\u0001\u0000\u0000\u0000\u00b4\u029b\u0001"+ + "\u0000\u0000\u0000\u00b6\u00b8\u0007\u0000\u0000\u0000\u00b7\u00b6\u0001"+ + "\u0000\u0000\u0000\u00b8\u00b9\u0001\u0000\u0000\u0000\u00b9\u00b7\u0001"+ + "\u0000\u0000\u0000\u00b9\u00ba\u0001\u0000\u0000\u0000\u00ba\u00bb\u0001"+ + "\u0000\u0000\u0000\u00bb\u00bc\u0006\u0000\u0000\u0000\u00bc\u0005\u0001"+ + "\u0000\u0000\u0000\u00bd\u00bf\u0005\r\u0000\u0000\u00be\u00bd\u0001\u0000"+ + "\u0000\u0000\u00be\u00bf\u0001\u0000\u0000\u0000\u00bf\u00c0\u0001\u0000"+ + "\u0000\u0000\u00c0\u00c2\u0005\n\u0000\u0000\u00c1\u00be\u0001\u0000\u0000"+ + "\u0000\u00c2\u00c3\u0001\u0000\u0000\u0000\u00c3\u00c1\u0001\u0000\u0000"+ + "\u0000\u00c3\u00c4\u0001\u0000\u0000\u0000\u00c4\u0007\u0001\u0000\u0000"+ + "\u0000\u00c5\u00c9\u0005#\u0000\u0000\u00c6\u00c8\b\u0001\u0000\u0000"+ + "\u00c7\u00c6\u0001\u0000\u0000\u0000\u00c8\u00cb\u0001\u0000\u0000\u0000"+ + "\u00c9\u00c7\u0001\u0000\u0000\u0000\u00c9\u00ca\u0001\u0000\u0000\u0000"+ + "\u00ca\u00cc\u0001\u0000\u0000\u0000\u00cb\u00c9\u0001\u0000\u0000\u0000"+ + "\u00cc\u00cd\u0006\u0002\u0001\u0000\u00cd\t\u0001\u0000\u0000\u0000\u00ce"+ + "\u00cf\u0005[\u0000\u0000\u00cf\u000b\u0001\u0000\u0000\u0000\u00d0\u00d1"+ + "\u0005[\u0000\u0000\u00d1\u00d2\u0005[\u0000\u0000\u00d2\r\u0001\u0000"+ + "\u0000\u0000\u00d3\u00d4\u0005]\u0000\u0000\u00d4\u000f\u0001\u0000\u0000"+ + "\u0000\u00d5\u00d6\u0005]\u0000\u0000\u00d6\u00d7\u0005]\u0000\u0000\u00d7"+ + "\u0011\u0001\u0000\u0000\u0000\u00d8\u00d9\u0005=\u0000\u0000\u00d9\u00da"+ + "\u0001\u0000\u0000\u0000\u00da\u00db\u0006\u0007\u0002\u0000\u00db\u0013"+ + "\u0001\u0000\u0000\u0000\u00dc\u00dd\u0005.\u0000\u0000\u00dd\u0015\u0001"+ + "\u0000\u0000\u0000\u00de\u00df\u0005,\u0000\u0000\u00df\u00e0\u0001\u0000"+ + "\u0000\u0000\u00e0\u00e1\u0006\t\u0000\u0000\u00e1\u0017\u0001\u0000\u0000"+ + "\u0000\u00e2\u00e3\u0007\u0002\u0000\u0000\u00e3\u0019\u0001\u0000\u0000"+ + "\u0000\u00e4\u00e5\u0007\u0003\u0000\u0000\u00e5\u001b\u0001\u0000\u0000"+ + "\u0000\u00e6\u00ea\u0005\\\u0000\u0000\u00e7\u00eb\u0007\u0004\u0000\u0000"+ + "\u00e8\u00eb\u0003\u001e\r\u0000\u00e9\u00eb\u0003 \u000e\u0000\u00ea"+ + "\u00e7\u0001\u0000\u0000\u0000\u00ea\u00e8\u0001\u0000\u0000\u0000\u00ea"+ + "\u00e9\u0001\u0000\u0000\u0000\u00eb\u001d\u0001\u0000\u0000\u0000\u00ec"+ + "\u00ed\u0005u\u0000\u0000\u00ed\u00ee\u0003F!\u0000\u00ee\u00ef\u0003"+ + "F!\u0000\u00ef\u00f0\u0003F!\u0000\u00f0\u00f1\u0003F!\u0000\u00f1\u001f"+ + "\u0001\u0000\u0000\u0000\u00f2\u00f3\u0005U\u0000\u0000\u00f3\u00f4\u0003"+ + "F!\u0000\u00f4\u00f5\u0003F!\u0000\u00f5\u00f6\u0003F!\u0000\u00f6\u00f7"+ + "\u0003F!\u0000\u00f7\u00f8\u0003F!\u0000\u00f8\u00f9\u0003F!\u0000\u00f9"+ + "\u00fa\u0003F!\u0000\u00fa\u00fb\u0003F!\u0000\u00fb!\u0001\u0000\u0000"+ + "\u0000\u00fc\u0101\u0005\"\u0000\u0000\u00fd\u0100\u0003\u001c\f\u0000"+ + "\u00fe\u0100\b\u0005\u0000\u0000\u00ff\u00fd\u0001\u0000\u0000\u0000\u00ff"+ + "\u00fe\u0001\u0000\u0000\u0000\u0100\u0103\u0001\u0000\u0000\u0000\u0101"+ + "\u0102\u0001\u0000\u0000\u0000\u0101\u00ff\u0001\u0000\u0000\u0000\u0102"+ + "\u0104\u0001\u0000\u0000\u0000\u0103\u0101\u0001\u0000\u0000\u0000\u0104"+ + "\u0105\u0005\"\u0000\u0000\u0105#\u0001\u0000\u0000\u0000\u0106\u010a"+ + "\u0005\'\u0000\u0000\u0107\u0109\b\u0006\u0000\u0000\u0108\u0107\u0001"+ + "\u0000\u0000\u0000\u0109\u010c\u0001\u0000\u0000\u0000\u010a\u010b\u0001"+ + "\u0000\u0000\u0000\u010a\u0108\u0001\u0000\u0000\u0000\u010b\u010d\u0001"+ + "\u0000\u0000\u0000\u010c\u010a\u0001\u0000\u0000\u0000\u010d\u010e\u0005"+ + "\'\u0000\u0000\u010e%\u0001\u0000\u0000\u0000\u010f\u0113\u0003\u001a"+ + "\u000b\u0000\u0110\u0113\u0003\u0018\n\u0000\u0111\u0113\u0007\u0007\u0000"+ + "\u0000\u0112\u010f\u0001\u0000\u0000\u0000\u0112\u0110\u0001\u0000\u0000"+ + "\u0000\u0112\u0111\u0001\u0000\u0000\u0000\u0113\u0114\u0001\u0000\u0000"+ + "\u0000\u0114\u0112\u0001\u0000\u0000\u0000\u0114\u0115\u0001\u0000\u0000"+ + "\u0000\u0115\'\u0001\u0000\u0000\u0000\u0116\u0117\u0003\u0004\u0000\u0000"+ + "\u0117\u0118\u0001\u0000\u0000\u0000\u0118\u0119\u0006\u0012\u0000\u0000"+ + "\u0119)\u0001\u0000\u0000\u0000\u011a\u011b\u0005{\u0000\u0000\u011b\u011c"+ + "\u0001\u0000\u0000\u0000\u011c\u011d\u0006\u0013\u0003\u0000\u011d+\u0001"+ + "\u0000\u0000\u0000\u011e\u011f\u0003\n\u0003\u0000\u011f\u0120\u0001\u0000"+ + "\u0000\u0000\u0120\u0121\u0006\u0014\u0004\u0000\u0121\u0122\u0006\u0014"+ + "\u0005\u0000\u0122-\u0001\u0000\u0000\u0000\u0123\u0124\u0005t\u0000\u0000"+ + "\u0124\u0125\u0005r\u0000\u0000\u0125\u0126\u0005u\u0000\u0000\u0126\u012d"+ + "\u0005e\u0000\u0000\u0127\u0128\u0005f\u0000\u0000\u0128\u0129\u0005a"+ + "\u0000\u0000\u0129\u012a\u0005l\u0000\u0000\u012a\u012b\u0005s\u0000\u0000"+ + "\u012b\u012d\u0005e\u0000\u0000\u012c\u0123\u0001\u0000\u0000\u0000\u012c"+ + "\u0127\u0001\u0000\u0000\u0000\u012d\u012e\u0001\u0000\u0000\u0000\u012e"+ + "\u012f\u0006\u0015\u0006\u0000\u012f/\u0001\u0000\u0000\u0000\u0130\u0132"+ + "\u0005\\\u0000\u0000\u0131\u0133\u0005\r\u0000\u0000\u0132\u0131\u0001"+ + "\u0000\u0000\u0000\u0132\u0133\u0001\u0000\u0000\u0000\u0133\u0134\u0001"+ + "\u0000\u0000\u0000\u0134\u0137\u0005\n\u0000\u0000\u0135\u0137\u0003\u001c"+ + "\f\u0000\u0136\u0130\u0001\u0000\u0000\u0000\u0136\u0135\u0001\u0000\u0000"+ + "\u0000\u01371\u0001\u0000\u0000\u0000\u0138\u0139\u0003\"\u000f\u0000"+ + "\u0139\u013a\u0001\u0000\u0000\u0000\u013a\u013b\u0006\u0017\u0007\u0000"+ + "\u013b\u013c\u0006\u0017\u0006\u0000\u013c3\u0001\u0000\u0000\u0000\u013d"+ + "\u013e\u0005\"\u0000\u0000\u013e\u013f\u0005\"\u0000\u0000\u013f\u0140"+ + "\u0005\"\u0000\u0000\u0140\u0145\u0001\u0000\u0000\u0000\u0141\u0144\u0003"+ + "0\u0016\u0000\u0142\u0144\b\b\u0000\u0000\u0143\u0141\u0001\u0000\u0000"+ + "\u0000\u0143\u0142\u0001\u0000\u0000\u0000\u0144\u0147\u0001\u0000\u0000"+ + "\u0000\u0145\u0146\u0001\u0000\u0000\u0000\u0145\u0143\u0001\u0000\u0000"+ + "\u0000\u0146\u0148\u0001\u0000\u0000\u0000\u0147\u0145\u0001\u0000\u0000"+ + "\u0000\u0148\u0149\u0005\"\u0000\u0000\u0149\u014a\u0005\"\u0000\u0000"+ + "\u014a\u014b\u0005\"\u0000\u0000\u014b\u014c\u0001\u0000\u0000\u0000\u014c"+ + "\u014d\u0006\u0018\u0006\u0000\u014d5\u0001\u0000\u0000\u0000\u014e\u014f"+ + "\u0003$\u0010\u0000\u014f\u0150\u0001\u0000\u0000\u0000\u0150\u0151\u0006"+ + "\u0019\b\u0000\u0151\u0152\u0006\u0019\u0006\u0000\u01527\u0001\u0000"+ + "\u0000\u0000\u0153\u0154\u0005\'\u0000\u0000\u0154\u0155\u0005\'\u0000"+ + "\u0000\u0155\u0156\u0005\'\u0000\u0000\u0156\u015a\u0001\u0000\u0000\u0000"+ + "\u0157\u0159\t\u0000\u0000\u0000\u0158\u0157\u0001\u0000\u0000\u0000\u0159"+ + "\u015c\u0001\u0000\u0000\u0000\u015a\u015b\u0001\u0000\u0000\u0000\u015a"+ + "\u0158\u0001\u0000\u0000\u0000\u015b\u015d\u0001\u0000\u0000\u0000\u015c"+ + "\u015a\u0001\u0000\u0000\u0000\u015d\u015e\u0005\'\u0000\u0000\u015e\u015f"+ + "\u0005\'\u0000\u0000\u015f\u0160\u0005\'\u0000\u0000\u0160\u0161\u0001"+ + "\u0000\u0000\u0000\u0161\u0162\u0006\u001a\u0006\u0000\u01629\u0001\u0000"+ + "\u0000\u0000\u0163\u0165\u0007\t\u0000\u0000\u0164\u0166\u0007\n\u0000"+ + "\u0000\u0165\u0164\u0001\u0000\u0000\u0000\u0165\u0166\u0001\u0000\u0000"+ + "\u0000\u0166\u0167\u0001\u0000\u0000\u0000\u0167\u0168\u0003<\u001c\u0000"+ + "\u0168;\u0001\u0000\u0000\u0000\u0169\u016f\u0003\u0018\n\u0000\u016a"+ + "\u016e\u0003\u0018\n\u0000\u016b\u016c\u0005_\u0000\u0000\u016c\u016e"+ + "\u0003\u0018\n\u0000\u016d\u016a\u0001\u0000\u0000\u0000\u016d\u016b\u0001"+ + "\u0000\u0000\u0000\u016e\u0171\u0001\u0000\u0000\u0000\u016f\u016d\u0001"+ + "\u0000\u0000\u0000\u016f\u0170\u0001\u0000\u0000\u0000\u0170=\u0001\u0000"+ + "\u0000\u0000\u0171\u016f\u0001\u0000\u0000\u0000\u0172\u0173\u0005.\u0000"+ + "\u0000\u0173\u0174\u0003<\u001c\u0000\u0174?\u0001\u0000\u0000\u0000\u0175"+ + "\u017b\u0003N%\u0000\u0176\u017c\u0003:\u001b\u0000\u0177\u0179\u0003"+ + ">\u001d\u0000\u0178\u017a\u0003:\u001b\u0000\u0179\u0178\u0001\u0000\u0000"+ + "\u0000\u0179\u017a\u0001\u0000\u0000\u0000\u017a\u017c\u0001\u0000\u0000"+ + "\u0000\u017b\u0176\u0001\u0000\u0000\u0000\u017b\u0177\u0001\u0000\u0000"+ + "\u0000\u017c\u017d\u0001\u0000\u0000\u0000\u017d\u017e\u0006\u001e\u0006"+ + "\u0000\u017eA\u0001\u0000\u0000\u0000\u017f\u0181\u0007\n\u0000\u0000"+ + "\u0180\u017f\u0001\u0000\u0000\u0000\u0180\u0181\u0001\u0000\u0000\u0000"+ + "\u0181\u0182\u0001\u0000\u0000\u0000\u0182\u0183\u0005i\u0000\u0000\u0183"+ + "\u0184\u0005n\u0000\u0000\u0184\u0185\u0005f\u0000\u0000\u0185\u0186\u0001"+ + "\u0000\u0000\u0000\u0186\u0187\u0006\u001f\u0006\u0000\u0187C\u0001\u0000"+ + "\u0000\u0000\u0188\u018a\u0007\n\u0000\u0000\u0189\u0188\u0001\u0000\u0000"+ + "\u0000\u0189\u018a\u0001\u0000\u0000\u0000\u018a\u018b\u0001\u0000\u0000"+ + "\u0000\u018b\u018c\u0005n\u0000\u0000\u018c\u018d\u0005a\u0000\u0000\u018d"+ + "\u018e\u0005n\u0000\u0000\u018e\u018f\u0001\u0000\u0000\u0000\u018f\u0190"+ + "\u0006 \u0006\u0000\u0190E\u0001\u0000\u0000\u0000\u0191\u0194\u0007\u000b"+ + "\u0000\u0000\u0192\u0194\u0003\u0018\n\u0000\u0193\u0191\u0001\u0000\u0000"+ + "\u0000\u0193\u0192\u0001\u0000\u0000\u0000\u0194G\u0001\u0000\u0000\u0000"+ + "\u0195\u0196\u0007\f\u0000\u0000\u0196I\u0001\u0000\u0000\u0000\u0197"+ + "\u0198\u0007\r\u0000\u0000\u0198K\u0001\u0000\u0000\u0000\u0199\u019a"+ + "\u0007\u000e\u0000\u0000\u019aM\u0001\u0000\u0000\u0000\u019b\u019d\u0007"+ + "\n\u0000\u0000\u019c\u019b\u0001\u0000\u0000\u0000\u019c\u019d\u0001\u0000"+ + "\u0000\u0000\u019d\u01a7\u0001\u0000\u0000\u0000\u019e\u01a8\u0003\u0018"+ + "\n\u0000\u019f\u01a3\u0003H\"\u0000\u01a0\u01a4\u0003\u0018\n\u0000\u01a1"+ + "\u01a2\u0005_\u0000\u0000\u01a2\u01a4\u0003\u0018\n\u0000\u01a3\u01a0"+ + "\u0001\u0000\u0000\u0000\u01a3\u01a1\u0001\u0000\u0000\u0000\u01a4\u01a5"+ + "\u0001\u0000\u0000\u0000\u01a5\u01a3\u0001\u0000\u0000\u0000\u01a5\u01a6"+ + "\u0001\u0000\u0000\u0000\u01a6\u01a8\u0001\u0000\u0000\u0000\u01a7\u019e"+ + "\u0001\u0000\u0000\u0000\u01a7\u019f\u0001\u0000\u0000\u0000\u01a8\u01a9"+ + "\u0001\u0000\u0000\u0000\u01a9\u01aa\u0006%\u0006\u0000\u01aaO\u0001\u0000"+ + "\u0000\u0000\u01ab\u01ac\u00050\u0000\u0000\u01ac\u01ad\u0005x\u0000\u0000"+ + "\u01ad\u01ae\u0001\u0000\u0000\u0000\u01ae\u01b4\u0003F!\u0000\u01af\u01b3"+ + "\u0003F!\u0000\u01b0\u01b1\u0005_\u0000\u0000\u01b1\u01b3\u0003F!\u0000"+ + "\u01b2\u01af\u0001\u0000\u0000\u0000\u01b2\u01b0\u0001\u0000\u0000\u0000"+ + "\u01b3\u01b6\u0001\u0000\u0000\u0000\u01b4\u01b2\u0001\u0000\u0000\u0000"+ + "\u01b4\u01b5\u0001\u0000\u0000\u0000\u01b5\u01b7\u0001\u0000\u0000\u0000"+ + "\u01b6\u01b4\u0001\u0000\u0000\u0000\u01b7\u01b8\u0006&\u0006\u0000\u01b8"+ + "Q\u0001\u0000\u0000\u0000\u01b9\u01ba\u00050\u0000\u0000\u01ba\u01bb\u0005"+ + "o\u0000\u0000\u01bb\u01bc\u0001\u0000\u0000\u0000\u01bc\u01c2\u0003J#"+ + "\u0000\u01bd\u01c1\u0003J#\u0000\u01be\u01bf\u0005_\u0000\u0000\u01bf"+ + "\u01c1\u0003J#\u0000\u01c0\u01bd\u0001\u0000\u0000\u0000\u01c0\u01be\u0001"+ + "\u0000\u0000\u0000\u01c1\u01c4\u0001\u0000\u0000\u0000\u01c2\u01c0\u0001"+ + "\u0000\u0000\u0000\u01c2\u01c3\u0001\u0000\u0000\u0000\u01c3\u01c5\u0001"+ + "\u0000\u0000\u0000\u01c4\u01c2\u0001\u0000\u0000\u0000\u01c5\u01c6\u0006"+ + "\'\u0006\u0000\u01c6S\u0001\u0000\u0000\u0000\u01c7\u01c8\u00050\u0000"+ + "\u0000\u01c8\u01c9\u0005b\u0000\u0000\u01c9\u01ca\u0001\u0000\u0000\u0000"+ + "\u01ca\u01d0\u0003L$\u0000\u01cb\u01cf\u0003L$\u0000\u01cc\u01cd\u0005"+ + "_\u0000\u0000\u01cd\u01cf\u0003L$\u0000\u01ce\u01cb\u0001\u0000\u0000"+ + "\u0000\u01ce\u01cc\u0001\u0000\u0000\u0000\u01cf\u01d2\u0001\u0000\u0000"+ + "\u0000\u01d0\u01ce\u0001\u0000\u0000\u0000\u01d0\u01d1\u0001\u0000\u0000"+ + "\u0000\u01d1\u01d3\u0001\u0000\u0000\u0000\u01d2\u01d0\u0001\u0000\u0000"+ + "\u0000\u01d3\u01d4\u0006(\u0006\u0000\u01d4U\u0001\u0000\u0000\u0000\u01d5"+ + "\u01d6\u0003\u0018\n\u0000\u01d6\u01d7\u0003\u0018\n\u0000\u01d7\u01d8"+ + "\u0003\u0018\n\u0000\u01d8\u01d9\u0003\u0018\n\u0000\u01d9W\u0001\u0000"+ + "\u0000\u0000\u01da\u01db\u0003\u0018\n\u0000\u01db\u01dc\u0003\u0018\n"+ + "\u0000\u01dcY\u0001\u0000\u0000\u0000\u01dd\u01de\u0003\u0018\n\u0000"+ + "\u01de\u01df\u0003\u0018\n\u0000\u01df[\u0001\u0000\u0000\u0000\u01e0"+ + "\u01e1\u0007\u000f\u0000\u0000\u01e1]\u0001\u0000\u0000\u0000\u01e2\u01e3"+ + "\u0003\u0018\n\u0000\u01e3\u01e4\u0003\u0018\n\u0000\u01e4_\u0001\u0000"+ + "\u0000\u0000\u01e5\u01e6\u0003\u0018\n\u0000\u01e6\u01e7\u0003\u0018\n"+ + "\u0000\u01e7a\u0001\u0000\u0000\u0000\u01e8\u01e9\u0003\u0018\n\u0000"+ + "\u01e9\u01ea\u0003\u0018\n\u0000\u01eac\u0001\u0000\u0000\u0000\u01eb"+ + "\u01ed\u0005.\u0000\u0000\u01ec\u01ee\u0003\u0018\n\u0000\u01ed\u01ec"+ + "\u0001\u0000\u0000\u0000\u01ee\u01ef\u0001\u0000\u0000\u0000\u01ef\u01ed"+ + "\u0001\u0000\u0000\u0000\u01ef\u01f0\u0001\u0000\u0000\u0000\u01f0e\u0001"+ + "\u0000\u0000\u0000\u01f1\u01f2\u0007\n\u0000\u0000\u01f2\u01f3\u0003^"+ + "-\u0000\u01f3\u01f4\u0005:\u0000\u0000\u01f4\u01f5\u0003`.\u0000\u01f5"+ + "g\u0001\u0000\u0000\u0000\u01f6\u01f9\u0005Z\u0000\u0000\u01f7\u01f9\u0003"+ + "f1\u0000\u01f8\u01f6\u0001\u0000\u0000\u0000\u01f8\u01f7\u0001\u0000\u0000"+ + "\u0000\u01f9i\u0001\u0000\u0000\u0000\u01fa\u01fb\u0003^-\u0000\u01fb"+ + "\u01fc\u0005:\u0000\u0000\u01fc\u01fd\u0003`.\u0000\u01fd\u01fe\u0005"+ + ":\u0000\u0000\u01fe\u0200\u0003b/\u0000\u01ff\u0201\u0003d0\u0000\u0200"+ + "\u01ff\u0001\u0000\u0000\u0000\u0200\u0201\u0001\u0000\u0000\u0000\u0201"+ + "k\u0001\u0000\u0000\u0000\u0202\u0203\u0003V)\u0000\u0203\u0204\u0005"+ + "-\u0000\u0000\u0204\u0205\u0003X*\u0000\u0205\u0206\u0005-\u0000\u0000"+ + "\u0206\u0207\u0003Z+\u0000\u0207m\u0001\u0000\u0000\u0000\u0208\u0209"+ + "\u0003j3\u0000\u0209\u020a\u0003h2\u0000\u020ao\u0001\u0000\u0000\u0000"+ + "\u020b\u020c\u0003l4\u0000\u020c\u020d\u0003\\,\u0000\u020d\u020e\u0003"+ + "n5\u0000\u020e\u020f\u0001\u0000\u0000\u0000\u020f\u0210\u00066\u0006"+ + "\u0000\u0210q\u0001\u0000\u0000\u0000\u0211\u0212\u0003l4\u0000\u0212"+ + "\u0213\u0003\\,\u0000\u0213\u0214\u0003j3\u0000\u0214\u0215\u0001\u0000"+ + "\u0000\u0000\u0215\u0216\u00067\u0006\u0000\u0216s\u0001\u0000\u0000\u0000"+ + "\u0217\u0218\u0003l4\u0000\u0218\u0219\u0001\u0000\u0000\u0000\u0219\u021a"+ + "\u00068\u0006\u0000\u021au\u0001\u0000\u0000\u0000\u021b\u021c\u0003j"+ + "3\u0000\u021c\u021d\u0001\u0000\u0000\u0000\u021d\u021e\u00069\u0006\u0000"+ + "\u021ew\u0001\u0000\u0000\u0000\u021f\u0220\u0003\u0004\u0000\u0000\u0220"+ + "\u0221\u0001\u0000\u0000\u0000\u0221\u0222\u0006:\u0000\u0000\u0222y\u0001"+ + "\u0000\u0000\u0000\u0223\u0224\u0003\u0014\b\u0000\u0224\u0225\u0001\u0000"+ + "\u0000\u0000\u0225\u0226\u0006;\t\u0000\u0226{\u0001\u0000\u0000\u0000"+ + "\u0227\u0228\u0003\u0016\t\u0000\u0228\u0229\u0001\u0000\u0000\u0000\u0229"+ + "\u022a\u0006<\n\u0000\u022a}\u0001\u0000\u0000\u0000\u022b\u022c\u0005"+ + "}\u0000\u0000\u022c\u022d\u0001\u0000\u0000\u0000\u022d\u022e\u0006=\u0006"+ + "\u0000\u022e\u007f\u0001\u0000\u0000\u0000\u022f\u0230\u0003\"\u000f\u0000"+ + "\u0230\u0231\u0001\u0000\u0000\u0000\u0231\u0232\u0006>\u0007\u0000\u0232"+ + "\u0081\u0001\u0000\u0000\u0000\u0233\u0234\u0003$\u0010\u0000\u0234\u0235"+ + "\u0001\u0000\u0000\u0000\u0235\u0236\u0006?\b\u0000\u0236\u0083\u0001"+ + "\u0000\u0000\u0000\u0237\u0238\u0003&\u0011\u0000\u0238\u0239\u0001\u0000"+ + "\u0000\u0000\u0239\u023a\u0006@\u000b\u0000\u023a\u0085\u0001\u0000\u0000"+ + "\u0000\u023b\u023c\u0003\u0012\u0007\u0000\u023c\u023d\u0001\u0000\u0000"+ + "\u0000\u023d\u023e\u0006A\f\u0000\u023e\u023f\u0006A\u0002\u0000\u023f"+ + "\u0087\u0001\u0000\u0000\u0000\u0240\u0241\u0003\u0004\u0000\u0000\u0241"+ + "\u0242\u0001\u0000\u0000\u0000\u0242\u0243\u0006B\u0000\u0000\u0243\u0089"+ + "\u0001\u0000\u0000\u0000\u0244\u0245\u0003\u0006\u0001\u0000\u0245\u0246"+ + "\u0001\u0000\u0000\u0000\u0246\u0247\u0006C\r\u0000\u0247\u008b\u0001"+ + "\u0000\u0000\u0000\u0248\u0249\u0003\b\u0002\u0000\u0249\u024a\u0001\u0000"+ + "\u0000\u0000\u024a\u024b\u0006D\u000e\u0000\u024b\u008d\u0001\u0000\u0000"+ + "\u0000\u024c\u024d\u0003\u0016\t\u0000\u024d\u024e\u0001\u0000\u0000\u0000"+ + "\u024e\u024f\u0006E\n\u0000\u024f\u008f\u0001\u0000\u0000\u0000\u0250"+ + "\u0251\u0003*\u0013\u0000\u0251\u0252\u0001\u0000\u0000\u0000\u0252\u0253"+ + "\u0006F\u000f\u0000\u0253\u0254\u0006F\u0010\u0000\u0254\u0091\u0001\u0000"+ + "\u0000\u0000\u0255\u0256\u0003\n\u0003\u0000\u0256\u0257\u0001\u0000\u0000"+ + "\u0000\u0257\u0258\u0006G\u0004\u0000\u0258\u0259\u0006G\u0011\u0000\u0259"+ + "\u0093\u0001\u0000\u0000\u0000\u025a\u025b\u0003\u000e\u0005\u0000\u025b"+ + "\u025c\u0001\u0000\u0000\u0000\u025c\u025d\u0006H\u0012\u0000\u025d\u025e"+ + "\u0006H\u0006\u0000\u025e\u0095\u0001\u0000\u0000\u0000\u025f\u0260\u0003"+ + ".\u0015\u0000\u0260\u0261\u0001\u0000\u0000\u0000\u0261\u0262\u0006I\u0013"+ + "\u0000\u0262\u0097\u0001\u0000\u0000\u0000\u0263\u0264\u0003\"\u000f\u0000"+ + "\u0264\u0265\u0001\u0000\u0000\u0000\u0265\u0266\u0006J\u0007\u0000\u0266"+ + "\u0099\u0001\u0000\u0000\u0000\u0267\u0268\u00034\u0018\u0000\u0268\u0269"+ + "\u0001\u0000\u0000\u0000\u0269\u026a\u0006K\u0014\u0000\u026a\u009b\u0001"+ + "\u0000\u0000\u0000\u026b\u026c\u0003$\u0010\u0000\u026c\u026d\u0001\u0000"+ + "\u0000\u0000\u026d\u026e\u0006L\b\u0000\u026e\u009d\u0001\u0000\u0000"+ + "\u0000\u026f\u0270\u00038\u001a\u0000\u0270\u0271\u0001\u0000\u0000\u0000"+ + "\u0271\u0272\u0006M\u0015\u0000\u0272\u009f\u0001\u0000\u0000\u0000\u0273"+ + "\u0274\u0003@\u001e\u0000\u0274\u0275\u0001\u0000\u0000\u0000\u0275\u0276"+ + "\u0006N\u0016\u0000\u0276\u00a1\u0001\u0000\u0000\u0000\u0277\u0278\u0003"+ + "B\u001f\u0000\u0278\u0279\u0001\u0000\u0000\u0000\u0279\u027a\u0006O\u0017"+ + "\u0000\u027a\u00a3\u0001\u0000\u0000\u0000\u027b\u027c\u0003D \u0000\u027c"+ + "\u027d\u0001\u0000\u0000\u0000\u027d\u027e\u0006P\u0018\u0000\u027e\u00a5"+ + "\u0001\u0000\u0000\u0000\u027f\u0280\u0003N%\u0000\u0280\u0281\u0001\u0000"+ + "\u0000\u0000\u0281\u0282\u0006Q\u0019\u0000\u0282\u00a7\u0001\u0000\u0000"+ + "\u0000\u0283\u0284\u0003P&\u0000\u0284\u0285\u0001\u0000\u0000\u0000\u0285"+ + "\u0286\u0006R\u001a\u0000\u0286\u00a9\u0001\u0000\u0000\u0000\u0287\u0288"+ + "\u0003R\'\u0000\u0288\u0289\u0001\u0000\u0000\u0000\u0289\u028a\u0006"+ + "S\u001b\u0000\u028a\u00ab\u0001\u0000\u0000\u0000\u028b\u028c\u0003T("+ + "\u0000\u028c\u028d\u0001\u0000\u0000\u0000\u028d\u028e\u0006T\u001c\u0000"+ + "\u028e\u00ad\u0001\u0000\u0000\u0000\u028f\u0290\u0003p6\u0000\u0290\u0291"+ + "\u0001\u0000\u0000\u0000\u0291\u0292\u0006U\u001d\u0000\u0292\u00af\u0001"+ + "\u0000\u0000\u0000\u0293\u0294\u0003r7\u0000\u0294\u0295\u0001\u0000\u0000"+ + "\u0000\u0295\u0296\u0006V\u001e\u0000\u0296\u00b1\u0001\u0000\u0000\u0000"+ + "\u0297\u0298\u0003t8\u0000\u0298\u0299\u0001\u0000\u0000\u0000\u0299\u029a"+ + "\u0006W\u001f\u0000\u029a\u00b3\u0001\u0000\u0000\u0000\u029b\u029c\u0003"+ + "v9\u0000\u029c\u029d\u0001\u0000\u0000\u0000\u029d\u029e\u0006X \u0000"+ + "\u029e\u00b5\u0001\u0000\u0000\u0000)\u0000\u0001\u0002\u0003\u00b9\u00be"+ + "\u00c3\u00c9\u00ea\u00ff\u0101\u010a\u0112\u0114\u012c\u0132\u0136\u0143"+ + "\u0145\u015a\u0165\u016d\u016f\u0179\u017b\u0180\u0189\u0193\u019c\u01a3"+ + "\u01a5\u01a7\u01b2\u01b4\u01c0\u01c2\u01ce\u01d0\u01ef\u01f8\u0200!\u0006"+ + "\u0000\u0000\u0000\u0002\u0000\u0005\u0001\u0000\u0002\u0002\u0000\u0007"+ + "\u0004\u0000\u0002\u0003\u0000\u0004\u0000\u0000\u0007\u000b\u0000\u0007"+ + "\f\u0000\u0007\t\u0000\u0007\n\u0000\u0007\r\u0000\u0007\b\u0000\u0007"+ + "\u0002\u0000\u0007\u0003\u0000\u0007\u000f\u0000\u0005\u0002\u0000\u0005"+ + "\u0003\u0000\u0007\u0006\u0000\u0007\u0010\u0000\u0007\u0011\u0000\u0007"+ + "\u0012\u0000\u0007\u0013\u0000\u0007\u0014\u0000\u0007\u0015\u0000\u0007"+ + "\u0016\u0000\u0007\u0017\u0000\u0007\u0018\u0000\u0007\u0019\u0000\u0007"+ + "\u001a\u0000\u0007\u001b\u0000\u0007\u001c\u0000\u0007\u001d\u0000"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.tokens b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.tokens new file mode 100644 index 00000000000..080a49ecbae --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.tokens @@ -0,0 +1,41 @@ +WS=1 +NL=2 +COMMENT=3 +L_BRACKET=4 +DOUBLE_L_BRACKET=5 +R_BRACKET=6 +DOUBLE_R_BRACKET=7 +EQUALS=8 +DOT=9 +COMMA=10 +BASIC_STRING=11 +LITERAL_STRING=12 +UNQUOTED_KEY=13 +VALUE_WS=14 +L_BRACE=15 +BOOLEAN=16 +ML_BASIC_STRING=17 +ML_LITERAL_STRING=18 +FLOAT=19 +INF=20 +NAN=21 +DEC_INT=22 +HEX_INT=23 +OCT_INT=24 +BIN_INT=25 +OFFSET_DATE_TIME=26 +LOCAL_DATE_TIME=27 +LOCAL_DATE=28 +LOCAL_TIME=29 +INLINE_TABLE_WS=30 +R_BRACE=31 +ARRAY_WS=32 +'['=4 +'[['=5 +']'=6 +']]'=7 +'='=8 +'.'=9 +','=10 +'{'=15 +'}'=31 diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.interp b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.interp new file mode 100644 index 00000000000..826b7607270 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.interp @@ -0,0 +1,96 @@ +token literal names: +null +null +null +null +'[' +'[[' +']' +']]' +'=' +'.' +',' +null +null +null +null +'{' +null +null +null +null +null +null +null +null +null +null +null +null +null +null +null +'}' +null + +token symbolic names: +null +WS +NL +COMMENT +L_BRACKET +DOUBLE_L_BRACKET +R_BRACKET +DOUBLE_R_BRACKET +EQUALS +DOT +COMMA +BASIC_STRING +LITERAL_STRING +UNQUOTED_KEY +VALUE_WS +L_BRACE +BOOLEAN +ML_BASIC_STRING +ML_LITERAL_STRING +FLOAT +INF +NAN +DEC_INT +HEX_INT +OCT_INT +BIN_INT +OFFSET_DATE_TIME +LOCAL_DATE_TIME +LOCAL_DATE +LOCAL_TIME +INLINE_TABLE_WS +R_BRACE +ARRAY_WS + +rule names: +document +expression +comment +keyValue +key +simpleKey +unquotedKey +quotedKey +dottedKey +value +string +integer +floatingPoint +bool +dateTime +commentOrNl +array +table +standardTable +inlineTable +arrayTable + + +atn: +[4, 1, 32, 235, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 1, 0, 3, 0, 44, 8, 0, 1, 0, 1, 0, 3, 0, 48, 8, 0, 5, 0, 50, 8, 0, 10, 0, 12, 0, 53, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 59, 8, 1, 1, 1, 1, 1, 3, 1, 63, 8, 1, 1, 1, 3, 1, 66, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 76, 8, 4, 1, 5, 1, 5, 3, 5, 80, 8, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 4, 8, 89, 8, 8, 11, 8, 12, 8, 90, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 100, 8, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 3, 15, 115, 8, 15, 1, 16, 1, 16, 5, 16, 119, 8, 16, 10, 16, 12, 16, 122, 9, 16, 1, 16, 1, 16, 1, 16, 5, 16, 127, 8, 16, 10, 16, 12, 16, 130, 9, 16, 1, 16, 1, 16, 1, 16, 5, 16, 135, 8, 16, 10, 16, 12, 16, 138, 9, 16, 1, 16, 1, 16, 3, 16, 142, 8, 16, 5, 16, 144, 8, 16, 10, 16, 12, 16, 147, 9, 16, 1, 16, 5, 16, 150, 8, 16, 10, 16, 12, 16, 153, 9, 16, 1, 16, 1, 16, 3, 16, 157, 8, 16, 1, 17, 1, 17, 3, 17, 161, 8, 17, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 167, 8, 18, 10, 18, 12, 18, 170, 9, 18, 1, 18, 5, 18, 173, 8, 18, 10, 18, 12, 18, 176, 9, 18, 1, 19, 1, 19, 5, 19, 180, 8, 19, 10, 19, 12, 19, 183, 9, 19, 1, 19, 1, 19, 1, 19, 5, 19, 188, 8, 19, 10, 19, 12, 19, 191, 9, 19, 1, 19, 1, 19, 1, 19, 5, 19, 196, 8, 19, 10, 19, 12, 19, 199, 9, 19, 1, 19, 1, 19, 3, 19, 203, 8, 19, 5, 19, 205, 8, 19, 10, 19, 12, 19, 208, 9, 19, 1, 19, 5, 19, 211, 8, 19, 10, 19, 12, 19, 214, 9, 19, 1, 19, 1, 19, 3, 19, 218, 8, 19, 1, 20, 1, 20, 1, 20, 1, 20, 5, 20, 224, 8, 20, 10, 20, 12, 20, 227, 9, 20, 1, 20, 5, 20, 230, 8, 20, 10, 20, 12, 20, 233, 9, 20, 1, 20, 0, 0, 21, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 0, 5, 1, 0, 11, 12, 2, 0, 11, 12, 17, 18, 1, 0, 22, 25, 1, 0, 19, 21, 1, 0, 26, 29, 249, 0, 43, 1, 0, 0, 0, 2, 65, 1, 0, 0, 0, 4, 67, 1, 0, 0, 0, 6, 69, 1, 0, 0, 0, 8, 75, 1, 0, 0, 0, 10, 79, 1, 0, 0, 0, 12, 81, 1, 0, 0, 0, 14, 83, 1, 0, 0, 0, 16, 85, 1, 0, 0, 0, 18, 99, 1, 0, 0, 0, 20, 101, 1, 0, 0, 0, 22, 103, 1, 0, 0, 0, 24, 105, 1, 0, 0, 0, 26, 107, 1, 0, 0, 0, 28, 109, 1, 0, 0, 0, 30, 114, 1, 0, 0, 0, 32, 156, 1, 0, 0, 0, 34, 160, 1, 0, 0, 0, 36, 162, 1, 0, 0, 0, 38, 217, 1, 0, 0, 0, 40, 219, 1, 0, 0, 0, 42, 44, 3, 2, 1, 0, 43, 42, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 51, 1, 0, 0, 0, 45, 47, 5, 2, 0, 0, 46, 48, 3, 2, 1, 0, 47, 46, 1, 0, 0, 0, 47, 48, 1, 0, 0, 0, 48, 50, 1, 0, 0, 0, 49, 45, 1, 0, 0, 0, 50, 53, 1, 0, 0, 0, 51, 49, 1, 0, 0, 0, 51, 52, 1, 0, 0, 0, 52, 54, 1, 0, 0, 0, 53, 51, 1, 0, 0, 0, 54, 55, 5, 0, 0, 1, 55, 1, 1, 0, 0, 0, 56, 58, 3, 6, 3, 0, 57, 59, 3, 4, 2, 0, 58, 57, 1, 0, 0, 0, 58, 59, 1, 0, 0, 0, 59, 66, 1, 0, 0, 0, 60, 62, 3, 34, 17, 0, 61, 63, 3, 4, 2, 0, 62, 61, 1, 0, 0, 0, 62, 63, 1, 0, 0, 0, 63, 66, 1, 0, 0, 0, 64, 66, 3, 4, 2, 0, 65, 56, 1, 0, 0, 0, 65, 60, 1, 0, 0, 0, 65, 64, 1, 0, 0, 0, 66, 3, 1, 0, 0, 0, 67, 68, 5, 3, 0, 0, 68, 5, 1, 0, 0, 0, 69, 70, 3, 8, 4, 0, 70, 71, 5, 8, 0, 0, 71, 72, 3, 18, 9, 0, 72, 7, 1, 0, 0, 0, 73, 76, 3, 10, 5, 0, 74, 76, 3, 16, 8, 0, 75, 73, 1, 0, 0, 0, 75, 74, 1, 0, 0, 0, 76, 9, 1, 0, 0, 0, 77, 80, 3, 14, 7, 0, 78, 80, 3, 12, 6, 0, 79, 77, 1, 0, 0, 0, 79, 78, 1, 0, 0, 0, 80, 11, 1, 0, 0, 0, 81, 82, 5, 13, 0, 0, 82, 13, 1, 0, 0, 0, 83, 84, 7, 0, 0, 0, 84, 15, 1, 0, 0, 0, 85, 88, 3, 10, 5, 0, 86, 87, 5, 9, 0, 0, 87, 89, 3, 10, 5, 0, 88, 86, 1, 0, 0, 0, 89, 90, 1, 0, 0, 0, 90, 88, 1, 0, 0, 0, 90, 91, 1, 0, 0, 0, 91, 17, 1, 0, 0, 0, 92, 100, 3, 20, 10, 0, 93, 100, 3, 22, 11, 0, 94, 100, 3, 24, 12, 0, 95, 100, 3, 26, 13, 0, 96, 100, 3, 28, 14, 0, 97, 100, 3, 32, 16, 0, 98, 100, 3, 38, 19, 0, 99, 92, 1, 0, 0, 0, 99, 93, 1, 0, 0, 0, 99, 94, 1, 0, 0, 0, 99, 95, 1, 0, 0, 0, 99, 96, 1, 0, 0, 0, 99, 97, 1, 0, 0, 0, 99, 98, 1, 0, 0, 0, 100, 19, 1, 0, 0, 0, 101, 102, 7, 1, 0, 0, 102, 21, 1, 0, 0, 0, 103, 104, 7, 2, 0, 0, 104, 23, 1, 0, 0, 0, 105, 106, 7, 3, 0, 0, 106, 25, 1, 0, 0, 0, 107, 108, 5, 16, 0, 0, 108, 27, 1, 0, 0, 0, 109, 110, 7, 4, 0, 0, 110, 29, 1, 0, 0, 0, 111, 112, 5, 3, 0, 0, 112, 115, 5, 2, 0, 0, 113, 115, 5, 2, 0, 0, 114, 111, 1, 0, 0, 0, 114, 113, 1, 0, 0, 0, 115, 31, 1, 0, 0, 0, 116, 120, 5, 4, 0, 0, 117, 119, 3, 30, 15, 0, 118, 117, 1, 0, 0, 0, 119, 122, 1, 0, 0, 0, 120, 118, 1, 0, 0, 0, 120, 121, 1, 0, 0, 0, 121, 123, 1, 0, 0, 0, 122, 120, 1, 0, 0, 0, 123, 157, 5, 6, 0, 0, 124, 128, 5, 4, 0, 0, 125, 127, 3, 30, 15, 0, 126, 125, 1, 0, 0, 0, 127, 130, 1, 0, 0, 0, 128, 126, 1, 0, 0, 0, 128, 129, 1, 0, 0, 0, 129, 131, 1, 0, 0, 0, 130, 128, 1, 0, 0, 0, 131, 145, 3, 18, 9, 0, 132, 136, 5, 10, 0, 0, 133, 135, 3, 30, 15, 0, 134, 133, 1, 0, 0, 0, 135, 138, 1, 0, 0, 0, 136, 134, 1, 0, 0, 0, 136, 137, 1, 0, 0, 0, 137, 139, 1, 0, 0, 0, 138, 136, 1, 0, 0, 0, 139, 141, 3, 18, 9, 0, 140, 142, 5, 10, 0, 0, 141, 140, 1, 0, 0, 0, 141, 142, 1, 0, 0, 0, 142, 144, 1, 0, 0, 0, 143, 132, 1, 0, 0, 0, 144, 147, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 145, 146, 1, 0, 0, 0, 146, 151, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 148, 150, 3, 30, 15, 0, 149, 148, 1, 0, 0, 0, 150, 153, 1, 0, 0, 0, 151, 149, 1, 0, 0, 0, 151, 152, 1, 0, 0, 0, 152, 154, 1, 0, 0, 0, 153, 151, 1, 0, 0, 0, 154, 155, 5, 6, 0, 0, 155, 157, 1, 0, 0, 0, 156, 116, 1, 0, 0, 0, 156, 124, 1, 0, 0, 0, 157, 33, 1, 0, 0, 0, 158, 161, 3, 36, 18, 0, 159, 161, 3, 40, 20, 0, 160, 158, 1, 0, 0, 0, 160, 159, 1, 0, 0, 0, 161, 35, 1, 0, 0, 0, 162, 163, 5, 4, 0, 0, 163, 164, 3, 8, 4, 0, 164, 174, 5, 6, 0, 0, 165, 167, 3, 30, 15, 0, 166, 165, 1, 0, 0, 0, 167, 170, 1, 0, 0, 0, 168, 166, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 171, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 173, 3, 2, 1, 0, 172, 168, 1, 0, 0, 0, 173, 176, 1, 0, 0, 0, 174, 172, 1, 0, 0, 0, 174, 175, 1, 0, 0, 0, 175, 37, 1, 0, 0, 0, 176, 174, 1, 0, 0, 0, 177, 181, 5, 15, 0, 0, 178, 180, 3, 30, 15, 0, 179, 178, 1, 0, 0, 0, 180, 183, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 181, 182, 1, 0, 0, 0, 182, 184, 1, 0, 0, 0, 183, 181, 1, 0, 0, 0, 184, 218, 5, 31, 0, 0, 185, 189, 5, 15, 0, 0, 186, 188, 3, 30, 15, 0, 187, 186, 1, 0, 0, 0, 188, 191, 1, 0, 0, 0, 189, 187, 1, 0, 0, 0, 189, 190, 1, 0, 0, 0, 190, 192, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 206, 3, 6, 3, 0, 193, 197, 5, 10, 0, 0, 194, 196, 3, 30, 15, 0, 195, 194, 1, 0, 0, 0, 196, 199, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 197, 198, 1, 0, 0, 0, 198, 200, 1, 0, 0, 0, 199, 197, 1, 0, 0, 0, 200, 202, 3, 6, 3, 0, 201, 203, 5, 10, 0, 0, 202, 201, 1, 0, 0, 0, 202, 203, 1, 0, 0, 0, 203, 205, 1, 0, 0, 0, 204, 193, 1, 0, 0, 0, 205, 208, 1, 0, 0, 0, 206, 204, 1, 0, 0, 0, 206, 207, 1, 0, 0, 0, 207, 212, 1, 0, 0, 0, 208, 206, 1, 0, 0, 0, 209, 211, 3, 30, 15, 0, 210, 209, 1, 0, 0, 0, 211, 214, 1, 0, 0, 0, 212, 210, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 215, 1, 0, 0, 0, 214, 212, 1, 0, 0, 0, 215, 216, 5, 31, 0, 0, 216, 218, 1, 0, 0, 0, 217, 177, 1, 0, 0, 0, 217, 185, 1, 0, 0, 0, 218, 39, 1, 0, 0, 0, 219, 220, 5, 5, 0, 0, 220, 221, 3, 8, 4, 0, 221, 231, 5, 7, 0, 0, 222, 224, 3, 30, 15, 0, 223, 222, 1, 0, 0, 0, 224, 227, 1, 0, 0, 0, 225, 223, 1, 0, 0, 0, 225, 226, 1, 0, 0, 0, 226, 228, 1, 0, 0, 0, 227, 225, 1, 0, 0, 0, 228, 230, 3, 2, 1, 0, 229, 225, 1, 0, 0, 0, 230, 233, 1, 0, 0, 0, 231, 229, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 41, 1, 0, 0, 0, 233, 231, 1, 0, 0, 0, 30, 43, 47, 51, 58, 62, 65, 75, 79, 90, 99, 114, 120, 128, 136, 141, 145, 151, 156, 160, 168, 174, 181, 189, 197, 202, 206, 212, 217, 225, 231] \ No newline at end of file diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.java new file mode 100644 index 00000000000..36f1d699925 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.java @@ -0,0 +1,1886 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Generated from java-escape by ANTLR 4.11.1 +package org.openrewrite.toml.internal.grammar; + +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.ATN; +import org.antlr.v4.runtime.atn.ATNDeserializer; +import org.antlr.v4.runtime.atn.ParserATNSimulator; +import org.antlr.v4.runtime.atn.PredictionContextCache; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.tree.ParseTreeListener; +import org.antlr.v4.runtime.tree.ParseTreeVisitor; +import org.antlr.v4.runtime.tree.TerminalNode; + +import java.util.List; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"}) +public class TomlParser extends Parser { + static { RuntimeMetaData.checkVersion("4.11.1", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + WS=1, NL=2, COMMENT=3, L_BRACKET=4, DOUBLE_L_BRACKET=5, R_BRACKET=6, DOUBLE_R_BRACKET=7, + EQUALS=8, DOT=9, COMMA=10, BASIC_STRING=11, LITERAL_STRING=12, UNQUOTED_KEY=13, + VALUE_WS=14, L_BRACE=15, BOOLEAN=16, ML_BASIC_STRING=17, ML_LITERAL_STRING=18, + FLOAT=19, INF=20, NAN=21, DEC_INT=22, HEX_INT=23, OCT_INT=24, BIN_INT=25, + OFFSET_DATE_TIME=26, LOCAL_DATE_TIME=27, LOCAL_DATE=28, LOCAL_TIME=29, + INLINE_TABLE_WS=30, R_BRACE=31, ARRAY_WS=32; + public static final int + RULE_document = 0, RULE_expression = 1, RULE_comment = 2, RULE_keyValue = 3, + RULE_key = 4, RULE_simpleKey = 5, RULE_unquotedKey = 6, RULE_quotedKey = 7, + RULE_dottedKey = 8, RULE_value = 9, RULE_string = 10, RULE_integer = 11, + RULE_floatingPoint = 12, RULE_bool = 13, RULE_dateTime = 14, RULE_commentOrNl = 15, + RULE_array = 16, RULE_table = 17, RULE_standardTable = 18, RULE_inlineTable = 19, + RULE_arrayTable = 20; + private static String[] makeRuleNames() { + return new String[] { + "document", "expression", "comment", "keyValue", "key", "simpleKey", + "unquotedKey", "quotedKey", "dottedKey", "value", "string", "integer", + "floatingPoint", "bool", "dateTime", "commentOrNl", "array", "table", + "standardTable", "inlineTable", "arrayTable" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, null, null, null, "'['", "'[['", "']'", "']]'", "'='", "'.'", "','", + null, null, null, null, "'{'", null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, "'}'" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, "WS", "NL", "COMMENT", "L_BRACKET", "DOUBLE_L_BRACKET", "R_BRACKET", + "DOUBLE_R_BRACKET", "EQUALS", "DOT", "COMMA", "BASIC_STRING", "LITERAL_STRING", + "UNQUOTED_KEY", "VALUE_WS", "L_BRACE", "BOOLEAN", "ML_BASIC_STRING", + "ML_LITERAL_STRING", "FLOAT", "INF", "NAN", "DEC_INT", "HEX_INT", "OCT_INT", + "BIN_INT", "OFFSET_DATE_TIME", "LOCAL_DATE_TIME", "LOCAL_DATE", "LOCAL_TIME", + "INLINE_TABLE_WS", "R_BRACE", "ARRAY_WS" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + @Override + public String getGrammarFileName() { return "java-escape"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public ATN getATN() { return _ATN; } + + public TomlParser(TokenStream input) { + super(input); + _interp = new ParserATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + @SuppressWarnings("CheckReturnValue") + public static class DocumentContext extends ParserRuleContext { + public TerminalNode EOF() { return getToken(TomlParser.EOF, 0); } + public List expression() { + return getRuleContexts(ExpressionContext.class); + } + public ExpressionContext expression(int i) { + return getRuleContext(ExpressionContext.class,i); + } + public List NL() { return getTokens(TomlParser.NL); } + public TerminalNode NL(int i) { + return getToken(TomlParser.NL, i); + } + public DocumentContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_document; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterDocument(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitDocument(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitDocument(this); + else return visitor.visitChildren(this); + } + } + + public final DocumentContext document() throws RecognitionException { + DocumentContext _localctx = new DocumentContext(_ctx, getState()); + enterRule(_localctx, 0, RULE_document); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(43); + _errHandler.sync(this); + _la = _input.LA(1); + if (((_la) & ~0x3f) == 0 && ((1L << _la) & 14392L) != 0) { + { + setState(42); + expression(); + } + } + + setState(51); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==NL) { + { + { + setState(45); + match(NL); + setState(47); + _errHandler.sync(this); + _la = _input.LA(1); + if (((_la) & ~0x3f) == 0 && ((1L << _la) & 14392L) != 0) { + { + setState(46); + expression(); + } + } + + } + } + setState(53); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(54); + match(EOF); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class ExpressionContext extends ParserRuleContext { + public KeyValueContext keyValue() { + return getRuleContext(KeyValueContext.class,0); + } + public CommentContext comment() { + return getRuleContext(CommentContext.class,0); + } + public TableContext table() { + return getRuleContext(TableContext.class,0); + } + public ExpressionContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_expression; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterExpression(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitExpression(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitExpression(this); + else return visitor.visitChildren(this); + } + } + + public final ExpressionContext expression() throws RecognitionException { + ExpressionContext _localctx = new ExpressionContext(_ctx, getState()); + enterRule(_localctx, 2, RULE_expression); + try { + setState(65); + _errHandler.sync(this); + switch (_input.LA(1)) { + case BASIC_STRING: + case LITERAL_STRING: + case UNQUOTED_KEY: + enterOuterAlt(_localctx, 1); + { + setState(56); + keyValue(); + setState(58); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) { + case 1: + { + setState(57); + comment(); + } + break; + } + } + break; + case L_BRACKET: + case DOUBLE_L_BRACKET: + enterOuterAlt(_localctx, 2); + { + setState(60); + table(); + setState(62); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) { + case 1: + { + setState(61); + comment(); + } + break; + } + } + break; + case COMMENT: + enterOuterAlt(_localctx, 3); + { + setState(64); + comment(); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class CommentContext extends ParserRuleContext { + public TerminalNode COMMENT() { return getToken(TomlParser.COMMENT, 0); } + public CommentContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_comment; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterComment(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitComment(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitComment(this); + else return visitor.visitChildren(this); + } + } + + public final CommentContext comment() throws RecognitionException { + CommentContext _localctx = new CommentContext(_ctx, getState()); + enterRule(_localctx, 4, RULE_comment); + try { + enterOuterAlt(_localctx, 1); + { + setState(67); + match(COMMENT); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class KeyValueContext extends ParserRuleContext { + public KeyContext key() { + return getRuleContext(KeyContext.class,0); + } + public TerminalNode EQUALS() { return getToken(TomlParser.EQUALS, 0); } + public ValueContext value() { + return getRuleContext(ValueContext.class,0); + } + public KeyValueContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_keyValue; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterKeyValue(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitKeyValue(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitKeyValue(this); + else return visitor.visitChildren(this); + } + } + + public final KeyValueContext keyValue() throws RecognitionException { + KeyValueContext _localctx = new KeyValueContext(_ctx, getState()); + enterRule(_localctx, 6, RULE_keyValue); + try { + enterOuterAlt(_localctx, 1); + { + setState(69); + key(); + setState(70); + match(EQUALS); + setState(71); + value(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class KeyContext extends ParserRuleContext { + public SimpleKeyContext simpleKey() { + return getRuleContext(SimpleKeyContext.class,0); + } + public DottedKeyContext dottedKey() { + return getRuleContext(DottedKeyContext.class,0); + } + public KeyContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_key; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterKey(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitKey(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitKey(this); + else return visitor.visitChildren(this); + } + } + + public final KeyContext key() throws RecognitionException { + KeyContext _localctx = new KeyContext(_ctx, getState()); + enterRule(_localctx, 8, RULE_key); + try { + setState(75); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(73); + simpleKey(); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(74); + dottedKey(); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class SimpleKeyContext extends ParserRuleContext { + public QuotedKeyContext quotedKey() { + return getRuleContext(QuotedKeyContext.class,0); + } + public UnquotedKeyContext unquotedKey() { + return getRuleContext(UnquotedKeyContext.class,0); + } + public SimpleKeyContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_simpleKey; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterSimpleKey(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitSimpleKey(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitSimpleKey(this); + else return visitor.visitChildren(this); + } + } + + public final SimpleKeyContext simpleKey() throws RecognitionException { + SimpleKeyContext _localctx = new SimpleKeyContext(_ctx, getState()); + enterRule(_localctx, 10, RULE_simpleKey); + try { + setState(79); + _errHandler.sync(this); + switch (_input.LA(1)) { + case BASIC_STRING: + case LITERAL_STRING: + enterOuterAlt(_localctx, 1); + { + setState(77); + quotedKey(); + } + break; + case UNQUOTED_KEY: + enterOuterAlt(_localctx, 2); + { + setState(78); + unquotedKey(); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class UnquotedKeyContext extends ParserRuleContext { + public TerminalNode UNQUOTED_KEY() { return getToken(TomlParser.UNQUOTED_KEY, 0); } + public UnquotedKeyContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_unquotedKey; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterUnquotedKey(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitUnquotedKey(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitUnquotedKey(this); + else return visitor.visitChildren(this); + } + } + + public final UnquotedKeyContext unquotedKey() throws RecognitionException { + UnquotedKeyContext _localctx = new UnquotedKeyContext(_ctx, getState()); + enterRule(_localctx, 12, RULE_unquotedKey); + try { + enterOuterAlt(_localctx, 1); + { + setState(81); + match(UNQUOTED_KEY); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class QuotedKeyContext extends ParserRuleContext { + public TerminalNode BASIC_STRING() { return getToken(TomlParser.BASIC_STRING, 0); } + public TerminalNode LITERAL_STRING() { return getToken(TomlParser.LITERAL_STRING, 0); } + public QuotedKeyContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_quotedKey; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterQuotedKey(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitQuotedKey(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitQuotedKey(this); + else return visitor.visitChildren(this); + } + } + + public final QuotedKeyContext quotedKey() throws RecognitionException { + QuotedKeyContext _localctx = new QuotedKeyContext(_ctx, getState()); + enterRule(_localctx, 14, RULE_quotedKey); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(83); + _la = _input.LA(1); + if ( !(_la==BASIC_STRING || _la==LITERAL_STRING) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class DottedKeyContext extends ParserRuleContext { + public List simpleKey() { + return getRuleContexts(SimpleKeyContext.class); + } + public SimpleKeyContext simpleKey(int i) { + return getRuleContext(SimpleKeyContext.class,i); + } + public List DOT() { return getTokens(TomlParser.DOT); } + public TerminalNode DOT(int i) { + return getToken(TomlParser.DOT, i); + } + public DottedKeyContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_dottedKey; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterDottedKey(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitDottedKey(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitDottedKey(this); + else return visitor.visitChildren(this); + } + } + + public final DottedKeyContext dottedKey() throws RecognitionException { + DottedKeyContext _localctx = new DottedKeyContext(_ctx, getState()); + enterRule(_localctx, 16, RULE_dottedKey); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(85); + simpleKey(); + setState(88); + _errHandler.sync(this); + _la = _input.LA(1); + do { + { + { + setState(86); + match(DOT); + setState(87); + simpleKey(); + } + } + setState(90); + _errHandler.sync(this); + _la = _input.LA(1); + } while ( _la==DOT ); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class ValueContext extends ParserRuleContext { + public StringContext string() { + return getRuleContext(StringContext.class,0); + } + public IntegerContext integer() { + return getRuleContext(IntegerContext.class,0); + } + public FloatingPointContext floatingPoint() { + return getRuleContext(FloatingPointContext.class,0); + } + public BoolContext bool() { + return getRuleContext(BoolContext.class,0); + } + public DateTimeContext dateTime() { + return getRuleContext(DateTimeContext.class,0); + } + public ArrayContext array() { + return getRuleContext(ArrayContext.class,0); + } + public InlineTableContext inlineTable() { + return getRuleContext(InlineTableContext.class,0); + } + public ValueContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_value; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterValue(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitValue(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitValue(this); + else return visitor.visitChildren(this); + } + } + + public final ValueContext value() throws RecognitionException { + ValueContext _localctx = new ValueContext(_ctx, getState()); + enterRule(_localctx, 18, RULE_value); + try { + setState(99); + _errHandler.sync(this); + switch (_input.LA(1)) { + case BASIC_STRING: + case LITERAL_STRING: + case ML_BASIC_STRING: + case ML_LITERAL_STRING: + enterOuterAlt(_localctx, 1); + { + setState(92); + string(); + } + break; + case DEC_INT: + case HEX_INT: + case OCT_INT: + case BIN_INT: + enterOuterAlt(_localctx, 2); + { + setState(93); + integer(); + } + break; + case FLOAT: + case INF: + case NAN: + enterOuterAlt(_localctx, 3); + { + setState(94); + floatingPoint(); + } + break; + case BOOLEAN: + enterOuterAlt(_localctx, 4); + { + setState(95); + bool(); + } + break; + case OFFSET_DATE_TIME: + case LOCAL_DATE_TIME: + case LOCAL_DATE: + case LOCAL_TIME: + enterOuterAlt(_localctx, 5); + { + setState(96); + dateTime(); + } + break; + case L_BRACKET: + enterOuterAlt(_localctx, 6); + { + setState(97); + array(); + } + break; + case L_BRACE: + enterOuterAlt(_localctx, 7); + { + setState(98); + inlineTable(); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class StringContext extends ParserRuleContext { + public TerminalNode BASIC_STRING() { return getToken(TomlParser.BASIC_STRING, 0); } + public TerminalNode ML_BASIC_STRING() { return getToken(TomlParser.ML_BASIC_STRING, 0); } + public TerminalNode LITERAL_STRING() { return getToken(TomlParser.LITERAL_STRING, 0); } + public TerminalNode ML_LITERAL_STRING() { return getToken(TomlParser.ML_LITERAL_STRING, 0); } + public StringContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_string; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterString(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitString(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitString(this); + else return visitor.visitChildren(this); + } + } + + public final StringContext string() throws RecognitionException { + StringContext _localctx = new StringContext(_ctx, getState()); + enterRule(_localctx, 20, RULE_string); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(101); + _la = _input.LA(1); + if ( !(((_la) & ~0x3f) == 0 && ((1L << _la) & 399360L) != 0) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class IntegerContext extends ParserRuleContext { + public TerminalNode DEC_INT() { return getToken(TomlParser.DEC_INT, 0); } + public TerminalNode HEX_INT() { return getToken(TomlParser.HEX_INT, 0); } + public TerminalNode OCT_INT() { return getToken(TomlParser.OCT_INT, 0); } + public TerminalNode BIN_INT() { return getToken(TomlParser.BIN_INT, 0); } + public IntegerContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_integer; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterInteger(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitInteger(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitInteger(this); + else return visitor.visitChildren(this); + } + } + + public final IntegerContext integer() throws RecognitionException { + IntegerContext _localctx = new IntegerContext(_ctx, getState()); + enterRule(_localctx, 22, RULE_integer); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(103); + _la = _input.LA(1); + if ( !(((_la) & ~0x3f) == 0 && ((1L << _la) & 62914560L) != 0) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class FloatingPointContext extends ParserRuleContext { + public TerminalNode FLOAT() { return getToken(TomlParser.FLOAT, 0); } + public TerminalNode INF() { return getToken(TomlParser.INF, 0); } + public TerminalNode NAN() { return getToken(TomlParser.NAN, 0); } + public FloatingPointContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_floatingPoint; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterFloatingPoint(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitFloatingPoint(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitFloatingPoint(this); + else return visitor.visitChildren(this); + } + } + + public final FloatingPointContext floatingPoint() throws RecognitionException { + FloatingPointContext _localctx = new FloatingPointContext(_ctx, getState()); + enterRule(_localctx, 24, RULE_floatingPoint); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(105); + _la = _input.LA(1); + if ( !(((_la) & ~0x3f) == 0 && ((1L << _la) & 3670016L) != 0) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class BoolContext extends ParserRuleContext { + public TerminalNode BOOLEAN() { return getToken(TomlParser.BOOLEAN, 0); } + public BoolContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_bool; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterBool(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitBool(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitBool(this); + else return visitor.visitChildren(this); + } + } + + public final BoolContext bool() throws RecognitionException { + BoolContext _localctx = new BoolContext(_ctx, getState()); + enterRule(_localctx, 26, RULE_bool); + try { + enterOuterAlt(_localctx, 1); + { + setState(107); + match(BOOLEAN); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class DateTimeContext extends ParserRuleContext { + public TerminalNode OFFSET_DATE_TIME() { return getToken(TomlParser.OFFSET_DATE_TIME, 0); } + public TerminalNode LOCAL_DATE_TIME() { return getToken(TomlParser.LOCAL_DATE_TIME, 0); } + public TerminalNode LOCAL_DATE() { return getToken(TomlParser.LOCAL_DATE, 0); } + public TerminalNode LOCAL_TIME() { return getToken(TomlParser.LOCAL_TIME, 0); } + public DateTimeContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_dateTime; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterDateTime(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitDateTime(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitDateTime(this); + else return visitor.visitChildren(this); + } + } + + public final DateTimeContext dateTime() throws RecognitionException { + DateTimeContext _localctx = new DateTimeContext(_ctx, getState()); + enterRule(_localctx, 28, RULE_dateTime); + int _la; + try { + enterOuterAlt(_localctx, 1); + { + setState(109); + _la = _input.LA(1); + if ( !(((_la) & ~0x3f) == 0 && ((1L << _la) & 1006632960L) != 0) ) { + _errHandler.recoverInline(this); + } + else { + if ( _input.LA(1)==Token.EOF ) matchedEOF = true; + _errHandler.reportMatch(this); + consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class CommentOrNlContext extends ParserRuleContext { + public TerminalNode COMMENT() { return getToken(TomlParser.COMMENT, 0); } + public TerminalNode NL() { return getToken(TomlParser.NL, 0); } + public CommentOrNlContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_commentOrNl; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterCommentOrNl(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitCommentOrNl(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitCommentOrNl(this); + else return visitor.visitChildren(this); + } + } + + public final CommentOrNlContext commentOrNl() throws RecognitionException { + CommentOrNlContext _localctx = new CommentOrNlContext(_ctx, getState()); + enterRule(_localctx, 30, RULE_commentOrNl); + try { + setState(114); + _errHandler.sync(this); + switch (_input.LA(1)) { + case COMMENT: + enterOuterAlt(_localctx, 1); + { + setState(111); + match(COMMENT); + setState(112); + match(NL); + } + break; + case NL: + enterOuterAlt(_localctx, 2); + { + setState(113); + match(NL); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class ArrayContext extends ParserRuleContext { + public TerminalNode L_BRACKET() { return getToken(TomlParser.L_BRACKET, 0); } + public TerminalNode R_BRACKET() { return getToken(TomlParser.R_BRACKET, 0); } + public List commentOrNl() { + return getRuleContexts(CommentOrNlContext.class); + } + public CommentOrNlContext commentOrNl(int i) { + return getRuleContext(CommentOrNlContext.class,i); + } + public List value() { + return getRuleContexts(ValueContext.class); + } + public ValueContext value(int i) { + return getRuleContext(ValueContext.class,i); + } + public List COMMA() { return getTokens(TomlParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(TomlParser.COMMA, i); + } + public ArrayContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_array; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterArray(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitArray(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitArray(this); + else return visitor.visitChildren(this); + } + } + + public final ArrayContext array() throws RecognitionException { + ArrayContext _localctx = new ArrayContext(_ctx, getState()); + enterRule(_localctx, 32, RULE_array); + int _la; + try { + setState(156); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,17,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(116); + match(L_BRACKET); + setState(120); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==NL || _la==COMMENT) { + { + { + setState(117); + commentOrNl(); + } + } + setState(122); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(123); + match(R_BRACKET); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(124); + match(L_BRACKET); + setState(128); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==NL || _la==COMMENT) { + { + { + setState(125); + commentOrNl(); + } + } + setState(130); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(131); + value(); + setState(145); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(132); + match(COMMA); + setState(136); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==NL || _la==COMMENT) { + { + { + setState(133); + commentOrNl(); + } + } + setState(138); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(139); + value(); + setState(141); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,14,_ctx) ) { + case 1: + { + setState(140); + match(COMMA); + } + break; + } + } + } + setState(147); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(151); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==NL || _la==COMMENT) { + { + { + setState(148); + commentOrNl(); + } + } + setState(153); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(154); + match(R_BRACKET); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class TableContext extends ParserRuleContext { + public StandardTableContext standardTable() { + return getRuleContext(StandardTableContext.class,0); + } + public ArrayTableContext arrayTable() { + return getRuleContext(ArrayTableContext.class,0); + } + public TableContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_table; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterTable(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitTable(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitTable(this); + else return visitor.visitChildren(this); + } + } + + public final TableContext table() throws RecognitionException { + TableContext _localctx = new TableContext(_ctx, getState()); + enterRule(_localctx, 34, RULE_table); + try { + setState(160); + _errHandler.sync(this); + switch (_input.LA(1)) { + case L_BRACKET: + enterOuterAlt(_localctx, 1); + { + setState(158); + standardTable(); + } + break; + case DOUBLE_L_BRACKET: + enterOuterAlt(_localctx, 2); + { + setState(159); + arrayTable(); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class StandardTableContext extends ParserRuleContext { + public TerminalNode L_BRACKET() { return getToken(TomlParser.L_BRACKET, 0); } + public KeyContext key() { + return getRuleContext(KeyContext.class,0); + } + public TerminalNode R_BRACKET() { return getToken(TomlParser.R_BRACKET, 0); } + public List expression() { + return getRuleContexts(ExpressionContext.class); + } + public ExpressionContext expression(int i) { + return getRuleContext(ExpressionContext.class,i); + } + public List commentOrNl() { + return getRuleContexts(CommentOrNlContext.class); + } + public CommentOrNlContext commentOrNl(int i) { + return getRuleContext(CommentOrNlContext.class,i); + } + public StandardTableContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_standardTable; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterStandardTable(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitStandardTable(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitStandardTable(this); + else return visitor.visitChildren(this); + } + } + + public final StandardTableContext standardTable() throws RecognitionException { + StandardTableContext _localctx = new StandardTableContext(_ctx, getState()); + enterRule(_localctx, 36, RULE_standardTable); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(162); + match(L_BRACKET); + setState(163); + key(); + setState(164); + match(R_BRACKET); + setState(174); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,20,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(168); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,19,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(165); + commentOrNl(); + } + } + } + setState(170); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,19,_ctx); + } + setState(171); + expression(); + } + } + } + setState(176); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,20,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class InlineTableContext extends ParserRuleContext { + public TerminalNode L_BRACE() { return getToken(TomlParser.L_BRACE, 0); } + public TerminalNode R_BRACE() { return getToken(TomlParser.R_BRACE, 0); } + public List commentOrNl() { + return getRuleContexts(CommentOrNlContext.class); + } + public CommentOrNlContext commentOrNl(int i) { + return getRuleContext(CommentOrNlContext.class,i); + } + public List keyValue() { + return getRuleContexts(KeyValueContext.class); + } + public KeyValueContext keyValue(int i) { + return getRuleContext(KeyValueContext.class,i); + } + public List COMMA() { return getTokens(TomlParser.COMMA); } + public TerminalNode COMMA(int i) { + return getToken(TomlParser.COMMA, i); + } + public InlineTableContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_inlineTable; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterInlineTable(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitInlineTable(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitInlineTable(this); + else return visitor.visitChildren(this); + } + } + + public final InlineTableContext inlineTable() throws RecognitionException { + InlineTableContext _localctx = new InlineTableContext(_ctx, getState()); + enterRule(_localctx, 38, RULE_inlineTable); + int _la; + try { + setState(217); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,27,_ctx) ) { + case 1: + enterOuterAlt(_localctx, 1); + { + setState(177); + match(L_BRACE); + setState(181); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==NL || _la==COMMENT) { + { + { + setState(178); + commentOrNl(); + } + } + setState(183); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(184); + match(R_BRACE); + } + break; + case 2: + enterOuterAlt(_localctx, 2); + { + setState(185); + match(L_BRACE); + setState(189); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==NL || _la==COMMENT) { + { + { + setState(186); + commentOrNl(); + } + } + setState(191); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(192); + keyValue(); + setState(206); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==COMMA) { + { + { + setState(193); + match(COMMA); + setState(197); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==NL || _la==COMMENT) { + { + { + setState(194); + commentOrNl(); + } + } + setState(199); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(200); + keyValue(); + setState(202); + _errHandler.sync(this); + switch ( getInterpreter().adaptivePredict(_input,24,_ctx) ) { + case 1: + { + setState(201); + match(COMMA); + } + break; + } + } + } + setState(208); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(212); + _errHandler.sync(this); + _la = _input.LA(1); + while (_la==NL || _la==COMMENT) { + { + { + setState(209); + commentOrNl(); + } + } + setState(214); + _errHandler.sync(this); + _la = _input.LA(1); + } + setState(215); + match(R_BRACE); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + @SuppressWarnings("CheckReturnValue") + public static class ArrayTableContext extends ParserRuleContext { + public TerminalNode DOUBLE_L_BRACKET() { return getToken(TomlParser.DOUBLE_L_BRACKET, 0); } + public KeyContext key() { + return getRuleContext(KeyContext.class,0); + } + public TerminalNode DOUBLE_R_BRACKET() { return getToken(TomlParser.DOUBLE_R_BRACKET, 0); } + public List expression() { + return getRuleContexts(ExpressionContext.class); + } + public ExpressionContext expression(int i) { + return getRuleContext(ExpressionContext.class,i); + } + public List commentOrNl() { + return getRuleContexts(CommentOrNlContext.class); + } + public CommentOrNlContext commentOrNl(int i) { + return getRuleContext(CommentOrNlContext.class,i); + } + public ArrayTableContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_arrayTable; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).enterArrayTable(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof TomlParserListener ) ((TomlParserListener)listener).exitArrayTable(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof TomlParserVisitor ) return ((TomlParserVisitor)visitor).visitArrayTable(this); + else return visitor.visitChildren(this); + } + } + + public final ArrayTableContext arrayTable() throws RecognitionException { + ArrayTableContext _localctx = new ArrayTableContext(_ctx, getState()); + enterRule(_localctx, 40, RULE_arrayTable); + try { + int _alt; + enterOuterAlt(_localctx, 1); + { + setState(219); + match(DOUBLE_L_BRACKET); + setState(220); + key(); + setState(221); + match(DOUBLE_R_BRACKET); + setState(231); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,29,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(225); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,28,_ctx); + while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + setState(222); + commentOrNl(); + } + } + } + setState(227); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,28,_ctx); + } + setState(228); + expression(); + } + } + } + setState(233); + _errHandler.sync(this); + _alt = getInterpreter().adaptivePredict(_input,29,_ctx); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static final String _serializedATN = + "\u0004\u0001 \u00eb\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ + "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ + "\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b\u0002"+ + "\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002\u000f\u0007\u000f"+ + "\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002\u0012\u0007\u0012"+ + "\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0001\u0000\u0003\u0000"+ + ",\b\u0000\u0001\u0000\u0001\u0000\u0003\u00000\b\u0000\u0005\u00002\b"+ + "\u0000\n\u0000\f\u00005\t\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001"+ + "\u0001\u0003\u0001;\b\u0001\u0001\u0001\u0001\u0001\u0003\u0001?\b\u0001"+ + "\u0001\u0001\u0003\u0001B\b\u0001\u0001\u0002\u0001\u0002\u0001\u0003"+ + "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004\u0003\u0004"+ + "L\b\u0004\u0001\u0005\u0001\u0005\u0003\u0005P\b\u0005\u0001\u0006\u0001"+ + "\u0006\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001\b\u0004\bY\b\b\u000b"+ + "\b\f\bZ\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0003"+ + "\td\b\t\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001"+ + "\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001\u000f"+ + "\u0003\u000fs\b\u000f\u0001\u0010\u0001\u0010\u0005\u0010w\b\u0010\n\u0010"+ + "\f\u0010z\t\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0005\u0010\u007f"+ + "\b\u0010\n\u0010\f\u0010\u0082\t\u0010\u0001\u0010\u0001\u0010\u0001\u0010"+ + "\u0005\u0010\u0087\b\u0010\n\u0010\f\u0010\u008a\t\u0010\u0001\u0010\u0001"+ + "\u0010\u0003\u0010\u008e\b\u0010\u0005\u0010\u0090\b\u0010\n\u0010\f\u0010"+ + "\u0093\t\u0010\u0001\u0010\u0005\u0010\u0096\b\u0010\n\u0010\f\u0010\u0099"+ + "\t\u0010\u0001\u0010\u0001\u0010\u0003\u0010\u009d\b\u0010\u0001\u0011"+ + "\u0001\u0011\u0003\u0011\u00a1\b\u0011\u0001\u0012\u0001\u0012\u0001\u0012"+ + "\u0001\u0012\u0005\u0012\u00a7\b\u0012\n\u0012\f\u0012\u00aa\t\u0012\u0001"+ + "\u0012\u0005\u0012\u00ad\b\u0012\n\u0012\f\u0012\u00b0\t\u0012\u0001\u0013"+ + "\u0001\u0013\u0005\u0013\u00b4\b\u0013\n\u0013\f\u0013\u00b7\t\u0013\u0001"+ + "\u0013\u0001\u0013\u0001\u0013\u0005\u0013\u00bc\b\u0013\n\u0013\f\u0013"+ + "\u00bf\t\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0005\u0013\u00c4\b"+ + "\u0013\n\u0013\f\u0013\u00c7\t\u0013\u0001\u0013\u0001\u0013\u0003\u0013"+ + "\u00cb\b\u0013\u0005\u0013\u00cd\b\u0013\n\u0013\f\u0013\u00d0\t\u0013"+ + "\u0001\u0013\u0005\u0013\u00d3\b\u0013\n\u0013\f\u0013\u00d6\t\u0013\u0001"+ + "\u0013\u0001\u0013\u0003\u0013\u00da\b\u0013\u0001\u0014\u0001\u0014\u0001"+ + "\u0014\u0001\u0014\u0005\u0014\u00e0\b\u0014\n\u0014\f\u0014\u00e3\t\u0014"+ + "\u0001\u0014\u0005\u0014\u00e6\b\u0014\n\u0014\f\u0014\u00e9\t\u0014\u0001"+ + "\u0014\u0000\u0000\u0015\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012"+ + "\u0014\u0016\u0018\u001a\u001c\u001e \"$&(\u0000\u0005\u0001\u0000\u000b"+ + "\f\u0002\u0000\u000b\f\u0011\u0012\u0001\u0000\u0016\u0019\u0001\u0000"+ + "\u0013\u0015\u0001\u0000\u001a\u001d\u00f9\u0000+\u0001\u0000\u0000\u0000"+ + "\u0002A\u0001\u0000\u0000\u0000\u0004C\u0001\u0000\u0000\u0000\u0006E"+ + "\u0001\u0000\u0000\u0000\bK\u0001\u0000\u0000\u0000\nO\u0001\u0000\u0000"+ + "\u0000\fQ\u0001\u0000\u0000\u0000\u000eS\u0001\u0000\u0000\u0000\u0010"+ + "U\u0001\u0000\u0000\u0000\u0012c\u0001\u0000\u0000\u0000\u0014e\u0001"+ + "\u0000\u0000\u0000\u0016g\u0001\u0000\u0000\u0000\u0018i\u0001\u0000\u0000"+ + "\u0000\u001ak\u0001\u0000\u0000\u0000\u001cm\u0001\u0000\u0000\u0000\u001e"+ + "r\u0001\u0000\u0000\u0000 \u009c\u0001\u0000\u0000\u0000\"\u00a0\u0001"+ + "\u0000\u0000\u0000$\u00a2\u0001\u0000\u0000\u0000&\u00d9\u0001\u0000\u0000"+ + "\u0000(\u00db\u0001\u0000\u0000\u0000*,\u0003\u0002\u0001\u0000+*\u0001"+ + "\u0000\u0000\u0000+,\u0001\u0000\u0000\u0000,3\u0001\u0000\u0000\u0000"+ + "-/\u0005\u0002\u0000\u0000.0\u0003\u0002\u0001\u0000/.\u0001\u0000\u0000"+ + "\u0000/0\u0001\u0000\u0000\u000002\u0001\u0000\u0000\u00001-\u0001\u0000"+ + "\u0000\u000025\u0001\u0000\u0000\u000031\u0001\u0000\u0000\u000034\u0001"+ + "\u0000\u0000\u000046\u0001\u0000\u0000\u000053\u0001\u0000\u0000\u0000"+ + "67\u0005\u0000\u0000\u00017\u0001\u0001\u0000\u0000\u00008:\u0003\u0006"+ + "\u0003\u00009;\u0003\u0004\u0002\u0000:9\u0001\u0000\u0000\u0000:;\u0001"+ + "\u0000\u0000\u0000;B\u0001\u0000\u0000\u0000<>\u0003\"\u0011\u0000=?\u0003"+ + "\u0004\u0002\u0000>=\u0001\u0000\u0000\u0000>?\u0001\u0000\u0000\u0000"+ + "?B\u0001\u0000\u0000\u0000@B\u0003\u0004\u0002\u0000A8\u0001\u0000\u0000"+ + "\u0000A<\u0001\u0000\u0000\u0000A@\u0001\u0000\u0000\u0000B\u0003\u0001"+ + "\u0000\u0000\u0000CD\u0005\u0003\u0000\u0000D\u0005\u0001\u0000\u0000"+ + "\u0000EF\u0003\b\u0004\u0000FG\u0005\b\u0000\u0000GH\u0003\u0012\t\u0000"+ + "H\u0007\u0001\u0000\u0000\u0000IL\u0003\n\u0005\u0000JL\u0003\u0010\b"+ + "\u0000KI\u0001\u0000\u0000\u0000KJ\u0001\u0000\u0000\u0000L\t\u0001\u0000"+ + "\u0000\u0000MP\u0003\u000e\u0007\u0000NP\u0003\f\u0006\u0000OM\u0001\u0000"+ + "\u0000\u0000ON\u0001\u0000\u0000\u0000P\u000b\u0001\u0000\u0000\u0000"+ + "QR\u0005\r\u0000\u0000R\r\u0001\u0000\u0000\u0000ST\u0007\u0000\u0000"+ + "\u0000T\u000f\u0001\u0000\u0000\u0000UX\u0003\n\u0005\u0000VW\u0005\t"+ + "\u0000\u0000WY\u0003\n\u0005\u0000XV\u0001\u0000\u0000\u0000YZ\u0001\u0000"+ + "\u0000\u0000ZX\u0001\u0000\u0000\u0000Z[\u0001\u0000\u0000\u0000[\u0011"+ + "\u0001\u0000\u0000\u0000\\d\u0003\u0014\n\u0000]d\u0003\u0016\u000b\u0000"+ + "^d\u0003\u0018\f\u0000_d\u0003\u001a\r\u0000`d\u0003\u001c\u000e\u0000"+ + "ad\u0003 \u0010\u0000bd\u0003&\u0013\u0000c\\\u0001\u0000\u0000\u0000"+ + "c]\u0001\u0000\u0000\u0000c^\u0001\u0000\u0000\u0000c_\u0001\u0000\u0000"+ + "\u0000c`\u0001\u0000\u0000\u0000ca\u0001\u0000\u0000\u0000cb\u0001\u0000"+ + "\u0000\u0000d\u0013\u0001\u0000\u0000\u0000ef\u0007\u0001\u0000\u0000"+ + "f\u0015\u0001\u0000\u0000\u0000gh\u0007\u0002\u0000\u0000h\u0017\u0001"+ + "\u0000\u0000\u0000ij\u0007\u0003\u0000\u0000j\u0019\u0001\u0000\u0000"+ + "\u0000kl\u0005\u0010\u0000\u0000l\u001b\u0001\u0000\u0000\u0000mn\u0007"+ + "\u0004\u0000\u0000n\u001d\u0001\u0000\u0000\u0000op\u0005\u0003\u0000"+ + "\u0000ps\u0005\u0002\u0000\u0000qs\u0005\u0002\u0000\u0000ro\u0001\u0000"+ + "\u0000\u0000rq\u0001\u0000\u0000\u0000s\u001f\u0001\u0000\u0000\u0000"+ + "tx\u0005\u0004\u0000\u0000uw\u0003\u001e\u000f\u0000vu\u0001\u0000\u0000"+ + "\u0000wz\u0001\u0000\u0000\u0000xv\u0001\u0000\u0000\u0000xy\u0001\u0000"+ + "\u0000\u0000y{\u0001\u0000\u0000\u0000zx\u0001\u0000\u0000\u0000{\u009d"+ + "\u0005\u0006\u0000\u0000|\u0080\u0005\u0004\u0000\u0000}\u007f\u0003\u001e"+ + "\u000f\u0000~}\u0001\u0000\u0000\u0000\u007f\u0082\u0001\u0000\u0000\u0000"+ + "\u0080~\u0001\u0000\u0000\u0000\u0080\u0081\u0001\u0000\u0000\u0000\u0081"+ + "\u0083\u0001\u0000\u0000\u0000\u0082\u0080\u0001\u0000\u0000\u0000\u0083"+ + "\u0091\u0003\u0012\t\u0000\u0084\u0088\u0005\n\u0000\u0000\u0085\u0087"+ + "\u0003\u001e\u000f\u0000\u0086\u0085\u0001\u0000\u0000\u0000\u0087\u008a"+ + "\u0001\u0000\u0000\u0000\u0088\u0086\u0001\u0000\u0000\u0000\u0088\u0089"+ + "\u0001\u0000\u0000\u0000\u0089\u008b\u0001\u0000\u0000\u0000\u008a\u0088"+ + "\u0001\u0000\u0000\u0000\u008b\u008d\u0003\u0012\t\u0000\u008c\u008e\u0005"+ + "\n\u0000\u0000\u008d\u008c\u0001\u0000\u0000\u0000\u008d\u008e\u0001\u0000"+ + "\u0000\u0000\u008e\u0090\u0001\u0000\u0000\u0000\u008f\u0084\u0001\u0000"+ + "\u0000\u0000\u0090\u0093\u0001\u0000\u0000\u0000\u0091\u008f\u0001\u0000"+ + "\u0000\u0000\u0091\u0092\u0001\u0000\u0000\u0000\u0092\u0097\u0001\u0000"+ + "\u0000\u0000\u0093\u0091\u0001\u0000\u0000\u0000\u0094\u0096\u0003\u001e"+ + "\u000f\u0000\u0095\u0094\u0001\u0000\u0000\u0000\u0096\u0099\u0001\u0000"+ + "\u0000\u0000\u0097\u0095\u0001\u0000\u0000\u0000\u0097\u0098\u0001\u0000"+ + "\u0000\u0000\u0098\u009a\u0001\u0000\u0000\u0000\u0099\u0097\u0001\u0000"+ + "\u0000\u0000\u009a\u009b\u0005\u0006\u0000\u0000\u009b\u009d\u0001\u0000"+ + "\u0000\u0000\u009ct\u0001\u0000\u0000\u0000\u009c|\u0001\u0000\u0000\u0000"+ + "\u009d!\u0001\u0000\u0000\u0000\u009e\u00a1\u0003$\u0012\u0000\u009f\u00a1"+ + "\u0003(\u0014\u0000\u00a0\u009e\u0001\u0000\u0000\u0000\u00a0\u009f\u0001"+ + "\u0000\u0000\u0000\u00a1#\u0001\u0000\u0000\u0000\u00a2\u00a3\u0005\u0004"+ + "\u0000\u0000\u00a3\u00a4\u0003\b\u0004\u0000\u00a4\u00ae\u0005\u0006\u0000"+ + "\u0000\u00a5\u00a7\u0003\u001e\u000f\u0000\u00a6\u00a5\u0001\u0000\u0000"+ + "\u0000\u00a7\u00aa\u0001\u0000\u0000\u0000\u00a8\u00a6\u0001\u0000\u0000"+ + "\u0000\u00a8\u00a9\u0001\u0000\u0000\u0000\u00a9\u00ab\u0001\u0000\u0000"+ + "\u0000\u00aa\u00a8\u0001\u0000\u0000\u0000\u00ab\u00ad\u0003\u0002\u0001"+ + "\u0000\u00ac\u00a8\u0001\u0000\u0000\u0000\u00ad\u00b0\u0001\u0000\u0000"+ + "\u0000\u00ae\u00ac\u0001\u0000\u0000\u0000\u00ae\u00af\u0001\u0000\u0000"+ + "\u0000\u00af%\u0001\u0000\u0000\u0000\u00b0\u00ae\u0001\u0000\u0000\u0000"+ + "\u00b1\u00b5\u0005\u000f\u0000\u0000\u00b2\u00b4\u0003\u001e\u000f\u0000"+ + "\u00b3\u00b2\u0001\u0000\u0000\u0000\u00b4\u00b7\u0001\u0000\u0000\u0000"+ + "\u00b5\u00b3\u0001\u0000\u0000\u0000\u00b5\u00b6\u0001\u0000\u0000\u0000"+ + "\u00b6\u00b8\u0001\u0000\u0000\u0000\u00b7\u00b5\u0001\u0000\u0000\u0000"+ + "\u00b8\u00da\u0005\u001f\u0000\u0000\u00b9\u00bd\u0005\u000f\u0000\u0000"+ + "\u00ba\u00bc\u0003\u001e\u000f\u0000\u00bb\u00ba\u0001\u0000\u0000\u0000"+ + "\u00bc\u00bf\u0001\u0000\u0000\u0000\u00bd\u00bb\u0001\u0000\u0000\u0000"+ + "\u00bd\u00be\u0001\u0000\u0000\u0000\u00be\u00c0\u0001\u0000\u0000\u0000"+ + "\u00bf\u00bd\u0001\u0000\u0000\u0000\u00c0\u00ce\u0003\u0006\u0003\u0000"+ + "\u00c1\u00c5\u0005\n\u0000\u0000\u00c2\u00c4\u0003\u001e\u000f\u0000\u00c3"+ + "\u00c2\u0001\u0000\u0000\u0000\u00c4\u00c7\u0001\u0000\u0000\u0000\u00c5"+ + "\u00c3\u0001\u0000\u0000\u0000\u00c5\u00c6\u0001\u0000\u0000\u0000\u00c6"+ + "\u00c8\u0001\u0000\u0000\u0000\u00c7\u00c5\u0001\u0000\u0000\u0000\u00c8"+ + "\u00ca\u0003\u0006\u0003\u0000\u00c9\u00cb\u0005\n\u0000\u0000\u00ca\u00c9"+ + "\u0001\u0000\u0000\u0000\u00ca\u00cb\u0001\u0000\u0000\u0000\u00cb\u00cd"+ + "\u0001\u0000\u0000\u0000\u00cc\u00c1\u0001\u0000\u0000\u0000\u00cd\u00d0"+ + "\u0001\u0000\u0000\u0000\u00ce\u00cc\u0001\u0000\u0000\u0000\u00ce\u00cf"+ + "\u0001\u0000\u0000\u0000\u00cf\u00d4\u0001\u0000\u0000\u0000\u00d0\u00ce"+ + "\u0001\u0000\u0000\u0000\u00d1\u00d3\u0003\u001e\u000f\u0000\u00d2\u00d1"+ + "\u0001\u0000\u0000\u0000\u00d3\u00d6\u0001\u0000\u0000\u0000\u00d4\u00d2"+ + "\u0001\u0000\u0000\u0000\u00d4\u00d5\u0001\u0000\u0000\u0000\u00d5\u00d7"+ + "\u0001\u0000\u0000\u0000\u00d6\u00d4\u0001\u0000\u0000\u0000\u00d7\u00d8"+ + "\u0005\u001f\u0000\u0000\u00d8\u00da\u0001\u0000\u0000\u0000\u00d9\u00b1"+ + "\u0001\u0000\u0000\u0000\u00d9\u00b9\u0001\u0000\u0000\u0000\u00da\'\u0001"+ + "\u0000\u0000\u0000\u00db\u00dc\u0005\u0005\u0000\u0000\u00dc\u00dd\u0003"+ + "\b\u0004\u0000\u00dd\u00e7\u0005\u0007\u0000\u0000\u00de\u00e0\u0003\u001e"+ + "\u000f\u0000\u00df\u00de\u0001\u0000\u0000\u0000\u00e0\u00e3\u0001\u0000"+ + "\u0000\u0000\u00e1\u00df\u0001\u0000\u0000\u0000\u00e1\u00e2\u0001\u0000"+ + "\u0000\u0000\u00e2\u00e4\u0001\u0000\u0000\u0000\u00e3\u00e1\u0001\u0000"+ + "\u0000\u0000\u00e4\u00e6\u0003\u0002\u0001\u0000\u00e5\u00e1\u0001\u0000"+ + "\u0000\u0000\u00e6\u00e9\u0001\u0000\u0000\u0000\u00e7\u00e5\u0001\u0000"+ + "\u0000\u0000\u00e7\u00e8\u0001\u0000\u0000\u0000\u00e8)\u0001\u0000\u0000"+ + "\u0000\u00e9\u00e7\u0001\u0000\u0000\u0000\u001e+/3:>AKOZcrx\u0080\u0088"+ + "\u008d\u0091\u0097\u009c\u00a0\u00a8\u00ae\u00b5\u00bd\u00c5\u00ca\u00ce"+ + "\u00d4\u00d9\u00e1\u00e7"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.tokens b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.tokens new file mode 100644 index 00000000000..080a49ecbae --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.tokens @@ -0,0 +1,41 @@ +WS=1 +NL=2 +COMMENT=3 +L_BRACKET=4 +DOUBLE_L_BRACKET=5 +R_BRACKET=6 +DOUBLE_R_BRACKET=7 +EQUALS=8 +DOT=9 +COMMA=10 +BASIC_STRING=11 +LITERAL_STRING=12 +UNQUOTED_KEY=13 +VALUE_WS=14 +L_BRACE=15 +BOOLEAN=16 +ML_BASIC_STRING=17 +ML_LITERAL_STRING=18 +FLOAT=19 +INF=20 +NAN=21 +DEC_INT=22 +HEX_INT=23 +OCT_INT=24 +BIN_INT=25 +OFFSET_DATE_TIME=26 +LOCAL_DATE_TIME=27 +LOCAL_DATE=28 +LOCAL_TIME=29 +INLINE_TABLE_WS=30 +R_BRACE=31 +ARRAY_WS=32 +'['=4 +'[['=5 +']'=6 +']]'=7 +'='=8 +'.'=9 +','=10 +'{'=15 +'}'=31 diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserBaseListener.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserBaseListener.java new file mode 100644 index 00000000000..e0944694241 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserBaseListener.java @@ -0,0 +1,307 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Generated from java-escape by ANTLR 4.11.1 +package org.openrewrite.toml.internal.grammar; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ErrorNode; +import org.antlr.v4.runtime.tree.TerminalNode; + +/** + * This class provides an empty implementation of {@link TomlParserListener}, + * which can be extended to create a listener which only needs to handle a subset + * of the available methods. + */ +@SuppressWarnings("CheckReturnValue") +public class TomlParserBaseListener implements TomlParserListener { + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterDocument(TomlParser.DocumentContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitDocument(TomlParser.DocumentContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterExpression(TomlParser.ExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitExpression(TomlParser.ExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterComment(TomlParser.CommentContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitComment(TomlParser.CommentContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterKeyValue(TomlParser.KeyValueContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitKeyValue(TomlParser.KeyValueContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterKey(TomlParser.KeyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitKey(TomlParser.KeyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterSimpleKey(TomlParser.SimpleKeyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitSimpleKey(TomlParser.SimpleKeyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterUnquotedKey(TomlParser.UnquotedKeyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitUnquotedKey(TomlParser.UnquotedKeyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterQuotedKey(TomlParser.QuotedKeyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitQuotedKey(TomlParser.QuotedKeyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterDottedKey(TomlParser.DottedKeyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitDottedKey(TomlParser.DottedKeyContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterValue(TomlParser.ValueContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitValue(TomlParser.ValueContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterString(TomlParser.StringContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitString(TomlParser.StringContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterInteger(TomlParser.IntegerContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitInteger(TomlParser.IntegerContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterFloatingPoint(TomlParser.FloatingPointContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitFloatingPoint(TomlParser.FloatingPointContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterBool(TomlParser.BoolContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitBool(TomlParser.BoolContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterDateTime(TomlParser.DateTimeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitDateTime(TomlParser.DateTimeContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterCommentOrNl(TomlParser.CommentOrNlContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitCommentOrNl(TomlParser.CommentOrNlContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterArray(TomlParser.ArrayContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitArray(TomlParser.ArrayContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterTable(TomlParser.TableContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitTable(TomlParser.TableContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterStandardTable(TomlParser.StandardTableContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitStandardTable(TomlParser.StandardTableContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterInlineTable(TomlParser.InlineTableContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitInlineTable(TomlParser.InlineTableContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterArrayTable(TomlParser.ArrayTableContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitArrayTable(TomlParser.ArrayTableContext ctx) { } + + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterEveryRule(ParserRuleContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitEveryRule(ParserRuleContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void visitTerminal(TerminalNode node) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void visitErrorNode(ErrorNode node) { } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserBaseVisitor.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserBaseVisitor.java new file mode 100644 index 00000000000..f4cfa1ebb80 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserBaseVisitor.java @@ -0,0 +1,177 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Generated from java-escape by ANTLR 4.11.1 +package org.openrewrite.toml.internal.grammar; +import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; + +/** + * This class provides an empty implementation of {@link TomlParserVisitor}, + * which can be extended to create a visitor which only needs to handle a subset + * of the available methods. + * + * @param The return type of the visit operation. Use {@link Void} for + * operations with no return type. + */ +@SuppressWarnings("CheckReturnValue") +public class TomlParserBaseVisitor extends AbstractParseTreeVisitor implements TomlParserVisitor { + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitDocument(TomlParser.DocumentContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitExpression(TomlParser.ExpressionContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitComment(TomlParser.CommentContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitKeyValue(TomlParser.KeyValueContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitKey(TomlParser.KeyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitSimpleKey(TomlParser.SimpleKeyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitUnquotedKey(TomlParser.UnquotedKeyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitQuotedKey(TomlParser.QuotedKeyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitDottedKey(TomlParser.DottedKeyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitValue(TomlParser.ValueContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitString(TomlParser.StringContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitInteger(TomlParser.IntegerContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitFloatingPoint(TomlParser.FloatingPointContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitBool(TomlParser.BoolContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitDateTime(TomlParser.DateTimeContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitCommentOrNl(TomlParser.CommentOrNlContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitArray(TomlParser.ArrayContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTable(TomlParser.TableContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitStandardTable(TomlParser.StandardTableContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitInlineTable(TomlParser.InlineTableContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitArrayTable(TomlParser.ArrayTableContext ctx) { return visitChildren(ctx); } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserListener.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserListener.java new file mode 100644 index 00000000000..5b428a22f42 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserListener.java @@ -0,0 +1,235 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Generated from java-escape by ANTLR 4.11.1 +package org.openrewrite.toml.internal.grammar; +import org.antlr.v4.runtime.tree.ParseTreeListener; + +/** + * This interface defines a complete listener for a parse tree produced by + * {@link TomlParser}. + */ +public interface TomlParserListener extends ParseTreeListener { + /** + * Enter a parse tree produced by {@link TomlParser#document}. + * @param ctx the parse tree + */ + void enterDocument(TomlParser.DocumentContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#document}. + * @param ctx the parse tree + */ + void exitDocument(TomlParser.DocumentContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#expression}. + * @param ctx the parse tree + */ + void enterExpression(TomlParser.ExpressionContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#expression}. + * @param ctx the parse tree + */ + void exitExpression(TomlParser.ExpressionContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#comment}. + * @param ctx the parse tree + */ + void enterComment(TomlParser.CommentContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#comment}. + * @param ctx the parse tree + */ + void exitComment(TomlParser.CommentContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#keyValue}. + * @param ctx the parse tree + */ + void enterKeyValue(TomlParser.KeyValueContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#keyValue}. + * @param ctx the parse tree + */ + void exitKeyValue(TomlParser.KeyValueContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#key}. + * @param ctx the parse tree + */ + void enterKey(TomlParser.KeyContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#key}. + * @param ctx the parse tree + */ + void exitKey(TomlParser.KeyContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#simpleKey}. + * @param ctx the parse tree + */ + void enterSimpleKey(TomlParser.SimpleKeyContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#simpleKey}. + * @param ctx the parse tree + */ + void exitSimpleKey(TomlParser.SimpleKeyContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#unquotedKey}. + * @param ctx the parse tree + */ + void enterUnquotedKey(TomlParser.UnquotedKeyContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#unquotedKey}. + * @param ctx the parse tree + */ + void exitUnquotedKey(TomlParser.UnquotedKeyContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#quotedKey}. + * @param ctx the parse tree + */ + void enterQuotedKey(TomlParser.QuotedKeyContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#quotedKey}. + * @param ctx the parse tree + */ + void exitQuotedKey(TomlParser.QuotedKeyContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#dottedKey}. + * @param ctx the parse tree + */ + void enterDottedKey(TomlParser.DottedKeyContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#dottedKey}. + * @param ctx the parse tree + */ + void exitDottedKey(TomlParser.DottedKeyContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#value}. + * @param ctx the parse tree + */ + void enterValue(TomlParser.ValueContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#value}. + * @param ctx the parse tree + */ + void exitValue(TomlParser.ValueContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#string}. + * @param ctx the parse tree + */ + void enterString(TomlParser.StringContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#string}. + * @param ctx the parse tree + */ + void exitString(TomlParser.StringContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#integer}. + * @param ctx the parse tree + */ + void enterInteger(TomlParser.IntegerContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#integer}. + * @param ctx the parse tree + */ + void exitInteger(TomlParser.IntegerContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#floatingPoint}. + * @param ctx the parse tree + */ + void enterFloatingPoint(TomlParser.FloatingPointContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#floatingPoint}. + * @param ctx the parse tree + */ + void exitFloatingPoint(TomlParser.FloatingPointContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#bool}. + * @param ctx the parse tree + */ + void enterBool(TomlParser.BoolContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#bool}. + * @param ctx the parse tree + */ + void exitBool(TomlParser.BoolContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#dateTime}. + * @param ctx the parse tree + */ + void enterDateTime(TomlParser.DateTimeContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#dateTime}. + * @param ctx the parse tree + */ + void exitDateTime(TomlParser.DateTimeContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#commentOrNl}. + * @param ctx the parse tree + */ + void enterCommentOrNl(TomlParser.CommentOrNlContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#commentOrNl}. + * @param ctx the parse tree + */ + void exitCommentOrNl(TomlParser.CommentOrNlContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#array}. + * @param ctx the parse tree + */ + void enterArray(TomlParser.ArrayContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#array}. + * @param ctx the parse tree + */ + void exitArray(TomlParser.ArrayContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#table}. + * @param ctx the parse tree + */ + void enterTable(TomlParser.TableContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#table}. + * @param ctx the parse tree + */ + void exitTable(TomlParser.TableContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#standardTable}. + * @param ctx the parse tree + */ + void enterStandardTable(TomlParser.StandardTableContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#standardTable}. + * @param ctx the parse tree + */ + void exitStandardTable(TomlParser.StandardTableContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#inlineTable}. + * @param ctx the parse tree + */ + void enterInlineTable(TomlParser.InlineTableContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#inlineTable}. + * @param ctx the parse tree + */ + void exitInlineTable(TomlParser.InlineTableContext ctx); + /** + * Enter a parse tree produced by {@link TomlParser#arrayTable}. + * @param ctx the parse tree + */ + void enterArrayTable(TomlParser.ArrayTableContext ctx); + /** + * Exit a parse tree produced by {@link TomlParser#arrayTable}. + * @param ctx the parse tree + */ + void exitArrayTable(TomlParser.ArrayTableContext ctx); +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserVisitor.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserVisitor.java new file mode 100644 index 00000000000..acbe51681b2 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParserVisitor.java @@ -0,0 +1,154 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Generated from java-escape by ANTLR 4.11.1 +package org.openrewrite.toml.internal.grammar; +import org.antlr.v4.runtime.tree.ParseTreeVisitor; + +/** + * This interface defines a complete generic visitor for a parse tree produced + * by {@link TomlParser}. + * + * @param The return type of the visit operation. Use {@link Void} for + * operations with no return type. + */ +public interface TomlParserVisitor extends ParseTreeVisitor { + /** + * Visit a parse tree produced by {@link TomlParser#document}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitDocument(TomlParser.DocumentContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#expression}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitExpression(TomlParser.ExpressionContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#comment}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitComment(TomlParser.CommentContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#keyValue}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitKeyValue(TomlParser.KeyValueContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#key}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitKey(TomlParser.KeyContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#simpleKey}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitSimpleKey(TomlParser.SimpleKeyContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#unquotedKey}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitUnquotedKey(TomlParser.UnquotedKeyContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#quotedKey}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitQuotedKey(TomlParser.QuotedKeyContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#dottedKey}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitDottedKey(TomlParser.DottedKeyContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#value}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitValue(TomlParser.ValueContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#string}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitString(TomlParser.StringContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#integer}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitInteger(TomlParser.IntegerContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#floatingPoint}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitFloatingPoint(TomlParser.FloatingPointContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#bool}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitBool(TomlParser.BoolContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#dateTime}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitDateTime(TomlParser.DateTimeContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#commentOrNl}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitCommentOrNl(TomlParser.CommentOrNlContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#array}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitArray(TomlParser.ArrayContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#table}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTable(TomlParser.TableContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#standardTable}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitStandardTable(TomlParser.StandardTableContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#inlineTable}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitInlineTable(TomlParser.InlineTableContext ctx); + /** + * Visit a parse tree produced by {@link TomlParser#arrayTable}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitArrayTable(TomlParser.ArrayTableContext ctx); +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/package-info.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/package-info.java new file mode 100644 index 00000000000..0dc7d998012 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +@NonNullFields +package org.openrewrite.toml.internal; + +import org.jspecify.annotations.NullMarked; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/marker/ArrayTable.java b/rewrite-toml/src/main/java/org/openrewrite/toml/marker/ArrayTable.java new file mode 100644 index 00000000000..d64194c1f75 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/marker/ArrayTable.java @@ -0,0 +1,28 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.marker; + +import lombok.Value; +import lombok.With; +import org.openrewrite.marker.Marker; + +import java.util.UUID; + +@Value +@With +public class ArrayTable implements Marker { + UUID id; +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/marker/InlineTable.java b/rewrite-toml/src/main/java/org/openrewrite/toml/marker/InlineTable.java new file mode 100644 index 00000000000..c444fed4f1e --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/marker/InlineTable.java @@ -0,0 +1,28 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.marker; + +import lombok.Value; +import lombok.With; +import org.openrewrite.marker.Marker; + +import java.util.UUID; + +@Value +@With +public class InlineTable implements Marker { + UUID id; +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/marker/package-info.java b/rewrite-toml/src/main/java/org/openrewrite/toml/marker/package-info.java new file mode 100644 index 00000000000..f660c6bdfc4 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/marker/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +@NonNullFields +package org.openrewrite.toml.marker; + +import org.jspecify.annotations.NullMarked; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/package-info.java b/rewrite-toml/src/main/java/org/openrewrite/toml/package-info.java new file mode 100644 index 00000000000..17c795873d3 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +@NonNullFields +package org.openrewrite.toml; + +import org.jspecify.annotations.NullMarked; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Comment.java b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Comment.java new file mode 100644 index 00000000000..64d0f5afc64 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Comment.java @@ -0,0 +1,28 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.tree; + +import lombok.Value; +import lombok.With; +import org.openrewrite.marker.Markers; + +@Value +@With +public class Comment { + String text; + String suffix; + Markers markers; +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Space.java b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Space.java new file mode 100644 index 00000000000..c79702a444d --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Space.java @@ -0,0 +1,270 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.tree; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; +import lombok.EqualsAndHashCode; +import org.jspecify.annotations.Nullable; +import org.openrewrite.marker.Markers; + +import java.util.*; + +import static java.util.Collections.emptyList; + +/** + * Wherever whitespace can occur in JSON, so can comments (at least block style comments). + * So whitespace and comments are like peanut butter and jelly. + */ +@EqualsAndHashCode +@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "@ref") +public class Space { + public static final Space EMPTY = new Space("", emptyList()); + public static final Space SINGLE_SPACE = new Space(" ", emptyList()); + + private final List comments; + + @Nullable + private final String whitespace; + + /* + * Most occurrences of spaces will have no comments or markers and will be repeated frequently throughout a source file. + * e.g.: a single space between keywords, or the common indentation of every line in a block. + * So use flyweights to avoid storing many instances of functionally identical spaces + */ + private static final Map flyweights = Collections.synchronizedMap(new WeakHashMap<>()); + + private Space(@Nullable String whitespace, List comments) { + this.comments = comments; + this.whitespace = whitespace == null || whitespace.isEmpty() ? null : whitespace; + } + + @JsonCreator + public static Space build(@Nullable String whitespace, List comments) { + if (comments.isEmpty()) { + if (whitespace == null || whitespace.isEmpty()) { + return Space.EMPTY; + } else if (whitespace.length() <= 100) { + //noinspection StringOperationCanBeSimplified + return flyweights.computeIfAbsent(whitespace, k -> new Space(new String(whitespace), comments)); + } + } + return new Space(whitespace, comments); + } + + public String getIndent() { + if (!comments.isEmpty()) { + return getWhitespaceIndent(comments.get(comments.size() - 1).getSuffix()); + } + return getWhitespaceIndent(whitespace); + } + + public String getLastWhitespace() { + if (!comments.isEmpty()) { + return comments.get(comments.size() - 1).getSuffix(); + } + return whitespace == null ? "" : whitespace; + } + + private String getWhitespaceIndent(@Nullable String whitespace) { + if (whitespace == null) { + return ""; + } + int lastNewline = whitespace.lastIndexOf('\n'); + if (lastNewline >= 0) { + return whitespace.substring(lastNewline + 1); + } else if (lastNewline == whitespace.length() - 1) { + return ""; + } + return whitespace; + } + + public List getComments() { + return comments; + } + + public String getWhitespace() { + return whitespace == null ? "" : whitespace; + } + + public boolean hasComment(String comment) { + for (Comment c : comments) { + if (c.getText().equals(comment)) { + return true; + } + } + return false; + } + + public Space withComments(List comments) { + if (comments == this.comments) { + return this; + } + if (comments.isEmpty() && (whitespace == null || whitespace.isEmpty())) { + return Space.EMPTY; + } + return build(whitespace, comments); + } + + public Space withWhitespace(String whitespace) { + if (comments.isEmpty() && whitespace.isEmpty()) { + return Space.EMPTY; + } + if ((whitespace.isEmpty() && this.whitespace == null) || whitespace.equals(this.whitespace)) { + return this; + } + return build(whitespace, comments); + } + + public boolean isEmpty() { + return this == EMPTY; + } + + public static Space firstPrefix(@Nullable List trees) { + return trees == null || trees.isEmpty() ? Space.EMPTY : trees.iterator().next().getPrefix(); + } + + public static Space format(String formatting) { + return format(formatting, 0, formatting.length()); + } + + public static Space format(String formatting, int beginIndex, int toIndex) { + if (beginIndex == toIndex) { + return Space.EMPTY; + } else if (toIndex == beginIndex + 1 && ' ' == formatting.charAt(beginIndex)) { + return Space.SINGLE_SPACE; + } else { + rangeCheck(formatting.length(), beginIndex, toIndex); + } + + StringBuilder prefix = new StringBuilder(); + StringBuilder comment = new StringBuilder(); + List comments = new ArrayList<>(1); + + boolean inSingleLineComment = false; + + for (int i = beginIndex; i < toIndex; i++) { + char c = formatting.charAt(i); + switch (c) { + case '#': + if (inSingleLineComment) { + comment.append(c); + } else { + inSingleLineComment = true; + comment.setLength(0); + } + break; + case '\r': + case '\n': + if (inSingleLineComment) { + inSingleLineComment = false; + comments.add(new Comment(comment.toString(), prefix.toString(), Markers.EMPTY)); + prefix.setLength(0); + comment.setLength(0); + prefix.append(c); + } else { + prefix.append(c); + } + break; + default: + if (inSingleLineComment) { + comment.append(c); + } else { + prefix.append(c); + } + } + } + // If a file ends with a single-line comment there may be no terminating newline + if (comment.length() > 0) { + comments.add(new Comment(comment.toString(), prefix.toString(), Markers.EMPTY)); + prefix.setLength(0); + } + + // Shift the whitespace on each comment forward to be a suffix of the comment before it, and the + // whitespace on the first comment to be the whitespace of the tree element. The remaining prefix is the suffix + // of the last comment. + String whitespace = prefix.toString(); + if (!comments.isEmpty()) { + for (int i = comments.size() - 1; i >= 0; i--) { + Comment c = comments.get(i); + String next = c.getSuffix(); + comments.set(i, c.withSuffix(whitespace)); + whitespace = next; + } + } + + return build(whitespace, comments); + } + + static void rangeCheck(int arrayLength, int fromIndex, int toIndex) { + if (fromIndex > toIndex) { + throw new IllegalArgumentException( + "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); + } + if (fromIndex < 0) { + throw new StringIndexOutOfBoundsException(fromIndex); + } + if (toIndex > arrayLength) { + throw new StringIndexOutOfBoundsException(toIndex); + } + } + + public static List formatFirstPrefix(List trees, Space prefix) { + if (!trees.isEmpty() && !trees.get(0).getPrefix().equals(prefix)) { + List formattedTrees = new ArrayList<>(trees); + formattedTrees.set(0, formattedTrees.get(0).withPrefix(prefix)); + return formattedTrees; + } + + return trees; + } + + private static final String[] spaces = { + "·₁", "·₂", "·₃", "·₄", "·₅", "·₆", "·₇", "·₈", "·₉", "·₊" + }; + + private static final String[] tabs = { + "-₁", "-₂", "-₃", "-₄", "-₅", "-₆", "-₇", "-₈", "-₉", "-₊" + }; + + @Override + public String toString() { + StringBuilder printedWs = new StringBuilder(); + int lastNewline = 0; + if (whitespace != null) { + char[] charArray = whitespace.toCharArray(); + for (int i = 0; i < charArray.length; i++) { + char c = charArray[i]; + if (c == '\n') { + printedWs.append("\\n"); + lastNewline = i + 1; + } else if (c == '\r') { + printedWs.append("\\r"); + lastNewline = i + 1; + } else if (c == ' ') { + printedWs.append(spaces[(i - lastNewline) % 10]); + } else if (c == '\t') { + printedWs.append(tabs[(i - lastNewline) % 10]); + } + } + } + + return "Space(" + + "comments=<" + (comments.size() == 1 ? "1 comment" : comments.size() + " comments") + + ">, whitespace='" + printedWs + "')"; + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Toml.java b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Toml.java new file mode 100644 index 00000000000..8d6037316fe --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Toml.java @@ -0,0 +1,358 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.tree; + +import lombok.*; +import lombok.experimental.NonFinal; +import org.jspecify.annotations.Nullable; +import org.openrewrite.*; +import org.openrewrite.marker.Markers; +import org.openrewrite.toml.TomlVisitor; +import org.openrewrite.toml.internal.TomlPrinter; + +import java.lang.ref.WeakReference; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.util.List; +import java.util.UUID; + +public interface Toml extends Tree { + + @SuppressWarnings("unchecked") + @Override + default R accept(TreeVisitor v, P p) { + return (R) acceptToml(v.adapt(TomlVisitor.class), p); + } + + default

@Nullable Toml acceptToml(TomlVisitor

v, P p) { + return v.defaultValue(this, p); + } + + @Override + default

boolean isAcceptable(TreeVisitor v, P p) { + return v.isAdaptableTo(TomlVisitor.class); + } + + Space getPrefix(); + + J withPrefix(Space prefix); + + @Value + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + class Array implements Toml { + @Nullable + @NonFinal + transient WeakReference padding; + + @With + @EqualsAndHashCode.Include + UUID id; + + @With + Space prefix; + + @With + Markers markers; + + List> values; + + public List getValues() { + return TomlRightPadded.getElements(values); + } + + public Array withValues(List values) { + return getPadding().withValues(TomlRightPadded.withElements(this.values, values)); + } + + @Override + public

Toml acceptToml(TomlVisitor

v, P p) { + return v.visitArray(this, p); + } + + public Padding getPadding() { + Padding p; + if (this.padding == null) { + p = new Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final Array t; + + public List> getValues() { + return t.values; + } + + public Array withValues(List> values) { + return t.values == values ? t : new Array(t.id, t.prefix, t.markers, values); + } + } + } + + @Value + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @With + class Document implements Toml, SourceFile { + @EqualsAndHashCode.Include + UUID id; + + Path sourcePath; + Space prefix; + Markers markers; + + @With(AccessLevel.PRIVATE) + String charsetName; + + boolean charsetBomMarked; + Checksum checksum; + FileAttributes fileAttributes; + + @Override + public Charset getCharset() { + return Charset.forName(charsetName); + } + + @Override + public SourceFile withCharset(Charset charset) { + return withCharsetName(charset.name()); + } + + List values; + Space eof; + + @Override + public

Toml acceptToml(TomlVisitor

v, P p) { + return v.visitDocument(this, p); + } + + @Override + public

TreeVisitor> printer(Cursor cursor) { + return new TomlPrinter<>(); + } + } + + @Value + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @With + class Empty implements Toml { + @EqualsAndHashCode.Include + UUID id; + + Space prefix; + Markers markers; + + @Override + public

Toml acceptToml(TomlVisitor

v, P p) { + return v.visitEmpty(this, p); + } + } + + @Value + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @With + class Identifier implements TomlKey { + @EqualsAndHashCode.Include + UUID id; + + Space prefix; + Markers markers; + String source; + String name; + + @Override + public

Toml acceptToml(TomlVisitor

v, P p) { + return v.visitIdentifier(this, p); + } + + @Override + public String toString() { + return "Identifier{prefix=" + prefix + ", name=" + name + "}"; + } + } + + @Value + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + @With + class KeyValue implements TomlValue { + @Nullable + @NonFinal + transient WeakReference padding; + + @EqualsAndHashCode.Include + UUID id; + + Space prefix; + + Markers markers; + + TomlRightPadded key; + + public TomlKey getKey() { + return key.getElement(); + } + + public KeyValue withKey(TomlKey key) { + return getPadding().withKey(TomlRightPadded.withElement(this.key, key)); + } + + Toml value; + + @Override + public

Toml acceptToml(TomlVisitor

v, P p) { + return v.visitKeyValue(this, p); + } + + public Padding getPadding() { + Padding p; + if (this.padding == null) { + p = new Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final KeyValue t; + + public TomlRightPadded getKey() { + return t.key; + } + + public KeyValue withKey(TomlRightPadded key) { + return t.key == key ? t : new KeyValue(t.id, t.prefix, t.markers, key, t.value); + } + } + + @Override + public String toString() { + return "KeyValue{prefix=" + prefix + ", key=" + key.getElement() + '}'; + } + } + + @Value + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @With + class Literal implements Toml { + @EqualsAndHashCode.Include + UUID id; + + Space prefix; + + Markers markers; + + TomlType.Primitive type; + + String source; + + Object value; + + @Override + public

Toml acceptToml(TomlVisitor

v, P p) { + return v.visitLiteral(this, p); + } + + @Override + public String toString() { + return "Literal{prefix=" + prefix + ", source=" + source + "}"; + } + } + + @Value + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + class Table implements TomlValue { + @Nullable + @NonFinal + transient WeakReference padding; + + @EqualsAndHashCode.Include + @With + UUID id; + + @With + Space prefix; + + @With + Markers markers; + + @With + TomlRightPadded name; + + List> values; + + public List getValues() { + return TomlRightPadded.getElements(values); + } + + public Table withValues(List values) { + return getPadding().withValues(TomlRightPadded.withElements(this.values, values)); + } + + @Override + public

Toml acceptToml(TomlVisitor

v, P p) { + return v.visitTable(this, p); + } + + public Table.Padding getPadding() { + Table.Padding p; + if (this.padding == null) { + p = new Table.Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new Table.Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final Table t; + + public List> getValues() { + return t.values; + } + + public Table withValues(List> values) { + return t.values == values ? t : new Table(t.id, t.prefix, t.markers, t.name, values); + } + } + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlKey.java b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlKey.java new file mode 100644 index 00000000000..bdf63eb1f0e --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlKey.java @@ -0,0 +1,19 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.tree; + +public interface TomlKey extends Toml { +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlRightPadded.java b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlRightPadded.java new file mode 100644 index 00000000000..911bd8adf7a --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlRightPadded.java @@ -0,0 +1,117 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.tree; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.With; +import lombok.experimental.FieldDefaults; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.marker.Markers; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; + +/** + * A Toml element that could have trailing space. + * + * @param + */ +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) +@Data +public class TomlRightPadded { + @With + T element; + + @With + Space after; + + @With + Markers markers; + + public TomlRightPadded map(UnaryOperator map) { + return withElement(map.apply(element)); + } + + public static List getElements(List> ls) { + List list = new ArrayList<>(); + for (TomlRightPadded l : ls) { + T elem = l.getElement(); + list.add(elem); + } + return list; + } + + public static

List> withElements(List> before, List

elements) { + // a cheaper check for the most common case when there are no changes + if (elements.size() == before.size()) { + boolean hasChanges = false; + for (int i = 0; i < before.size(); i++) { + if (before.get(i).getElement() != elements.get(i)) { + hasChanges = true; + break; + } + } + if (!hasChanges) { + return before; + } + } + + List> after = new ArrayList<>(elements.size()); + Map> beforeById = before.stream().collect(Collectors + .toMap(j -> j.getElement().getId(), Function.identity())); + + for (P t : elements) { + if (beforeById.get(t.getId()) != null) { + TomlRightPadded

found = beforeById.get(t.getId()); + after.add(found.withElement(t)); + } else { + after.add(new TomlRightPadded<>(t, Space.EMPTY, Markers.EMPTY)); + } + } + + return after; + } + + public static TomlRightPadded build(T element) { + return new TomlRightPadded<>(element, Space.EMPTY, Markers.EMPTY); + } + + public static @Nullable TomlRightPadded withElement(@Nullable TomlRightPadded before, @Nullable T elements) { + if (before == null) { + if (elements == null) { + return null; + } + return new TomlRightPadded<>(elements, Space.EMPTY, Markers.EMPTY); + } + if (elements == null) { + return null; + } + return before.withElement(elements); + } + + @Override + public String toString() { + return "TomlRightPadded(element=" + element.getClass().getSimpleName() + ", after=" + after + ')'; + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlType.java b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlType.java new file mode 100644 index 00000000000..abe678a6c1d --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlType.java @@ -0,0 +1,29 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.tree; + +public interface TomlType { + enum Primitive implements TomlType { + Boolean, + Float, + Integer, + LocalDate, + LocalDateTime, + LocalTime, + OffsetDateTime, + String + } +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlValue.java b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlValue.java new file mode 100644 index 00000000000..767d3d382a4 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/TomlValue.java @@ -0,0 +1,19 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml.tree; + +public interface TomlValue extends Toml { +} diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/package-info.java b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/package-info.java new file mode 100644 index 00000000000..2a3f1d8f923 --- /dev/null +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +@NonNullFields +package org.openrewrite.toml.tree; + +import org.jspecify.annotations.NullMarked; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java b/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java new file mode 100644 index 00000000000..ecde113dc0e --- /dev/null +++ b/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java @@ -0,0 +1,341 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml; + +import org.junit.jupiter.api.Test; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.toml.Assertions.toml; + +class TomlParserTest implements RewriteTest { + @Test + void keyValueString() { + rewriteRun( + toml( + """ + str = "I'm a string. \\"You can quote me\\". Name\\tJos\\u00E9\\nLocation\\tSF." + """ + ) + ); + } + + @Test + void keyValueInteger() { + rewriteRun( + toml( + """ + int1 = +99 + int2 = 42 + int3 = 0 + int4 = -17 + int5 = 1_000 + + # hexadecimal with prefix `0x` + hex1 = 0xDEADBEEF + hex2 = 0xdeadbeef + hex3 = 0xdead_beef + # octal with prefix `0o` + oct1 = 0o01234567 + oct2 = 0o755 # useful for Unix file permissions + + # binary with prefix `0b` + bin1 = 0b11010110 + """ + ) + ); + } + + @Test + void keyValueFloat() { + rewriteRun( + toml( + """ + # fractional + flt1 = +1.0 + flt2 = 3.1415 + flt3 = -0.01 + + # exponent + flt4 = 5e+22 + flt5 = 1e06 + flt6 = -2E-2 + + # both + flt7 = 6.626e-34 + + flt8 = 224_617.445_991_228 + + # infinity + sf1 = inf # positive infinity + sf2 = +inf # positive infinity + sf3 = -inf # negative infinity + + # not a number + sf4 = nan # actual sNaN/qNaN encoding is implementation-specific + sf5 = +nan # sa + sf6 = -nan # valid, actual encoding is implementation-specific + """ + ) + ); + } + + @Test + void keyValueBool() { + rewriteRun( + toml( + """ + bool1 = true + bool2 = false + """ + ) + ); + } + + @Test + void keyValueOffsetDateTime() { + rewriteRun( + toml( + """ + odt1 = 1979-05-27T07:32:00Z + odt2 = 1979-05-27T00:32:00-07:00 + odt3 = 1979-05-27T00:32:00.999999-07:00 + odt4 = 1979-05-27 07:32:00Z + """ + ) + ); + } + + @Test + void keyValueLocalDateTime() { + rewriteRun( + toml( + """ + ldt1 = 1979-05-27T07:32:00 + ldt2 = 1979-05-27T00:32:00.999999 + """ + ) + ); + } + + @Test + void keyValueLocalDate() { + rewriteRun( + toml( + """ + ld1 = 1979-05-27 + """ + ) + ); + } + + @Test + void keyValueLocalTime() { + rewriteRun( + toml( + """ + lt1 = 07:32:00 + lt2 = 00:32:00.999999 + """ + ) + ); + } + + @Test + void keyValueArray() { + rewriteRun( + toml( + """ + integers = [ 1, 2, 3 ] + colors = [ "red", "yellow", "green" ] + nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ] + nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ] + string_array = [ "all", 'strings', ""\"are the same""\", '''type''' ] + + # Mixed-type arrays are allowed + numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ] + contributors = [ + "Foo Bar ", + { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" } + ] + integers2 = [ + 1, 2, 3 + ] + + integers3 = [ + 1, + 2, # this is ok + ] + """ + ) + ); + } + + @Test + void table() { + rewriteRun( + toml( + """ + [table-1] + key1 = "some string" + key2 = 123 + + [table-2] + key1 = "another string" + key2 = 456 + + [dog."tater.man"] + type.name = "pug" + """ + ) + ); + } + + @Test + void arrayTable() { + rewriteRun( + toml( + """ + [[products]] + name = "Hammer" + sku = 738594937 + + [[products]] # empty table within the array + + [[products]] + name = "Nail" + sku = 284758393 + + color = "gray" + """ + ) + ); + } + + @Test + void bareKeys() { + rewriteRun( + toml( + """ + key = "value" + bare_key = "value" + bare-key = "value" + 1234 = "value" + """ + ) + ); + } + + @Test + void quotedKeys() { + rewriteRun( + toml( + """ + "127.0.0.1" = "value" + "character encoding" = "value" + "ʎǝʞ" = "value" + 'key2' = "value" + 'quoted "value"' = "value" + """ + ) + ); + } + + @Test + void dottedKeys() { + rewriteRun( + toml( + """ + physical.color = "orange" + physical.shape = "round" + site."google.com" = true + """ + ) + ); + } + + @Test + void extraWhitespaceDottedKeys() { + rewriteRun( + toml( + """ + fruit.name = "banana" # this is best practice + fruit. color = "yellow" # same as fruit.color + fruit . flavor = "banana" # same as fruit.flavor + """ + ) + ); + } + + @Test + void extraWhitespaceTable() { + rewriteRun( + toml( + """ + [a.b.c] # this is best practice + [ d.e.f ] # same as [d.e.f] + [ g . h . i ] # same as [g.h.i] + [ j . "ʞ" . 'l' ] # same as [j."ʞ".'l'] + """ + ) + ); + } + + @Test + void extraWhitespaceArrayTable() { + rewriteRun( + toml( + """ + [[a.b.c]] # this is best practice + [[ d.e.f ]] # same as [[d.e.f]] + [[ g . h . i ]] # same as [[g.h.i]] + [[ j . "ʞ" . 'l' ]] # same as [[j."ʞ".'l']] + """ + ) + ); + } + + @Test + void empty() { + rewriteRun( + toml( + "" + ) + ); + } + + @Test + void trailingComment() { + rewriteRun( + toml( + """ + str = "I'm a string. \\"You can quote me\\". Name\\tJos\\u00E9\\nLocation\\tSF." + # trailing comment + """ + ) + ); + } + + @Test + void multiBytesUnicode() { + rewriteRun( + toml( + """ + robot.name = "r2d2" # 🤖 + """ + ) + ); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index f280b567997..1cc35fdf9ba 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,6 +27,7 @@ val allProjects = listOf( "rewrite-properties", "rewrite-protobuf", "rewrite-test", + "rewrite-toml", "rewrite-xml", "rewrite-yaml", ) From 19dfd6a9042bbaaceaa9a10654c2bf29909284eb Mon Sep 17 00:00:00 2001 From: Shannon Pamperl Date: Fri, 3 Jan 2025 15:17:33 -0600 Subject: [PATCH 102/179] Polish toml --- .../src/main/java/org/openrewrite/toml/tree/Space.java | 2 +- .../src/test/java/org/openrewrite/toml/TomlParserTest.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Space.java b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Space.java index c79702a444d..caf3dcb87ee 100644 --- a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Space.java +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Space.java @@ -27,7 +27,7 @@ import static java.util.Collections.emptyList; /** - * Wherever whitespace can occur in JSON, so can comments (at least block style comments). + * Wherever whitespace can occur in TOML, so can comments (at least block style comments). * So whitespace and comments are like peanut butter and jelly. */ @EqualsAndHashCode diff --git a/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java b/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java index ecde113dc0e..fefa837ee9b 100644 --- a/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java +++ b/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java @@ -85,7 +85,7 @@ void keyValueFloat() { # not a number sf4 = nan # actual sNaN/qNaN encoding is implementation-specific - sf5 = +nan # sa + sf5 = +nan # same as `nan` sf6 = -nan # valid, actual encoding is implementation-specific """ ) @@ -271,9 +271,9 @@ void extraWhitespaceDottedKeys() { rewriteRun( toml( """ - fruit.name = "banana" # this is best practice + fruit.name = "banana" # this is best practice fruit. color = "yellow" # same as fruit.color - fruit . flavor = "banana" # same as fruit.flavor + fruit . flavor = "banana" # same as fruit.flavor """ ) ); From 6dd029fe7be0aa3ddc1b27a63e9637e18b972c8a Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Fri, 3 Jan 2025 22:28:31 +0100 Subject: [PATCH 103/179] Do not match unnamed variables in NameCaseConvention Fixes openrewrite/rewrite-static-analysis#424 --- .../main/java/org/openrewrite/internal/NameCaseConvention.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/NameCaseConvention.java b/rewrite-core/src/main/java/org/openrewrite/internal/NameCaseConvention.java index 74639b39b89..038a065c074 100755 --- a/rewrite-core/src/main/java/org/openrewrite/internal/NameCaseConvention.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/NameCaseConvention.java @@ -96,6 +96,9 @@ public boolean matches(String str) { } public static boolean matches(NameCaseConvention convention, String str) { + if (str.isEmpty()) { + return false; + } switch (convention) { case LOWER_CAMEL: if (!Character.isLowerCase(str.charAt(0)) && str.charAt(0) != '$') { From e6a8499145bc0d07aef301c3c1f7315fc574cf8c Mon Sep 17 00:00:00 2001 From: Leanne Kerford Date: Fri, 3 Jan 2025 13:30:27 -0800 Subject: [PATCH 104/179] Adding option cutOffDate to RemoveOwaspSuppressions (#4846) * Adding option cutOffDate to RemoveOwaspSuppressions There are cases were we want to only remove suppressions up to a specific date, this allows a cut off date to be provided when removed expired suppressions * Update rewrite-xml/src/main/java/org/openrewrite/xml/security/RemoveOwaspSuppressions.java Co-authored-by: Tim te Beek --------- Co-authored-by: Tim te Beek --- .../xml/security/RemoveOwaspSuppressions.java | 23 +++++++---- .../security/RemoveOwaspSuppressionsTest.java | 38 ++++++++++++++++++- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/security/RemoveOwaspSuppressions.java b/rewrite-xml/src/main/java/org/openrewrite/xml/security/RemoveOwaspSuppressions.java index 80a22dc8596..d071a8a5acb 100644 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/security/RemoveOwaspSuppressions.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/security/RemoveOwaspSuppressions.java @@ -17,10 +17,8 @@ import lombok.EqualsAndHashCode; import lombok.Value; -import org.openrewrite.ExecutionContext; -import org.openrewrite.Preconditions; -import org.openrewrite.Recipe; -import org.openrewrite.TreeVisitor; +import org.jspecify.annotations.Nullable; +import org.openrewrite.*; import org.openrewrite.internal.ListUtils; import org.openrewrite.xml.XPathMatcher; import org.openrewrite.xml.XmlIsoVisitor; @@ -39,11 +37,18 @@ public String getDisplayName() { return "Remove out-of-date OWASP suppressions"; } + @Option(displayName = "Until date", + required = false, + description = "Suppressions will be removed if they expired before the provided date. Default will be yesterday.", + example = "2023-01-01") + @Nullable + String cutOffDate; + @Override public String getDescription() { return "Remove all OWASP suppressions with a suppression end date in the past, as these are no longer valid. " + - "For use with the OWASP `dependency-check` tool. " + - "More details on OWASP suppression files can be found [here](https://jeremylong.github.io/DependencyCheck/general/suppression.html)."; + "For use with the OWASP `dependency-check` tool. " + + "More details on OWASP suppression files can be found [here](https://jeremylong.github.io/DependencyCheck/general/suppression.html)."; } @Override @@ -69,8 +74,12 @@ private boolean isPastDueSuppression(Content content) { maybeDate = maybeDate.substring(0, maybeDate.length() - 1); } try { + LocalDate maxDate = LocalDate.now().minusDays(1); + if (cutOffDate != null) { + maxDate = LocalDate.parse(cutOffDate); + } LocalDate date = LocalDate.parse(maybeDate); - if (date.isBefore(LocalDate.now().minusDays(1))) { + if (date.isBefore(maxDate)) { return true; } } catch (DateTimeParseException e) { diff --git a/rewrite-xml/src/test/java/org/openrewrite/xml/security/RemoveOwaspSuppressionsTest.java b/rewrite-xml/src/test/java/org/openrewrite/xml/security/RemoveOwaspSuppressionsTest.java index d2c06eb121b..27f004ae1de 100644 --- a/rewrite-xml/src/test/java/org/openrewrite/xml/security/RemoveOwaspSuppressionsTest.java +++ b/rewrite-xml/src/test/java/org/openrewrite/xml/security/RemoveOwaspSuppressionsTest.java @@ -27,7 +27,7 @@ class RemoveOwaspSuppressionsTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.recipe(new RemoveOwaspSuppressions()); + spec.recipe(new RemoveOwaspSuppressions(null)); } @Test @@ -159,4 +159,40 @@ void ignoresMalformedDates() { spec -> spec.path("suppressions.xml")) ); } + + @Test + void provideExplicitDateRange() { + rewriteRun( + spec -> spec.recipe(new RemoveOwaspSuppressions("2023-02-01")), + xml(""" + + + + + + + """, + """ + + + """, + spec -> spec.path("suppressions.xml")) + ); + } + + @Test + void provideExplicitDateRangeDoNotRemove() { + rewriteRun( + spec -> spec.recipe(new RemoveOwaspSuppressions("2023-01-01")), + xml(""" + + + + + + + """, + spec -> spec.path("suppressions.xml")) + ); + } } From c455436d01e816b96301f474875e8010d1ab8d32 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Mon, 6 Jan 2025 10:21:37 +0100 Subject: [PATCH 105/179] Support pattern operator for groovy (#4847) --- .../org/openrewrite/groovy/GroovyParserVisitor.java | 12 ++++++++---- .../java/org/openrewrite/groovy/tree/BinaryTest.java | 1 - .../openrewrite/groovy/tree/RealWorldGroovyTest.java | 1 - 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index c745fbffdc7..421f80ac5da 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -1290,9 +1290,11 @@ public void visitConstantExpression(ConstantExpression expression) { } else { String delimiter = getDelimiter(); if (delimiter != null) { + // handle the `pattern` operator + String endDelimiter = "~/".equals(delimiter) ? "/" : delimiter; // Get the string literal from the source, so escaping of newlines and the like works out of the box - value = sourceSubstring(cursor + delimiter.length(), delimiter); - text = delimiter + value + delimiter; + value = sourceSubstring(cursor + delimiter.length(), endDelimiter); + text = delimiter + value + endDelimiter; } } } else if (expression.isNullExpression()) { @@ -1575,7 +1577,7 @@ public void visitGStringExpression(GStringExpression gstring) { } } else if (e instanceof ConstantExpression) { // Get the string literal from the source, so escaping of newlines and the like works out of the box - String value = sourceSubstring(cursor, delimiter); + String value = sourceSubstring(cursor, ("~/".equals(delimiter) ? "/" : delimiter)); // There could be a closer GString before the end of the closing delimiter, so shorten the string if needs be int indexNextSign = source.indexOf("$", cursor); if (indexNextSign != -1 && indexNextSign < (cursor + value.length())) { @@ -2419,7 +2421,7 @@ private Space sourceBefore(String untilDelim) { * The cursor will not be moved. */ private String sourceSubstring(int beginIndex, String untilDelim) { - int endIndex = source.indexOf(untilDelim, cursor + untilDelim.length()); + int endIndex = source.indexOf(untilDelim, Math.max(beginIndex, cursor + untilDelim.length())); // don't stop if last char is escaped. while (source.charAt(endIndex - 1) == '\\') { endIndex = source.indexOf(untilDelim, endIndex + 1); @@ -2485,6 +2487,8 @@ private int determineParenthesisLevel(int childLineNumber, int parentLineNumber, return "\"\"\""; } else if (maybeDelimiter.startsWith("'''")) { return "'''"; + } else if (maybeDelimiter.startsWith("~/")) { + return "~/"; } else if (maybeDelimiter.startsWith("/")) { return "/"; } else if (maybeDelimiter.startsWith("\"")) { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java index 1f9b86eba7b..ea37ae1215d 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/BinaryTest.java @@ -79,7 +79,6 @@ def foo(int a) { } @Test - @ExpectedToFail("Pattern operator is not yet supported") // https://groovy-lang.org/operators.html#_pattern_operator void regexPatternOperator() { rewriteRun( groovy( diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java index 2f9998c197a..4b128e21c18 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/RealWorldGroovyTest.java @@ -28,7 +28,6 @@ class RealWorldGroovyTest implements RewriteTest { @Test - @ExpectedToFail("Pattern operator is not yet supported") // https://groovy-lang.org/operators.html#_pattern_operator @Issue("https://github.com/spring-projects/spring-boot/blob/v3.4.1/settings.gradle") void springBootSettingsGradle() { rewriteRun( From a3249f208fab91e0d287b46d05ee8e9f15a9b884 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Mon, 6 Jan 2025 14:14:48 +0100 Subject: [PATCH 106/179] Skip parsing groovy generated transform methods (#4848) * Skip parsing groovy generated transform methods * Skip parsing groovy generated transform methods * Skip parsing groovy generated transform methods * Skip parsing groovy generated transform methods * improvement * improvement * improvement * improvement --- .../groovy/GroovyParserVisitor.java | 60 +++++++++----- .../groovy/tree/AnnotationTest.java | 79 +++++++++++++++++++ 2 files changed, 121 insertions(+), 18 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 421f80ac5da..09bb6957cc7 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -16,6 +16,8 @@ package org.openrewrite.groovy; import groovy.lang.GroovySystem; +import groovy.transform.Generated; +import groovy.transform.Immutable; import groovyjarjarasm.asm.Opcodes; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -305,7 +307,7 @@ J.Block visitClassBlock(ClassNode clazz) { org.codehaus.groovy.ast.stmt.Statement statement = ((BlockStatement) method.getCode()).getStatements().get(0); sortedByPosition.computeIfAbsent(pos(statement), i -> new ArrayList<>()).add(statement); } - } else { + } else if (method.getAnnotations(new ClassNode(Generated.class)).isEmpty()) { sortedByPosition.computeIfAbsent(pos(method), i -> new ArrayList<>()).add(method); } } @@ -448,7 +450,6 @@ private void visitVariableField(FieldNode field) { @Override protected void visitAnnotation(AnnotationNode annotation) { RewriteGroovyVisitor bodyVisitor = new RewriteGroovyVisitor(annotation, this); - String lastArgKey = annotation.getMembers().keySet().stream().reduce("", (k1, k2) -> k2); Space prefix = sourceBefore("@"); NameTree annotationType = visitTypeTree(annotation.getClassNode()); @@ -457,8 +458,10 @@ protected void visitAnnotation(AnnotationNode annotation) { arguments = JContainer.build( sourceBefore("("), annotation.getMembers().entrySet().stream() + // Non-value implicit properties should not be represented in our LST. + .filter(it -> sourceStartsWith(it.getKey()) || "value".equals(it.getKey())) .map(arg -> { - boolean isImplicitValue = "value".equals(arg.getKey()) && !source.startsWith("value", indexOfNextNonWhitespace(cursor, source)); + boolean isImplicitValue = "value".equals(arg.getKey()) && !sourceStartsWith("value"); Space argPrefix = isImplicitValue ? whitespace() : sourceBefore(arg.getKey()); Space isSign = isImplicitValue ? null : sourceBefore("="); Expression expression; @@ -478,8 +481,12 @@ protected void visitAnnotation(AnnotationNode annotation) { .collect(toList()), Markers.EMPTY ); - } else if (source.startsWith("(", indexOfNextNonWhitespace(cursor, source))) { - // An annotation with empty arguments like @Foo() + // Rare scenario where annotation does only have non-value implicit properties + if (arguments.getElements().isEmpty()) { + arguments = null; + } + } else if (sourceStartsWith("(")) { + // Annotation with empty arguments like @Foo() arguments = JContainer.build(sourceBefore("("), singletonList(JRightPadded.build(new J.Empty(randomId(), sourceBefore(")"), Markers.EMPTY))), Markers.EMPTY); @@ -551,7 +558,7 @@ class B { class B { } Space varargs = null; - if (paramType instanceof J.ArrayType && hasVarargs()) { + if (paramType instanceof J.ArrayType && sourceStartsWith("...")) { int varargStart = indexOfNextNonWhitespace(cursor, source); varargs = format(source, cursor, varargStart); cursor = varargStart + 3; @@ -642,8 +649,17 @@ public List visitAndGetAnnotations(AnnotatedNode node) { List paramAnnotations = new ArrayList<>(node.getAnnotations().size()); for (AnnotationNode annotationNode : node.getAnnotations()) { - visitAnnotation(annotationNode); - paramAnnotations.add(pollQueue()); + // The groovy compiler can add or remove annotations for AST transformations. + // Because @groovy.transform.Immutable is discarded in favour of other transform annotations, the removed annotation must be parsed by hand. + if (sourceStartsWith("@" + Immutable.class.getSimpleName()) || sourceStartsWith("@" + Immutable.class.getCanonicalName()) ) { + visitAnnotation(new AnnotationNode(new ClassNode(Immutable.class))); + paramAnnotations.add(pollQueue()); + } + + if (appearsInSource(annotationNode)) { + visitAnnotation(annotationNode); + paramAnnotations.add(pollQueue()); + } } return paramAnnotations; } @@ -747,7 +763,7 @@ public void visitArgumentlistExpression(ArgumentListExpression expression) { } List unparsedArgs = expression.getExpressions().stream() - .filter(GroovyParserVisitor::appearsInSource) + .filter(GroovyParserVisitor.this::appearsInSource) .collect(toList()); // If the first parameter to a function is a Map, then groovy allows "named parameters" style invocations, see: // https://docs.groovy-lang.org/latest/html/documentation/#_named_parameters_2 @@ -1017,7 +1033,7 @@ public void visitBinaryExpression(BinaryExpression binary) { public void visitBlockStatement(BlockStatement block) { Space fmt = EMPTY; Space staticInitPadding = EMPTY; - boolean isStaticInit = source.substring(indexOfNextNonWhitespace(cursor, source)).startsWith("static"); + boolean isStaticInit = sourceStartsWith("static"); Object parent = nodeCursor.getParentOrThrow().getValue(); if (isStaticInit) { fmt = sourceBefore("static"); @@ -2367,7 +2383,7 @@ private TypeTree arrayType(ClassNode classNode) { } Space prefix = whitespace(); TypeTree elemType = typeTree(typeTree); - JLeftPadded dimension = hasVarargs() ? null : padLeft(sourceBefore("["), sourceBefore("]")); + JLeftPadded dimension = sourceStartsWith("...") ? null : padLeft(sourceBefore("["), sourceBefore("]")); return new J.ArrayType(randomId(), prefix, Markers.EMPTY, count == 1 ? elemType : mapDimensions(elemType, classNode.getComponentType()), null, @@ -2392,10 +2408,6 @@ private TypeTree mapDimensions(TypeTree baseType, ClassNode classNode) { return baseType; } - private boolean hasVarargs() { - return source.startsWith("...", indexOfNextNonWhitespace(cursor, source)); - } - /** * Get all characters of the source file between the cursor and the given delimiter. * The cursor will be moved past the delimiter. @@ -2416,6 +2428,14 @@ private Space sourceBefore(String untilDelim) { return space; } + /** + * Tests if the source beginning at the current cursor starts with the specified delimiter. + * Whitespace characters are excluded, the cursor will not be moved. + */ + private boolean sourceStartsWith(String delimiter) { + return source.startsWith(delimiter, indexOfNextNonWhitespace(cursor, source)); + } + /** * Returns a string that is a part of this source. The substring begins at the specified beginIndex and extends until delimiter. * The cursor will not be moved. @@ -2708,13 +2728,17 @@ private J.TypeParameter visitTypeParameter(GenericsType genericType) { /** * Sometimes the groovy compiler inserts phantom elements into argument lists and class bodies, - * presumably to pass type information around. These elements do not appear in source code and should not - * be represented in our AST. + * presumably to pass type information around. Other times the groovy compiler adds extra transform annotations. + * These elements do not appear in source code and should not be represented in our LST. * * @param node possible phantom node * @return true if the node reports that it does have a position within the source code */ - private static boolean appearsInSource(ASTNode node) { + private boolean appearsInSource(ASTNode node) { + if (node instanceof AnnotationNode) { + return sourceStartsWith("@" + ((AnnotationNode) node).getClassNode().getUnresolvedName()); + } + return node.getColumnNumber() >= 0 && node.getLineNumber() >= 0 && node.getLastColumnNumber() >= 0 && node.getLastLineNumber() >= 0; } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AnnotationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AnnotationTest.java index b028da0dfa5..c9f14d23010 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AnnotationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/AnnotationTest.java @@ -30,6 +30,21 @@ void simple() { groovy( """ @Foo + class Test implements Runnable { + @java.lang.Override + void run() {} + } + """ + ) + ); + } + + @Test + void simpleFQN() { + rewriteRun( + groovy( + """ + @org.springframework.stereotype.Service class Test {} """ ) @@ -48,6 +63,19 @@ class Test {} ); } + @Test + void inline() { + rewriteRun( + groovy( + """ + @Foo class Test implements Runnable { + @Override void run() {} + } + """ + ) + ); + } + @Test void withProperties() { rewriteRun( @@ -84,4 +112,55 @@ class Test {} ) ); } + + @Issue("https://github.com/openrewrite/rewrite/issues/4254") + @Test + void groovyTransformAnnotation() { + rewriteRun( + groovy( + """ + import groovy.transform.EqualsAndHashCode + import groovy.transform.ToString + + @Foo + @ToString + @EqualsAndHashCode + @Bar + class Test {} + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite/issues/4254") + @Test + void groovyTransformImmutableAnnotation() { + rewriteRun( + groovy( + """ + import groovy.transform.Immutable + import groovy.transform.TupleConstructor + + @Foo + @TupleConstructor + @Immutable + @Bar + class Test {} + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite/issues/4254") + @Test + void groovyTransformImmutableFQNAnnotation() { + rewriteRun( + groovy( + """ + @groovy.transform.Immutable + class Test {} + """ + ) + ); + } } From a1d0f36bec74a1472976c96484d376d9a8727a48 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Mon, 6 Jan 2025 15:34:31 +0100 Subject: [PATCH 107/179] Support semicolon for groovy packages (#4850) --- .../org/openrewrite/groovy/GroovyParserVisitor.java | 5 ++--- .../java/org/openrewrite/groovy/GroovyPrinter.java | 1 + .../groovy/tree/ClassDeclarationTest.java | 13 +++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 09bb6957cc7..bbed7c6c14b 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -136,9 +136,8 @@ public G.CompilationUnit visit(SourceUnit unit, ModuleNode ast) throws GroovyPar JRightPadded pkg = null; if (ast.getPackage() != null) { prefix = whitespace(); - cursor += "package".length(); - pkg = JRightPadded.build(new J.Package(randomId(), EMPTY, Markers.EMPTY, - typeTree(null), emptyList())); + skip("package"); + pkg = maybeSemicolon(new J.Package(randomId(), EMPTY, Markers.EMPTY, typeTree(null), emptyList())); } for (ImportNode anImport : ast.getImports()) { diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java index 0ab2bb60c2c..69923fd1a1c 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyPrinter.java @@ -57,6 +57,7 @@ public J visitCompilationUnit(G.CompilationUnit cu, PrintOutputCapture

p) { JRightPadded pkg = cu.getPadding().getPackageDeclaration(); if (pkg != null) { visit(pkg.getElement(), p); + visitMarkers(pkg.getMarkers(), p); visitSpace(pkg.getAfter(), Space.Location.PACKAGE_SUFFIX, p); } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java index 6399b556685..c9da577914b 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/ClassDeclarationTest.java @@ -138,6 +138,19 @@ public class A{} ); } + @Test + void hasPackageWithTrailingComma() { + rewriteRun( + groovy( + """ + package org.openrewrite; + + class A{} + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite/issues/1736") @Test void parameterizedFieldDoesNotAffectClassType() { From 28d88c437c539284ce13eaeb0f249e8bd6b00aa3 Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Mon, 6 Jan 2025 12:47:54 -0800 Subject: [PATCH 108/179] Standardize semicolon-delineated path separation in file patterns --- .../java/org/openrewrite/FindSourceFiles.java | 32 ++++++++++++++++--- .../main/java/org/openrewrite/text/Find.java | 12 ++----- .../org/openrewrite/text/FindAndReplace.java | 12 ++----- .../org/openrewrite/FindSourceFilesTest.java | 20 ++++++++++-- 4 files changed, 50 insertions(+), 26 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java b/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java index bf0aa62a234..0b2f15d3a1b 100644 --- a/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java +++ b/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java @@ -17,12 +17,15 @@ import lombok.EqualsAndHashCode; import lombok.Value; +import org.apache.commons.lang3.StringUtils; import org.jspecify.annotations.Nullable; -import org.openrewrite.internal.StringUtils; import org.openrewrite.marker.SearchResult; import org.openrewrite.table.SourcesFiles; import java.nio.file.Path; +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Stream; @Value @@ -31,12 +34,29 @@ public class FindSourceFiles extends Recipe { transient SourcesFiles results = new SourcesFiles(this); @Option(displayName = "File pattern", - description = "A glob expression representing a file path to search for (relative to the project root). Blank/null matches all.", + description = "A glob expression representing a file path to search for (relative to the project root). Blank/null matches all." + + "Multiple patterns may be specified, separated by a semicolon `;`. " + + "If multiple patterns are supplied any of the patterns matching will be interpreted as a match.", required = false, example = ".github/workflows/*.yml") @Nullable String filePattern; + @EqualsAndHashCode.Exclude + transient String[] filePatterns; + + public FindSourceFiles(@Nullable String filePattern) { + this.filePattern = filePattern; + this.filePatterns = Optional.ofNullable(filePattern) + .map(it -> it.split(";")) + .map(Arrays::stream) + .orElseGet(Stream::empty) + .map(String::trim) + .filter(StringUtils::isNotBlank) + .map(FindSourceFiles::normalize) + .toArray(String[]::new); + } + @Override public String getDisplayName() { return "Find files"; @@ -44,7 +64,7 @@ public String getDisplayName() { @Override public String getDescription() { - return "Find files by source path."; + return "Find files by source path. Paths are always interpreted as relative to the repository root."; } @Override @@ -56,7 +76,7 @@ public TreeVisitor getVisitor() { if (tree instanceof SourceFile) { SourceFile sourceFile = (SourceFile) tree; Path sourcePath = sourceFile.getSourcePath(); - if (StringUtils.isBlank(filePattern) || PathUtils.matchesGlob(sourcePath, normalize(filePattern))) { + if (matches(sourcePath)) { results.insertRow(ctx, new SourcesFiles.Row(sourcePath.toString(), tree.getClass().getSimpleName())); return SearchResult.found(sourceFile); @@ -75,4 +95,8 @@ private static String normalize(String filePattern) { } return filePattern; } + + private boolean matches(Path sourcePath) { + return filePatterns.length == 0 || Arrays.stream(filePatterns).anyMatch(pattern -> PathUtils.matchesGlob(sourcePath, pattern)); + } } diff --git a/rewrite-core/src/main/java/org/openrewrite/text/Find.java b/rewrite-core/src/main/java/org/openrewrite/text/Find.java index ad25c20266c..24ef0290980 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/Find.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/Find.java @@ -28,7 +28,6 @@ import org.openrewrite.table.TextMatches; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -86,7 +85,7 @@ public String getDescription() { description = "A glob expression that can be used to constrain which directories or source files should be searched. " + "Multiple patterns may be specified, separated by a semicolon `;`. " + "If multiple patterns are supplied any of the patterns matching will be interpreted as a match. " + - "When not set, all source files are searched. ", + "When not set, all source files are searched.", required = false, example = "**/*.java") @Nullable @@ -179,15 +178,8 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { return plainText.withText("").withSnippets(snippets); } }; - //noinspection DuplicatedCode if (filePattern != null) { - //noinspection unchecked - TreeVisitor check = Preconditions.or(Arrays.stream(filePattern.split(";")) - .map(FindSourceFiles::new) - .map(Recipe::getVisitor) - .toArray(TreeVisitor[]::new)); - - visitor = Preconditions.check(check, visitor); + visitor = Preconditions.check(new FindSourceFiles(filePattern), visitor); } return visitor; } diff --git a/rewrite-core/src/main/java/org/openrewrite/text/FindAndReplace.java b/rewrite-core/src/main/java/org/openrewrite/text/FindAndReplace.java index 0842da78a57..5a284180a62 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/FindAndReplace.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/FindAndReplace.java @@ -27,7 +27,6 @@ import org.openrewrite.quark.Quark; import org.openrewrite.remote.Remote; -import java.util.Arrays; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -95,7 +94,7 @@ public String getDescription() { description = "A glob expression that can be used to constrain which directories or source files should be searched. " + "Multiple patterns may be specified, separated by a semicolon `;`. " + "If multiple patterns are supplied any of the patterns matching will be interpreted as a match. " + - "When not set, all source files are searched. ", + "When not set, all source files are searched.", required = false, example = "**/*.java") @Nullable @@ -153,15 +152,8 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { .withMarkers(sourceFile.getMarkers().add(new AlreadyReplaced(randomId(), find, replace))); } }; - //noinspection DuplicatedCode if (filePattern != null) { - //noinspection unchecked - TreeVisitor check = Preconditions.or(Arrays.stream(filePattern.split(";")) - .map(FindSourceFiles::new) - .map(Recipe::getVisitor) - .toArray(TreeVisitor[]::new)); - - visitor = Preconditions.check(check, visitor); + visitor = Preconditions.check(new FindSourceFiles(filePattern), visitor); } if (Boolean.TRUE.equals(plaintextOnly)) { diff --git a/rewrite-test/src/test/java/org/openrewrite/FindSourceFilesTest.java b/rewrite-test/src/test/java/org/openrewrite/FindSourceFilesTest.java index ecb8a32977b..7d1255ef5f3 100644 --- a/rewrite-test/src/test/java/org/openrewrite/FindSourceFilesTest.java +++ b/rewrite-test/src/test/java/org/openrewrite/FindSourceFilesTest.java @@ -15,7 +15,6 @@ */ package org.openrewrite; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullSource; @@ -154,7 +153,6 @@ void findDotfiles() { @Test @Issue("https://github.com/openrewrite/rewrite/pull/3758") - @Disabled("{} syntax not supported yet") void eitherOr() { rewriteRun( spec -> spec.recipe(new FindSourceFiles("**/*.{md,txt}")), @@ -171,6 +169,24 @@ void eitherOr() { ); } + @Test + void multiplePathsSemicolonDelimitedPaths() { + rewriteRun( + spec -> spec.recipe(new FindSourceFiles("a.txt ; b.txt")), + text( + "this one", + "~~>this one", + spec -> spec.path("a.txt") + ), + text( + "also this one", + "~~>also this one", + spec -> spec.path("b.txt") + ), + text("not this one", spec -> spec.path("c.txt")) + ); + } + @Test void negation() { rewriteRun( From 621dcfa15c597b64e365ef69569e344681bb8106 Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Mon, 6 Jan 2025 12:53:27 -0800 Subject: [PATCH 109/179] Use our StringUtils --- .../src/main/java/org/openrewrite/FindSourceFiles.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java b/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java index 0b2f15d3a1b..20cf360f697 100644 --- a/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java +++ b/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java @@ -17,8 +17,8 @@ import lombok.EqualsAndHashCode; import lombok.Value; -import org.apache.commons.lang3.StringUtils; import org.jspecify.annotations.Nullable; +import org.openrewrite.internal.StringUtils; import org.openrewrite.marker.SearchResult; import org.openrewrite.table.SourcesFiles; @@ -52,7 +52,7 @@ public FindSourceFiles(@Nullable String filePattern) { .map(Arrays::stream) .orElseGet(Stream::empty) .map(String::trim) - .filter(StringUtils::isNotBlank) + .filter(StringUtils::isNotEmpty) .map(FindSourceFiles::normalize) .toArray(String[]::new); } From 15f77515e074658c82901e6596fa0fdec157c734 Mon Sep 17 00:00:00 2001 From: Niels de Bruin Date: Tue, 7 Jan 2025 12:58:08 +0100 Subject: [PATCH 110/179] Add recipe to enable Develocity build cache in xml configuration (#4856) * Add enable buildcache recipe * Polish * Use `` * Rename recipe to be Develocity specific, to avoid confusion with Maven build cache --------- Co-authored-by: Tim te Beek --- .../maven/EnableDevelocityBuildCache.java | 109 +++++++++++++ .../maven/EnableDevelocityBuildCacheTest.java | 146 ++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 rewrite-maven/src/main/java/org/openrewrite/maven/EnableDevelocityBuildCache.java create mode 100644 rewrite-maven/src/test/java/org/openrewrite/maven/EnableDevelocityBuildCacheTest.java diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/EnableDevelocityBuildCache.java b/rewrite-maven/src/main/java/org/openrewrite/maven/EnableDevelocityBuildCache.java new file mode 100644 index 00000000000..1d35b34e765 --- /dev/null +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/EnableDevelocityBuildCache.java @@ -0,0 +1,109 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.maven; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.jspecify.annotations.Nullable; +import org.openrewrite.*; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.xml.XmlVisitor; +import org.openrewrite.xml.tree.Xml; + +@Value +@EqualsAndHashCode(callSuper = false) +public class EnableDevelocityBuildCache extends Recipe { + + @Override + public String getDisplayName() { + return "Enable Develocity build cache"; + } + + @Override + public String getDescription() { + return "Add Develocity build cache configuration to any `.mvn/` Develocity configuration file that lack existing configuration."; + } + + @Option(displayName = "Enable local build cache", + description = "Value for `//develocity/buildCache/local/enabled`.", + example = "true", + required = false) + @Nullable + String buildCacheLocalEnabled; + + @Option(displayName = "Enable remote build cache", + description = "Value for `//develocity/buildCache/remote/enabled`.", + example = "true", + required = false) + @Nullable + String buildCacheRemoteEnabled; + + @Option(displayName = "Enable remote build cache store", + description = "Value for `//develocity/buildCache/remote/storeEnabled`.", + example = "#{isTrue(env['CI'])}", + required = false) + @Nullable + String buildCacheRemoteStoreEnabled; + + @Override + public Validated validate(ExecutionContext ctx) { + return super.validate(ctx) + .and(Validated.notBlank("buildCacheLocalEnabled", buildCacheLocalEnabled) + .or(Validated.notBlank("buildCacheRemoteEnabled", buildCacheRemoteEnabled)) + .or(Validated.notBlank("buildCacheRemoteStoreEnabled", buildCacheRemoteStoreEnabled))); + } + + @Override + public TreeVisitor getVisitor() { + XmlVisitor visitor = new XmlVisitor() { + @Override + public Xml visitDocument(Xml.Document document, ExecutionContext ctx) { + Xml.Tag rootTag = document.getRoot(); + + if ("develocity".equals(rootTag.getName()) && !rootTag.getChild("buildCache").isPresent()) { + Xml.Tag tag = Xml.Tag.build(buildCacheConfig()); + rootTag = maybeAutoFormat(rootTag, rootTag.withContent(ListUtils.concat(rootTag.getChildren(), tag)), ctx); + return document.withRoot(rootTag); + } + return document; + } + }; + + return Preconditions.check(new FindSourceFiles(".mvn/*.xml"), visitor); + } + + private String buildCacheConfig() { + StringBuilder sb = new StringBuilder(""); + if (!StringUtils.isBlank(buildCacheLocalEnabled)) { + sb.append(""); + sb.append("").append(buildCacheLocalEnabled).append(""); + sb.append(""); + } + if (!StringUtils.isBlank(buildCacheRemoteEnabled) || !StringUtils.isBlank(buildCacheRemoteStoreEnabled)) { + sb.append(""); + if (!StringUtils.isBlank(buildCacheRemoteEnabled)) { + sb.append("").append(buildCacheRemoteEnabled).append(""); + } + if (!StringUtils.isBlank(buildCacheRemoteStoreEnabled)) { + sb.append("").append(buildCacheRemoteStoreEnabled).append(""); + } + sb.append(""); + } + sb.append(""); + return sb.toString(); + } +} diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/EnableDevelocityBuildCacheTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/EnableDevelocityBuildCacheTest.java new file mode 100644 index 00000000000..dfdda0ae48e --- /dev/null +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/EnableDevelocityBuildCacheTest.java @@ -0,0 +1,146 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.maven; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.Validated; +import org.openrewrite.test.RewriteTest; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.openrewrite.xml.Assertions.xml; + +class EnableDevelocityBuildCacheTest implements RewriteTest { + + @DocumentExample + @Test + void addBuildCacheAllConfigWithOptions() { + rewriteRun( + spec -> spec.recipe(new EnableDevelocityBuildCache("true", "true", "#{isTrue(env['CI'])}")), + xml( + """ + + + """, + """ + + + + true + + + true + #{isTrue(env['CI'])} + + + + """, + spec -> spec.path(".mvn/develocity.xml") + ) + ); + } + + @Test + void requireAtLeastOneOption() { + Validated validate = new EnableDevelocityBuildCache(null, null, null).validate(new InMemoryExecutionContext()); + assertThat(validate.isValid()).isFalse(); + } + + @Test + void addBuildCacheConfigWithLocalOnly() { + rewriteRun( + spec -> spec.recipe(new EnableDevelocityBuildCache("true", null, null)), + xml( + """ + + + """, + """ + + + + true + + + + """, + spec -> spec.path(".mvn/develocity.xml") + ) + ); + } + + @Test + void addBuildCacheAllConfigWithRemoteOnly() { + rewriteRun( + spec -> spec.recipe(new EnableDevelocityBuildCache(null, "true", "#{isTrue(env['CI'])}")), + xml( + """ + + + """, + """ + + + + true + #{isTrue(env['CI'])} + + + + """, + spec -> spec.path(".mvn/develocity.xml") + ) + ); + } + + @Test + void shouldNotModifyExistingConfiguration() { + rewriteRun( + spec -> spec.recipe(new EnableDevelocityBuildCache("true", "true", "true")), + xml( + """ + + + + false + + + false + false + + + + """, + spec -> spec.path(".mvn/develocity.xml") + ) + ); + } + + @Test + void shouldNotModifyOtherLocations() { + rewriteRun( + spec -> spec.recipe(new EnableDevelocityBuildCache("true", "true", "true")), + xml( + """ + + + """, + spec -> spec.path("src/test/resources/develocity.xml") + ) + ); + } +} From fd719558d65e83fbf234cf55c03d241ef66470f2 Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Tue, 7 Jan 2025 13:13:30 +0100 Subject: [PATCH 111/179] HCL - comments in multilines `for` (#4858) * UT for #4857 * Fixing lexer to accept comemnts within for expressions * licenseFormat --- rewrite-hcl/src/main/antlr/HCLLexer.g4 | 4 +- .../hcl/internal/grammar/HCLLexer.interp | 2 +- .../hcl/internal/grammar/HCLLexer.java | 558 +++++++++--------- .../org/openrewrite/hcl/tree/HclForTest.java | 18 + 4 files changed, 302 insertions(+), 280 deletions(-) diff --git a/rewrite-hcl/src/main/antlr/HCLLexer.g4 b/rewrite-hcl/src/main/antlr/HCLLexer.g4 index 474d5a9babf..6266c3e22ec 100644 --- a/rewrite-hcl/src/main/antlr/HCLLexer.g4 +++ b/rewrite-hcl/src/main/antlr/HCLLexer.g4 @@ -14,8 +14,8 @@ lexer grammar HCLLexer; private Stack heredocIdentifier = new Stack(); } -FOR_BRACE : '{' (WS|NEWLINE)* 'for' WS; -FOR_BRACK : '[' (WS|NEWLINE)* 'for' WS; +FOR_BRACE : '{' (WS|NEWLINE|COMMENT|LINE_COMMENT)* 'for' WS; +FOR_BRACK : '[' (WS|NEWLINE|COMMENT|LINE_COMMENT)* 'for' WS; IF : 'if'; IN : 'in'; diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp index b210722ef06..1c2aaad6d58 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp @@ -169,4 +169,4 @@ HEREDOC_PREAMBLE HEREDOC atn: -[4, 0, 47, 446, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 1, 0, 1, 0, 1, 0, 5, 0, 124, 8, 0, 10, 0, 12, 0, 127, 9, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 5, 1, 138, 8, 1, 10, 1, 12, 1, 141, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 3, 7, 165, 8, 7, 1, 8, 1, 8, 1, 8, 5, 8, 170, 8, 8, 10, 8, 12, 8, 173, 9, 8, 1, 9, 4, 9, 176, 8, 9, 11, 9, 12, 9, 177, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 186, 8, 10, 10, 10, 12, 10, 189, 9, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 3, 11, 199, 8, 11, 1, 11, 5, 11, 202, 8, 11, 10, 11, 12, 11, 205, 9, 11, 1, 11, 3, 11, 208, 8, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 3, 13, 220, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 226, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 246, 8, 15, 1, 16, 1, 16, 1, 17, 4, 17, 251, 8, 17, 11, 17, 12, 17, 252, 1, 17, 1, 17, 5, 17, 257, 8, 17, 10, 17, 12, 17, 260, 9, 17, 1, 17, 3, 17, 263, 8, 17, 1, 17, 4, 17, 266, 8, 17, 11, 17, 12, 17, 267, 1, 17, 1, 17, 4, 17, 272, 8, 17, 11, 17, 12, 17, 273, 3, 17, 276, 8, 17, 1, 18, 1, 18, 3, 18, 280, 8, 18, 1, 18, 4, 18, 283, 8, 18, 11, 18, 12, 18, 284, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 296, 8, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 311, 8, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 4, 49, 382, 8, 49, 11, 49, 12, 49, 383, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 396, 8, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 5, 53, 411, 8, 53, 10, 53, 12, 53, 414, 9, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 4, 56, 433, 8, 56, 11, 56, 12, 56, 434, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 3, 57, 445, 8, 57, 1, 187, 0, 58, 4, 1, 6, 2, 8, 3, 10, 4, 12, 5, 14, 6, 16, 7, 18, 0, 20, 8, 22, 9, 24, 10, 26, 11, 28, 12, 30, 0, 32, 0, 34, 0, 36, 0, 38, 13, 40, 0, 42, 14, 44, 15, 46, 16, 48, 17, 50, 18, 52, 19, 54, 20, 56, 21, 58, 22, 60, 23, 62, 24, 64, 25, 66, 26, 68, 27, 70, 28, 72, 29, 74, 30, 76, 31, 78, 32, 80, 33, 82, 34, 84, 35, 86, 36, 88, 37, 90, 38, 92, 39, 94, 40, 96, 41, 98, 42, 100, 43, 102, 44, 104, 45, 106, 0, 108, 0, 110, 0, 112, 0, 114, 0, 116, 46, 118, 47, 4, 0, 1, 2, 3, 14, 4, 0, 10, 10, 13, 13, 34, 34, 36, 37, 3, 0, 9, 9, 12, 13, 32, 32, 2, 0, 10, 10, 13, 13, 1, 0, 48, 57, 4, 0, 36, 36, 65, 90, 95, 95, 97, 122, 2, 0, 0, 127, 55296, 56319, 1, 0, 55296, 56319, 1, 0, 56320, 57343, 5, 0, 34, 34, 92, 92, 110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 3, 0, 10, 10, 13, 13, 36, 37, 1, 0, 123, 123, 476, 0, 4, 1, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 10, 1, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 14, 1, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 24, 1, 0, 0, 0, 0, 26, 1, 0, 0, 0, 0, 28, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 44, 1, 0, 0, 0, 0, 46, 1, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 50, 1, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 54, 1, 0, 0, 0, 0, 56, 1, 0, 0, 0, 0, 58, 1, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 62, 1, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 66, 1, 0, 0, 0, 0, 68, 1, 0, 0, 0, 0, 70, 1, 0, 0, 0, 0, 72, 1, 0, 0, 0, 0, 74, 1, 0, 0, 0, 0, 76, 1, 0, 0, 0, 0, 78, 1, 0, 0, 0, 0, 80, 1, 0, 0, 0, 0, 82, 1, 0, 0, 0, 0, 84, 1, 0, 0, 0, 0, 86, 1, 0, 0, 0, 0, 88, 1, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 92, 1, 0, 0, 0, 0, 94, 1, 0, 0, 0, 0, 96, 1, 0, 0, 0, 0, 98, 1, 0, 0, 0, 1, 100, 1, 0, 0, 0, 1, 102, 1, 0, 0, 0, 1, 104, 1, 0, 0, 0, 1, 106, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 3, 112, 1, 0, 0, 0, 3, 114, 1, 0, 0, 0, 3, 116, 1, 0, 0, 0, 3, 118, 1, 0, 0, 0, 4, 120, 1, 0, 0, 0, 6, 134, 1, 0, 0, 0, 8, 148, 1, 0, 0, 0, 10, 151, 1, 0, 0, 0, 12, 154, 1, 0, 0, 0, 14, 157, 1, 0, 0, 0, 16, 160, 1, 0, 0, 0, 18, 164, 1, 0, 0, 0, 20, 166, 1, 0, 0, 0, 22, 175, 1, 0, 0, 0, 24, 181, 1, 0, 0, 0, 26, 198, 1, 0, 0, 0, 28, 213, 1, 0, 0, 0, 30, 219, 1, 0, 0, 0, 32, 225, 1, 0, 0, 0, 34, 245, 1, 0, 0, 0, 36, 247, 1, 0, 0, 0, 38, 275, 1, 0, 0, 0, 40, 277, 1, 0, 0, 0, 42, 295, 1, 0, 0, 0, 44, 297, 1, 0, 0, 0, 46, 301, 1, 0, 0, 0, 48, 306, 1, 0, 0, 0, 50, 314, 1, 0, 0, 0, 52, 316, 1, 0, 0, 0, 54, 319, 1, 0, 0, 0, 56, 322, 1, 0, 0, 0, 58, 324, 1, 0, 0, 0, 60, 326, 1, 0, 0, 0, 62, 328, 1, 0, 0, 0, 64, 330, 1, 0, 0, 0, 66, 332, 1, 0, 0, 0, 68, 335, 1, 0, 0, 0, 70, 338, 1, 0, 0, 0, 72, 340, 1, 0, 0, 0, 74, 342, 1, 0, 0, 0, 76, 344, 1, 0, 0, 0, 78, 346, 1, 0, 0, 0, 80, 348, 1, 0, 0, 0, 82, 350, 1, 0, 0, 0, 84, 353, 1, 0, 0, 0, 86, 355, 1, 0, 0, 0, 88, 357, 1, 0, 0, 0, 90, 360, 1, 0, 0, 0, 92, 363, 1, 0, 0, 0, 94, 365, 1, 0, 0, 0, 96, 367, 1, 0, 0, 0, 98, 371, 1, 0, 0, 0, 100, 373, 1, 0, 0, 0, 102, 381, 1, 0, 0, 0, 104, 395, 1, 0, 0, 0, 106, 397, 1, 0, 0, 0, 108, 402, 1, 0, 0, 0, 110, 407, 1, 0, 0, 0, 112, 419, 1, 0, 0, 0, 114, 423, 1, 0, 0, 0, 116, 432, 1, 0, 0, 0, 118, 444, 1, 0, 0, 0, 120, 125, 5, 123, 0, 0, 121, 124, 3, 22, 9, 0, 122, 124, 3, 28, 12, 0, 123, 121, 1, 0, 0, 0, 123, 122, 1, 0, 0, 0, 124, 127, 1, 0, 0, 0, 125, 123, 1, 0, 0, 0, 125, 126, 1, 0, 0, 0, 126, 128, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 128, 129, 5, 102, 0, 0, 129, 130, 5, 111, 0, 0, 130, 131, 5, 114, 0, 0, 131, 132, 1, 0, 0, 0, 132, 133, 3, 22, 9, 0, 133, 5, 1, 0, 0, 0, 134, 139, 5, 91, 0, 0, 135, 138, 3, 22, 9, 0, 136, 138, 3, 28, 12, 0, 137, 135, 1, 0, 0, 0, 137, 136, 1, 0, 0, 0, 138, 141, 1, 0, 0, 0, 139, 137, 1, 0, 0, 0, 139, 140, 1, 0, 0, 0, 140, 142, 1, 0, 0, 0, 141, 139, 1, 0, 0, 0, 142, 143, 5, 102, 0, 0, 143, 144, 5, 111, 0, 0, 144, 145, 5, 114, 0, 0, 145, 146, 1, 0, 0, 0, 146, 147, 3, 22, 9, 0, 147, 7, 1, 0, 0, 0, 148, 149, 5, 105, 0, 0, 149, 150, 5, 102, 0, 0, 150, 9, 1, 0, 0, 0, 151, 152, 5, 105, 0, 0, 152, 153, 5, 110, 0, 0, 153, 11, 1, 0, 0, 0, 154, 155, 5, 123, 0, 0, 155, 156, 6, 4, 0, 0, 156, 13, 1, 0, 0, 0, 157, 158, 5, 125, 0, 0, 158, 159, 6, 5, 1, 0, 159, 15, 1, 0, 0, 0, 160, 161, 5, 61, 0, 0, 161, 17, 1, 0, 0, 0, 162, 165, 8, 0, 0, 0, 163, 165, 3, 34, 15, 0, 164, 162, 1, 0, 0, 0, 164, 163, 1, 0, 0, 0, 165, 19, 1, 0, 0, 0, 166, 171, 3, 32, 14, 0, 167, 170, 3, 30, 13, 0, 168, 170, 5, 45, 0, 0, 169, 167, 1, 0, 0, 0, 169, 168, 1, 0, 0, 0, 170, 173, 1, 0, 0, 0, 171, 169, 1, 0, 0, 0, 171, 172, 1, 0, 0, 0, 172, 21, 1, 0, 0, 0, 173, 171, 1, 0, 0, 0, 174, 176, 7, 1, 0, 0, 175, 174, 1, 0, 0, 0, 176, 177, 1, 0, 0, 0, 177, 175, 1, 0, 0, 0, 177, 178, 1, 0, 0, 0, 178, 179, 1, 0, 0, 0, 179, 180, 6, 9, 2, 0, 180, 23, 1, 0, 0, 0, 181, 182, 5, 47, 0, 0, 182, 183, 5, 42, 0, 0, 183, 187, 1, 0, 0, 0, 184, 186, 9, 0, 0, 0, 185, 184, 1, 0, 0, 0, 186, 189, 1, 0, 0, 0, 187, 188, 1, 0, 0, 0, 187, 185, 1, 0, 0, 0, 188, 190, 1, 0, 0, 0, 189, 187, 1, 0, 0, 0, 190, 191, 5, 42, 0, 0, 191, 192, 5, 47, 0, 0, 192, 193, 1, 0, 0, 0, 193, 194, 6, 10, 2, 0, 194, 25, 1, 0, 0, 0, 195, 196, 5, 47, 0, 0, 196, 199, 5, 47, 0, 0, 197, 199, 5, 35, 0, 0, 198, 195, 1, 0, 0, 0, 198, 197, 1, 0, 0, 0, 199, 203, 1, 0, 0, 0, 200, 202, 8, 2, 0, 0, 201, 200, 1, 0, 0, 0, 202, 205, 1, 0, 0, 0, 203, 201, 1, 0, 0, 0, 203, 204, 1, 0, 0, 0, 204, 207, 1, 0, 0, 0, 205, 203, 1, 0, 0, 0, 206, 208, 5, 13, 0, 0, 207, 206, 1, 0, 0, 0, 207, 208, 1, 0, 0, 0, 208, 209, 1, 0, 0, 0, 209, 210, 5, 10, 0, 0, 210, 211, 1, 0, 0, 0, 211, 212, 6, 11, 2, 0, 212, 27, 1, 0, 0, 0, 213, 214, 5, 10, 0, 0, 214, 215, 1, 0, 0, 0, 215, 216, 6, 12, 2, 0, 216, 29, 1, 0, 0, 0, 217, 220, 3, 32, 14, 0, 218, 220, 7, 3, 0, 0, 219, 217, 1, 0, 0, 0, 219, 218, 1, 0, 0, 0, 220, 31, 1, 0, 0, 0, 221, 226, 7, 4, 0, 0, 222, 226, 8, 5, 0, 0, 223, 224, 7, 6, 0, 0, 224, 226, 7, 7, 0, 0, 225, 221, 1, 0, 0, 0, 225, 222, 1, 0, 0, 0, 225, 223, 1, 0, 0, 0, 226, 33, 1, 0, 0, 0, 227, 228, 5, 92, 0, 0, 228, 246, 7, 8, 0, 0, 229, 230, 5, 92, 0, 0, 230, 231, 3, 36, 16, 0, 231, 232, 3, 36, 16, 0, 232, 233, 3, 36, 16, 0, 233, 234, 3, 36, 16, 0, 234, 246, 1, 0, 0, 0, 235, 236, 5, 92, 0, 0, 236, 237, 3, 36, 16, 0, 237, 238, 3, 36, 16, 0, 238, 239, 3, 36, 16, 0, 239, 240, 3, 36, 16, 0, 240, 241, 3, 36, 16, 0, 241, 242, 3, 36, 16, 0, 242, 243, 3, 36, 16, 0, 243, 244, 3, 36, 16, 0, 244, 246, 1, 0, 0, 0, 245, 227, 1, 0, 0, 0, 245, 229, 1, 0, 0, 0, 245, 235, 1, 0, 0, 0, 246, 35, 1, 0, 0, 0, 247, 248, 7, 9, 0, 0, 248, 37, 1, 0, 0, 0, 249, 251, 7, 3, 0, 0, 250, 249, 1, 0, 0, 0, 251, 252, 1, 0, 0, 0, 252, 250, 1, 0, 0, 0, 252, 253, 1, 0, 0, 0, 253, 254, 1, 0, 0, 0, 254, 258, 5, 46, 0, 0, 255, 257, 7, 3, 0, 0, 256, 255, 1, 0, 0, 0, 257, 260, 1, 0, 0, 0, 258, 256, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 262, 1, 0, 0, 0, 260, 258, 1, 0, 0, 0, 261, 263, 3, 40, 18, 0, 262, 261, 1, 0, 0, 0, 262, 263, 1, 0, 0, 0, 263, 276, 1, 0, 0, 0, 264, 266, 7, 3, 0, 0, 265, 264, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 265, 1, 0, 0, 0, 267, 268, 1, 0, 0, 0, 268, 269, 1, 0, 0, 0, 269, 276, 3, 40, 18, 0, 270, 272, 7, 3, 0, 0, 271, 270, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 271, 1, 0, 0, 0, 273, 274, 1, 0, 0, 0, 274, 276, 1, 0, 0, 0, 275, 250, 1, 0, 0, 0, 275, 265, 1, 0, 0, 0, 275, 271, 1, 0, 0, 0, 276, 39, 1, 0, 0, 0, 277, 279, 7, 10, 0, 0, 278, 280, 7, 11, 0, 0, 279, 278, 1, 0, 0, 0, 279, 280, 1, 0, 0, 0, 280, 282, 1, 0, 0, 0, 281, 283, 7, 3, 0, 0, 282, 281, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 282, 1, 0, 0, 0, 284, 285, 1, 0, 0, 0, 285, 41, 1, 0, 0, 0, 286, 287, 5, 116, 0, 0, 287, 288, 5, 114, 0, 0, 288, 289, 5, 117, 0, 0, 289, 296, 5, 101, 0, 0, 290, 291, 5, 102, 0, 0, 291, 292, 5, 97, 0, 0, 292, 293, 5, 108, 0, 0, 293, 294, 5, 115, 0, 0, 294, 296, 5, 101, 0, 0, 295, 286, 1, 0, 0, 0, 295, 290, 1, 0, 0, 0, 296, 43, 1, 0, 0, 0, 297, 298, 5, 34, 0, 0, 298, 299, 1, 0, 0, 0, 299, 300, 6, 20, 3, 0, 300, 45, 1, 0, 0, 0, 301, 302, 5, 110, 0, 0, 302, 303, 5, 117, 0, 0, 303, 304, 5, 108, 0, 0, 304, 305, 5, 108, 0, 0, 305, 47, 1, 0, 0, 0, 306, 307, 5, 60, 0, 0, 307, 308, 5, 60, 0, 0, 308, 310, 1, 0, 0, 0, 309, 311, 5, 45, 0, 0, 310, 309, 1, 0, 0, 0, 310, 311, 1, 0, 0, 0, 311, 312, 1, 0, 0, 0, 312, 313, 6, 22, 4, 0, 313, 49, 1, 0, 0, 0, 314, 315, 5, 43, 0, 0, 315, 51, 1, 0, 0, 0, 316, 317, 5, 38, 0, 0, 317, 318, 5, 38, 0, 0, 318, 53, 1, 0, 0, 0, 319, 320, 5, 61, 0, 0, 320, 321, 5, 61, 0, 0, 321, 55, 1, 0, 0, 0, 322, 323, 5, 60, 0, 0, 323, 57, 1, 0, 0, 0, 324, 325, 5, 58, 0, 0, 325, 59, 1, 0, 0, 0, 326, 327, 5, 91, 0, 0, 327, 61, 1, 0, 0, 0, 328, 329, 5, 40, 0, 0, 329, 63, 1, 0, 0, 0, 330, 331, 5, 45, 0, 0, 331, 65, 1, 0, 0, 0, 332, 333, 5, 124, 0, 0, 333, 334, 5, 124, 0, 0, 334, 67, 1, 0, 0, 0, 335, 336, 5, 33, 0, 0, 336, 337, 5, 61, 0, 0, 337, 69, 1, 0, 0, 0, 338, 339, 5, 62, 0, 0, 339, 71, 1, 0, 0, 0, 340, 341, 5, 63, 0, 0, 341, 73, 1, 0, 0, 0, 342, 343, 5, 93, 0, 0, 343, 75, 1, 0, 0, 0, 344, 345, 5, 41, 0, 0, 345, 77, 1, 0, 0, 0, 346, 347, 5, 42, 0, 0, 347, 79, 1, 0, 0, 0, 348, 349, 5, 33, 0, 0, 349, 81, 1, 0, 0, 0, 350, 351, 5, 60, 0, 0, 351, 352, 5, 61, 0, 0, 352, 83, 1, 0, 0, 0, 353, 354, 5, 46, 0, 0, 354, 85, 1, 0, 0, 0, 355, 356, 5, 47, 0, 0, 356, 87, 1, 0, 0, 0, 357, 358, 5, 62, 0, 0, 358, 359, 5, 61, 0, 0, 359, 89, 1, 0, 0, 0, 360, 361, 5, 61, 0, 0, 361, 362, 5, 62, 0, 0, 362, 91, 1, 0, 0, 0, 363, 364, 5, 44, 0, 0, 364, 93, 1, 0, 0, 0, 365, 366, 5, 37, 0, 0, 366, 95, 1, 0, 0, 0, 367, 368, 5, 46, 0, 0, 368, 369, 5, 46, 0, 0, 369, 370, 5, 46, 0, 0, 370, 97, 1, 0, 0, 0, 371, 372, 5, 126, 0, 0, 372, 99, 1, 0, 0, 0, 373, 374, 5, 36, 0, 0, 374, 375, 5, 123, 0, 0, 375, 376, 1, 0, 0, 0, 376, 377, 6, 48, 5, 0, 377, 378, 1, 0, 0, 0, 378, 379, 6, 48, 6, 0, 379, 101, 1, 0, 0, 0, 380, 382, 3, 104, 50, 0, 381, 380, 1, 0, 0, 0, 382, 383, 1, 0, 0, 0, 383, 381, 1, 0, 0, 0, 383, 384, 1, 0, 0, 0, 384, 103, 1, 0, 0, 0, 385, 396, 8, 0, 0, 0, 386, 387, 5, 36, 0, 0, 387, 396, 5, 36, 0, 0, 388, 389, 5, 36, 0, 0, 389, 396, 4, 50, 0, 0, 390, 391, 5, 37, 0, 0, 391, 396, 5, 37, 0, 0, 392, 393, 5, 37, 0, 0, 393, 396, 4, 50, 1, 0, 394, 396, 3, 34, 15, 0, 395, 385, 1, 0, 0, 0, 395, 386, 1, 0, 0, 0, 395, 388, 1, 0, 0, 0, 395, 390, 1, 0, 0, 0, 395, 392, 1, 0, 0, 0, 395, 394, 1, 0, 0, 0, 396, 105, 1, 0, 0, 0, 397, 398, 5, 34, 0, 0, 398, 399, 1, 0, 0, 0, 399, 400, 6, 51, 7, 0, 400, 401, 6, 51, 8, 0, 401, 107, 1, 0, 0, 0, 402, 403, 5, 10, 0, 0, 403, 404, 1, 0, 0, 0, 404, 405, 6, 52, 9, 0, 405, 406, 6, 52, 10, 0, 406, 109, 1, 0, 0, 0, 407, 412, 3, 32, 14, 0, 408, 411, 3, 30, 13, 0, 409, 411, 5, 45, 0, 0, 410, 408, 1, 0, 0, 0, 410, 409, 1, 0, 0, 0, 411, 414, 1, 0, 0, 0, 412, 410, 1, 0, 0, 0, 412, 413, 1, 0, 0, 0, 413, 415, 1, 0, 0, 0, 414, 412, 1, 0, 0, 0, 415, 416, 6, 53, 11, 0, 416, 417, 1, 0, 0, 0, 417, 418, 6, 53, 12, 0, 418, 111, 1, 0, 0, 0, 419, 420, 5, 10, 0, 0, 420, 421, 1, 0, 0, 0, 421, 422, 6, 54, 9, 0, 422, 113, 1, 0, 0, 0, 423, 424, 5, 36, 0, 0, 424, 425, 5, 123, 0, 0, 425, 426, 1, 0, 0, 0, 426, 427, 6, 55, 13, 0, 427, 428, 1, 0, 0, 0, 428, 429, 6, 55, 14, 0, 429, 430, 6, 55, 6, 0, 430, 115, 1, 0, 0, 0, 431, 433, 3, 118, 57, 0, 432, 431, 1, 0, 0, 0, 433, 434, 1, 0, 0, 0, 434, 432, 1, 0, 0, 0, 434, 435, 1, 0, 0, 0, 435, 436, 1, 0, 0, 0, 436, 437, 6, 56, 15, 0, 437, 117, 1, 0, 0, 0, 438, 445, 8, 12, 0, 0, 439, 440, 5, 36, 0, 0, 440, 445, 8, 13, 0, 0, 441, 442, 5, 37, 0, 0, 442, 445, 8, 13, 0, 0, 443, 445, 3, 34, 15, 0, 444, 438, 1, 0, 0, 0, 444, 439, 1, 0, 0, 0, 444, 441, 1, 0, 0, 0, 444, 443, 1, 0, 0, 0, 445, 119, 1, 0, 0, 0, 35, 0, 1, 2, 3, 123, 125, 137, 139, 164, 169, 171, 177, 187, 198, 203, 207, 219, 225, 245, 252, 258, 262, 267, 273, 275, 279, 284, 295, 310, 383, 395, 410, 412, 434, 444, 16, 1, 4, 0, 1, 5, 1, 0, 1, 0, 5, 1, 0, 5, 2, 0, 1, 48, 2, 5, 0, 0, 7, 15, 0, 4, 0, 0, 7, 12, 0, 2, 3, 0, 1, 53, 3, 7, 8, 0, 1, 55, 4, 7, 43, 0, 1, 56, 5] \ No newline at end of file +[4, 0, 47, 450, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 126, 8, 0, 10, 0, 12, 0, 129, 9, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 142, 8, 1, 10, 1, 12, 1, 145, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 3, 7, 169, 8, 7, 1, 8, 1, 8, 1, 8, 5, 8, 174, 8, 8, 10, 8, 12, 8, 177, 9, 8, 1, 9, 4, 9, 180, 8, 9, 11, 9, 12, 9, 181, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 190, 8, 10, 10, 10, 12, 10, 193, 9, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 3, 11, 203, 8, 11, 1, 11, 5, 11, 206, 8, 11, 10, 11, 12, 11, 209, 9, 11, 1, 11, 3, 11, 212, 8, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 3, 13, 224, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 230, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 250, 8, 15, 1, 16, 1, 16, 1, 17, 4, 17, 255, 8, 17, 11, 17, 12, 17, 256, 1, 17, 1, 17, 5, 17, 261, 8, 17, 10, 17, 12, 17, 264, 9, 17, 1, 17, 3, 17, 267, 8, 17, 1, 17, 4, 17, 270, 8, 17, 11, 17, 12, 17, 271, 1, 17, 1, 17, 4, 17, 276, 8, 17, 11, 17, 12, 17, 277, 3, 17, 280, 8, 17, 1, 18, 1, 18, 3, 18, 284, 8, 18, 1, 18, 4, 18, 287, 8, 18, 11, 18, 12, 18, 288, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 300, 8, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 315, 8, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 4, 49, 386, 8, 49, 11, 49, 12, 49, 387, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 400, 8, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 5, 53, 415, 8, 53, 10, 53, 12, 53, 418, 9, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 4, 56, 437, 8, 56, 11, 56, 12, 56, 438, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 3, 57, 449, 8, 57, 1, 191, 0, 58, 4, 1, 6, 2, 8, 3, 10, 4, 12, 5, 14, 6, 16, 7, 18, 0, 20, 8, 22, 9, 24, 10, 26, 11, 28, 12, 30, 0, 32, 0, 34, 0, 36, 0, 38, 13, 40, 0, 42, 14, 44, 15, 46, 16, 48, 17, 50, 18, 52, 19, 54, 20, 56, 21, 58, 22, 60, 23, 62, 24, 64, 25, 66, 26, 68, 27, 70, 28, 72, 29, 74, 30, 76, 31, 78, 32, 80, 33, 82, 34, 84, 35, 86, 36, 88, 37, 90, 38, 92, 39, 94, 40, 96, 41, 98, 42, 100, 43, 102, 44, 104, 45, 106, 0, 108, 0, 110, 0, 112, 0, 114, 0, 116, 46, 118, 47, 4, 0, 1, 2, 3, 14, 4, 0, 10, 10, 13, 13, 34, 34, 36, 37, 3, 0, 9, 9, 12, 13, 32, 32, 2, 0, 10, 10, 13, 13, 1, 0, 48, 57, 4, 0, 36, 36, 65, 90, 95, 95, 97, 122, 2, 0, 0, 127, 55296, 56319, 1, 0, 55296, 56319, 1, 0, 56320, 57343, 5, 0, 34, 34, 92, 92, 110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 3, 0, 10, 10, 13, 13, 36, 37, 1, 0, 123, 123, 484, 0, 4, 1, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 10, 1, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 14, 1, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 24, 1, 0, 0, 0, 0, 26, 1, 0, 0, 0, 0, 28, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 44, 1, 0, 0, 0, 0, 46, 1, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 50, 1, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 54, 1, 0, 0, 0, 0, 56, 1, 0, 0, 0, 0, 58, 1, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 62, 1, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 66, 1, 0, 0, 0, 0, 68, 1, 0, 0, 0, 0, 70, 1, 0, 0, 0, 0, 72, 1, 0, 0, 0, 0, 74, 1, 0, 0, 0, 0, 76, 1, 0, 0, 0, 0, 78, 1, 0, 0, 0, 0, 80, 1, 0, 0, 0, 0, 82, 1, 0, 0, 0, 0, 84, 1, 0, 0, 0, 0, 86, 1, 0, 0, 0, 0, 88, 1, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 92, 1, 0, 0, 0, 0, 94, 1, 0, 0, 0, 0, 96, 1, 0, 0, 0, 0, 98, 1, 0, 0, 0, 1, 100, 1, 0, 0, 0, 1, 102, 1, 0, 0, 0, 1, 104, 1, 0, 0, 0, 1, 106, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 3, 112, 1, 0, 0, 0, 3, 114, 1, 0, 0, 0, 3, 116, 1, 0, 0, 0, 3, 118, 1, 0, 0, 0, 4, 120, 1, 0, 0, 0, 6, 136, 1, 0, 0, 0, 8, 152, 1, 0, 0, 0, 10, 155, 1, 0, 0, 0, 12, 158, 1, 0, 0, 0, 14, 161, 1, 0, 0, 0, 16, 164, 1, 0, 0, 0, 18, 168, 1, 0, 0, 0, 20, 170, 1, 0, 0, 0, 22, 179, 1, 0, 0, 0, 24, 185, 1, 0, 0, 0, 26, 202, 1, 0, 0, 0, 28, 217, 1, 0, 0, 0, 30, 223, 1, 0, 0, 0, 32, 229, 1, 0, 0, 0, 34, 249, 1, 0, 0, 0, 36, 251, 1, 0, 0, 0, 38, 279, 1, 0, 0, 0, 40, 281, 1, 0, 0, 0, 42, 299, 1, 0, 0, 0, 44, 301, 1, 0, 0, 0, 46, 305, 1, 0, 0, 0, 48, 310, 1, 0, 0, 0, 50, 318, 1, 0, 0, 0, 52, 320, 1, 0, 0, 0, 54, 323, 1, 0, 0, 0, 56, 326, 1, 0, 0, 0, 58, 328, 1, 0, 0, 0, 60, 330, 1, 0, 0, 0, 62, 332, 1, 0, 0, 0, 64, 334, 1, 0, 0, 0, 66, 336, 1, 0, 0, 0, 68, 339, 1, 0, 0, 0, 70, 342, 1, 0, 0, 0, 72, 344, 1, 0, 0, 0, 74, 346, 1, 0, 0, 0, 76, 348, 1, 0, 0, 0, 78, 350, 1, 0, 0, 0, 80, 352, 1, 0, 0, 0, 82, 354, 1, 0, 0, 0, 84, 357, 1, 0, 0, 0, 86, 359, 1, 0, 0, 0, 88, 361, 1, 0, 0, 0, 90, 364, 1, 0, 0, 0, 92, 367, 1, 0, 0, 0, 94, 369, 1, 0, 0, 0, 96, 371, 1, 0, 0, 0, 98, 375, 1, 0, 0, 0, 100, 377, 1, 0, 0, 0, 102, 385, 1, 0, 0, 0, 104, 399, 1, 0, 0, 0, 106, 401, 1, 0, 0, 0, 108, 406, 1, 0, 0, 0, 110, 411, 1, 0, 0, 0, 112, 423, 1, 0, 0, 0, 114, 427, 1, 0, 0, 0, 116, 436, 1, 0, 0, 0, 118, 448, 1, 0, 0, 0, 120, 127, 5, 123, 0, 0, 121, 126, 3, 22, 9, 0, 122, 126, 3, 28, 12, 0, 123, 126, 3, 24, 10, 0, 124, 126, 3, 26, 11, 0, 125, 121, 1, 0, 0, 0, 125, 122, 1, 0, 0, 0, 125, 123, 1, 0, 0, 0, 125, 124, 1, 0, 0, 0, 126, 129, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 128, 1, 0, 0, 0, 128, 130, 1, 0, 0, 0, 129, 127, 1, 0, 0, 0, 130, 131, 5, 102, 0, 0, 131, 132, 5, 111, 0, 0, 132, 133, 5, 114, 0, 0, 133, 134, 1, 0, 0, 0, 134, 135, 3, 22, 9, 0, 135, 5, 1, 0, 0, 0, 136, 143, 5, 91, 0, 0, 137, 142, 3, 22, 9, 0, 138, 142, 3, 28, 12, 0, 139, 142, 3, 24, 10, 0, 140, 142, 3, 26, 11, 0, 141, 137, 1, 0, 0, 0, 141, 138, 1, 0, 0, 0, 141, 139, 1, 0, 0, 0, 141, 140, 1, 0, 0, 0, 142, 145, 1, 0, 0, 0, 143, 141, 1, 0, 0, 0, 143, 144, 1, 0, 0, 0, 144, 146, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 146, 147, 5, 102, 0, 0, 147, 148, 5, 111, 0, 0, 148, 149, 5, 114, 0, 0, 149, 150, 1, 0, 0, 0, 150, 151, 3, 22, 9, 0, 151, 7, 1, 0, 0, 0, 152, 153, 5, 105, 0, 0, 153, 154, 5, 102, 0, 0, 154, 9, 1, 0, 0, 0, 155, 156, 5, 105, 0, 0, 156, 157, 5, 110, 0, 0, 157, 11, 1, 0, 0, 0, 158, 159, 5, 123, 0, 0, 159, 160, 6, 4, 0, 0, 160, 13, 1, 0, 0, 0, 161, 162, 5, 125, 0, 0, 162, 163, 6, 5, 1, 0, 163, 15, 1, 0, 0, 0, 164, 165, 5, 61, 0, 0, 165, 17, 1, 0, 0, 0, 166, 169, 8, 0, 0, 0, 167, 169, 3, 34, 15, 0, 168, 166, 1, 0, 0, 0, 168, 167, 1, 0, 0, 0, 169, 19, 1, 0, 0, 0, 170, 175, 3, 32, 14, 0, 171, 174, 3, 30, 13, 0, 172, 174, 5, 45, 0, 0, 173, 171, 1, 0, 0, 0, 173, 172, 1, 0, 0, 0, 174, 177, 1, 0, 0, 0, 175, 173, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 21, 1, 0, 0, 0, 177, 175, 1, 0, 0, 0, 178, 180, 7, 1, 0, 0, 179, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 181, 182, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 184, 6, 9, 2, 0, 184, 23, 1, 0, 0, 0, 185, 186, 5, 47, 0, 0, 186, 187, 5, 42, 0, 0, 187, 191, 1, 0, 0, 0, 188, 190, 9, 0, 0, 0, 189, 188, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 194, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 194, 195, 5, 42, 0, 0, 195, 196, 5, 47, 0, 0, 196, 197, 1, 0, 0, 0, 197, 198, 6, 10, 2, 0, 198, 25, 1, 0, 0, 0, 199, 200, 5, 47, 0, 0, 200, 203, 5, 47, 0, 0, 201, 203, 5, 35, 0, 0, 202, 199, 1, 0, 0, 0, 202, 201, 1, 0, 0, 0, 203, 207, 1, 0, 0, 0, 204, 206, 8, 2, 0, 0, 205, 204, 1, 0, 0, 0, 206, 209, 1, 0, 0, 0, 207, 205, 1, 0, 0, 0, 207, 208, 1, 0, 0, 0, 208, 211, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 210, 212, 5, 13, 0, 0, 211, 210, 1, 0, 0, 0, 211, 212, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 214, 5, 10, 0, 0, 214, 215, 1, 0, 0, 0, 215, 216, 6, 11, 2, 0, 216, 27, 1, 0, 0, 0, 217, 218, 5, 10, 0, 0, 218, 219, 1, 0, 0, 0, 219, 220, 6, 12, 2, 0, 220, 29, 1, 0, 0, 0, 221, 224, 3, 32, 14, 0, 222, 224, 7, 3, 0, 0, 223, 221, 1, 0, 0, 0, 223, 222, 1, 0, 0, 0, 224, 31, 1, 0, 0, 0, 225, 230, 7, 4, 0, 0, 226, 230, 8, 5, 0, 0, 227, 228, 7, 6, 0, 0, 228, 230, 7, 7, 0, 0, 229, 225, 1, 0, 0, 0, 229, 226, 1, 0, 0, 0, 229, 227, 1, 0, 0, 0, 230, 33, 1, 0, 0, 0, 231, 232, 5, 92, 0, 0, 232, 250, 7, 8, 0, 0, 233, 234, 5, 92, 0, 0, 234, 235, 3, 36, 16, 0, 235, 236, 3, 36, 16, 0, 236, 237, 3, 36, 16, 0, 237, 238, 3, 36, 16, 0, 238, 250, 1, 0, 0, 0, 239, 240, 5, 92, 0, 0, 240, 241, 3, 36, 16, 0, 241, 242, 3, 36, 16, 0, 242, 243, 3, 36, 16, 0, 243, 244, 3, 36, 16, 0, 244, 245, 3, 36, 16, 0, 245, 246, 3, 36, 16, 0, 246, 247, 3, 36, 16, 0, 247, 248, 3, 36, 16, 0, 248, 250, 1, 0, 0, 0, 249, 231, 1, 0, 0, 0, 249, 233, 1, 0, 0, 0, 249, 239, 1, 0, 0, 0, 250, 35, 1, 0, 0, 0, 251, 252, 7, 9, 0, 0, 252, 37, 1, 0, 0, 0, 253, 255, 7, 3, 0, 0, 254, 253, 1, 0, 0, 0, 255, 256, 1, 0, 0, 0, 256, 254, 1, 0, 0, 0, 256, 257, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 258, 262, 5, 46, 0, 0, 259, 261, 7, 3, 0, 0, 260, 259, 1, 0, 0, 0, 261, 264, 1, 0, 0, 0, 262, 260, 1, 0, 0, 0, 262, 263, 1, 0, 0, 0, 263, 266, 1, 0, 0, 0, 264, 262, 1, 0, 0, 0, 265, 267, 3, 40, 18, 0, 266, 265, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 280, 1, 0, 0, 0, 268, 270, 7, 3, 0, 0, 269, 268, 1, 0, 0, 0, 270, 271, 1, 0, 0, 0, 271, 269, 1, 0, 0, 0, 271, 272, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 280, 3, 40, 18, 0, 274, 276, 7, 3, 0, 0, 275, 274, 1, 0, 0, 0, 276, 277, 1, 0, 0, 0, 277, 275, 1, 0, 0, 0, 277, 278, 1, 0, 0, 0, 278, 280, 1, 0, 0, 0, 279, 254, 1, 0, 0, 0, 279, 269, 1, 0, 0, 0, 279, 275, 1, 0, 0, 0, 280, 39, 1, 0, 0, 0, 281, 283, 7, 10, 0, 0, 282, 284, 7, 11, 0, 0, 283, 282, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 286, 1, 0, 0, 0, 285, 287, 7, 3, 0, 0, 286, 285, 1, 0, 0, 0, 287, 288, 1, 0, 0, 0, 288, 286, 1, 0, 0, 0, 288, 289, 1, 0, 0, 0, 289, 41, 1, 0, 0, 0, 290, 291, 5, 116, 0, 0, 291, 292, 5, 114, 0, 0, 292, 293, 5, 117, 0, 0, 293, 300, 5, 101, 0, 0, 294, 295, 5, 102, 0, 0, 295, 296, 5, 97, 0, 0, 296, 297, 5, 108, 0, 0, 297, 298, 5, 115, 0, 0, 298, 300, 5, 101, 0, 0, 299, 290, 1, 0, 0, 0, 299, 294, 1, 0, 0, 0, 300, 43, 1, 0, 0, 0, 301, 302, 5, 34, 0, 0, 302, 303, 1, 0, 0, 0, 303, 304, 6, 20, 3, 0, 304, 45, 1, 0, 0, 0, 305, 306, 5, 110, 0, 0, 306, 307, 5, 117, 0, 0, 307, 308, 5, 108, 0, 0, 308, 309, 5, 108, 0, 0, 309, 47, 1, 0, 0, 0, 310, 311, 5, 60, 0, 0, 311, 312, 5, 60, 0, 0, 312, 314, 1, 0, 0, 0, 313, 315, 5, 45, 0, 0, 314, 313, 1, 0, 0, 0, 314, 315, 1, 0, 0, 0, 315, 316, 1, 0, 0, 0, 316, 317, 6, 22, 4, 0, 317, 49, 1, 0, 0, 0, 318, 319, 5, 43, 0, 0, 319, 51, 1, 0, 0, 0, 320, 321, 5, 38, 0, 0, 321, 322, 5, 38, 0, 0, 322, 53, 1, 0, 0, 0, 323, 324, 5, 61, 0, 0, 324, 325, 5, 61, 0, 0, 325, 55, 1, 0, 0, 0, 326, 327, 5, 60, 0, 0, 327, 57, 1, 0, 0, 0, 328, 329, 5, 58, 0, 0, 329, 59, 1, 0, 0, 0, 330, 331, 5, 91, 0, 0, 331, 61, 1, 0, 0, 0, 332, 333, 5, 40, 0, 0, 333, 63, 1, 0, 0, 0, 334, 335, 5, 45, 0, 0, 335, 65, 1, 0, 0, 0, 336, 337, 5, 124, 0, 0, 337, 338, 5, 124, 0, 0, 338, 67, 1, 0, 0, 0, 339, 340, 5, 33, 0, 0, 340, 341, 5, 61, 0, 0, 341, 69, 1, 0, 0, 0, 342, 343, 5, 62, 0, 0, 343, 71, 1, 0, 0, 0, 344, 345, 5, 63, 0, 0, 345, 73, 1, 0, 0, 0, 346, 347, 5, 93, 0, 0, 347, 75, 1, 0, 0, 0, 348, 349, 5, 41, 0, 0, 349, 77, 1, 0, 0, 0, 350, 351, 5, 42, 0, 0, 351, 79, 1, 0, 0, 0, 352, 353, 5, 33, 0, 0, 353, 81, 1, 0, 0, 0, 354, 355, 5, 60, 0, 0, 355, 356, 5, 61, 0, 0, 356, 83, 1, 0, 0, 0, 357, 358, 5, 46, 0, 0, 358, 85, 1, 0, 0, 0, 359, 360, 5, 47, 0, 0, 360, 87, 1, 0, 0, 0, 361, 362, 5, 62, 0, 0, 362, 363, 5, 61, 0, 0, 363, 89, 1, 0, 0, 0, 364, 365, 5, 61, 0, 0, 365, 366, 5, 62, 0, 0, 366, 91, 1, 0, 0, 0, 367, 368, 5, 44, 0, 0, 368, 93, 1, 0, 0, 0, 369, 370, 5, 37, 0, 0, 370, 95, 1, 0, 0, 0, 371, 372, 5, 46, 0, 0, 372, 373, 5, 46, 0, 0, 373, 374, 5, 46, 0, 0, 374, 97, 1, 0, 0, 0, 375, 376, 5, 126, 0, 0, 376, 99, 1, 0, 0, 0, 377, 378, 5, 36, 0, 0, 378, 379, 5, 123, 0, 0, 379, 380, 1, 0, 0, 0, 380, 381, 6, 48, 5, 0, 381, 382, 1, 0, 0, 0, 382, 383, 6, 48, 6, 0, 383, 101, 1, 0, 0, 0, 384, 386, 3, 104, 50, 0, 385, 384, 1, 0, 0, 0, 386, 387, 1, 0, 0, 0, 387, 385, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 103, 1, 0, 0, 0, 389, 400, 8, 0, 0, 0, 390, 391, 5, 36, 0, 0, 391, 400, 5, 36, 0, 0, 392, 393, 5, 36, 0, 0, 393, 400, 4, 50, 0, 0, 394, 395, 5, 37, 0, 0, 395, 400, 5, 37, 0, 0, 396, 397, 5, 37, 0, 0, 397, 400, 4, 50, 1, 0, 398, 400, 3, 34, 15, 0, 399, 389, 1, 0, 0, 0, 399, 390, 1, 0, 0, 0, 399, 392, 1, 0, 0, 0, 399, 394, 1, 0, 0, 0, 399, 396, 1, 0, 0, 0, 399, 398, 1, 0, 0, 0, 400, 105, 1, 0, 0, 0, 401, 402, 5, 34, 0, 0, 402, 403, 1, 0, 0, 0, 403, 404, 6, 51, 7, 0, 404, 405, 6, 51, 8, 0, 405, 107, 1, 0, 0, 0, 406, 407, 5, 10, 0, 0, 407, 408, 1, 0, 0, 0, 408, 409, 6, 52, 9, 0, 409, 410, 6, 52, 10, 0, 410, 109, 1, 0, 0, 0, 411, 416, 3, 32, 14, 0, 412, 415, 3, 30, 13, 0, 413, 415, 5, 45, 0, 0, 414, 412, 1, 0, 0, 0, 414, 413, 1, 0, 0, 0, 415, 418, 1, 0, 0, 0, 416, 414, 1, 0, 0, 0, 416, 417, 1, 0, 0, 0, 417, 419, 1, 0, 0, 0, 418, 416, 1, 0, 0, 0, 419, 420, 6, 53, 11, 0, 420, 421, 1, 0, 0, 0, 421, 422, 6, 53, 12, 0, 422, 111, 1, 0, 0, 0, 423, 424, 5, 10, 0, 0, 424, 425, 1, 0, 0, 0, 425, 426, 6, 54, 9, 0, 426, 113, 1, 0, 0, 0, 427, 428, 5, 36, 0, 0, 428, 429, 5, 123, 0, 0, 429, 430, 1, 0, 0, 0, 430, 431, 6, 55, 13, 0, 431, 432, 1, 0, 0, 0, 432, 433, 6, 55, 14, 0, 433, 434, 6, 55, 6, 0, 434, 115, 1, 0, 0, 0, 435, 437, 3, 118, 57, 0, 436, 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 436, 1, 0, 0, 0, 438, 439, 1, 0, 0, 0, 439, 440, 1, 0, 0, 0, 440, 441, 6, 56, 15, 0, 441, 117, 1, 0, 0, 0, 442, 449, 8, 12, 0, 0, 443, 444, 5, 36, 0, 0, 444, 449, 8, 13, 0, 0, 445, 446, 5, 37, 0, 0, 446, 449, 8, 13, 0, 0, 447, 449, 3, 34, 15, 0, 448, 442, 1, 0, 0, 0, 448, 443, 1, 0, 0, 0, 448, 445, 1, 0, 0, 0, 448, 447, 1, 0, 0, 0, 449, 119, 1, 0, 0, 0, 35, 0, 1, 2, 3, 125, 127, 141, 143, 168, 173, 175, 181, 191, 202, 207, 211, 223, 229, 249, 256, 262, 266, 271, 277, 279, 283, 288, 299, 314, 387, 399, 414, 416, 438, 448, 16, 1, 4, 0, 1, 5, 1, 0, 1, 0, 5, 1, 0, 5, 2, 0, 1, 48, 2, 5, 0, 0, 7, 15, 0, 4, 0, 0, 7, 12, 0, 2, 3, 0, 1, 53, 3, 7, 8, 0, 1, 55, 4, 7, 43, 0, 1, 56, 5] \ No newline at end of file diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java index 1a843f9b242..e952ee91f0a 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java @@ -257,7 +257,7 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre } public static final String _serializedATN = - "\u0004\u0000/\u01be\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ + "\u0004\u0000/\u01c2\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ "\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ @@ -274,284 +274,288 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre "-\u0007-\u0002.\u0007.\u0002/\u0007/\u00020\u00070\u00021\u00071\u0002"+ "2\u00072\u00023\u00073\u00024\u00074\u00025\u00075\u00026\u00076\u0002"+ "7\u00077\u00028\u00078\u00029\u00079\u0001\u0000\u0001\u0000\u0001\u0000"+ - "\u0005\u0000|\b\u0000\n\u0000\f\u0000\u007f\t\u0000\u0001\u0000\u0001"+ - "\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001"+ - "\u0001\u0001\u0001\u0005\u0001\u008a\b\u0001\n\u0001\f\u0001\u008d\t\u0001"+ - "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ - "\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0003"+ - "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0005"+ - "\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0003\u0007\u00a5\b\u0007"+ - "\u0001\b\u0001\b\u0001\b\u0005\b\u00aa\b\b\n\b\f\b\u00ad\t\b\u0001\t\u0004"+ - "\t\u00b0\b\t\u000b\t\f\t\u00b1\u0001\t\u0001\t\u0001\n\u0001\n\u0001\n"+ - "\u0001\n\u0005\n\u00ba\b\n\n\n\f\n\u00bd\t\n\u0001\n\u0001\n\u0001\n\u0001"+ - "\n\u0001\n\u0001\u000b\u0001\u000b\u0001\u000b\u0003\u000b\u00c7\b\u000b"+ - "\u0001\u000b\u0005\u000b\u00ca\b\u000b\n\u000b\f\u000b\u00cd\t\u000b\u0001"+ - "\u000b\u0003\u000b\u00d0\b\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001"+ - "\u000b\u0001\f\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0003\r\u00dc\b"+ - "\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0003\u000e\u00e2\b"+ - "\u000e\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+ + "\u0001\u0000\u0001\u0000\u0005\u0000~\b\u0000\n\u0000\f\u0000\u0081\t"+ + "\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001"+ + "\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0005"+ + "\u0001\u008e\b\u0001\n\u0001\f\u0001\u0091\t\u0001\u0001\u0001\u0001\u0001"+ + "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002\u0001\u0002"+ + "\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004"+ + "\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006"+ + "\u0001\u0007\u0001\u0007\u0003\u0007\u00a9\b\u0007\u0001\b\u0001\b\u0001"+ + "\b\u0005\b\u00ae\b\b\n\b\f\b\u00b1\t\b\u0001\t\u0004\t\u00b4\b\t\u000b"+ + "\t\f\t\u00b5\u0001\t\u0001\t\u0001\n\u0001\n\u0001\n\u0001\n\u0005\n\u00be"+ + "\b\n\n\n\f\n\u00c1\t\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\u000b"+ + "\u0001\u000b\u0001\u000b\u0003\u000b\u00cb\b\u000b\u0001\u000b\u0005\u000b"+ + "\u00ce\b\u000b\n\u000b\f\u000b\u00d1\t\u000b\u0001\u000b\u0003\u000b\u00d4"+ + "\b\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001"+ + "\f\u0001\f\u0001\f\u0001\r\u0001\r\u0003\r\u00e0\b\r\u0001\u000e\u0001"+ + "\u000e\u0001\u000e\u0001\u000e\u0003\u000e\u00e6\b\u000e\u0001\u000f\u0001"+ "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+ "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+ - "\u000f\u0003\u000f\u00f6\b\u000f\u0001\u0010\u0001\u0010\u0001\u0011\u0004"+ - "\u0011\u00fb\b\u0011\u000b\u0011\f\u0011\u00fc\u0001\u0011\u0001\u0011"+ - "\u0005\u0011\u0101\b\u0011\n\u0011\f\u0011\u0104\t\u0011\u0001\u0011\u0003"+ - "\u0011\u0107\b\u0011\u0001\u0011\u0004\u0011\u010a\b\u0011\u000b\u0011"+ - "\f\u0011\u010b\u0001\u0011\u0001\u0011\u0004\u0011\u0110\b\u0011\u000b"+ - "\u0011\f\u0011\u0111\u0003\u0011\u0114\b\u0011\u0001\u0012\u0001\u0012"+ - "\u0003\u0012\u0118\b\u0012\u0001\u0012\u0004\u0012\u011b\b\u0012\u000b"+ - "\u0012\f\u0012\u011c\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+ - "\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0003\u0013\u0128"+ - "\b\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001"+ - "\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001"+ - "\u0016\u0001\u0016\u0003\u0016\u0137\b\u0016\u0001\u0016\u0001\u0016\u0001"+ - "\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0019\u0001"+ - "\u0019\u0001\u0019\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001"+ - "\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001"+ - "\u001f\u0001\u001f\u0001\u001f\u0001 \u0001 \u0001 \u0001!\u0001!\u0001"+ - "\"\u0001\"\u0001#\u0001#\u0001$\u0001$\u0001%\u0001%\u0001&\u0001&\u0001"+ - "\'\u0001\'\u0001\'\u0001(\u0001(\u0001)\u0001)\u0001*\u0001*\u0001*\u0001"+ - "+\u0001+\u0001+\u0001,\u0001,\u0001-\u0001-\u0001.\u0001.\u0001.\u0001"+ - ".\u0001/\u0001/\u00010\u00010\u00010\u00010\u00010\u00010\u00010\u0001"+ - "1\u00041\u017e\b1\u000b1\f1\u017f\u00012\u00012\u00012\u00012\u00012\u0001"+ - "2\u00012\u00012\u00012\u00012\u00032\u018c\b2\u00013\u00013\u00013\u0001"+ - "3\u00013\u00014\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u0005"+ - "5\u019b\b5\n5\f5\u019e\t5\u00015\u00015\u00015\u00015\u00016\u00016\u0001"+ - "6\u00016\u00017\u00017\u00017\u00017\u00017\u00017\u00017\u00017\u0001"+ - "8\u00048\u01b1\b8\u000b8\f8\u01b2\u00018\u00018\u00019\u00019\u00019\u0001"+ - "9\u00019\u00019\u00039\u01bd\b9\u0001\u00bb\u0000:\u0004\u0001\u0006\u0002"+ - "\b\u0003\n\u0004\f\u0005\u000e\u0006\u0010\u0007\u0012\u0000\u0014\b\u0016"+ - "\t\u0018\n\u001a\u000b\u001c\f\u001e\u0000 \u0000\"\u0000$\u0000&\r(\u0000"+ - "*\u000e,\u000f.\u00100\u00112\u00124\u00136\u00148\u0015:\u0016<\u0017"+ - ">\u0018@\u0019B\u001aD\u001bF\u001cH\u001dJ\u001eL\u001fN P!R\"T#V$X%"+ - "Z&\\\'^(`)b*d+f,h-j\u0000l\u0000n\u0000p\u0000r\u0000t.v/\u0004\u0000"+ - "\u0001\u0002\u0003\u000e\u0004\u0000\n\n\r\r\"\"$%\u0003\u0000\t\t\f\r"+ - " \u0002\u0000\n\n\r\r\u0001\u000009\u0004\u0000$$AZ__az\u0002\u0000\u0000"+ - "\u007f\u8000\ud800\u8000\udbff\u0001\u0000\u8000\ud800\u8000\udbff\u0001"+ - "\u0000\u8000\udc00\u8000\udfff\u0005\u0000\"\"\\\\nnrrtt\u0003\u00000"+ - "9AFaf\u0002\u0000EEee\u0002\u0000++--\u0003\u0000\n\n\r\r$%\u0001\u0000"+ - "{{\u01dc\u0000\u0004\u0001\u0000\u0000\u0000\u0000\u0006\u0001\u0000\u0000"+ - "\u0000\u0000\b\u0001\u0000\u0000\u0000\u0000\n\u0001\u0000\u0000\u0000"+ - "\u0000\f\u0001\u0000\u0000\u0000\u0000\u000e\u0001\u0000\u0000\u0000\u0000"+ - "\u0010\u0001\u0000\u0000\u0000\u0000\u0014\u0001\u0000\u0000\u0000\u0000"+ - "\u0016\u0001\u0000\u0000\u0000\u0000\u0018\u0001\u0000\u0000\u0000\u0000"+ - "\u001a\u0001\u0000\u0000\u0000\u0000\u001c\u0001\u0000\u0000\u0000\u0000"+ - "&\u0001\u0000\u0000\u0000\u0000*\u0001\u0000\u0000\u0000\u0000,\u0001"+ - "\u0000\u0000\u0000\u0000.\u0001\u0000\u0000\u0000\u00000\u0001\u0000\u0000"+ - "\u0000\u00002\u0001\u0000\u0000\u0000\u00004\u0001\u0000\u0000\u0000\u0000"+ - "6\u0001\u0000\u0000\u0000\u00008\u0001\u0000\u0000\u0000\u0000:\u0001"+ - "\u0000\u0000\u0000\u0000<\u0001\u0000\u0000\u0000\u0000>\u0001\u0000\u0000"+ - "\u0000\u0000@\u0001\u0000\u0000\u0000\u0000B\u0001\u0000\u0000\u0000\u0000"+ - "D\u0001\u0000\u0000\u0000\u0000F\u0001\u0000\u0000\u0000\u0000H\u0001"+ - "\u0000\u0000\u0000\u0000J\u0001\u0000\u0000\u0000\u0000L\u0001\u0000\u0000"+ - "\u0000\u0000N\u0001\u0000\u0000\u0000\u0000P\u0001\u0000\u0000\u0000\u0000"+ - "R\u0001\u0000\u0000\u0000\u0000T\u0001\u0000\u0000\u0000\u0000V\u0001"+ - "\u0000\u0000\u0000\u0000X\u0001\u0000\u0000\u0000\u0000Z\u0001\u0000\u0000"+ - "\u0000\u0000\\\u0001\u0000\u0000\u0000\u0000^\u0001\u0000\u0000\u0000"+ - "\u0000`\u0001\u0000\u0000\u0000\u0000b\u0001\u0000\u0000\u0000\u0001d"+ - "\u0001\u0000\u0000\u0000\u0001f\u0001\u0000\u0000\u0000\u0001h\u0001\u0000"+ - "\u0000\u0000\u0001j\u0001\u0000\u0000\u0000\u0002l\u0001\u0000\u0000\u0000"+ - "\u0002n\u0001\u0000\u0000\u0000\u0003p\u0001\u0000\u0000\u0000\u0003r"+ - "\u0001\u0000\u0000\u0000\u0003t\u0001\u0000\u0000\u0000\u0003v\u0001\u0000"+ - "\u0000\u0000\u0004x\u0001\u0000\u0000\u0000\u0006\u0086\u0001\u0000\u0000"+ - "\u0000\b\u0094\u0001\u0000\u0000\u0000\n\u0097\u0001\u0000\u0000\u0000"+ - "\f\u009a\u0001\u0000\u0000\u0000\u000e\u009d\u0001\u0000\u0000\u0000\u0010"+ - "\u00a0\u0001\u0000\u0000\u0000\u0012\u00a4\u0001\u0000\u0000\u0000\u0014"+ - "\u00a6\u0001\u0000\u0000\u0000\u0016\u00af\u0001\u0000\u0000\u0000\u0018"+ - "\u00b5\u0001\u0000\u0000\u0000\u001a\u00c6\u0001\u0000\u0000\u0000\u001c"+ - "\u00d5\u0001\u0000\u0000\u0000\u001e\u00db\u0001\u0000\u0000\u0000 \u00e1"+ - "\u0001\u0000\u0000\u0000\"\u00f5\u0001\u0000\u0000\u0000$\u00f7\u0001"+ - "\u0000\u0000\u0000&\u0113\u0001\u0000\u0000\u0000(\u0115\u0001\u0000\u0000"+ - "\u0000*\u0127\u0001\u0000\u0000\u0000,\u0129\u0001\u0000\u0000\u0000."+ - "\u012d\u0001\u0000\u0000\u00000\u0132\u0001\u0000\u0000\u00002\u013a\u0001"+ - "\u0000\u0000\u00004\u013c\u0001\u0000\u0000\u00006\u013f\u0001\u0000\u0000"+ - "\u00008\u0142\u0001\u0000\u0000\u0000:\u0144\u0001\u0000\u0000\u0000<"+ - "\u0146\u0001\u0000\u0000\u0000>\u0148\u0001\u0000\u0000\u0000@\u014a\u0001"+ - "\u0000\u0000\u0000B\u014c\u0001\u0000\u0000\u0000D\u014f\u0001\u0000\u0000"+ - "\u0000F\u0152\u0001\u0000\u0000\u0000H\u0154\u0001\u0000\u0000\u0000J"+ - "\u0156\u0001\u0000\u0000\u0000L\u0158\u0001\u0000\u0000\u0000N\u015a\u0001"+ - "\u0000\u0000\u0000P\u015c\u0001\u0000\u0000\u0000R\u015e\u0001\u0000\u0000"+ - "\u0000T\u0161\u0001\u0000\u0000\u0000V\u0163\u0001\u0000\u0000\u0000X"+ - "\u0165\u0001\u0000\u0000\u0000Z\u0168\u0001\u0000\u0000\u0000\\\u016b"+ - "\u0001\u0000\u0000\u0000^\u016d\u0001\u0000\u0000\u0000`\u016f\u0001\u0000"+ - "\u0000\u0000b\u0173\u0001\u0000\u0000\u0000d\u0175\u0001\u0000\u0000\u0000"+ - "f\u017d\u0001\u0000\u0000\u0000h\u018b\u0001\u0000\u0000\u0000j\u018d"+ - "\u0001\u0000\u0000\u0000l\u0192\u0001\u0000\u0000\u0000n\u0197\u0001\u0000"+ - "\u0000\u0000p\u01a3\u0001\u0000\u0000\u0000r\u01a7\u0001\u0000\u0000\u0000"+ - "t\u01b0\u0001\u0000\u0000\u0000v\u01bc\u0001\u0000\u0000\u0000x}\u0005"+ - "{\u0000\u0000y|\u0003\u0016\t\u0000z|\u0003\u001c\f\u0000{y\u0001\u0000"+ - "\u0000\u0000{z\u0001\u0000\u0000\u0000|\u007f\u0001\u0000\u0000\u0000"+ - "}{\u0001\u0000\u0000\u0000}~\u0001\u0000\u0000\u0000~\u0080\u0001\u0000"+ - "\u0000\u0000\u007f}\u0001\u0000\u0000\u0000\u0080\u0081\u0005f\u0000\u0000"+ - "\u0081\u0082\u0005o\u0000\u0000\u0082\u0083\u0005r\u0000\u0000\u0083\u0084"+ - "\u0001\u0000\u0000\u0000\u0084\u0085\u0003\u0016\t\u0000\u0085\u0005\u0001"+ - "\u0000\u0000\u0000\u0086\u008b\u0005[\u0000\u0000\u0087\u008a\u0003\u0016"+ - "\t\u0000\u0088\u008a\u0003\u001c\f\u0000\u0089\u0087\u0001\u0000\u0000"+ - "\u0000\u0089\u0088\u0001\u0000\u0000\u0000\u008a\u008d\u0001\u0000\u0000"+ - "\u0000\u008b\u0089\u0001\u0000\u0000\u0000\u008b\u008c\u0001\u0000\u0000"+ - "\u0000\u008c\u008e\u0001\u0000\u0000\u0000\u008d\u008b\u0001\u0000\u0000"+ - "\u0000\u008e\u008f\u0005f\u0000\u0000\u008f\u0090\u0005o\u0000\u0000\u0090"+ - "\u0091\u0005r\u0000\u0000\u0091\u0092\u0001\u0000\u0000\u0000\u0092\u0093"+ - "\u0003\u0016\t\u0000\u0093\u0007\u0001\u0000\u0000\u0000\u0094\u0095\u0005"+ - "i\u0000\u0000\u0095\u0096\u0005f\u0000\u0000\u0096\t\u0001\u0000\u0000"+ - "\u0000\u0097\u0098\u0005i\u0000\u0000\u0098\u0099\u0005n\u0000\u0000\u0099"+ - "\u000b\u0001\u0000\u0000\u0000\u009a\u009b\u0005{\u0000\u0000\u009b\u009c"+ - "\u0006\u0004\u0000\u0000\u009c\r\u0001\u0000\u0000\u0000\u009d\u009e\u0005"+ - "}\u0000\u0000\u009e\u009f\u0006\u0005\u0001\u0000\u009f\u000f\u0001\u0000"+ - "\u0000\u0000\u00a0\u00a1\u0005=\u0000\u0000\u00a1\u0011\u0001\u0000\u0000"+ - "\u0000\u00a2\u00a5\b\u0000\u0000\u0000\u00a3\u00a5\u0003\"\u000f\u0000"+ - "\u00a4\u00a2\u0001\u0000\u0000\u0000\u00a4\u00a3\u0001\u0000\u0000\u0000"+ - "\u00a5\u0013\u0001\u0000\u0000\u0000\u00a6\u00ab\u0003 \u000e\u0000\u00a7"+ - "\u00aa\u0003\u001e\r\u0000\u00a8\u00aa\u0005-\u0000\u0000\u00a9\u00a7"+ - "\u0001\u0000\u0000\u0000\u00a9\u00a8\u0001\u0000\u0000\u0000\u00aa\u00ad"+ - "\u0001\u0000\u0000\u0000\u00ab\u00a9\u0001\u0000\u0000\u0000\u00ab\u00ac"+ - "\u0001\u0000\u0000\u0000\u00ac\u0015\u0001\u0000\u0000\u0000\u00ad\u00ab"+ - "\u0001\u0000\u0000\u0000\u00ae\u00b0\u0007\u0001\u0000\u0000\u00af\u00ae"+ - "\u0001\u0000\u0000\u0000\u00b0\u00b1\u0001\u0000\u0000\u0000\u00b1\u00af"+ - "\u0001\u0000\u0000\u0000\u00b1\u00b2\u0001\u0000\u0000\u0000\u00b2\u00b3"+ - "\u0001\u0000\u0000\u0000\u00b3\u00b4\u0006\t\u0002\u0000\u00b4\u0017\u0001"+ - "\u0000\u0000\u0000\u00b5\u00b6\u0005/\u0000\u0000\u00b6\u00b7\u0005*\u0000"+ - "\u0000\u00b7\u00bb\u0001\u0000\u0000\u0000\u00b8\u00ba\t\u0000\u0000\u0000"+ - "\u00b9\u00b8\u0001\u0000\u0000\u0000\u00ba\u00bd\u0001\u0000\u0000\u0000"+ - "\u00bb\u00bc\u0001\u0000\u0000\u0000\u00bb\u00b9\u0001\u0000\u0000\u0000"+ - "\u00bc\u00be\u0001\u0000\u0000\u0000\u00bd\u00bb\u0001\u0000\u0000\u0000"+ - "\u00be\u00bf\u0005*\u0000\u0000\u00bf\u00c0\u0005/\u0000\u0000\u00c0\u00c1"+ - "\u0001\u0000\u0000\u0000\u00c1\u00c2\u0006\n\u0002\u0000\u00c2\u0019\u0001"+ - "\u0000\u0000\u0000\u00c3\u00c4\u0005/\u0000\u0000\u00c4\u00c7\u0005/\u0000"+ - "\u0000\u00c5\u00c7\u0005#\u0000\u0000\u00c6\u00c3\u0001\u0000\u0000\u0000"+ - "\u00c6\u00c5\u0001\u0000\u0000\u0000\u00c7\u00cb\u0001\u0000\u0000\u0000"+ - "\u00c8\u00ca\b\u0002\u0000\u0000\u00c9\u00c8\u0001\u0000\u0000\u0000\u00ca"+ - "\u00cd\u0001\u0000\u0000\u0000\u00cb\u00c9\u0001\u0000\u0000\u0000\u00cb"+ - "\u00cc\u0001\u0000\u0000\u0000\u00cc\u00cf\u0001\u0000\u0000\u0000\u00cd"+ - "\u00cb\u0001\u0000\u0000\u0000\u00ce\u00d0\u0005\r\u0000\u0000\u00cf\u00ce"+ - "\u0001\u0000\u0000\u0000\u00cf\u00d0\u0001\u0000\u0000\u0000\u00d0\u00d1"+ - "\u0001\u0000\u0000\u0000\u00d1\u00d2\u0005\n\u0000\u0000\u00d2\u00d3\u0001"+ - "\u0000\u0000\u0000\u00d3\u00d4\u0006\u000b\u0002\u0000\u00d4\u001b\u0001"+ - "\u0000\u0000\u0000\u00d5\u00d6\u0005\n\u0000\u0000\u00d6\u00d7\u0001\u0000"+ - "\u0000\u0000\u00d7\u00d8\u0006\f\u0002\u0000\u00d8\u001d\u0001\u0000\u0000"+ - "\u0000\u00d9\u00dc\u0003 \u000e\u0000\u00da\u00dc\u0007\u0003\u0000\u0000"+ - "\u00db\u00d9\u0001\u0000\u0000\u0000\u00db\u00da\u0001\u0000\u0000\u0000"+ - "\u00dc\u001f\u0001\u0000\u0000\u0000\u00dd\u00e2\u0007\u0004\u0000\u0000"+ - "\u00de\u00e2\b\u0005\u0000\u0000\u00df\u00e0\u0007\u0006\u0000\u0000\u00e0"+ - "\u00e2\u0007\u0007\u0000\u0000\u00e1\u00dd\u0001\u0000\u0000\u0000\u00e1"+ - "\u00de\u0001\u0000\u0000\u0000\u00e1\u00df\u0001\u0000\u0000\u0000\u00e2"+ - "!\u0001\u0000\u0000\u0000\u00e3\u00e4\u0005\\\u0000\u0000\u00e4\u00f6"+ - "\u0007\b\u0000\u0000\u00e5\u00e6\u0005\\\u0000\u0000\u00e6\u00e7\u0003"+ - "$\u0010\u0000\u00e7\u00e8\u0003$\u0010\u0000\u00e8\u00e9\u0003$\u0010"+ - "\u0000\u00e9\u00ea\u0003$\u0010\u0000\u00ea\u00f6\u0001\u0000\u0000\u0000"+ - "\u00eb\u00ec\u0005\\\u0000\u0000\u00ec\u00ed\u0003$\u0010\u0000\u00ed"+ - "\u00ee\u0003$\u0010\u0000\u00ee\u00ef\u0003$\u0010\u0000\u00ef\u00f0\u0003"+ - "$\u0010\u0000\u00f0\u00f1\u0003$\u0010\u0000\u00f1\u00f2\u0003$\u0010"+ - "\u0000\u00f2\u00f3\u0003$\u0010\u0000\u00f3\u00f4\u0003$\u0010\u0000\u00f4"+ - "\u00f6\u0001\u0000\u0000\u0000\u00f5\u00e3\u0001\u0000\u0000\u0000\u00f5"+ - "\u00e5\u0001\u0000\u0000\u0000\u00f5\u00eb\u0001\u0000\u0000\u0000\u00f6"+ - "#\u0001\u0000\u0000\u0000\u00f7\u00f8\u0007\t\u0000\u0000\u00f8%\u0001"+ - "\u0000\u0000\u0000\u00f9\u00fb\u0007\u0003\u0000\u0000\u00fa\u00f9\u0001"+ - "\u0000\u0000\u0000\u00fb\u00fc\u0001\u0000\u0000\u0000\u00fc\u00fa\u0001"+ - "\u0000\u0000\u0000\u00fc\u00fd\u0001\u0000\u0000\u0000\u00fd\u00fe\u0001"+ - "\u0000\u0000\u0000\u00fe\u0102\u0005.\u0000\u0000\u00ff\u0101\u0007\u0003"+ - "\u0000\u0000\u0100\u00ff\u0001\u0000\u0000\u0000\u0101\u0104\u0001\u0000"+ - "\u0000\u0000\u0102\u0100\u0001\u0000\u0000\u0000\u0102\u0103\u0001\u0000"+ - "\u0000\u0000\u0103\u0106\u0001\u0000\u0000\u0000\u0104\u0102\u0001\u0000"+ - "\u0000\u0000\u0105\u0107\u0003(\u0012\u0000\u0106\u0105\u0001\u0000\u0000"+ - "\u0000\u0106\u0107\u0001\u0000\u0000\u0000\u0107\u0114\u0001\u0000\u0000"+ - "\u0000\u0108\u010a\u0007\u0003\u0000\u0000\u0109\u0108\u0001\u0000\u0000"+ - "\u0000\u010a\u010b\u0001\u0000\u0000\u0000\u010b\u0109\u0001\u0000\u0000"+ - "\u0000\u010b\u010c\u0001\u0000\u0000\u0000\u010c\u010d\u0001\u0000\u0000"+ - "\u0000\u010d\u0114\u0003(\u0012\u0000\u010e\u0110\u0007\u0003\u0000\u0000"+ - "\u010f\u010e\u0001\u0000\u0000\u0000\u0110\u0111\u0001\u0000\u0000\u0000"+ - "\u0111\u010f\u0001\u0000\u0000\u0000\u0111\u0112\u0001\u0000\u0000\u0000"+ - "\u0112\u0114\u0001\u0000\u0000\u0000\u0113\u00fa\u0001\u0000\u0000\u0000"+ - "\u0113\u0109\u0001\u0000\u0000\u0000\u0113\u010f\u0001\u0000\u0000\u0000"+ - "\u0114\'\u0001\u0000\u0000\u0000\u0115\u0117\u0007\n\u0000\u0000\u0116"+ - "\u0118\u0007\u000b\u0000\u0000\u0117\u0116\u0001\u0000\u0000\u0000\u0117"+ - "\u0118\u0001\u0000\u0000\u0000\u0118\u011a\u0001\u0000\u0000\u0000\u0119"+ - "\u011b\u0007\u0003\u0000\u0000\u011a\u0119\u0001\u0000\u0000\u0000\u011b"+ - "\u011c\u0001\u0000\u0000\u0000\u011c\u011a\u0001\u0000\u0000\u0000\u011c"+ - "\u011d\u0001\u0000\u0000\u0000\u011d)\u0001\u0000\u0000\u0000\u011e\u011f"+ - "\u0005t\u0000\u0000\u011f\u0120\u0005r\u0000\u0000\u0120\u0121\u0005u"+ - "\u0000\u0000\u0121\u0128\u0005e\u0000\u0000\u0122\u0123\u0005f\u0000\u0000"+ - "\u0123\u0124\u0005a\u0000\u0000\u0124\u0125\u0005l\u0000\u0000\u0125\u0126"+ - "\u0005s\u0000\u0000\u0126\u0128\u0005e\u0000\u0000\u0127\u011e\u0001\u0000"+ - "\u0000\u0000\u0127\u0122\u0001\u0000\u0000\u0000\u0128+\u0001\u0000\u0000"+ - "\u0000\u0129\u012a\u0005\"\u0000\u0000\u012a\u012b\u0001\u0000\u0000\u0000"+ - "\u012b\u012c\u0006\u0014\u0003\u0000\u012c-\u0001\u0000\u0000\u0000\u012d"+ - "\u012e\u0005n\u0000\u0000\u012e\u012f\u0005u\u0000\u0000\u012f\u0130\u0005"+ - "l\u0000\u0000\u0130\u0131\u0005l\u0000\u0000\u0131/\u0001\u0000\u0000"+ - "\u0000\u0132\u0133\u0005<\u0000\u0000\u0133\u0134\u0005<\u0000\u0000\u0134"+ - "\u0136\u0001\u0000\u0000\u0000\u0135\u0137\u0005-\u0000\u0000\u0136\u0135"+ - "\u0001\u0000\u0000\u0000\u0136\u0137\u0001\u0000\u0000\u0000\u0137\u0138"+ - "\u0001\u0000\u0000\u0000\u0138\u0139\u0006\u0016\u0004\u0000\u01391\u0001"+ - "\u0000\u0000\u0000\u013a\u013b\u0005+\u0000\u0000\u013b3\u0001\u0000\u0000"+ - "\u0000\u013c\u013d\u0005&\u0000\u0000\u013d\u013e\u0005&\u0000\u0000\u013e"+ - "5\u0001\u0000\u0000\u0000\u013f\u0140\u0005=\u0000\u0000\u0140\u0141\u0005"+ - "=\u0000\u0000\u01417\u0001\u0000\u0000\u0000\u0142\u0143\u0005<\u0000"+ - "\u0000\u01439\u0001\u0000\u0000\u0000\u0144\u0145\u0005:\u0000\u0000\u0145"+ - ";\u0001\u0000\u0000\u0000\u0146\u0147\u0005[\u0000\u0000\u0147=\u0001"+ - "\u0000\u0000\u0000\u0148\u0149\u0005(\u0000\u0000\u0149?\u0001\u0000\u0000"+ - "\u0000\u014a\u014b\u0005-\u0000\u0000\u014bA\u0001\u0000\u0000\u0000\u014c"+ - "\u014d\u0005|\u0000\u0000\u014d\u014e\u0005|\u0000\u0000\u014eC\u0001"+ - "\u0000\u0000\u0000\u014f\u0150\u0005!\u0000\u0000\u0150\u0151\u0005=\u0000"+ - "\u0000\u0151E\u0001\u0000\u0000\u0000\u0152\u0153\u0005>\u0000\u0000\u0153"+ - "G\u0001\u0000\u0000\u0000\u0154\u0155\u0005?\u0000\u0000\u0155I\u0001"+ - "\u0000\u0000\u0000\u0156\u0157\u0005]\u0000\u0000\u0157K\u0001\u0000\u0000"+ - "\u0000\u0158\u0159\u0005)\u0000\u0000\u0159M\u0001\u0000\u0000\u0000\u015a"+ - "\u015b\u0005*\u0000\u0000\u015bO\u0001\u0000\u0000\u0000\u015c\u015d\u0005"+ - "!\u0000\u0000\u015dQ\u0001\u0000\u0000\u0000\u015e\u015f\u0005<\u0000"+ - "\u0000\u015f\u0160\u0005=\u0000\u0000\u0160S\u0001\u0000\u0000\u0000\u0161"+ - "\u0162\u0005.\u0000\u0000\u0162U\u0001\u0000\u0000\u0000\u0163\u0164\u0005"+ - "/\u0000\u0000\u0164W\u0001\u0000\u0000\u0000\u0165\u0166\u0005>\u0000"+ - "\u0000\u0166\u0167\u0005=\u0000\u0000\u0167Y\u0001\u0000\u0000\u0000\u0168"+ - "\u0169\u0005=\u0000\u0000\u0169\u016a\u0005>\u0000\u0000\u016a[\u0001"+ - "\u0000\u0000\u0000\u016b\u016c\u0005,\u0000\u0000\u016c]\u0001\u0000\u0000"+ - "\u0000\u016d\u016e\u0005%\u0000\u0000\u016e_\u0001\u0000\u0000\u0000\u016f"+ - "\u0170\u0005.\u0000\u0000\u0170\u0171\u0005.\u0000\u0000\u0171\u0172\u0005"+ - ".\u0000\u0000\u0172a\u0001\u0000\u0000\u0000\u0173\u0174\u0005~\u0000"+ - "\u0000\u0174c\u0001\u0000\u0000\u0000\u0175\u0176\u0005$\u0000\u0000\u0176"+ - "\u0177\u0005{\u0000\u0000\u0177\u0178\u0001\u0000\u0000\u0000\u0178\u0179"+ - "\u00060\u0005\u0000\u0179\u017a\u0001\u0000\u0000\u0000\u017a\u017b\u0006"+ - "0\u0006\u0000\u017be\u0001\u0000\u0000\u0000\u017c\u017e\u0003h2\u0000"+ - "\u017d\u017c\u0001\u0000\u0000\u0000\u017e\u017f\u0001\u0000\u0000\u0000"+ - "\u017f\u017d\u0001\u0000\u0000\u0000\u017f\u0180\u0001\u0000\u0000\u0000"+ - "\u0180g\u0001\u0000\u0000\u0000\u0181\u018c\b\u0000\u0000\u0000\u0182"+ - "\u0183\u0005$\u0000\u0000\u0183\u018c\u0005$\u0000\u0000\u0184\u0185\u0005"+ - "$\u0000\u0000\u0185\u018c\u00042\u0000\u0000\u0186\u0187\u0005%\u0000"+ - "\u0000\u0187\u018c\u0005%\u0000\u0000\u0188\u0189\u0005%\u0000\u0000\u0189"+ - "\u018c\u00042\u0001\u0000\u018a\u018c\u0003\"\u000f\u0000\u018b\u0181"+ - "\u0001\u0000\u0000\u0000\u018b\u0182\u0001\u0000\u0000\u0000\u018b\u0184"+ - "\u0001\u0000\u0000\u0000\u018b\u0186\u0001\u0000\u0000\u0000\u018b\u0188"+ - "\u0001\u0000\u0000\u0000\u018b\u018a\u0001\u0000\u0000\u0000\u018ci\u0001"+ - "\u0000\u0000\u0000\u018d\u018e\u0005\"\u0000\u0000\u018e\u018f\u0001\u0000"+ - "\u0000\u0000\u018f\u0190\u00063\u0007\u0000\u0190\u0191\u00063\b\u0000"+ - "\u0191k\u0001\u0000\u0000\u0000\u0192\u0193\u0005\n\u0000\u0000\u0193"+ - "\u0194\u0001\u0000\u0000\u0000\u0194\u0195\u00064\t\u0000\u0195\u0196"+ - "\u00064\n\u0000\u0196m\u0001\u0000\u0000\u0000\u0197\u019c\u0003 \u000e"+ - "\u0000\u0198\u019b\u0003\u001e\r\u0000\u0199\u019b\u0005-\u0000\u0000"+ - "\u019a\u0198\u0001\u0000\u0000\u0000\u019a\u0199\u0001\u0000\u0000\u0000"+ - "\u019b\u019e\u0001\u0000\u0000\u0000\u019c\u019a\u0001\u0000\u0000\u0000"+ - "\u019c\u019d\u0001\u0000\u0000\u0000\u019d\u019f\u0001\u0000\u0000\u0000"+ - "\u019e\u019c\u0001\u0000\u0000\u0000\u019f\u01a0\u00065\u000b\u0000\u01a0"+ - "\u01a1\u0001\u0000\u0000\u0000\u01a1\u01a2\u00065\f\u0000\u01a2o\u0001"+ - "\u0000\u0000\u0000\u01a3\u01a4\u0005\n\u0000\u0000\u01a4\u01a5\u0001\u0000"+ - "\u0000\u0000\u01a5\u01a6\u00066\t\u0000\u01a6q\u0001\u0000\u0000\u0000"+ - "\u01a7\u01a8\u0005$\u0000\u0000\u01a8\u01a9\u0005{\u0000\u0000\u01a9\u01aa"+ - "\u0001\u0000\u0000\u0000\u01aa\u01ab\u00067\r\u0000\u01ab\u01ac\u0001"+ - "\u0000\u0000\u0000\u01ac\u01ad\u00067\u000e\u0000\u01ad\u01ae\u00067\u0006"+ - "\u0000\u01aes\u0001\u0000\u0000\u0000\u01af\u01b1\u0003v9\u0000\u01b0"+ - "\u01af\u0001\u0000\u0000\u0000\u01b1\u01b2\u0001\u0000\u0000\u0000\u01b2"+ - "\u01b0\u0001\u0000\u0000\u0000\u01b2\u01b3\u0001\u0000\u0000\u0000\u01b3"+ - "\u01b4\u0001\u0000\u0000\u0000\u01b4\u01b5\u00068\u000f\u0000\u01b5u\u0001"+ - "\u0000\u0000\u0000\u01b6\u01bd\b\f\u0000\u0000\u01b7\u01b8\u0005$\u0000"+ - "\u0000\u01b8\u01bd\b\r\u0000\u0000\u01b9\u01ba\u0005%\u0000\u0000\u01ba"+ - "\u01bd\b\r\u0000\u0000\u01bb\u01bd\u0003\"\u000f\u0000\u01bc\u01b6\u0001"+ - "\u0000\u0000\u0000\u01bc\u01b7\u0001\u0000\u0000\u0000\u01bc\u01b9\u0001"+ - "\u0000\u0000\u0000\u01bc\u01bb\u0001\u0000\u0000\u0000\u01bdw\u0001\u0000"+ - "\u0000\u0000#\u0000\u0001\u0002\u0003{}\u0089\u008b\u00a4\u00a9\u00ab"+ - "\u00b1\u00bb\u00c6\u00cb\u00cf\u00db\u00e1\u00f5\u00fc\u0102\u0106\u010b"+ - "\u0111\u0113\u0117\u011c\u0127\u0136\u017f\u018b\u019a\u019c\u01b2\u01bc"+ - "\u0010\u0001\u0004\u0000\u0001\u0005\u0001\u0000\u0001\u0000\u0005\u0001"+ - "\u0000\u0005\u0002\u0000\u00010\u0002\u0005\u0000\u0000\u0007\u000f\u0000"+ - "\u0004\u0000\u0000\u0007\f\u0000\u0002\u0003\u0000\u00015\u0003\u0007"+ - "\b\u0000\u00017\u0004\u0007+\u0000\u00018\u0005"; + "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0003\u000f\u00fa"+ + "\b\u000f\u0001\u0010\u0001\u0010\u0001\u0011\u0004\u0011\u00ff\b\u0011"+ + "\u000b\u0011\f\u0011\u0100\u0001\u0011\u0001\u0011\u0005\u0011\u0105\b"+ + "\u0011\n\u0011\f\u0011\u0108\t\u0011\u0001\u0011\u0003\u0011\u010b\b\u0011"+ + "\u0001\u0011\u0004\u0011\u010e\b\u0011\u000b\u0011\f\u0011\u010f\u0001"+ + "\u0011\u0001\u0011\u0004\u0011\u0114\b\u0011\u000b\u0011\f\u0011\u0115"+ + "\u0003\u0011\u0118\b\u0011\u0001\u0012\u0001\u0012\u0003\u0012\u011c\b"+ + "\u0012\u0001\u0012\u0004\u0012\u011f\b\u0012\u000b\u0012\f\u0012\u0120"+ + "\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013"+ + "\u0001\u0013\u0001\u0013\u0001\u0013\u0003\u0013\u012c\b\u0013\u0001\u0014"+ + "\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0015"+ + "\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016"+ + "\u0003\u0016\u013b\b\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017"+ + "\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001\u0019"+ + "\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c"+ + "\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001f\u0001\u001f"+ + "\u0001\u001f\u0001 \u0001 \u0001 \u0001!\u0001!\u0001\"\u0001\"\u0001"+ + "#\u0001#\u0001$\u0001$\u0001%\u0001%\u0001&\u0001&\u0001\'\u0001\'\u0001"+ + "\'\u0001(\u0001(\u0001)\u0001)\u0001*\u0001*\u0001*\u0001+\u0001+\u0001"+ + "+\u0001,\u0001,\u0001-\u0001-\u0001.\u0001.\u0001.\u0001.\u0001/\u0001"+ + "/\u00010\u00010\u00010\u00010\u00010\u00010\u00010\u00011\u00041\u0182"+ + "\b1\u000b1\f1\u0183\u00012\u00012\u00012\u00012\u00012\u00012\u00012\u0001"+ + "2\u00012\u00012\u00032\u0190\b2\u00013\u00013\u00013\u00013\u00013\u0001"+ + "4\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u00055\u019f\b5\n5"+ + "\f5\u01a2\t5\u00015\u00015\u00015\u00015\u00016\u00016\u00016\u00016\u0001"+ + "7\u00017\u00017\u00017\u00017\u00017\u00017\u00017\u00018\u00048\u01b5"+ + "\b8\u000b8\f8\u01b6\u00018\u00018\u00019\u00019\u00019\u00019\u00019\u0001"+ + "9\u00039\u01c1\b9\u0001\u00bf\u0000:\u0004\u0001\u0006\u0002\b\u0003\n"+ + "\u0004\f\u0005\u000e\u0006\u0010\u0007\u0012\u0000\u0014\b\u0016\t\u0018"+ + "\n\u001a\u000b\u001c\f\u001e\u0000 \u0000\"\u0000$\u0000&\r(\u0000*\u000e"+ + ",\u000f.\u00100\u00112\u00124\u00136\u00148\u0015:\u0016<\u0017>\u0018"+ + "@\u0019B\u001aD\u001bF\u001cH\u001dJ\u001eL\u001fN P!R\"T#V$X%Z&\\\'^"+ + "(`)b*d+f,h-j\u0000l\u0000n\u0000p\u0000r\u0000t.v/\u0004\u0000\u0001\u0002"+ + "\u0003\u000e\u0004\u0000\n\n\r\r\"\"$%\u0003\u0000\t\t\f\r \u0002\u0000"+ + "\n\n\r\r\u0001\u000009\u0004\u0000$$AZ__az\u0002\u0000\u0000\u007f\u8000"+ + "\ud800\u8000\udbff\u0001\u0000\u8000\ud800\u8000\udbff\u0001\u0000\u8000"+ + "\udc00\u8000\udfff\u0005\u0000\"\"\\\\nnrrtt\u0003\u000009AFaf\u0002\u0000"+ + "EEee\u0002\u0000++--\u0003\u0000\n\n\r\r$%\u0001\u0000{{\u01e4\u0000\u0004"+ + "\u0001\u0000\u0000\u0000\u0000\u0006\u0001\u0000\u0000\u0000\u0000\b\u0001"+ + "\u0000\u0000\u0000\u0000\n\u0001\u0000\u0000\u0000\u0000\f\u0001\u0000"+ + "\u0000\u0000\u0000\u000e\u0001\u0000\u0000\u0000\u0000\u0010\u0001\u0000"+ + "\u0000\u0000\u0000\u0014\u0001\u0000\u0000\u0000\u0000\u0016\u0001\u0000"+ + "\u0000\u0000\u0000\u0018\u0001\u0000\u0000\u0000\u0000\u001a\u0001\u0000"+ + "\u0000\u0000\u0000\u001c\u0001\u0000\u0000\u0000\u0000&\u0001\u0000\u0000"+ + "\u0000\u0000*\u0001\u0000\u0000\u0000\u0000,\u0001\u0000\u0000\u0000\u0000"+ + ".\u0001\u0000\u0000\u0000\u00000\u0001\u0000\u0000\u0000\u00002\u0001"+ + "\u0000\u0000\u0000\u00004\u0001\u0000\u0000\u0000\u00006\u0001\u0000\u0000"+ + "\u0000\u00008\u0001\u0000\u0000\u0000\u0000:\u0001\u0000\u0000\u0000\u0000"+ + "<\u0001\u0000\u0000\u0000\u0000>\u0001\u0000\u0000\u0000\u0000@\u0001"+ + "\u0000\u0000\u0000\u0000B\u0001\u0000\u0000\u0000\u0000D\u0001\u0000\u0000"+ + "\u0000\u0000F\u0001\u0000\u0000\u0000\u0000H\u0001\u0000\u0000\u0000\u0000"+ + "J\u0001\u0000\u0000\u0000\u0000L\u0001\u0000\u0000\u0000\u0000N\u0001"+ + "\u0000\u0000\u0000\u0000P\u0001\u0000\u0000\u0000\u0000R\u0001\u0000\u0000"+ + "\u0000\u0000T\u0001\u0000\u0000\u0000\u0000V\u0001\u0000\u0000\u0000\u0000"+ + "X\u0001\u0000\u0000\u0000\u0000Z\u0001\u0000\u0000\u0000\u0000\\\u0001"+ + "\u0000\u0000\u0000\u0000^\u0001\u0000\u0000\u0000\u0000`\u0001\u0000\u0000"+ + "\u0000\u0000b\u0001\u0000\u0000\u0000\u0001d\u0001\u0000\u0000\u0000\u0001"+ + "f\u0001\u0000\u0000\u0000\u0001h\u0001\u0000\u0000\u0000\u0001j\u0001"+ + "\u0000\u0000\u0000\u0002l\u0001\u0000\u0000\u0000\u0002n\u0001\u0000\u0000"+ + "\u0000\u0003p\u0001\u0000\u0000\u0000\u0003r\u0001\u0000\u0000\u0000\u0003"+ + "t\u0001\u0000\u0000\u0000\u0003v\u0001\u0000\u0000\u0000\u0004x\u0001"+ + "\u0000\u0000\u0000\u0006\u0088\u0001\u0000\u0000\u0000\b\u0098\u0001\u0000"+ + "\u0000\u0000\n\u009b\u0001\u0000\u0000\u0000\f\u009e\u0001\u0000\u0000"+ + "\u0000\u000e\u00a1\u0001\u0000\u0000\u0000\u0010\u00a4\u0001\u0000\u0000"+ + "\u0000\u0012\u00a8\u0001\u0000\u0000\u0000\u0014\u00aa\u0001\u0000\u0000"+ + "\u0000\u0016\u00b3\u0001\u0000\u0000\u0000\u0018\u00b9\u0001\u0000\u0000"+ + "\u0000\u001a\u00ca\u0001\u0000\u0000\u0000\u001c\u00d9\u0001\u0000\u0000"+ + "\u0000\u001e\u00df\u0001\u0000\u0000\u0000 \u00e5\u0001\u0000\u0000\u0000"+ + "\"\u00f9\u0001\u0000\u0000\u0000$\u00fb\u0001\u0000\u0000\u0000&\u0117"+ + "\u0001\u0000\u0000\u0000(\u0119\u0001\u0000\u0000\u0000*\u012b\u0001\u0000"+ + "\u0000\u0000,\u012d\u0001\u0000\u0000\u0000.\u0131\u0001\u0000\u0000\u0000"+ + "0\u0136\u0001\u0000\u0000\u00002\u013e\u0001\u0000\u0000\u00004\u0140"+ + "\u0001\u0000\u0000\u00006\u0143\u0001\u0000\u0000\u00008\u0146\u0001\u0000"+ + "\u0000\u0000:\u0148\u0001\u0000\u0000\u0000<\u014a\u0001\u0000\u0000\u0000"+ + ">\u014c\u0001\u0000\u0000\u0000@\u014e\u0001\u0000\u0000\u0000B\u0150"+ + "\u0001\u0000\u0000\u0000D\u0153\u0001\u0000\u0000\u0000F\u0156\u0001\u0000"+ + "\u0000\u0000H\u0158\u0001\u0000\u0000\u0000J\u015a\u0001\u0000\u0000\u0000"+ + "L\u015c\u0001\u0000\u0000\u0000N\u015e\u0001\u0000\u0000\u0000P\u0160"+ + "\u0001\u0000\u0000\u0000R\u0162\u0001\u0000\u0000\u0000T\u0165\u0001\u0000"+ + "\u0000\u0000V\u0167\u0001\u0000\u0000\u0000X\u0169\u0001\u0000\u0000\u0000"+ + "Z\u016c\u0001\u0000\u0000\u0000\\\u016f\u0001\u0000\u0000\u0000^\u0171"+ + "\u0001\u0000\u0000\u0000`\u0173\u0001\u0000\u0000\u0000b\u0177\u0001\u0000"+ + "\u0000\u0000d\u0179\u0001\u0000\u0000\u0000f\u0181\u0001\u0000\u0000\u0000"+ + "h\u018f\u0001\u0000\u0000\u0000j\u0191\u0001\u0000\u0000\u0000l\u0196"+ + "\u0001\u0000\u0000\u0000n\u019b\u0001\u0000\u0000\u0000p\u01a7\u0001\u0000"+ + "\u0000\u0000r\u01ab\u0001\u0000\u0000\u0000t\u01b4\u0001\u0000\u0000\u0000"+ + "v\u01c0\u0001\u0000\u0000\u0000x\u007f\u0005{\u0000\u0000y~\u0003\u0016"+ + "\t\u0000z~\u0003\u001c\f\u0000{~\u0003\u0018\n\u0000|~\u0003\u001a\u000b"+ + "\u0000}y\u0001\u0000\u0000\u0000}z\u0001\u0000\u0000\u0000}{\u0001\u0000"+ + "\u0000\u0000}|\u0001\u0000\u0000\u0000~\u0081\u0001\u0000\u0000\u0000"+ + "\u007f}\u0001\u0000\u0000\u0000\u007f\u0080\u0001\u0000\u0000\u0000\u0080"+ + "\u0082\u0001\u0000\u0000\u0000\u0081\u007f\u0001\u0000\u0000\u0000\u0082"+ + "\u0083\u0005f\u0000\u0000\u0083\u0084\u0005o\u0000\u0000\u0084\u0085\u0005"+ + "r\u0000\u0000\u0085\u0086\u0001\u0000\u0000\u0000\u0086\u0087\u0003\u0016"+ + "\t\u0000\u0087\u0005\u0001\u0000\u0000\u0000\u0088\u008f\u0005[\u0000"+ + "\u0000\u0089\u008e\u0003\u0016\t\u0000\u008a\u008e\u0003\u001c\f\u0000"+ + "\u008b\u008e\u0003\u0018\n\u0000\u008c\u008e\u0003\u001a\u000b\u0000\u008d"+ + "\u0089\u0001\u0000\u0000\u0000\u008d\u008a\u0001\u0000\u0000\u0000\u008d"+ + "\u008b\u0001\u0000\u0000\u0000\u008d\u008c\u0001\u0000\u0000\u0000\u008e"+ + "\u0091\u0001\u0000\u0000\u0000\u008f\u008d\u0001\u0000\u0000\u0000\u008f"+ + "\u0090\u0001\u0000\u0000\u0000\u0090\u0092\u0001\u0000\u0000\u0000\u0091"+ + "\u008f\u0001\u0000\u0000\u0000\u0092\u0093\u0005f\u0000\u0000\u0093\u0094"+ + "\u0005o\u0000\u0000\u0094\u0095\u0005r\u0000\u0000\u0095\u0096\u0001\u0000"+ + "\u0000\u0000\u0096\u0097\u0003\u0016\t\u0000\u0097\u0007\u0001\u0000\u0000"+ + "\u0000\u0098\u0099\u0005i\u0000\u0000\u0099\u009a\u0005f\u0000\u0000\u009a"+ + "\t\u0001\u0000\u0000\u0000\u009b\u009c\u0005i\u0000\u0000\u009c\u009d"+ + "\u0005n\u0000\u0000\u009d\u000b\u0001\u0000\u0000\u0000\u009e\u009f\u0005"+ + "{\u0000\u0000\u009f\u00a0\u0006\u0004\u0000\u0000\u00a0\r\u0001\u0000"+ + "\u0000\u0000\u00a1\u00a2\u0005}\u0000\u0000\u00a2\u00a3\u0006\u0005\u0001"+ + "\u0000\u00a3\u000f\u0001\u0000\u0000\u0000\u00a4\u00a5\u0005=\u0000\u0000"+ + "\u00a5\u0011\u0001\u0000\u0000\u0000\u00a6\u00a9\b\u0000\u0000\u0000\u00a7"+ + "\u00a9\u0003\"\u000f\u0000\u00a8\u00a6\u0001\u0000\u0000\u0000\u00a8\u00a7"+ + "\u0001\u0000\u0000\u0000\u00a9\u0013\u0001\u0000\u0000\u0000\u00aa\u00af"+ + "\u0003 \u000e\u0000\u00ab\u00ae\u0003\u001e\r\u0000\u00ac\u00ae\u0005"+ + "-\u0000\u0000\u00ad\u00ab\u0001\u0000\u0000\u0000\u00ad\u00ac\u0001\u0000"+ + "\u0000\u0000\u00ae\u00b1\u0001\u0000\u0000\u0000\u00af\u00ad\u0001\u0000"+ + "\u0000\u0000\u00af\u00b0\u0001\u0000\u0000\u0000\u00b0\u0015\u0001\u0000"+ + "\u0000\u0000\u00b1\u00af\u0001\u0000\u0000\u0000\u00b2\u00b4\u0007\u0001"+ + "\u0000\u0000\u00b3\u00b2\u0001\u0000\u0000\u0000\u00b4\u00b5\u0001\u0000"+ + "\u0000\u0000\u00b5\u00b3\u0001\u0000\u0000\u0000\u00b5\u00b6\u0001\u0000"+ + "\u0000\u0000\u00b6\u00b7\u0001\u0000\u0000\u0000\u00b7\u00b8\u0006\t\u0002"+ + "\u0000\u00b8\u0017\u0001\u0000\u0000\u0000\u00b9\u00ba\u0005/\u0000\u0000"+ + "\u00ba\u00bb\u0005*\u0000\u0000\u00bb\u00bf\u0001\u0000\u0000\u0000\u00bc"+ + "\u00be\t\u0000\u0000\u0000\u00bd\u00bc\u0001\u0000\u0000\u0000\u00be\u00c1"+ + "\u0001\u0000\u0000\u0000\u00bf\u00c0\u0001\u0000\u0000\u0000\u00bf\u00bd"+ + "\u0001\u0000\u0000\u0000\u00c0\u00c2\u0001\u0000\u0000\u0000\u00c1\u00bf"+ + "\u0001\u0000\u0000\u0000\u00c2\u00c3\u0005*\u0000\u0000\u00c3\u00c4\u0005"+ + "/\u0000\u0000\u00c4\u00c5\u0001\u0000\u0000\u0000\u00c5\u00c6\u0006\n"+ + "\u0002\u0000\u00c6\u0019\u0001\u0000\u0000\u0000\u00c7\u00c8\u0005/\u0000"+ + "\u0000\u00c8\u00cb\u0005/\u0000\u0000\u00c9\u00cb\u0005#\u0000\u0000\u00ca"+ + "\u00c7\u0001\u0000\u0000\u0000\u00ca\u00c9\u0001\u0000\u0000\u0000\u00cb"+ + "\u00cf\u0001\u0000\u0000\u0000\u00cc\u00ce\b\u0002\u0000\u0000\u00cd\u00cc"+ + "\u0001\u0000\u0000\u0000\u00ce\u00d1\u0001\u0000\u0000\u0000\u00cf\u00cd"+ + "\u0001\u0000\u0000\u0000\u00cf\u00d0\u0001\u0000\u0000\u0000\u00d0\u00d3"+ + "\u0001\u0000\u0000\u0000\u00d1\u00cf\u0001\u0000\u0000\u0000\u00d2\u00d4"+ + "\u0005\r\u0000\u0000\u00d3\u00d2\u0001\u0000\u0000\u0000\u00d3\u00d4\u0001"+ + "\u0000\u0000\u0000\u00d4\u00d5\u0001\u0000\u0000\u0000\u00d5\u00d6\u0005"+ + "\n\u0000\u0000\u00d6\u00d7\u0001\u0000\u0000\u0000\u00d7\u00d8\u0006\u000b"+ + "\u0002\u0000\u00d8\u001b\u0001\u0000\u0000\u0000\u00d9\u00da\u0005\n\u0000"+ + "\u0000\u00da\u00db\u0001\u0000\u0000\u0000\u00db\u00dc\u0006\f\u0002\u0000"+ + "\u00dc\u001d\u0001\u0000\u0000\u0000\u00dd\u00e0\u0003 \u000e\u0000\u00de"+ + "\u00e0\u0007\u0003\u0000\u0000\u00df\u00dd\u0001\u0000\u0000\u0000\u00df"+ + "\u00de\u0001\u0000\u0000\u0000\u00e0\u001f\u0001\u0000\u0000\u0000\u00e1"+ + "\u00e6\u0007\u0004\u0000\u0000\u00e2\u00e6\b\u0005\u0000\u0000\u00e3\u00e4"+ + "\u0007\u0006\u0000\u0000\u00e4\u00e6\u0007\u0007\u0000\u0000\u00e5\u00e1"+ + "\u0001\u0000\u0000\u0000\u00e5\u00e2\u0001\u0000\u0000\u0000\u00e5\u00e3"+ + "\u0001\u0000\u0000\u0000\u00e6!\u0001\u0000\u0000\u0000\u00e7\u00e8\u0005"+ + "\\\u0000\u0000\u00e8\u00fa\u0007\b\u0000\u0000\u00e9\u00ea\u0005\\\u0000"+ + "\u0000\u00ea\u00eb\u0003$\u0010\u0000\u00eb\u00ec\u0003$\u0010\u0000\u00ec"+ + "\u00ed\u0003$\u0010\u0000\u00ed\u00ee\u0003$\u0010\u0000\u00ee\u00fa\u0001"+ + "\u0000\u0000\u0000\u00ef\u00f0\u0005\\\u0000\u0000\u00f0\u00f1\u0003$"+ + "\u0010\u0000\u00f1\u00f2\u0003$\u0010\u0000\u00f2\u00f3\u0003$\u0010\u0000"+ + "\u00f3\u00f4\u0003$\u0010\u0000\u00f4\u00f5\u0003$\u0010\u0000\u00f5\u00f6"+ + "\u0003$\u0010\u0000\u00f6\u00f7\u0003$\u0010\u0000\u00f7\u00f8\u0003$"+ + "\u0010\u0000\u00f8\u00fa\u0001\u0000\u0000\u0000\u00f9\u00e7\u0001\u0000"+ + "\u0000\u0000\u00f9\u00e9\u0001\u0000\u0000\u0000\u00f9\u00ef\u0001\u0000"+ + "\u0000\u0000\u00fa#\u0001\u0000\u0000\u0000\u00fb\u00fc\u0007\t\u0000"+ + "\u0000\u00fc%\u0001\u0000\u0000\u0000\u00fd\u00ff\u0007\u0003\u0000\u0000"+ + "\u00fe\u00fd\u0001\u0000\u0000\u0000\u00ff\u0100\u0001\u0000\u0000\u0000"+ + "\u0100\u00fe\u0001\u0000\u0000\u0000\u0100\u0101\u0001\u0000\u0000\u0000"+ + "\u0101\u0102\u0001\u0000\u0000\u0000\u0102\u0106\u0005.\u0000\u0000\u0103"+ + "\u0105\u0007\u0003\u0000\u0000\u0104\u0103\u0001\u0000\u0000\u0000\u0105"+ + "\u0108\u0001\u0000\u0000\u0000\u0106\u0104\u0001\u0000\u0000\u0000\u0106"+ + "\u0107\u0001\u0000\u0000\u0000\u0107\u010a\u0001\u0000\u0000\u0000\u0108"+ + "\u0106\u0001\u0000\u0000\u0000\u0109\u010b\u0003(\u0012\u0000\u010a\u0109"+ + "\u0001\u0000\u0000\u0000\u010a\u010b\u0001\u0000\u0000\u0000\u010b\u0118"+ + "\u0001\u0000\u0000\u0000\u010c\u010e\u0007\u0003\u0000\u0000\u010d\u010c"+ + "\u0001\u0000\u0000\u0000\u010e\u010f\u0001\u0000\u0000\u0000\u010f\u010d"+ + "\u0001\u0000\u0000\u0000\u010f\u0110\u0001\u0000\u0000\u0000\u0110\u0111"+ + "\u0001\u0000\u0000\u0000\u0111\u0118\u0003(\u0012\u0000\u0112\u0114\u0007"+ + "\u0003\u0000\u0000\u0113\u0112\u0001\u0000\u0000\u0000\u0114\u0115\u0001"+ + "\u0000\u0000\u0000\u0115\u0113\u0001\u0000\u0000\u0000\u0115\u0116\u0001"+ + "\u0000\u0000\u0000\u0116\u0118\u0001\u0000\u0000\u0000\u0117\u00fe\u0001"+ + "\u0000\u0000\u0000\u0117\u010d\u0001\u0000\u0000\u0000\u0117\u0113\u0001"+ + "\u0000\u0000\u0000\u0118\'\u0001\u0000\u0000\u0000\u0119\u011b\u0007\n"+ + "\u0000\u0000\u011a\u011c\u0007\u000b\u0000\u0000\u011b\u011a\u0001\u0000"+ + "\u0000\u0000\u011b\u011c\u0001\u0000\u0000\u0000\u011c\u011e\u0001\u0000"+ + "\u0000\u0000\u011d\u011f\u0007\u0003\u0000\u0000\u011e\u011d\u0001\u0000"+ + "\u0000\u0000\u011f\u0120\u0001\u0000\u0000\u0000\u0120\u011e\u0001\u0000"+ + "\u0000\u0000\u0120\u0121\u0001\u0000\u0000\u0000\u0121)\u0001\u0000\u0000"+ + "\u0000\u0122\u0123\u0005t\u0000\u0000\u0123\u0124\u0005r\u0000\u0000\u0124"+ + "\u0125\u0005u\u0000\u0000\u0125\u012c\u0005e\u0000\u0000\u0126\u0127\u0005"+ + "f\u0000\u0000\u0127\u0128\u0005a\u0000\u0000\u0128\u0129\u0005l\u0000"+ + "\u0000\u0129\u012a\u0005s\u0000\u0000\u012a\u012c\u0005e\u0000\u0000\u012b"+ + "\u0122\u0001\u0000\u0000\u0000\u012b\u0126\u0001\u0000\u0000\u0000\u012c"+ + "+\u0001\u0000\u0000\u0000\u012d\u012e\u0005\"\u0000\u0000\u012e\u012f"+ + "\u0001\u0000\u0000\u0000\u012f\u0130\u0006\u0014\u0003\u0000\u0130-\u0001"+ + "\u0000\u0000\u0000\u0131\u0132\u0005n\u0000\u0000\u0132\u0133\u0005u\u0000"+ + "\u0000\u0133\u0134\u0005l\u0000\u0000\u0134\u0135\u0005l\u0000\u0000\u0135"+ + "/\u0001\u0000\u0000\u0000\u0136\u0137\u0005<\u0000\u0000\u0137\u0138\u0005"+ + "<\u0000\u0000\u0138\u013a\u0001\u0000\u0000\u0000\u0139\u013b\u0005-\u0000"+ + "\u0000\u013a\u0139\u0001\u0000\u0000\u0000\u013a\u013b\u0001\u0000\u0000"+ + "\u0000\u013b\u013c\u0001\u0000\u0000\u0000\u013c\u013d\u0006\u0016\u0004"+ + "\u0000\u013d1\u0001\u0000\u0000\u0000\u013e\u013f\u0005+\u0000\u0000\u013f"+ + "3\u0001\u0000\u0000\u0000\u0140\u0141\u0005&\u0000\u0000\u0141\u0142\u0005"+ + "&\u0000\u0000\u01425\u0001\u0000\u0000\u0000\u0143\u0144\u0005=\u0000"+ + "\u0000\u0144\u0145\u0005=\u0000\u0000\u01457\u0001\u0000\u0000\u0000\u0146"+ + "\u0147\u0005<\u0000\u0000\u01479\u0001\u0000\u0000\u0000\u0148\u0149\u0005"+ + ":\u0000\u0000\u0149;\u0001\u0000\u0000\u0000\u014a\u014b\u0005[\u0000"+ + "\u0000\u014b=\u0001\u0000\u0000\u0000\u014c\u014d\u0005(\u0000\u0000\u014d"+ + "?\u0001\u0000\u0000\u0000\u014e\u014f\u0005-\u0000\u0000\u014fA\u0001"+ + "\u0000\u0000\u0000\u0150\u0151\u0005|\u0000\u0000\u0151\u0152\u0005|\u0000"+ + "\u0000\u0152C\u0001\u0000\u0000\u0000\u0153\u0154\u0005!\u0000\u0000\u0154"+ + "\u0155\u0005=\u0000\u0000\u0155E\u0001\u0000\u0000\u0000\u0156\u0157\u0005"+ + ">\u0000\u0000\u0157G\u0001\u0000\u0000\u0000\u0158\u0159\u0005?\u0000"+ + "\u0000\u0159I\u0001\u0000\u0000\u0000\u015a\u015b\u0005]\u0000\u0000\u015b"+ + "K\u0001\u0000\u0000\u0000\u015c\u015d\u0005)\u0000\u0000\u015dM\u0001"+ + "\u0000\u0000\u0000\u015e\u015f\u0005*\u0000\u0000\u015fO\u0001\u0000\u0000"+ + "\u0000\u0160\u0161\u0005!\u0000\u0000\u0161Q\u0001\u0000\u0000\u0000\u0162"+ + "\u0163\u0005<\u0000\u0000\u0163\u0164\u0005=\u0000\u0000\u0164S\u0001"+ + "\u0000\u0000\u0000\u0165\u0166\u0005.\u0000\u0000\u0166U\u0001\u0000\u0000"+ + "\u0000\u0167\u0168\u0005/\u0000\u0000\u0168W\u0001\u0000\u0000\u0000\u0169"+ + "\u016a\u0005>\u0000\u0000\u016a\u016b\u0005=\u0000\u0000\u016bY\u0001"+ + "\u0000\u0000\u0000\u016c\u016d\u0005=\u0000\u0000\u016d\u016e\u0005>\u0000"+ + "\u0000\u016e[\u0001\u0000\u0000\u0000\u016f\u0170\u0005,\u0000\u0000\u0170"+ + "]\u0001\u0000\u0000\u0000\u0171\u0172\u0005%\u0000\u0000\u0172_\u0001"+ + "\u0000\u0000\u0000\u0173\u0174\u0005.\u0000\u0000\u0174\u0175\u0005.\u0000"+ + "\u0000\u0175\u0176\u0005.\u0000\u0000\u0176a\u0001\u0000\u0000\u0000\u0177"+ + "\u0178\u0005~\u0000\u0000\u0178c\u0001\u0000\u0000\u0000\u0179\u017a\u0005"+ + "$\u0000\u0000\u017a\u017b\u0005{\u0000\u0000\u017b\u017c\u0001\u0000\u0000"+ + "\u0000\u017c\u017d\u00060\u0005\u0000\u017d\u017e\u0001\u0000\u0000\u0000"+ + "\u017e\u017f\u00060\u0006\u0000\u017fe\u0001\u0000\u0000\u0000\u0180\u0182"+ + "\u0003h2\u0000\u0181\u0180\u0001\u0000\u0000\u0000\u0182\u0183\u0001\u0000"+ + "\u0000\u0000\u0183\u0181\u0001\u0000\u0000\u0000\u0183\u0184\u0001\u0000"+ + "\u0000\u0000\u0184g\u0001\u0000\u0000\u0000\u0185\u0190\b\u0000\u0000"+ + "\u0000\u0186\u0187\u0005$\u0000\u0000\u0187\u0190\u0005$\u0000\u0000\u0188"+ + "\u0189\u0005$\u0000\u0000\u0189\u0190\u00042\u0000\u0000\u018a\u018b\u0005"+ + "%\u0000\u0000\u018b\u0190\u0005%\u0000\u0000\u018c\u018d\u0005%\u0000"+ + "\u0000\u018d\u0190\u00042\u0001\u0000\u018e\u0190\u0003\"\u000f\u0000"+ + "\u018f\u0185\u0001\u0000\u0000\u0000\u018f\u0186\u0001\u0000\u0000\u0000"+ + "\u018f\u0188\u0001\u0000\u0000\u0000\u018f\u018a\u0001\u0000\u0000\u0000"+ + "\u018f\u018c\u0001\u0000\u0000\u0000\u018f\u018e\u0001\u0000\u0000\u0000"+ + "\u0190i\u0001\u0000\u0000\u0000\u0191\u0192\u0005\"\u0000\u0000\u0192"+ + "\u0193\u0001\u0000\u0000\u0000\u0193\u0194\u00063\u0007\u0000\u0194\u0195"+ + "\u00063\b\u0000\u0195k\u0001\u0000\u0000\u0000\u0196\u0197\u0005\n\u0000"+ + "\u0000\u0197\u0198\u0001\u0000\u0000\u0000\u0198\u0199\u00064\t\u0000"+ + "\u0199\u019a\u00064\n\u0000\u019am\u0001\u0000\u0000\u0000\u019b\u01a0"+ + "\u0003 \u000e\u0000\u019c\u019f\u0003\u001e\r\u0000\u019d\u019f\u0005"+ + "-\u0000\u0000\u019e\u019c\u0001\u0000\u0000\u0000\u019e\u019d\u0001\u0000"+ + "\u0000\u0000\u019f\u01a2\u0001\u0000\u0000\u0000\u01a0\u019e\u0001\u0000"+ + "\u0000\u0000\u01a0\u01a1\u0001\u0000\u0000\u0000\u01a1\u01a3\u0001\u0000"+ + "\u0000\u0000\u01a2\u01a0\u0001\u0000\u0000\u0000\u01a3\u01a4\u00065\u000b"+ + "\u0000\u01a4\u01a5\u0001\u0000\u0000\u0000\u01a5\u01a6\u00065\f\u0000"+ + "\u01a6o\u0001\u0000\u0000\u0000\u01a7\u01a8\u0005\n\u0000\u0000\u01a8"+ + "\u01a9\u0001\u0000\u0000\u0000\u01a9\u01aa\u00066\t\u0000\u01aaq\u0001"+ + "\u0000\u0000\u0000\u01ab\u01ac\u0005$\u0000\u0000\u01ac\u01ad\u0005{\u0000"+ + "\u0000\u01ad\u01ae\u0001\u0000\u0000\u0000\u01ae\u01af\u00067\r\u0000"+ + "\u01af\u01b0\u0001\u0000\u0000\u0000\u01b0\u01b1\u00067\u000e\u0000\u01b1"+ + "\u01b2\u00067\u0006\u0000\u01b2s\u0001\u0000\u0000\u0000\u01b3\u01b5\u0003"+ + "v9\u0000\u01b4\u01b3\u0001\u0000\u0000\u0000\u01b5\u01b6\u0001\u0000\u0000"+ + "\u0000\u01b6\u01b4\u0001\u0000\u0000\u0000\u01b6\u01b7\u0001\u0000\u0000"+ + "\u0000\u01b7\u01b8\u0001\u0000\u0000\u0000\u01b8\u01b9\u00068\u000f\u0000"+ + "\u01b9u\u0001\u0000\u0000\u0000\u01ba\u01c1\b\f\u0000\u0000\u01bb\u01bc"+ + "\u0005$\u0000\u0000\u01bc\u01c1\b\r\u0000\u0000\u01bd\u01be\u0005%\u0000"+ + "\u0000\u01be\u01c1\b\r\u0000\u0000\u01bf\u01c1\u0003\"\u000f\u0000\u01c0"+ + "\u01ba\u0001\u0000\u0000\u0000\u01c0\u01bb\u0001\u0000\u0000\u0000\u01c0"+ + "\u01bd\u0001\u0000\u0000\u0000\u01c0\u01bf\u0001\u0000\u0000\u0000\u01c1"+ + "w\u0001\u0000\u0000\u0000#\u0000\u0001\u0002\u0003}\u007f\u008d\u008f"+ + "\u00a8\u00ad\u00af\u00b5\u00bf\u00ca\u00cf\u00d3\u00df\u00e5\u00f9\u0100"+ + "\u0106\u010a\u010f\u0115\u0117\u011b\u0120\u012b\u013a\u0183\u018f\u019e"+ + "\u01a0\u01b6\u01c0\u0010\u0001\u0004\u0000\u0001\u0005\u0001\u0000\u0001"+ + "\u0000\u0005\u0001\u0000\u0005\u0002\u0000\u00010\u0002\u0005\u0000\u0000"+ + "\u0007\u000f\u0000\u0004\u0000\u0000\u0007\f\u0000\u0002\u0003\u0000\u0001"+ + "5\u0003\u0007\b\u0000\u00017\u0004\u0007+\u0000\u00018\u0005"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclForTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclForTest.java index a6730994b79..211b33fa258 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclForTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclForTest.java @@ -16,6 +16,7 @@ package org.openrewrite.hcl.tree; import org.junit.jupiter.api.Test; +import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; import static org.openrewrite.hcl.Assertions.hcl; @@ -74,4 +75,21 @@ void forEach() { ) ); } + + @Test + @Issue("https://github.com/openrewrite/rewrite/issues/4857") + void commentInAFor() { + rewriteRun( + hcl( + """ + locals { + a = { + # this is some super smart logic here + for i, v in ["a", "b"]: v => i + } + } + """ + ) + ); + } } From b3f17cea87340343832ded6c3a18eb22a9aeea12 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Tue, 7 Jan 2025 13:30:16 +0100 Subject: [PATCH 112/179] Rename recipe options and inline visitor and method --- .../maven/EnableDevelocityBuildCache.java | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/EnableDevelocityBuildCache.java b/rewrite-maven/src/main/java/org/openrewrite/maven/EnableDevelocityBuildCache.java index 1d35b34e765..ef3f58f0ca6 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/EnableDevelocityBuildCache.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/EnableDevelocityBuildCache.java @@ -43,33 +43,33 @@ public String getDescription() { example = "true", required = false) @Nullable - String buildCacheLocalEnabled; + String localEnabled; @Option(displayName = "Enable remote build cache", description = "Value for `//develocity/buildCache/remote/enabled`.", example = "true", required = false) @Nullable - String buildCacheRemoteEnabled; + String remoteEnabled; @Option(displayName = "Enable remote build cache store", description = "Value for `//develocity/buildCache/remote/storeEnabled`.", example = "#{isTrue(env['CI'])}", required = false) @Nullable - String buildCacheRemoteStoreEnabled; + String remoteStoreEnabled; @Override public Validated validate(ExecutionContext ctx) { return super.validate(ctx) - .and(Validated.notBlank("buildCacheLocalEnabled", buildCacheLocalEnabled) - .or(Validated.notBlank("buildCacheRemoteEnabled", buildCacheRemoteEnabled)) - .or(Validated.notBlank("buildCacheRemoteStoreEnabled", buildCacheRemoteStoreEnabled))); + .and(Validated.notBlank("localEnabled", localEnabled) + .or(Validated.notBlank("remoteEnabled", remoteEnabled)) + .or(Validated.notBlank("remoteStoreEnabled", remoteStoreEnabled))); } @Override public TreeVisitor getVisitor() { - XmlVisitor visitor = new XmlVisitor() { + return Preconditions.check(new FindSourceFiles(".mvn/*.xml"), new XmlVisitor() { @Override public Xml visitDocument(Xml.Document document, ExecutionContext ctx) { Xml.Tag rootTag = document.getRoot(); @@ -81,29 +81,27 @@ public Xml visitDocument(Xml.Document document, ExecutionContext ctx) { } return document; } - }; - return Preconditions.check(new FindSourceFiles(".mvn/*.xml"), visitor); - } - - private String buildCacheConfig() { - StringBuilder sb = new StringBuilder(""); - if (!StringUtils.isBlank(buildCacheLocalEnabled)) { - sb.append(""); - sb.append("").append(buildCacheLocalEnabled).append(""); - sb.append(""); - } - if (!StringUtils.isBlank(buildCacheRemoteEnabled) || !StringUtils.isBlank(buildCacheRemoteStoreEnabled)) { - sb.append(""); - if (!StringUtils.isBlank(buildCacheRemoteEnabled)) { - sb.append("").append(buildCacheRemoteEnabled).append(""); - } - if (!StringUtils.isBlank(buildCacheRemoteStoreEnabled)) { - sb.append("").append(buildCacheRemoteStoreEnabled).append(""); + private String buildCacheConfig() { + StringBuilder sb = new StringBuilder(""); + if (!StringUtils.isBlank(localEnabled)) { + sb.append(""); + sb.append("").append(localEnabled).append(""); + sb.append(""); + } + if (!StringUtils.isBlank(remoteEnabled) || !StringUtils.isBlank(remoteStoreEnabled)) { + sb.append(""); + if (!StringUtils.isBlank(remoteEnabled)) { + sb.append("").append(remoteEnabled).append(""); + } + if (!StringUtils.isBlank(remoteStoreEnabled)) { + sb.append("").append(remoteStoreEnabled).append(""); + } + sb.append(""); + } + sb.append(""); + return sb.toString(); } - sb.append(""); - } - sb.append(""); - return sb.toString(); + }); } } From 6ddcc37dbb2cad5c88ea347642d5ade9fd52da7c Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Tue, 7 Jan 2025 15:44:58 +0100 Subject: [PATCH 113/179] Lombok support for java 21 (#4860) * Lombok support for java 21 * Minimize diff with Java 17 to make it easier to spot intentional changes * Minimize diff some more to add missing `var` handling --------- Co-authored-by: Tim te Beek --- .../ReloadableJava17ParserVisitor.java | 1 - rewrite-java-21/build.gradle.kts | 1 + .../java/isolated/ReloadableJava21Parser.java | 169 +++++++++++++----- .../ReloadableJava21ParserVisitor.java | 129 ++++++++++--- .../org/openrewrite/java/tree/LombokTest.java | 2 +- 5 files changed, 229 insertions(+), 73 deletions(-) diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 673d84fff4e..9f56bfb0b3c 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -544,7 +544,6 @@ public J visitCompilationUnit(CompilationUnitTree node, Space fmt) { Map annotationPosTable = mapAnnotations(node.getPackageAnnotations(), new HashMap<>(node.getPackageAnnotations().size())); - List packageAnnotations = collectAnnotations(annotationPosTable); J.Package packageDecl = null; diff --git a/rewrite-java-21/build.gradle.kts b/rewrite-java-21/build.gradle.kts index 143abb855fc..8ab5e091748 100644 --- a/rewrite-java-21/build.gradle.kts +++ b/rewrite-java-21/build.gradle.kts @@ -17,6 +17,7 @@ val javaTck = configurations.create("javaTck") { dependencies { api(project(":rewrite-core")) api(project(":rewrite-java")) + runtimeOnly(project(":rewrite-java-lombok")) compileOnly("org.slf4j:slf4j-api:1.7.+") diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21Parser.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21Parser.java index 823e2103f10..5b3ac22b69e 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21Parser.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21Parser.java @@ -21,10 +21,12 @@ import com.sun.tools.javac.comp.Modules; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.JavaCompiler; +import com.sun.tools.javac.main.Option; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Options; +import lombok.Getter; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import org.objectweb.asm.ClassReader; @@ -33,7 +35,6 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.SourceFile; -import org.openrewrite.internal.StringUtils; import org.openrewrite.java.JavaParser; import org.openrewrite.java.JavaParsingException; import org.openrewrite.java.internal.JavaTypeCache; @@ -43,20 +44,27 @@ import org.openrewrite.tree.ParseError; import org.openrewrite.tree.ParsingEventListener; import org.openrewrite.tree.ParsingExecutionContextView; +import org.slf4j.LoggerFactory; +import javax.annotation.processing.Processor; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; import javax.tools.StandardLocation; import java.io.*; +import java.lang.reflect.Constructor; import java.net.URI; +import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; /** @@ -77,14 +85,16 @@ public class ReloadableJava21Parser implements JavaParser { private final JavaCompiler compiler; private final ResettableLog compilerLog; private final Collection styles; - - private ReloadableJava21Parser(boolean logCompilationWarningsAndErrors, - @Nullable Collection classpath, - Collection classBytesClasspath, - @Nullable Collection dependsOn, - Charset charset, - Collection styles, - JavaTypeCache typeCache) { + private final List annotationProcessors; + + private ReloadableJava21Parser( + boolean logCompilationWarningsAndErrors, + @Nullable Collection classpath, + Collection classBytesClasspath, + @Nullable Collection dependsOn, + Charset charset, + Collection styles, + JavaTypeCache typeCache) { this.classpath = classpath; this.dependsOn = dependsOn; this.styles = styles; @@ -106,6 +116,70 @@ private ReloadableJava21Parser(boolean logCompilationWarningsAndErrors, Options.instance(context).put("-g", "-g"); Options.instance(context).put("-proc", "none"); + // Ensure type attribution continues despite errors in individual files or nodes. + // If an error occurs in a single file or node, type attribution should still proceed + // for all other source files and unaffected nodes within the same file. + Options.instance(context).put("should-stop.ifError", "GENERATE"); + + LOMBOK: + if (System.getenv().getOrDefault("REWRITE_LOMBOK", System.getProperty("rewrite.lombok")) != null && + classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) { + Processor lombokProcessor = null; + try { + // https://projectlombok.org/contributing/lombok-execution-path + List overrideClasspath = new ArrayList<>(); + for (Path part : classpath) { + if (part.toString().contains("lombok")) { + overrideClasspath.add(part.toString()); + } + } + // make sure the rewrite-java-lombok dependency comes first + boolean found = false; + for (int i = 0; i < overrideClasspath.size(); i++) { + if (overrideClasspath.get(i).contains("rewrite-java-lombok")) { + overrideClasspath.add(0, overrideClasspath.remove(i)); + found = true; + } + } + if (!found) { + // try to find `rewrite-java-lombok` using class loader + URL resource = getClass().getClassLoader().getResource("org/openrewrite/java/lombok/OpenRewriteConfigurationKeysLoader.class"); + if (resource != null && resource.getProtocol().equals("jar") && resource.getPath().startsWith("file:")) { + String path = Paths.get(URI.create(resource.getPath().substring(0, resource.getPath().indexOf("!")))).toString(); + overrideClasspath.add(0, path); + } else { + break LOMBOK; + } + } + System.setProperty("shadow.override.lombok", String.join(File.pathSeparator, overrideClasspath)); + + Class shadowLoaderClass = Class.forName("lombok.launch.ShadowClassLoader", true, getClass().getClassLoader()); + Constructor shadowLoaderConstructor = shadowLoaderClass.getDeclaredConstructor( + Class.forName("java.lang.ClassLoader"), + Class.forName("java.lang.String"), + Class.forName("java.lang.String"), + Class.forName("java.util.List"), + Class.forName("java.util.List")); + shadowLoaderConstructor.setAccessible(true); + + ClassLoader lombokShadowLoader = (ClassLoader) shadowLoaderConstructor.newInstance( + getClass().getClassLoader(), + "lombok", + null, + emptyList(), + singletonList("lombok.patcher.Symbols") + ); + lombokProcessor = (Processor) lombokShadowLoader.loadClass("lombok.core.AnnotationProcessor").getDeclaredConstructor().newInstance(); + Options.instance(context).put(Option.PROCESSOR, "lombok.launch.AnnotationProcessorHider$AnnotationProcessor"); + } catch (ReflectiveOperationException ignore) { + // Lombok was not found or could not be initialized + } finally { + annotationProcessors = lombokProcessor != null ? singletonList(lombokProcessor) : emptyList(); + } + } else { + annotationProcessors = emptyList(); + } + // MUST be created (registered with the context) after pfm and compilerLog compiler = new JavaCompiler(context); @@ -124,7 +198,7 @@ public void write(char[] cbuf, int off, int len) { if (logCompilationWarningsAndErrors) { String log = new String(Arrays.copyOfRange(cbuf, off, len)); if (!log.isBlank()) { - org.slf4j.LoggerFactory.getLogger(ReloadableJava21Parser.class).warn(log); + LoggerFactory.getLogger(ReloadableJava21Parser.class).warn(log); } } } @@ -164,6 +238,7 @@ public Stream parseInputs(Iterable sourceFiles, @Nullable Pat ); J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); + //noinspection DataFlowIssue cuByPath.setValue(null); // allow memory used by this JCCompilationUnit to be released parsingListener.parsed(input, cu); return requirePrintEqualsInput(cu, input, relativeTo, ctx); @@ -188,39 +263,46 @@ LinkedHashMap parseInputsToCompilerAst(Iterable } LinkedHashMap cus = new LinkedHashMap<>(); - acceptedInputs(sourceFiles).forEach(input1 -> { + List inputFileObjects = acceptedInputs(sourceFiles) + .map(input -> new ReloadableJava21ParserInputFileObject(input, ctx)) + .toList(); + if (!annotationProcessors.isEmpty()) { + compiler.initProcessAnnotations(annotationProcessors, inputFileObjects, emptyList()); + } + try { + //noinspection unchecked + com.sun.tools.javac.util.List jcCompilationUnits = compiler.parseFiles((List) (List) inputFileObjects, true); + for (int i = 0; i < inputFileObjects.size(); i++) { + cus.put(inputFileObjects.get(i).getInput(), jcCompilationUnits.get(i)); + } try { - JCTree.JCCompilationUnit jcCompilationUnit = compiler.parse(new ReloadableJava21ParserInputFileObject(input1, ctx)); - cus.put(input1, jcCompilationUnit); - } catch (IllegalStateException e) { - if ("endPosTable already set".equals(e.getMessage())) { - throw new IllegalStateException( - "Call reset() on JavaParser before parsing another set of source files that " + - "have some of the same fully qualified names. Source file [" + - input1.getPath() + "]\n[\n" + StringUtils.readFully(input1.getSource(ctx), getCharset(ctx)) + "\n]", e); + initModules(cus.values()); + enterAll(cus.values()); + + // For some reason this is necessary in JDK 9+, where the internal block counter that + // annotationsBlocked() tests against remains >0 after attribution. + Annotate annotate = Annotate.instance(context); + while (annotate.annotationsBlocked()) { + annotate.unblockAnnotations(); // also flushes once unblocked } - throw e; + if (!annotationProcessors.isEmpty()) { + compiler.processAnnotations(jcCompilationUnits, emptyList()); + } + compiler.attribute(compiler.todo); + } catch (Throwable t) { + // when symbol entering fails on problems like missing types, attribution can often times proceed + // unhindered, but it sometimes cannot (so attribution is always best-effort in the presence of errors) + ctx.getOnError().accept(new JavaParsingException("Failed symbol entering or attribution", t)); } - }); - - try { - initModules(cus.values()); - enterAll(cus.values()); - - // For some reason this is necessary in JDK 9+, where the internal block counter that - // annotationsBlocked() tests against remains >0 after attribution. - Annotate annotate = Annotate.instance(context); - while (annotate.annotationsBlocked()) { - annotate.unblockAnnotations(); // also flushes once unblocked + } catch (IllegalStateException e) { + if ("endPosTable already set".equals(e.getMessage())) { + throw new IllegalStateException( + "Call reset() on JavaParser before parsing another set of source files that " + + "have some of the same fully qualified names.", e); } - - compiler.attribute(compiler.todo); - } catch ( - Throwable t) { - // when symbol entering fails on problems like missing types, attribution can often times proceed - // unhindered, but it sometimes cannot (so attribution is always best-effort in the presence of errors) - ctx.getOnError().accept(new JavaParsingException("Failed symbol entering or attribution", t)); + throw e; } + return cus; } @@ -333,9 +415,9 @@ public Iterable list(Location location, String packageName, Set< Iterable listed = super.list(location, packageName, kinds, recurse); return classByteClasspath.isEmpty() ? listed : Stream.concat(classByteClasspath.stream() - .filter(jfo -> jfo.getPackage().equals(packageName)), - StreamSupport.stream(listed.spliterator(), false) - ).collect(toList()); + .filter(jfo -> jfo.getPackage().equals(packageName)), + StreamSupport.stream(listed.spliterator(), false) + ).collect(toList()); } return super.list(location, packageName, kinds, recurse); } @@ -343,6 +425,7 @@ public Iterable list(Location location, String packageName, Set< private static class PackageAwareJavaFileObject extends SimpleJavaFileObject { private final String pkg; + @Getter private final String className; private final byte[] classBytes; @@ -376,10 +459,6 @@ public String getPackage() { return pkg; } - public String getClassName() { - return className; - } - @Override public InputStream openInputStream() { return new ByteArrayInputStream(classBytes); diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index 0eeba8521e6..c1c20fd3ff4 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -19,6 +19,7 @@ import com.sun.source.doctree.DocCommentTree; import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; +import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DocCommentTable; @@ -391,6 +392,7 @@ public J visitCatch(CatchTree node, Space fmt) { public J visitClass(ClassTree node, Space fmt) { Map annotationPosTable = mapAnnotations(node.getModifiers().getAnnotations(), new HashMap<>(node.getModifiers().getAnnotations().size())); + ReloadableJava21ModifierResults modifierResults = sortedModifiersAndAnnotations(node.getModifiers(), annotationPosTable); List kindAnnotations = collectAnnotations(annotationPosTable); @@ -437,7 +439,7 @@ public J visitClass(ClassTree node, Space fmt) { } JLeftPadded extendings = node.getExtendsClause() == null ? null : - padLeft(sourceBefore("extends"), convertOrNull(node.getExtendsClause())); + padLeft(sourceBefore("extends"), convert(node.getExtendsClause())); JContainer implementings = null; if (node.getImplementsClause() != null && !node.getImplementsClause().isEmpty()) { @@ -700,7 +702,7 @@ public J visitForLoop(ForLoopTree node, Space fmt) { commaDelim.apply(t) ); - JRightPadded condition = convertOrNull(node.getCondition(), semiDelim); + JRightPadded condition = convert(node.getCondition(), semiDelim); if (condition == null) { condition = padRight(new J.Empty(randomId(), sourceBefore(";"), Markers.EMPTY), EMPTY); } @@ -955,6 +957,7 @@ public J visitMethod(MethodTree node, Space fmt) { Map annotationPosTable = mapAnnotations(node.getModifiers().getAnnotations(), new HashMap<>(node.getModifiers().getAnnotations().size())); + ReloadableJava21ModifierResults modifierResults = sortedModifiersAndAnnotations(node.getModifiers(), annotationPosTable); J.TypeParameters typeParams; @@ -970,7 +973,7 @@ public J visitMethod(MethodTree node, Space fmt) { } List returnTypeAnnotations = collectAnnotations(annotationPosTable); - TypeTree returnType = convertOrNull(node.getReturnType()); + TypeTree returnType = convert(node.getReturnType()); if (returnType != null && !returnTypeAnnotations.isEmpty()) { returnType = new J.AnnotatedType(randomId(), Space.EMPTY, Markers.EMPTY, returnTypeAnnotations, returnType); @@ -1017,7 +1020,7 @@ public J visitMethod(MethodTree node, Space fmt) { JContainer.build(sourceBefore("throws"), convertAll(node.getThrows(), commaDelim, noDelim), Markers.EMPTY); - J.Block body = convertOrNull(node.getBody()); + J.Block body = convert(node.getBody()); JLeftPadded defaultValue = node.getDefaultValue() == null ? null : padLeft(sourceBefore("default"), convert(node.getDefaultValue())); @@ -1043,9 +1046,9 @@ public J visitNewArray(NewArrayTree node, Space fmt) { while (elementType instanceof JCArrayTypeTree) { elementType = ((JCArrayTypeTree) elementType).elemtype; } - typeExpr = convertOrNull(elementType); + typeExpr = convert(elementType); } else { - typeExpr = convertOrNull(jcVarType); + typeExpr = convert(jcVarType); } List nodeDimensions = node.getDimensions(); @@ -1095,7 +1098,7 @@ public J visitNewClass(NewClassTree node, Space fmt) { } // for enum definitions with anonymous class initializers, endPos of node identifier will be -1 - TypeTree clazz = endPos(node.getIdentifier()) >= 0 ? convertOrNull(node.getIdentifier()) : null; + TypeTree clazz = endPos(node.getIdentifier()) >= 0 ? convert(node.getIdentifier()) : null; JContainer args; if (positionOfNext("(", '{') > -1) { @@ -1204,7 +1207,7 @@ public J visitPrimitiveType(PrimitiveTypeTree node, Space fmt) { @Override public J visitReturn(ReturnTree node, Space fmt) { skip("return"); - Expression expression = convertOrNull(node.getExpression()); + Expression expression = convert(node.getExpression()); return new J.Return(randomId(), fmt, Markers.EMPTY, expression); } @@ -1569,8 +1572,14 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm // this is a lambda parameter with an inferred type expression typeExpr = null; } else { - typeExpr = new J.Identifier(randomId(), sourceBefore("var"), Markers.EMPTY, emptyList(), "var", typeMapping.type(vartype), null); - typeExpr = typeExpr.withMarkers(typeExpr.getMarkers().add(JavaVarKeyword.build())); + boolean lombokVal = isLombokVal(node); + typeExpr = new J.Identifier(randomId(), + sourceBefore(lombokVal ? "val" : "var"), + Markers.build(singletonList(JavaVarKeyword.build())), + emptyList(), + lombokVal ? "val" : "var", + typeMapping.type(vartype), + null); } } else if (vartype instanceof JCArrayTypeTree) { JCExpression elementType = vartype; @@ -1590,6 +1599,10 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm typeExpr = convert(vartype); } + if (typeExpr == null && node.declaredUsingVar()) { + typeExpr = new J.Identifier(randomId(), sourceBefore("var"), Markers.build(singletonList(JavaVarKeyword.build())), emptyList(), "var", typeMapping.type(vartype), null); + } + if (typeExpr != null && !typeExprAnnotations.isEmpty()) { Space prefix = typeExprAnnotations.get(0).getPrefix(); typeExpr = new J.AnnotatedType(randomId(), prefix, Markers.EMPTY, ListUtils.mapFirst(typeExprAnnotations, a -> a.withPrefix(EMPTY)), typeExpr); @@ -1623,7 +1636,7 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm new J.VariableDeclarations.NamedVariable(randomId(), namedVarPrefix, Markers.EMPTY, name, dimensionsAfterName, - n.init != null ? padLeft(sourceBefore("="), convertOrNull(n.init)) : null, + n.init != null ? padLeft(sourceBefore("="), convert(n.init)) : null, (JavaType.Variable) typeMapping.type(n) ), i == nodes.size() - 1 ? EMPTY : sourceBefore(",") @@ -1680,7 +1693,7 @@ public J visitWildcard(WildcardTree node, Space fmt) { bound = null; } - return new J.Wildcard(randomId(), fmt, Markers.EMPTY, bound, convertOrNull(wildcard.inner)); + return new J.Wildcard(randomId(), fmt, Markers.EMPTY, bound, convert(wildcard.inner)); } /** @@ -1688,10 +1701,12 @@ public J visitWildcard(WildcardTree node, Space fmt) { * Conversion utilities * -------------- */ - - private J2 convert(Tree t) { + private @Nullable J2 convert(@Nullable Tree t) { + if (t == null) { + return null; + } try { - String prefix = source.substring(cursor, max(((JCTree) t).getStartPosition(), cursor)); + String prefix = source.substring(cursor, Math.max(cursor, getActualStartPosition((JCTree) t))); cursor += prefix.length(); // Java 21 and 23 have a different return type from getCommentTree; with reflection we can support both Method getCommentTreeMethod = DocCommentTable.class.getMethod("getCommentTree", JCTree.class); @@ -1707,6 +1722,14 @@ private J2 convert(Tree t) { } } + private static int getActualStartPosition(JCTree t) { + // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation + if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { + return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); + } + return t.getStartPosition(); + } + private void reportJavaParsingException(Throwable ex) { // this SHOULD never happen, but is here simply as a diagnostic measure in the event of unexpected exceptions StringBuilder message = new StringBuilder("Failed to convert for the following cursor stack:"); @@ -1731,7 +1754,10 @@ private void reportJavaParsingException(Throwable ex) { ctx.getOnError().accept(new JavaParsingException(message.toString(), ex)); } - private JRightPadded convert(Tree t, Function suffix) { + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix) { + if (t == null) { + return null; + } J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); @@ -1776,14 +1802,6 @@ private long lineNumber(Tree tree) { return source.substring(0, ((JCTree) tree).getStartPosition()).chars().filter(c -> c == '\n').count() + 1; } - private @Nullable T convertOrNull(@Nullable Tree t) { - return t == null ? null : convert(t); - } - - private @Nullable JRightPadded convertOrNull(@Nullable Tree t, Function suffix) { - return t == null ? null : convert(t, suffix); - } - private List convertAll(List trees) { List converted = new ArrayList<>(trees.size()); for (Tree tree : trees) { @@ -1888,6 +1906,9 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { + if (isLombokGenerated(t)) { + continue; + } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); } @@ -1917,6 +1938,53 @@ private List> convertStatements(@Nullable List collectAnnotations(Map annotat boolean inMultilineComment = false; for (int i = cursor; i <= maxAnnotationPosition && i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { - annotations.add(convert(annotationPosTable.get(i))); + JCAnnotation jcAnnotation = annotationPosTable.get(i); + if (isLombokGenerated(jcAnnotation)) { + continue; + } + annotations.add(convert(jcAnnotation)); i = cursor; continue; } diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index 3a7f7850365..6a355210012 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -34,7 +34,7 @@ import static org.openrewrite.java.Assertions.java; @SuppressWarnings({"CaughtExceptionImmediatelyRethrown", "LombokGetterMayBeUsed", "LombokSetterMayBeUsed", "DefaultAnnotationParam", "NotNullFieldNotInitialized", "ProtectedMemberInFinalClass", "WriteOnlyObject", "ConcatenationWithEmptyString"}) -@EnabledOnJre({JRE.JAVA_11, JRE.JAVA_17}) +@EnabledOnJre({JRE.JAVA_11, JRE.JAVA_17, JRE.JAVA_21}) class LombokTest implements RewriteTest { @BeforeAll From 0e5b4395d7e70225539dd8b8d33001f6246c2345 Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Tue, 7 Jan 2025 15:47:39 +0100 Subject: [PATCH 114/179] HCL - comments as the final lines (#4861) * Support final line being a comment * licenseFormat --- rewrite-hcl/src/main/antlr/HCLLexer.g4 | 8 +- .../hcl/internal/grammar/HCLLexer.interp | 2 +- .../hcl/internal/grammar/HCLLexer.java | 508 +++++++++--------- .../java/org/openrewrite/hcl/tree/Space.java | 5 + .../openrewrite/hcl/tree/HclCommentTest.java | 18 +- 5 files changed, 281 insertions(+), 260 deletions(-) diff --git a/rewrite-hcl/src/main/antlr/HCLLexer.g4 b/rewrite-hcl/src/main/antlr/HCLLexer.g4 index 6266c3e22ec..7bdf3d0c17f 100644 --- a/rewrite-hcl/src/main/antlr/HCLLexer.g4 +++ b/rewrite-hcl/src/main/antlr/HCLLexer.g4 @@ -49,10 +49,10 @@ Identifier // Lexical Elements - Comments and Whitespace // https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#comments-and-whitespace -WS : [ \t\r\u000C]+ -> channel(HIDDEN); -COMMENT : '/*' .*? '*/' -> channel(HIDDEN); -LINE_COMMENT : ('//' | '#') ~[\r\n]* '\r'?'\n' -> channel(HIDDEN); -NEWLINE : '\n' -> channel(HIDDEN); +WS : [ \t\r\u000C]+ -> channel(HIDDEN); +COMMENT : '/*' .*? '*/' -> channel(HIDDEN); +LINE_COMMENT : ('//' | '#') ~[\r\n]* '\r'? ('\n' | EOF) -> channel(HIDDEN); +NEWLINE : '\n' -> channel(HIDDEN); fragment LetterOrDigit : Letter diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp index 1c2aaad6d58..9097230066a 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp @@ -169,4 +169,4 @@ HEREDOC_PREAMBLE HEREDOC atn: -[4, 0, 47, 450, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 126, 8, 0, 10, 0, 12, 0, 129, 9, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 142, 8, 1, 10, 1, 12, 1, 145, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 3, 7, 169, 8, 7, 1, 8, 1, 8, 1, 8, 5, 8, 174, 8, 8, 10, 8, 12, 8, 177, 9, 8, 1, 9, 4, 9, 180, 8, 9, 11, 9, 12, 9, 181, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 190, 8, 10, 10, 10, 12, 10, 193, 9, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 3, 11, 203, 8, 11, 1, 11, 5, 11, 206, 8, 11, 10, 11, 12, 11, 209, 9, 11, 1, 11, 3, 11, 212, 8, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 3, 13, 224, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 230, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 250, 8, 15, 1, 16, 1, 16, 1, 17, 4, 17, 255, 8, 17, 11, 17, 12, 17, 256, 1, 17, 1, 17, 5, 17, 261, 8, 17, 10, 17, 12, 17, 264, 9, 17, 1, 17, 3, 17, 267, 8, 17, 1, 17, 4, 17, 270, 8, 17, 11, 17, 12, 17, 271, 1, 17, 1, 17, 4, 17, 276, 8, 17, 11, 17, 12, 17, 277, 3, 17, 280, 8, 17, 1, 18, 1, 18, 3, 18, 284, 8, 18, 1, 18, 4, 18, 287, 8, 18, 11, 18, 12, 18, 288, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 300, 8, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 315, 8, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 4, 49, 386, 8, 49, 11, 49, 12, 49, 387, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 400, 8, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 5, 53, 415, 8, 53, 10, 53, 12, 53, 418, 9, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 4, 56, 437, 8, 56, 11, 56, 12, 56, 438, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 3, 57, 449, 8, 57, 1, 191, 0, 58, 4, 1, 6, 2, 8, 3, 10, 4, 12, 5, 14, 6, 16, 7, 18, 0, 20, 8, 22, 9, 24, 10, 26, 11, 28, 12, 30, 0, 32, 0, 34, 0, 36, 0, 38, 13, 40, 0, 42, 14, 44, 15, 46, 16, 48, 17, 50, 18, 52, 19, 54, 20, 56, 21, 58, 22, 60, 23, 62, 24, 64, 25, 66, 26, 68, 27, 70, 28, 72, 29, 74, 30, 76, 31, 78, 32, 80, 33, 82, 34, 84, 35, 86, 36, 88, 37, 90, 38, 92, 39, 94, 40, 96, 41, 98, 42, 100, 43, 102, 44, 104, 45, 106, 0, 108, 0, 110, 0, 112, 0, 114, 0, 116, 46, 118, 47, 4, 0, 1, 2, 3, 14, 4, 0, 10, 10, 13, 13, 34, 34, 36, 37, 3, 0, 9, 9, 12, 13, 32, 32, 2, 0, 10, 10, 13, 13, 1, 0, 48, 57, 4, 0, 36, 36, 65, 90, 95, 95, 97, 122, 2, 0, 0, 127, 55296, 56319, 1, 0, 55296, 56319, 1, 0, 56320, 57343, 5, 0, 34, 34, 92, 92, 110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 3, 0, 10, 10, 13, 13, 36, 37, 1, 0, 123, 123, 484, 0, 4, 1, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 10, 1, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 14, 1, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 24, 1, 0, 0, 0, 0, 26, 1, 0, 0, 0, 0, 28, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 44, 1, 0, 0, 0, 0, 46, 1, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 50, 1, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 54, 1, 0, 0, 0, 0, 56, 1, 0, 0, 0, 0, 58, 1, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 62, 1, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 66, 1, 0, 0, 0, 0, 68, 1, 0, 0, 0, 0, 70, 1, 0, 0, 0, 0, 72, 1, 0, 0, 0, 0, 74, 1, 0, 0, 0, 0, 76, 1, 0, 0, 0, 0, 78, 1, 0, 0, 0, 0, 80, 1, 0, 0, 0, 0, 82, 1, 0, 0, 0, 0, 84, 1, 0, 0, 0, 0, 86, 1, 0, 0, 0, 0, 88, 1, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 92, 1, 0, 0, 0, 0, 94, 1, 0, 0, 0, 0, 96, 1, 0, 0, 0, 0, 98, 1, 0, 0, 0, 1, 100, 1, 0, 0, 0, 1, 102, 1, 0, 0, 0, 1, 104, 1, 0, 0, 0, 1, 106, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 3, 112, 1, 0, 0, 0, 3, 114, 1, 0, 0, 0, 3, 116, 1, 0, 0, 0, 3, 118, 1, 0, 0, 0, 4, 120, 1, 0, 0, 0, 6, 136, 1, 0, 0, 0, 8, 152, 1, 0, 0, 0, 10, 155, 1, 0, 0, 0, 12, 158, 1, 0, 0, 0, 14, 161, 1, 0, 0, 0, 16, 164, 1, 0, 0, 0, 18, 168, 1, 0, 0, 0, 20, 170, 1, 0, 0, 0, 22, 179, 1, 0, 0, 0, 24, 185, 1, 0, 0, 0, 26, 202, 1, 0, 0, 0, 28, 217, 1, 0, 0, 0, 30, 223, 1, 0, 0, 0, 32, 229, 1, 0, 0, 0, 34, 249, 1, 0, 0, 0, 36, 251, 1, 0, 0, 0, 38, 279, 1, 0, 0, 0, 40, 281, 1, 0, 0, 0, 42, 299, 1, 0, 0, 0, 44, 301, 1, 0, 0, 0, 46, 305, 1, 0, 0, 0, 48, 310, 1, 0, 0, 0, 50, 318, 1, 0, 0, 0, 52, 320, 1, 0, 0, 0, 54, 323, 1, 0, 0, 0, 56, 326, 1, 0, 0, 0, 58, 328, 1, 0, 0, 0, 60, 330, 1, 0, 0, 0, 62, 332, 1, 0, 0, 0, 64, 334, 1, 0, 0, 0, 66, 336, 1, 0, 0, 0, 68, 339, 1, 0, 0, 0, 70, 342, 1, 0, 0, 0, 72, 344, 1, 0, 0, 0, 74, 346, 1, 0, 0, 0, 76, 348, 1, 0, 0, 0, 78, 350, 1, 0, 0, 0, 80, 352, 1, 0, 0, 0, 82, 354, 1, 0, 0, 0, 84, 357, 1, 0, 0, 0, 86, 359, 1, 0, 0, 0, 88, 361, 1, 0, 0, 0, 90, 364, 1, 0, 0, 0, 92, 367, 1, 0, 0, 0, 94, 369, 1, 0, 0, 0, 96, 371, 1, 0, 0, 0, 98, 375, 1, 0, 0, 0, 100, 377, 1, 0, 0, 0, 102, 385, 1, 0, 0, 0, 104, 399, 1, 0, 0, 0, 106, 401, 1, 0, 0, 0, 108, 406, 1, 0, 0, 0, 110, 411, 1, 0, 0, 0, 112, 423, 1, 0, 0, 0, 114, 427, 1, 0, 0, 0, 116, 436, 1, 0, 0, 0, 118, 448, 1, 0, 0, 0, 120, 127, 5, 123, 0, 0, 121, 126, 3, 22, 9, 0, 122, 126, 3, 28, 12, 0, 123, 126, 3, 24, 10, 0, 124, 126, 3, 26, 11, 0, 125, 121, 1, 0, 0, 0, 125, 122, 1, 0, 0, 0, 125, 123, 1, 0, 0, 0, 125, 124, 1, 0, 0, 0, 126, 129, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 128, 1, 0, 0, 0, 128, 130, 1, 0, 0, 0, 129, 127, 1, 0, 0, 0, 130, 131, 5, 102, 0, 0, 131, 132, 5, 111, 0, 0, 132, 133, 5, 114, 0, 0, 133, 134, 1, 0, 0, 0, 134, 135, 3, 22, 9, 0, 135, 5, 1, 0, 0, 0, 136, 143, 5, 91, 0, 0, 137, 142, 3, 22, 9, 0, 138, 142, 3, 28, 12, 0, 139, 142, 3, 24, 10, 0, 140, 142, 3, 26, 11, 0, 141, 137, 1, 0, 0, 0, 141, 138, 1, 0, 0, 0, 141, 139, 1, 0, 0, 0, 141, 140, 1, 0, 0, 0, 142, 145, 1, 0, 0, 0, 143, 141, 1, 0, 0, 0, 143, 144, 1, 0, 0, 0, 144, 146, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 146, 147, 5, 102, 0, 0, 147, 148, 5, 111, 0, 0, 148, 149, 5, 114, 0, 0, 149, 150, 1, 0, 0, 0, 150, 151, 3, 22, 9, 0, 151, 7, 1, 0, 0, 0, 152, 153, 5, 105, 0, 0, 153, 154, 5, 102, 0, 0, 154, 9, 1, 0, 0, 0, 155, 156, 5, 105, 0, 0, 156, 157, 5, 110, 0, 0, 157, 11, 1, 0, 0, 0, 158, 159, 5, 123, 0, 0, 159, 160, 6, 4, 0, 0, 160, 13, 1, 0, 0, 0, 161, 162, 5, 125, 0, 0, 162, 163, 6, 5, 1, 0, 163, 15, 1, 0, 0, 0, 164, 165, 5, 61, 0, 0, 165, 17, 1, 0, 0, 0, 166, 169, 8, 0, 0, 0, 167, 169, 3, 34, 15, 0, 168, 166, 1, 0, 0, 0, 168, 167, 1, 0, 0, 0, 169, 19, 1, 0, 0, 0, 170, 175, 3, 32, 14, 0, 171, 174, 3, 30, 13, 0, 172, 174, 5, 45, 0, 0, 173, 171, 1, 0, 0, 0, 173, 172, 1, 0, 0, 0, 174, 177, 1, 0, 0, 0, 175, 173, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 21, 1, 0, 0, 0, 177, 175, 1, 0, 0, 0, 178, 180, 7, 1, 0, 0, 179, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 181, 182, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 184, 6, 9, 2, 0, 184, 23, 1, 0, 0, 0, 185, 186, 5, 47, 0, 0, 186, 187, 5, 42, 0, 0, 187, 191, 1, 0, 0, 0, 188, 190, 9, 0, 0, 0, 189, 188, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 194, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 194, 195, 5, 42, 0, 0, 195, 196, 5, 47, 0, 0, 196, 197, 1, 0, 0, 0, 197, 198, 6, 10, 2, 0, 198, 25, 1, 0, 0, 0, 199, 200, 5, 47, 0, 0, 200, 203, 5, 47, 0, 0, 201, 203, 5, 35, 0, 0, 202, 199, 1, 0, 0, 0, 202, 201, 1, 0, 0, 0, 203, 207, 1, 0, 0, 0, 204, 206, 8, 2, 0, 0, 205, 204, 1, 0, 0, 0, 206, 209, 1, 0, 0, 0, 207, 205, 1, 0, 0, 0, 207, 208, 1, 0, 0, 0, 208, 211, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 210, 212, 5, 13, 0, 0, 211, 210, 1, 0, 0, 0, 211, 212, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 214, 5, 10, 0, 0, 214, 215, 1, 0, 0, 0, 215, 216, 6, 11, 2, 0, 216, 27, 1, 0, 0, 0, 217, 218, 5, 10, 0, 0, 218, 219, 1, 0, 0, 0, 219, 220, 6, 12, 2, 0, 220, 29, 1, 0, 0, 0, 221, 224, 3, 32, 14, 0, 222, 224, 7, 3, 0, 0, 223, 221, 1, 0, 0, 0, 223, 222, 1, 0, 0, 0, 224, 31, 1, 0, 0, 0, 225, 230, 7, 4, 0, 0, 226, 230, 8, 5, 0, 0, 227, 228, 7, 6, 0, 0, 228, 230, 7, 7, 0, 0, 229, 225, 1, 0, 0, 0, 229, 226, 1, 0, 0, 0, 229, 227, 1, 0, 0, 0, 230, 33, 1, 0, 0, 0, 231, 232, 5, 92, 0, 0, 232, 250, 7, 8, 0, 0, 233, 234, 5, 92, 0, 0, 234, 235, 3, 36, 16, 0, 235, 236, 3, 36, 16, 0, 236, 237, 3, 36, 16, 0, 237, 238, 3, 36, 16, 0, 238, 250, 1, 0, 0, 0, 239, 240, 5, 92, 0, 0, 240, 241, 3, 36, 16, 0, 241, 242, 3, 36, 16, 0, 242, 243, 3, 36, 16, 0, 243, 244, 3, 36, 16, 0, 244, 245, 3, 36, 16, 0, 245, 246, 3, 36, 16, 0, 246, 247, 3, 36, 16, 0, 247, 248, 3, 36, 16, 0, 248, 250, 1, 0, 0, 0, 249, 231, 1, 0, 0, 0, 249, 233, 1, 0, 0, 0, 249, 239, 1, 0, 0, 0, 250, 35, 1, 0, 0, 0, 251, 252, 7, 9, 0, 0, 252, 37, 1, 0, 0, 0, 253, 255, 7, 3, 0, 0, 254, 253, 1, 0, 0, 0, 255, 256, 1, 0, 0, 0, 256, 254, 1, 0, 0, 0, 256, 257, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 258, 262, 5, 46, 0, 0, 259, 261, 7, 3, 0, 0, 260, 259, 1, 0, 0, 0, 261, 264, 1, 0, 0, 0, 262, 260, 1, 0, 0, 0, 262, 263, 1, 0, 0, 0, 263, 266, 1, 0, 0, 0, 264, 262, 1, 0, 0, 0, 265, 267, 3, 40, 18, 0, 266, 265, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 280, 1, 0, 0, 0, 268, 270, 7, 3, 0, 0, 269, 268, 1, 0, 0, 0, 270, 271, 1, 0, 0, 0, 271, 269, 1, 0, 0, 0, 271, 272, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 280, 3, 40, 18, 0, 274, 276, 7, 3, 0, 0, 275, 274, 1, 0, 0, 0, 276, 277, 1, 0, 0, 0, 277, 275, 1, 0, 0, 0, 277, 278, 1, 0, 0, 0, 278, 280, 1, 0, 0, 0, 279, 254, 1, 0, 0, 0, 279, 269, 1, 0, 0, 0, 279, 275, 1, 0, 0, 0, 280, 39, 1, 0, 0, 0, 281, 283, 7, 10, 0, 0, 282, 284, 7, 11, 0, 0, 283, 282, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 286, 1, 0, 0, 0, 285, 287, 7, 3, 0, 0, 286, 285, 1, 0, 0, 0, 287, 288, 1, 0, 0, 0, 288, 286, 1, 0, 0, 0, 288, 289, 1, 0, 0, 0, 289, 41, 1, 0, 0, 0, 290, 291, 5, 116, 0, 0, 291, 292, 5, 114, 0, 0, 292, 293, 5, 117, 0, 0, 293, 300, 5, 101, 0, 0, 294, 295, 5, 102, 0, 0, 295, 296, 5, 97, 0, 0, 296, 297, 5, 108, 0, 0, 297, 298, 5, 115, 0, 0, 298, 300, 5, 101, 0, 0, 299, 290, 1, 0, 0, 0, 299, 294, 1, 0, 0, 0, 300, 43, 1, 0, 0, 0, 301, 302, 5, 34, 0, 0, 302, 303, 1, 0, 0, 0, 303, 304, 6, 20, 3, 0, 304, 45, 1, 0, 0, 0, 305, 306, 5, 110, 0, 0, 306, 307, 5, 117, 0, 0, 307, 308, 5, 108, 0, 0, 308, 309, 5, 108, 0, 0, 309, 47, 1, 0, 0, 0, 310, 311, 5, 60, 0, 0, 311, 312, 5, 60, 0, 0, 312, 314, 1, 0, 0, 0, 313, 315, 5, 45, 0, 0, 314, 313, 1, 0, 0, 0, 314, 315, 1, 0, 0, 0, 315, 316, 1, 0, 0, 0, 316, 317, 6, 22, 4, 0, 317, 49, 1, 0, 0, 0, 318, 319, 5, 43, 0, 0, 319, 51, 1, 0, 0, 0, 320, 321, 5, 38, 0, 0, 321, 322, 5, 38, 0, 0, 322, 53, 1, 0, 0, 0, 323, 324, 5, 61, 0, 0, 324, 325, 5, 61, 0, 0, 325, 55, 1, 0, 0, 0, 326, 327, 5, 60, 0, 0, 327, 57, 1, 0, 0, 0, 328, 329, 5, 58, 0, 0, 329, 59, 1, 0, 0, 0, 330, 331, 5, 91, 0, 0, 331, 61, 1, 0, 0, 0, 332, 333, 5, 40, 0, 0, 333, 63, 1, 0, 0, 0, 334, 335, 5, 45, 0, 0, 335, 65, 1, 0, 0, 0, 336, 337, 5, 124, 0, 0, 337, 338, 5, 124, 0, 0, 338, 67, 1, 0, 0, 0, 339, 340, 5, 33, 0, 0, 340, 341, 5, 61, 0, 0, 341, 69, 1, 0, 0, 0, 342, 343, 5, 62, 0, 0, 343, 71, 1, 0, 0, 0, 344, 345, 5, 63, 0, 0, 345, 73, 1, 0, 0, 0, 346, 347, 5, 93, 0, 0, 347, 75, 1, 0, 0, 0, 348, 349, 5, 41, 0, 0, 349, 77, 1, 0, 0, 0, 350, 351, 5, 42, 0, 0, 351, 79, 1, 0, 0, 0, 352, 353, 5, 33, 0, 0, 353, 81, 1, 0, 0, 0, 354, 355, 5, 60, 0, 0, 355, 356, 5, 61, 0, 0, 356, 83, 1, 0, 0, 0, 357, 358, 5, 46, 0, 0, 358, 85, 1, 0, 0, 0, 359, 360, 5, 47, 0, 0, 360, 87, 1, 0, 0, 0, 361, 362, 5, 62, 0, 0, 362, 363, 5, 61, 0, 0, 363, 89, 1, 0, 0, 0, 364, 365, 5, 61, 0, 0, 365, 366, 5, 62, 0, 0, 366, 91, 1, 0, 0, 0, 367, 368, 5, 44, 0, 0, 368, 93, 1, 0, 0, 0, 369, 370, 5, 37, 0, 0, 370, 95, 1, 0, 0, 0, 371, 372, 5, 46, 0, 0, 372, 373, 5, 46, 0, 0, 373, 374, 5, 46, 0, 0, 374, 97, 1, 0, 0, 0, 375, 376, 5, 126, 0, 0, 376, 99, 1, 0, 0, 0, 377, 378, 5, 36, 0, 0, 378, 379, 5, 123, 0, 0, 379, 380, 1, 0, 0, 0, 380, 381, 6, 48, 5, 0, 381, 382, 1, 0, 0, 0, 382, 383, 6, 48, 6, 0, 383, 101, 1, 0, 0, 0, 384, 386, 3, 104, 50, 0, 385, 384, 1, 0, 0, 0, 386, 387, 1, 0, 0, 0, 387, 385, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 103, 1, 0, 0, 0, 389, 400, 8, 0, 0, 0, 390, 391, 5, 36, 0, 0, 391, 400, 5, 36, 0, 0, 392, 393, 5, 36, 0, 0, 393, 400, 4, 50, 0, 0, 394, 395, 5, 37, 0, 0, 395, 400, 5, 37, 0, 0, 396, 397, 5, 37, 0, 0, 397, 400, 4, 50, 1, 0, 398, 400, 3, 34, 15, 0, 399, 389, 1, 0, 0, 0, 399, 390, 1, 0, 0, 0, 399, 392, 1, 0, 0, 0, 399, 394, 1, 0, 0, 0, 399, 396, 1, 0, 0, 0, 399, 398, 1, 0, 0, 0, 400, 105, 1, 0, 0, 0, 401, 402, 5, 34, 0, 0, 402, 403, 1, 0, 0, 0, 403, 404, 6, 51, 7, 0, 404, 405, 6, 51, 8, 0, 405, 107, 1, 0, 0, 0, 406, 407, 5, 10, 0, 0, 407, 408, 1, 0, 0, 0, 408, 409, 6, 52, 9, 0, 409, 410, 6, 52, 10, 0, 410, 109, 1, 0, 0, 0, 411, 416, 3, 32, 14, 0, 412, 415, 3, 30, 13, 0, 413, 415, 5, 45, 0, 0, 414, 412, 1, 0, 0, 0, 414, 413, 1, 0, 0, 0, 415, 418, 1, 0, 0, 0, 416, 414, 1, 0, 0, 0, 416, 417, 1, 0, 0, 0, 417, 419, 1, 0, 0, 0, 418, 416, 1, 0, 0, 0, 419, 420, 6, 53, 11, 0, 420, 421, 1, 0, 0, 0, 421, 422, 6, 53, 12, 0, 422, 111, 1, 0, 0, 0, 423, 424, 5, 10, 0, 0, 424, 425, 1, 0, 0, 0, 425, 426, 6, 54, 9, 0, 426, 113, 1, 0, 0, 0, 427, 428, 5, 36, 0, 0, 428, 429, 5, 123, 0, 0, 429, 430, 1, 0, 0, 0, 430, 431, 6, 55, 13, 0, 431, 432, 1, 0, 0, 0, 432, 433, 6, 55, 14, 0, 433, 434, 6, 55, 6, 0, 434, 115, 1, 0, 0, 0, 435, 437, 3, 118, 57, 0, 436, 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 436, 1, 0, 0, 0, 438, 439, 1, 0, 0, 0, 439, 440, 1, 0, 0, 0, 440, 441, 6, 56, 15, 0, 441, 117, 1, 0, 0, 0, 442, 449, 8, 12, 0, 0, 443, 444, 5, 36, 0, 0, 444, 449, 8, 13, 0, 0, 445, 446, 5, 37, 0, 0, 446, 449, 8, 13, 0, 0, 447, 449, 3, 34, 15, 0, 448, 442, 1, 0, 0, 0, 448, 443, 1, 0, 0, 0, 448, 445, 1, 0, 0, 0, 448, 447, 1, 0, 0, 0, 449, 119, 1, 0, 0, 0, 35, 0, 1, 2, 3, 125, 127, 141, 143, 168, 173, 175, 181, 191, 202, 207, 211, 223, 229, 249, 256, 262, 266, 271, 277, 279, 283, 288, 299, 314, 387, 399, 414, 416, 438, 448, 16, 1, 4, 0, 1, 5, 1, 0, 1, 0, 5, 1, 0, 5, 2, 0, 1, 48, 2, 5, 0, 0, 7, 15, 0, 4, 0, 0, 7, 12, 0, 2, 3, 0, 1, 53, 3, 7, 8, 0, 1, 55, 4, 7, 43, 0, 1, 56, 5] \ No newline at end of file +[4, 0, 47, 451, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 126, 8, 0, 10, 0, 12, 0, 129, 9, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 142, 8, 1, 10, 1, 12, 1, 145, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 3, 7, 169, 8, 7, 1, 8, 1, 8, 1, 8, 5, 8, 174, 8, 8, 10, 8, 12, 8, 177, 9, 8, 1, 9, 4, 9, 180, 8, 9, 11, 9, 12, 9, 181, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 190, 8, 10, 10, 10, 12, 10, 193, 9, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 3, 11, 203, 8, 11, 1, 11, 5, 11, 206, 8, 11, 10, 11, 12, 11, 209, 9, 11, 1, 11, 3, 11, 212, 8, 11, 1, 11, 3, 11, 215, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 3, 13, 225, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 231, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 251, 8, 15, 1, 16, 1, 16, 1, 17, 4, 17, 256, 8, 17, 11, 17, 12, 17, 257, 1, 17, 1, 17, 5, 17, 262, 8, 17, 10, 17, 12, 17, 265, 9, 17, 1, 17, 3, 17, 268, 8, 17, 1, 17, 4, 17, 271, 8, 17, 11, 17, 12, 17, 272, 1, 17, 1, 17, 4, 17, 277, 8, 17, 11, 17, 12, 17, 278, 3, 17, 281, 8, 17, 1, 18, 1, 18, 3, 18, 285, 8, 18, 1, 18, 4, 18, 288, 8, 18, 11, 18, 12, 18, 289, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 301, 8, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 316, 8, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 4, 49, 387, 8, 49, 11, 49, 12, 49, 388, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 401, 8, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 5, 53, 416, 8, 53, 10, 53, 12, 53, 419, 9, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 4, 56, 438, 8, 56, 11, 56, 12, 56, 439, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 3, 57, 450, 8, 57, 1, 191, 0, 58, 4, 1, 6, 2, 8, 3, 10, 4, 12, 5, 14, 6, 16, 7, 18, 0, 20, 8, 22, 9, 24, 10, 26, 11, 28, 12, 30, 0, 32, 0, 34, 0, 36, 0, 38, 13, 40, 0, 42, 14, 44, 15, 46, 16, 48, 17, 50, 18, 52, 19, 54, 20, 56, 21, 58, 22, 60, 23, 62, 24, 64, 25, 66, 26, 68, 27, 70, 28, 72, 29, 74, 30, 76, 31, 78, 32, 80, 33, 82, 34, 84, 35, 86, 36, 88, 37, 90, 38, 92, 39, 94, 40, 96, 41, 98, 42, 100, 43, 102, 44, 104, 45, 106, 0, 108, 0, 110, 0, 112, 0, 114, 0, 116, 46, 118, 47, 4, 0, 1, 2, 3, 15, 4, 0, 10, 10, 13, 13, 34, 34, 36, 37, 3, 0, 9, 9, 12, 13, 32, 32, 2, 0, 10, 10, 13, 13, 1, 1, 10, 10, 1, 0, 48, 57, 4, 0, 36, 36, 65, 90, 95, 95, 97, 122, 2, 0, 0, 127, 55296, 56319, 1, 0, 55296, 56319, 1, 0, 56320, 57343, 5, 0, 34, 34, 92, 92, 110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 3, 0, 10, 10, 13, 13, 36, 37, 1, 0, 123, 123, 485, 0, 4, 1, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 10, 1, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 14, 1, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 24, 1, 0, 0, 0, 0, 26, 1, 0, 0, 0, 0, 28, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 44, 1, 0, 0, 0, 0, 46, 1, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 50, 1, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 54, 1, 0, 0, 0, 0, 56, 1, 0, 0, 0, 0, 58, 1, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 62, 1, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 66, 1, 0, 0, 0, 0, 68, 1, 0, 0, 0, 0, 70, 1, 0, 0, 0, 0, 72, 1, 0, 0, 0, 0, 74, 1, 0, 0, 0, 0, 76, 1, 0, 0, 0, 0, 78, 1, 0, 0, 0, 0, 80, 1, 0, 0, 0, 0, 82, 1, 0, 0, 0, 0, 84, 1, 0, 0, 0, 0, 86, 1, 0, 0, 0, 0, 88, 1, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 92, 1, 0, 0, 0, 0, 94, 1, 0, 0, 0, 0, 96, 1, 0, 0, 0, 0, 98, 1, 0, 0, 0, 1, 100, 1, 0, 0, 0, 1, 102, 1, 0, 0, 0, 1, 104, 1, 0, 0, 0, 1, 106, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 3, 112, 1, 0, 0, 0, 3, 114, 1, 0, 0, 0, 3, 116, 1, 0, 0, 0, 3, 118, 1, 0, 0, 0, 4, 120, 1, 0, 0, 0, 6, 136, 1, 0, 0, 0, 8, 152, 1, 0, 0, 0, 10, 155, 1, 0, 0, 0, 12, 158, 1, 0, 0, 0, 14, 161, 1, 0, 0, 0, 16, 164, 1, 0, 0, 0, 18, 168, 1, 0, 0, 0, 20, 170, 1, 0, 0, 0, 22, 179, 1, 0, 0, 0, 24, 185, 1, 0, 0, 0, 26, 202, 1, 0, 0, 0, 28, 218, 1, 0, 0, 0, 30, 224, 1, 0, 0, 0, 32, 230, 1, 0, 0, 0, 34, 250, 1, 0, 0, 0, 36, 252, 1, 0, 0, 0, 38, 280, 1, 0, 0, 0, 40, 282, 1, 0, 0, 0, 42, 300, 1, 0, 0, 0, 44, 302, 1, 0, 0, 0, 46, 306, 1, 0, 0, 0, 48, 311, 1, 0, 0, 0, 50, 319, 1, 0, 0, 0, 52, 321, 1, 0, 0, 0, 54, 324, 1, 0, 0, 0, 56, 327, 1, 0, 0, 0, 58, 329, 1, 0, 0, 0, 60, 331, 1, 0, 0, 0, 62, 333, 1, 0, 0, 0, 64, 335, 1, 0, 0, 0, 66, 337, 1, 0, 0, 0, 68, 340, 1, 0, 0, 0, 70, 343, 1, 0, 0, 0, 72, 345, 1, 0, 0, 0, 74, 347, 1, 0, 0, 0, 76, 349, 1, 0, 0, 0, 78, 351, 1, 0, 0, 0, 80, 353, 1, 0, 0, 0, 82, 355, 1, 0, 0, 0, 84, 358, 1, 0, 0, 0, 86, 360, 1, 0, 0, 0, 88, 362, 1, 0, 0, 0, 90, 365, 1, 0, 0, 0, 92, 368, 1, 0, 0, 0, 94, 370, 1, 0, 0, 0, 96, 372, 1, 0, 0, 0, 98, 376, 1, 0, 0, 0, 100, 378, 1, 0, 0, 0, 102, 386, 1, 0, 0, 0, 104, 400, 1, 0, 0, 0, 106, 402, 1, 0, 0, 0, 108, 407, 1, 0, 0, 0, 110, 412, 1, 0, 0, 0, 112, 424, 1, 0, 0, 0, 114, 428, 1, 0, 0, 0, 116, 437, 1, 0, 0, 0, 118, 449, 1, 0, 0, 0, 120, 127, 5, 123, 0, 0, 121, 126, 3, 22, 9, 0, 122, 126, 3, 28, 12, 0, 123, 126, 3, 24, 10, 0, 124, 126, 3, 26, 11, 0, 125, 121, 1, 0, 0, 0, 125, 122, 1, 0, 0, 0, 125, 123, 1, 0, 0, 0, 125, 124, 1, 0, 0, 0, 126, 129, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 128, 1, 0, 0, 0, 128, 130, 1, 0, 0, 0, 129, 127, 1, 0, 0, 0, 130, 131, 5, 102, 0, 0, 131, 132, 5, 111, 0, 0, 132, 133, 5, 114, 0, 0, 133, 134, 1, 0, 0, 0, 134, 135, 3, 22, 9, 0, 135, 5, 1, 0, 0, 0, 136, 143, 5, 91, 0, 0, 137, 142, 3, 22, 9, 0, 138, 142, 3, 28, 12, 0, 139, 142, 3, 24, 10, 0, 140, 142, 3, 26, 11, 0, 141, 137, 1, 0, 0, 0, 141, 138, 1, 0, 0, 0, 141, 139, 1, 0, 0, 0, 141, 140, 1, 0, 0, 0, 142, 145, 1, 0, 0, 0, 143, 141, 1, 0, 0, 0, 143, 144, 1, 0, 0, 0, 144, 146, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 146, 147, 5, 102, 0, 0, 147, 148, 5, 111, 0, 0, 148, 149, 5, 114, 0, 0, 149, 150, 1, 0, 0, 0, 150, 151, 3, 22, 9, 0, 151, 7, 1, 0, 0, 0, 152, 153, 5, 105, 0, 0, 153, 154, 5, 102, 0, 0, 154, 9, 1, 0, 0, 0, 155, 156, 5, 105, 0, 0, 156, 157, 5, 110, 0, 0, 157, 11, 1, 0, 0, 0, 158, 159, 5, 123, 0, 0, 159, 160, 6, 4, 0, 0, 160, 13, 1, 0, 0, 0, 161, 162, 5, 125, 0, 0, 162, 163, 6, 5, 1, 0, 163, 15, 1, 0, 0, 0, 164, 165, 5, 61, 0, 0, 165, 17, 1, 0, 0, 0, 166, 169, 8, 0, 0, 0, 167, 169, 3, 34, 15, 0, 168, 166, 1, 0, 0, 0, 168, 167, 1, 0, 0, 0, 169, 19, 1, 0, 0, 0, 170, 175, 3, 32, 14, 0, 171, 174, 3, 30, 13, 0, 172, 174, 5, 45, 0, 0, 173, 171, 1, 0, 0, 0, 173, 172, 1, 0, 0, 0, 174, 177, 1, 0, 0, 0, 175, 173, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 21, 1, 0, 0, 0, 177, 175, 1, 0, 0, 0, 178, 180, 7, 1, 0, 0, 179, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 181, 182, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 184, 6, 9, 2, 0, 184, 23, 1, 0, 0, 0, 185, 186, 5, 47, 0, 0, 186, 187, 5, 42, 0, 0, 187, 191, 1, 0, 0, 0, 188, 190, 9, 0, 0, 0, 189, 188, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 194, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 194, 195, 5, 42, 0, 0, 195, 196, 5, 47, 0, 0, 196, 197, 1, 0, 0, 0, 197, 198, 6, 10, 2, 0, 198, 25, 1, 0, 0, 0, 199, 200, 5, 47, 0, 0, 200, 203, 5, 47, 0, 0, 201, 203, 5, 35, 0, 0, 202, 199, 1, 0, 0, 0, 202, 201, 1, 0, 0, 0, 203, 207, 1, 0, 0, 0, 204, 206, 8, 2, 0, 0, 205, 204, 1, 0, 0, 0, 206, 209, 1, 0, 0, 0, 207, 205, 1, 0, 0, 0, 207, 208, 1, 0, 0, 0, 208, 211, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 210, 212, 5, 13, 0, 0, 211, 210, 1, 0, 0, 0, 211, 212, 1, 0, 0, 0, 212, 214, 1, 0, 0, 0, 213, 215, 7, 3, 0, 0, 214, 213, 1, 0, 0, 0, 215, 216, 1, 0, 0, 0, 216, 217, 6, 11, 2, 0, 217, 27, 1, 0, 0, 0, 218, 219, 5, 10, 0, 0, 219, 220, 1, 0, 0, 0, 220, 221, 6, 12, 2, 0, 221, 29, 1, 0, 0, 0, 222, 225, 3, 32, 14, 0, 223, 225, 7, 4, 0, 0, 224, 222, 1, 0, 0, 0, 224, 223, 1, 0, 0, 0, 225, 31, 1, 0, 0, 0, 226, 231, 7, 5, 0, 0, 227, 231, 8, 6, 0, 0, 228, 229, 7, 7, 0, 0, 229, 231, 7, 8, 0, 0, 230, 226, 1, 0, 0, 0, 230, 227, 1, 0, 0, 0, 230, 228, 1, 0, 0, 0, 231, 33, 1, 0, 0, 0, 232, 233, 5, 92, 0, 0, 233, 251, 7, 9, 0, 0, 234, 235, 5, 92, 0, 0, 235, 236, 3, 36, 16, 0, 236, 237, 3, 36, 16, 0, 237, 238, 3, 36, 16, 0, 238, 239, 3, 36, 16, 0, 239, 251, 1, 0, 0, 0, 240, 241, 5, 92, 0, 0, 241, 242, 3, 36, 16, 0, 242, 243, 3, 36, 16, 0, 243, 244, 3, 36, 16, 0, 244, 245, 3, 36, 16, 0, 245, 246, 3, 36, 16, 0, 246, 247, 3, 36, 16, 0, 247, 248, 3, 36, 16, 0, 248, 249, 3, 36, 16, 0, 249, 251, 1, 0, 0, 0, 250, 232, 1, 0, 0, 0, 250, 234, 1, 0, 0, 0, 250, 240, 1, 0, 0, 0, 251, 35, 1, 0, 0, 0, 252, 253, 7, 10, 0, 0, 253, 37, 1, 0, 0, 0, 254, 256, 7, 4, 0, 0, 255, 254, 1, 0, 0, 0, 256, 257, 1, 0, 0, 0, 257, 255, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 263, 5, 46, 0, 0, 260, 262, 7, 4, 0, 0, 261, 260, 1, 0, 0, 0, 262, 265, 1, 0, 0, 0, 263, 261, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 267, 1, 0, 0, 0, 265, 263, 1, 0, 0, 0, 266, 268, 3, 40, 18, 0, 267, 266, 1, 0, 0, 0, 267, 268, 1, 0, 0, 0, 268, 281, 1, 0, 0, 0, 269, 271, 7, 4, 0, 0, 270, 269, 1, 0, 0, 0, 271, 272, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 274, 1, 0, 0, 0, 274, 281, 3, 40, 18, 0, 275, 277, 7, 4, 0, 0, 276, 275, 1, 0, 0, 0, 277, 278, 1, 0, 0, 0, 278, 276, 1, 0, 0, 0, 278, 279, 1, 0, 0, 0, 279, 281, 1, 0, 0, 0, 280, 255, 1, 0, 0, 0, 280, 270, 1, 0, 0, 0, 280, 276, 1, 0, 0, 0, 281, 39, 1, 0, 0, 0, 282, 284, 7, 11, 0, 0, 283, 285, 7, 12, 0, 0, 284, 283, 1, 0, 0, 0, 284, 285, 1, 0, 0, 0, 285, 287, 1, 0, 0, 0, 286, 288, 7, 4, 0, 0, 287, 286, 1, 0, 0, 0, 288, 289, 1, 0, 0, 0, 289, 287, 1, 0, 0, 0, 289, 290, 1, 0, 0, 0, 290, 41, 1, 0, 0, 0, 291, 292, 5, 116, 0, 0, 292, 293, 5, 114, 0, 0, 293, 294, 5, 117, 0, 0, 294, 301, 5, 101, 0, 0, 295, 296, 5, 102, 0, 0, 296, 297, 5, 97, 0, 0, 297, 298, 5, 108, 0, 0, 298, 299, 5, 115, 0, 0, 299, 301, 5, 101, 0, 0, 300, 291, 1, 0, 0, 0, 300, 295, 1, 0, 0, 0, 301, 43, 1, 0, 0, 0, 302, 303, 5, 34, 0, 0, 303, 304, 1, 0, 0, 0, 304, 305, 6, 20, 3, 0, 305, 45, 1, 0, 0, 0, 306, 307, 5, 110, 0, 0, 307, 308, 5, 117, 0, 0, 308, 309, 5, 108, 0, 0, 309, 310, 5, 108, 0, 0, 310, 47, 1, 0, 0, 0, 311, 312, 5, 60, 0, 0, 312, 313, 5, 60, 0, 0, 313, 315, 1, 0, 0, 0, 314, 316, 5, 45, 0, 0, 315, 314, 1, 0, 0, 0, 315, 316, 1, 0, 0, 0, 316, 317, 1, 0, 0, 0, 317, 318, 6, 22, 4, 0, 318, 49, 1, 0, 0, 0, 319, 320, 5, 43, 0, 0, 320, 51, 1, 0, 0, 0, 321, 322, 5, 38, 0, 0, 322, 323, 5, 38, 0, 0, 323, 53, 1, 0, 0, 0, 324, 325, 5, 61, 0, 0, 325, 326, 5, 61, 0, 0, 326, 55, 1, 0, 0, 0, 327, 328, 5, 60, 0, 0, 328, 57, 1, 0, 0, 0, 329, 330, 5, 58, 0, 0, 330, 59, 1, 0, 0, 0, 331, 332, 5, 91, 0, 0, 332, 61, 1, 0, 0, 0, 333, 334, 5, 40, 0, 0, 334, 63, 1, 0, 0, 0, 335, 336, 5, 45, 0, 0, 336, 65, 1, 0, 0, 0, 337, 338, 5, 124, 0, 0, 338, 339, 5, 124, 0, 0, 339, 67, 1, 0, 0, 0, 340, 341, 5, 33, 0, 0, 341, 342, 5, 61, 0, 0, 342, 69, 1, 0, 0, 0, 343, 344, 5, 62, 0, 0, 344, 71, 1, 0, 0, 0, 345, 346, 5, 63, 0, 0, 346, 73, 1, 0, 0, 0, 347, 348, 5, 93, 0, 0, 348, 75, 1, 0, 0, 0, 349, 350, 5, 41, 0, 0, 350, 77, 1, 0, 0, 0, 351, 352, 5, 42, 0, 0, 352, 79, 1, 0, 0, 0, 353, 354, 5, 33, 0, 0, 354, 81, 1, 0, 0, 0, 355, 356, 5, 60, 0, 0, 356, 357, 5, 61, 0, 0, 357, 83, 1, 0, 0, 0, 358, 359, 5, 46, 0, 0, 359, 85, 1, 0, 0, 0, 360, 361, 5, 47, 0, 0, 361, 87, 1, 0, 0, 0, 362, 363, 5, 62, 0, 0, 363, 364, 5, 61, 0, 0, 364, 89, 1, 0, 0, 0, 365, 366, 5, 61, 0, 0, 366, 367, 5, 62, 0, 0, 367, 91, 1, 0, 0, 0, 368, 369, 5, 44, 0, 0, 369, 93, 1, 0, 0, 0, 370, 371, 5, 37, 0, 0, 371, 95, 1, 0, 0, 0, 372, 373, 5, 46, 0, 0, 373, 374, 5, 46, 0, 0, 374, 375, 5, 46, 0, 0, 375, 97, 1, 0, 0, 0, 376, 377, 5, 126, 0, 0, 377, 99, 1, 0, 0, 0, 378, 379, 5, 36, 0, 0, 379, 380, 5, 123, 0, 0, 380, 381, 1, 0, 0, 0, 381, 382, 6, 48, 5, 0, 382, 383, 1, 0, 0, 0, 383, 384, 6, 48, 6, 0, 384, 101, 1, 0, 0, 0, 385, 387, 3, 104, 50, 0, 386, 385, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 386, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 103, 1, 0, 0, 0, 390, 401, 8, 0, 0, 0, 391, 392, 5, 36, 0, 0, 392, 401, 5, 36, 0, 0, 393, 394, 5, 36, 0, 0, 394, 401, 4, 50, 0, 0, 395, 396, 5, 37, 0, 0, 396, 401, 5, 37, 0, 0, 397, 398, 5, 37, 0, 0, 398, 401, 4, 50, 1, 0, 399, 401, 3, 34, 15, 0, 400, 390, 1, 0, 0, 0, 400, 391, 1, 0, 0, 0, 400, 393, 1, 0, 0, 0, 400, 395, 1, 0, 0, 0, 400, 397, 1, 0, 0, 0, 400, 399, 1, 0, 0, 0, 401, 105, 1, 0, 0, 0, 402, 403, 5, 34, 0, 0, 403, 404, 1, 0, 0, 0, 404, 405, 6, 51, 7, 0, 405, 406, 6, 51, 8, 0, 406, 107, 1, 0, 0, 0, 407, 408, 5, 10, 0, 0, 408, 409, 1, 0, 0, 0, 409, 410, 6, 52, 9, 0, 410, 411, 6, 52, 10, 0, 411, 109, 1, 0, 0, 0, 412, 417, 3, 32, 14, 0, 413, 416, 3, 30, 13, 0, 414, 416, 5, 45, 0, 0, 415, 413, 1, 0, 0, 0, 415, 414, 1, 0, 0, 0, 416, 419, 1, 0, 0, 0, 417, 415, 1, 0, 0, 0, 417, 418, 1, 0, 0, 0, 418, 420, 1, 0, 0, 0, 419, 417, 1, 0, 0, 0, 420, 421, 6, 53, 11, 0, 421, 422, 1, 0, 0, 0, 422, 423, 6, 53, 12, 0, 423, 111, 1, 0, 0, 0, 424, 425, 5, 10, 0, 0, 425, 426, 1, 0, 0, 0, 426, 427, 6, 54, 9, 0, 427, 113, 1, 0, 0, 0, 428, 429, 5, 36, 0, 0, 429, 430, 5, 123, 0, 0, 430, 431, 1, 0, 0, 0, 431, 432, 6, 55, 13, 0, 432, 433, 1, 0, 0, 0, 433, 434, 6, 55, 14, 0, 434, 435, 6, 55, 6, 0, 435, 115, 1, 0, 0, 0, 436, 438, 3, 118, 57, 0, 437, 436, 1, 0, 0, 0, 438, 439, 1, 0, 0, 0, 439, 437, 1, 0, 0, 0, 439, 440, 1, 0, 0, 0, 440, 441, 1, 0, 0, 0, 441, 442, 6, 56, 15, 0, 442, 117, 1, 0, 0, 0, 443, 450, 8, 13, 0, 0, 444, 445, 5, 36, 0, 0, 445, 450, 8, 14, 0, 0, 446, 447, 5, 37, 0, 0, 447, 450, 8, 14, 0, 0, 448, 450, 3, 34, 15, 0, 449, 443, 1, 0, 0, 0, 449, 444, 1, 0, 0, 0, 449, 446, 1, 0, 0, 0, 449, 448, 1, 0, 0, 0, 450, 119, 1, 0, 0, 0, 36, 0, 1, 2, 3, 125, 127, 141, 143, 168, 173, 175, 181, 191, 202, 207, 211, 214, 224, 230, 250, 257, 263, 267, 272, 278, 280, 284, 289, 300, 315, 388, 400, 415, 417, 439, 449, 16, 1, 4, 0, 1, 5, 1, 0, 1, 0, 5, 1, 0, 5, 2, 0, 1, 48, 2, 5, 0, 0, 7, 15, 0, 4, 0, 0, 7, 12, 0, 2, 3, 0, 1, 53, 3, 7, 8, 0, 1, 55, 4, 7, 43, 0, 1, 56, 5] \ No newline at end of file diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java index e952ee91f0a..d35cc37fe7c 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java @@ -257,7 +257,7 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre } public static final String _serializedATN = - "\u0004\u0000/\u01c2\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ + "\u0004\u0000/\u01c3\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ "\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ @@ -287,24 +287,24 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre "\b\n\n\n\f\n\u00c1\t\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\u000b"+ "\u0001\u000b\u0001\u000b\u0003\u000b\u00cb\b\u000b\u0001\u000b\u0005\u000b"+ "\u00ce\b\u000b\n\u000b\f\u000b\u00d1\t\u000b\u0001\u000b\u0003\u000b\u00d4"+ - "\b\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001"+ - "\f\u0001\f\u0001\f\u0001\r\u0001\r\u0003\r\u00e0\b\r\u0001\u000e\u0001"+ - "\u000e\u0001\u000e\u0001\u000e\u0003\u000e\u00e6\b\u000e\u0001\u000f\u0001"+ + "\b\u000b\u0001\u000b\u0003\u000b\u00d7\b\u000b\u0001\u000b\u0001\u000b"+ + "\u0001\f\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0003\r\u00e1\b\r\u0001"+ + "\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0003\u000e\u00e7\b\u000e\u0001"+ "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+ "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+ - "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0003\u000f\u00fa"+ - "\b\u000f\u0001\u0010\u0001\u0010\u0001\u0011\u0004\u0011\u00ff\b\u0011"+ - "\u000b\u0011\f\u0011\u0100\u0001\u0011\u0001\u0011\u0005\u0011\u0105\b"+ - "\u0011\n\u0011\f\u0011\u0108\t\u0011\u0001\u0011\u0003\u0011\u010b\b\u0011"+ - "\u0001\u0011\u0004\u0011\u010e\b\u0011\u000b\u0011\f\u0011\u010f\u0001"+ - "\u0011\u0001\u0011\u0004\u0011\u0114\b\u0011\u000b\u0011\f\u0011\u0115"+ - "\u0003\u0011\u0118\b\u0011\u0001\u0012\u0001\u0012\u0003\u0012\u011c\b"+ - "\u0012\u0001\u0012\u0004\u0012\u011f\b\u0012\u000b\u0012\f\u0012\u0120"+ + "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0003"+ + "\u000f\u00fb\b\u000f\u0001\u0010\u0001\u0010\u0001\u0011\u0004\u0011\u0100"+ + "\b\u0011\u000b\u0011\f\u0011\u0101\u0001\u0011\u0001\u0011\u0005\u0011"+ + "\u0106\b\u0011\n\u0011\f\u0011\u0109\t\u0011\u0001\u0011\u0003\u0011\u010c"+ + "\b\u0011\u0001\u0011\u0004\u0011\u010f\b\u0011\u000b\u0011\f\u0011\u0110"+ + "\u0001\u0011\u0001\u0011\u0004\u0011\u0115\b\u0011\u000b\u0011\f\u0011"+ + "\u0116\u0003\u0011\u0119\b\u0011\u0001\u0012\u0001\u0012\u0003\u0012\u011d"+ + "\b\u0012\u0001\u0012\u0004\u0012\u0120\b\u0012\u000b\u0012\f\u0012\u0121"+ "\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013"+ - "\u0001\u0013\u0001\u0013\u0001\u0013\u0003\u0013\u012c\b\u0013\u0001\u0014"+ + "\u0001\u0013\u0001\u0013\u0001\u0013\u0003\u0013\u012d\b\u0013\u0001\u0014"+ "\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0015"+ "\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016"+ - "\u0003\u0016\u013b\b\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017"+ + "\u0003\u0016\u013c\b\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017"+ "\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001\u0019"+ "\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c"+ "\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001f\u0001\u001f"+ @@ -312,250 +312,252 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre "#\u0001#\u0001$\u0001$\u0001%\u0001%\u0001&\u0001&\u0001\'\u0001\'\u0001"+ "\'\u0001(\u0001(\u0001)\u0001)\u0001*\u0001*\u0001*\u0001+\u0001+\u0001"+ "+\u0001,\u0001,\u0001-\u0001-\u0001.\u0001.\u0001.\u0001.\u0001/\u0001"+ - "/\u00010\u00010\u00010\u00010\u00010\u00010\u00010\u00011\u00041\u0182"+ - "\b1\u000b1\f1\u0183\u00012\u00012\u00012\u00012\u00012\u00012\u00012\u0001"+ - "2\u00012\u00012\u00032\u0190\b2\u00013\u00013\u00013\u00013\u00013\u0001"+ - "4\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u00055\u019f\b5\n5"+ - "\f5\u01a2\t5\u00015\u00015\u00015\u00015\u00016\u00016\u00016\u00016\u0001"+ - "7\u00017\u00017\u00017\u00017\u00017\u00017\u00017\u00018\u00048\u01b5"+ - "\b8\u000b8\f8\u01b6\u00018\u00018\u00019\u00019\u00019\u00019\u00019\u0001"+ - "9\u00039\u01c1\b9\u0001\u00bf\u0000:\u0004\u0001\u0006\u0002\b\u0003\n"+ + "/\u00010\u00010\u00010\u00010\u00010\u00010\u00010\u00011\u00041\u0183"+ + "\b1\u000b1\f1\u0184\u00012\u00012\u00012\u00012\u00012\u00012\u00012\u0001"+ + "2\u00012\u00012\u00032\u0191\b2\u00013\u00013\u00013\u00013\u00013\u0001"+ + "4\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u00055\u01a0\b5\n5"+ + "\f5\u01a3\t5\u00015\u00015\u00015\u00015\u00016\u00016\u00016\u00016\u0001"+ + "7\u00017\u00017\u00017\u00017\u00017\u00017\u00017\u00018\u00048\u01b6"+ + "\b8\u000b8\f8\u01b7\u00018\u00018\u00019\u00019\u00019\u00019\u00019\u0001"+ + "9\u00039\u01c2\b9\u0001\u00bf\u0000:\u0004\u0001\u0006\u0002\b\u0003\n"+ "\u0004\f\u0005\u000e\u0006\u0010\u0007\u0012\u0000\u0014\b\u0016\t\u0018"+ "\n\u001a\u000b\u001c\f\u001e\u0000 \u0000\"\u0000$\u0000&\r(\u0000*\u000e"+ ",\u000f.\u00100\u00112\u00124\u00136\u00148\u0015:\u0016<\u0017>\u0018"+ "@\u0019B\u001aD\u001bF\u001cH\u001dJ\u001eL\u001fN P!R\"T#V$X%Z&\\\'^"+ "(`)b*d+f,h-j\u0000l\u0000n\u0000p\u0000r\u0000t.v/\u0004\u0000\u0001\u0002"+ - "\u0003\u000e\u0004\u0000\n\n\r\r\"\"$%\u0003\u0000\t\t\f\r \u0002\u0000"+ - "\n\n\r\r\u0001\u000009\u0004\u0000$$AZ__az\u0002\u0000\u0000\u007f\u8000"+ - "\ud800\u8000\udbff\u0001\u0000\u8000\ud800\u8000\udbff\u0001\u0000\u8000"+ - "\udc00\u8000\udfff\u0005\u0000\"\"\\\\nnrrtt\u0003\u000009AFaf\u0002\u0000"+ - "EEee\u0002\u0000++--\u0003\u0000\n\n\r\r$%\u0001\u0000{{\u01e4\u0000\u0004"+ - "\u0001\u0000\u0000\u0000\u0000\u0006\u0001\u0000\u0000\u0000\u0000\b\u0001"+ - "\u0000\u0000\u0000\u0000\n\u0001\u0000\u0000\u0000\u0000\f\u0001\u0000"+ - "\u0000\u0000\u0000\u000e\u0001\u0000\u0000\u0000\u0000\u0010\u0001\u0000"+ - "\u0000\u0000\u0000\u0014\u0001\u0000\u0000\u0000\u0000\u0016\u0001\u0000"+ - "\u0000\u0000\u0000\u0018\u0001\u0000\u0000\u0000\u0000\u001a\u0001\u0000"+ - "\u0000\u0000\u0000\u001c\u0001\u0000\u0000\u0000\u0000&\u0001\u0000\u0000"+ - "\u0000\u0000*\u0001\u0000\u0000\u0000\u0000,\u0001\u0000\u0000\u0000\u0000"+ - ".\u0001\u0000\u0000\u0000\u00000\u0001\u0000\u0000\u0000\u00002\u0001"+ - "\u0000\u0000\u0000\u00004\u0001\u0000\u0000\u0000\u00006\u0001\u0000\u0000"+ - "\u0000\u00008\u0001\u0000\u0000\u0000\u0000:\u0001\u0000\u0000\u0000\u0000"+ - "<\u0001\u0000\u0000\u0000\u0000>\u0001\u0000\u0000\u0000\u0000@\u0001"+ - "\u0000\u0000\u0000\u0000B\u0001\u0000\u0000\u0000\u0000D\u0001\u0000\u0000"+ - "\u0000\u0000F\u0001\u0000\u0000\u0000\u0000H\u0001\u0000\u0000\u0000\u0000"+ - "J\u0001\u0000\u0000\u0000\u0000L\u0001\u0000\u0000\u0000\u0000N\u0001"+ - "\u0000\u0000\u0000\u0000P\u0001\u0000\u0000\u0000\u0000R\u0001\u0000\u0000"+ - "\u0000\u0000T\u0001\u0000\u0000\u0000\u0000V\u0001\u0000\u0000\u0000\u0000"+ - "X\u0001\u0000\u0000\u0000\u0000Z\u0001\u0000\u0000\u0000\u0000\\\u0001"+ - "\u0000\u0000\u0000\u0000^\u0001\u0000\u0000\u0000\u0000`\u0001\u0000\u0000"+ - "\u0000\u0000b\u0001\u0000\u0000\u0000\u0001d\u0001\u0000\u0000\u0000\u0001"+ - "f\u0001\u0000\u0000\u0000\u0001h\u0001\u0000\u0000\u0000\u0001j\u0001"+ - "\u0000\u0000\u0000\u0002l\u0001\u0000\u0000\u0000\u0002n\u0001\u0000\u0000"+ - "\u0000\u0003p\u0001\u0000\u0000\u0000\u0003r\u0001\u0000\u0000\u0000\u0003"+ - "t\u0001\u0000\u0000\u0000\u0003v\u0001\u0000\u0000\u0000\u0004x\u0001"+ - "\u0000\u0000\u0000\u0006\u0088\u0001\u0000\u0000\u0000\b\u0098\u0001\u0000"+ - "\u0000\u0000\n\u009b\u0001\u0000\u0000\u0000\f\u009e\u0001\u0000\u0000"+ - "\u0000\u000e\u00a1\u0001\u0000\u0000\u0000\u0010\u00a4\u0001\u0000\u0000"+ - "\u0000\u0012\u00a8\u0001\u0000\u0000\u0000\u0014\u00aa\u0001\u0000\u0000"+ - "\u0000\u0016\u00b3\u0001\u0000\u0000\u0000\u0018\u00b9\u0001\u0000\u0000"+ - "\u0000\u001a\u00ca\u0001\u0000\u0000\u0000\u001c\u00d9\u0001\u0000\u0000"+ - "\u0000\u001e\u00df\u0001\u0000\u0000\u0000 \u00e5\u0001\u0000\u0000\u0000"+ - "\"\u00f9\u0001\u0000\u0000\u0000$\u00fb\u0001\u0000\u0000\u0000&\u0117"+ - "\u0001\u0000\u0000\u0000(\u0119\u0001\u0000\u0000\u0000*\u012b\u0001\u0000"+ - "\u0000\u0000,\u012d\u0001\u0000\u0000\u0000.\u0131\u0001\u0000\u0000\u0000"+ - "0\u0136\u0001\u0000\u0000\u00002\u013e\u0001\u0000\u0000\u00004\u0140"+ - "\u0001\u0000\u0000\u00006\u0143\u0001\u0000\u0000\u00008\u0146\u0001\u0000"+ - "\u0000\u0000:\u0148\u0001\u0000\u0000\u0000<\u014a\u0001\u0000\u0000\u0000"+ - ">\u014c\u0001\u0000\u0000\u0000@\u014e\u0001\u0000\u0000\u0000B\u0150"+ - "\u0001\u0000\u0000\u0000D\u0153\u0001\u0000\u0000\u0000F\u0156\u0001\u0000"+ - "\u0000\u0000H\u0158\u0001\u0000\u0000\u0000J\u015a\u0001\u0000\u0000\u0000"+ - "L\u015c\u0001\u0000\u0000\u0000N\u015e\u0001\u0000\u0000\u0000P\u0160"+ - "\u0001\u0000\u0000\u0000R\u0162\u0001\u0000\u0000\u0000T\u0165\u0001\u0000"+ - "\u0000\u0000V\u0167\u0001\u0000\u0000\u0000X\u0169\u0001\u0000\u0000\u0000"+ - "Z\u016c\u0001\u0000\u0000\u0000\\\u016f\u0001\u0000\u0000\u0000^\u0171"+ - "\u0001\u0000\u0000\u0000`\u0173\u0001\u0000\u0000\u0000b\u0177\u0001\u0000"+ - "\u0000\u0000d\u0179\u0001\u0000\u0000\u0000f\u0181\u0001\u0000\u0000\u0000"+ - "h\u018f\u0001\u0000\u0000\u0000j\u0191\u0001\u0000\u0000\u0000l\u0196"+ - "\u0001\u0000\u0000\u0000n\u019b\u0001\u0000\u0000\u0000p\u01a7\u0001\u0000"+ - "\u0000\u0000r\u01ab\u0001\u0000\u0000\u0000t\u01b4\u0001\u0000\u0000\u0000"+ - "v\u01c0\u0001\u0000\u0000\u0000x\u007f\u0005{\u0000\u0000y~\u0003\u0016"+ - "\t\u0000z~\u0003\u001c\f\u0000{~\u0003\u0018\n\u0000|~\u0003\u001a\u000b"+ - "\u0000}y\u0001\u0000\u0000\u0000}z\u0001\u0000\u0000\u0000}{\u0001\u0000"+ - "\u0000\u0000}|\u0001\u0000\u0000\u0000~\u0081\u0001\u0000\u0000\u0000"+ - "\u007f}\u0001\u0000\u0000\u0000\u007f\u0080\u0001\u0000\u0000\u0000\u0080"+ - "\u0082\u0001\u0000\u0000\u0000\u0081\u007f\u0001\u0000\u0000\u0000\u0082"+ - "\u0083\u0005f\u0000\u0000\u0083\u0084\u0005o\u0000\u0000\u0084\u0085\u0005"+ - "r\u0000\u0000\u0085\u0086\u0001\u0000\u0000\u0000\u0086\u0087\u0003\u0016"+ - "\t\u0000\u0087\u0005\u0001\u0000\u0000\u0000\u0088\u008f\u0005[\u0000"+ - "\u0000\u0089\u008e\u0003\u0016\t\u0000\u008a\u008e\u0003\u001c\f\u0000"+ - "\u008b\u008e\u0003\u0018\n\u0000\u008c\u008e\u0003\u001a\u000b\u0000\u008d"+ - "\u0089\u0001\u0000\u0000\u0000\u008d\u008a\u0001\u0000\u0000\u0000\u008d"+ - "\u008b\u0001\u0000\u0000\u0000\u008d\u008c\u0001\u0000\u0000\u0000\u008e"+ - "\u0091\u0001\u0000\u0000\u0000\u008f\u008d\u0001\u0000\u0000\u0000\u008f"+ - "\u0090\u0001\u0000\u0000\u0000\u0090\u0092\u0001\u0000\u0000\u0000\u0091"+ - "\u008f\u0001\u0000\u0000\u0000\u0092\u0093\u0005f\u0000\u0000\u0093\u0094"+ - "\u0005o\u0000\u0000\u0094\u0095\u0005r\u0000\u0000\u0095\u0096\u0001\u0000"+ - "\u0000\u0000\u0096\u0097\u0003\u0016\t\u0000\u0097\u0007\u0001\u0000\u0000"+ - "\u0000\u0098\u0099\u0005i\u0000\u0000\u0099\u009a\u0005f\u0000\u0000\u009a"+ - "\t\u0001\u0000\u0000\u0000\u009b\u009c\u0005i\u0000\u0000\u009c\u009d"+ - "\u0005n\u0000\u0000\u009d\u000b\u0001\u0000\u0000\u0000\u009e\u009f\u0005"+ - "{\u0000\u0000\u009f\u00a0\u0006\u0004\u0000\u0000\u00a0\r\u0001\u0000"+ - "\u0000\u0000\u00a1\u00a2\u0005}\u0000\u0000\u00a2\u00a3\u0006\u0005\u0001"+ - "\u0000\u00a3\u000f\u0001\u0000\u0000\u0000\u00a4\u00a5\u0005=\u0000\u0000"+ - "\u00a5\u0011\u0001\u0000\u0000\u0000\u00a6\u00a9\b\u0000\u0000\u0000\u00a7"+ - "\u00a9\u0003\"\u000f\u0000\u00a8\u00a6\u0001\u0000\u0000\u0000\u00a8\u00a7"+ - "\u0001\u0000\u0000\u0000\u00a9\u0013\u0001\u0000\u0000\u0000\u00aa\u00af"+ - "\u0003 \u000e\u0000\u00ab\u00ae\u0003\u001e\r\u0000\u00ac\u00ae\u0005"+ - "-\u0000\u0000\u00ad\u00ab\u0001\u0000\u0000\u0000\u00ad\u00ac\u0001\u0000"+ - "\u0000\u0000\u00ae\u00b1\u0001\u0000\u0000\u0000\u00af\u00ad\u0001\u0000"+ - "\u0000\u0000\u00af\u00b0\u0001\u0000\u0000\u0000\u00b0\u0015\u0001\u0000"+ - "\u0000\u0000\u00b1\u00af\u0001\u0000\u0000\u0000\u00b2\u00b4\u0007\u0001"+ - "\u0000\u0000\u00b3\u00b2\u0001\u0000\u0000\u0000\u00b4\u00b5\u0001\u0000"+ - "\u0000\u0000\u00b5\u00b3\u0001\u0000\u0000\u0000\u00b5\u00b6\u0001\u0000"+ - "\u0000\u0000\u00b6\u00b7\u0001\u0000\u0000\u0000\u00b7\u00b8\u0006\t\u0002"+ - "\u0000\u00b8\u0017\u0001\u0000\u0000\u0000\u00b9\u00ba\u0005/\u0000\u0000"+ - "\u00ba\u00bb\u0005*\u0000\u0000\u00bb\u00bf\u0001\u0000\u0000\u0000\u00bc"+ - "\u00be\t\u0000\u0000\u0000\u00bd\u00bc\u0001\u0000\u0000\u0000\u00be\u00c1"+ - "\u0001\u0000\u0000\u0000\u00bf\u00c0\u0001\u0000\u0000\u0000\u00bf\u00bd"+ - "\u0001\u0000\u0000\u0000\u00c0\u00c2\u0001\u0000\u0000\u0000\u00c1\u00bf"+ - "\u0001\u0000\u0000\u0000\u00c2\u00c3\u0005*\u0000\u0000\u00c3\u00c4\u0005"+ - "/\u0000\u0000\u00c4\u00c5\u0001\u0000\u0000\u0000\u00c5\u00c6\u0006\n"+ - "\u0002\u0000\u00c6\u0019\u0001\u0000\u0000\u0000\u00c7\u00c8\u0005/\u0000"+ - "\u0000\u00c8\u00cb\u0005/\u0000\u0000\u00c9\u00cb\u0005#\u0000\u0000\u00ca"+ - "\u00c7\u0001\u0000\u0000\u0000\u00ca\u00c9\u0001\u0000\u0000\u0000\u00cb"+ - "\u00cf\u0001\u0000\u0000\u0000\u00cc\u00ce\b\u0002\u0000\u0000\u00cd\u00cc"+ - "\u0001\u0000\u0000\u0000\u00ce\u00d1\u0001\u0000\u0000\u0000\u00cf\u00cd"+ - "\u0001\u0000\u0000\u0000\u00cf\u00d0\u0001\u0000\u0000\u0000\u00d0\u00d3"+ - "\u0001\u0000\u0000\u0000\u00d1\u00cf\u0001\u0000\u0000\u0000\u00d2\u00d4"+ - "\u0005\r\u0000\u0000\u00d3\u00d2\u0001\u0000\u0000\u0000\u00d3\u00d4\u0001"+ - "\u0000\u0000\u0000\u00d4\u00d5\u0001\u0000\u0000\u0000\u00d5\u00d6\u0005"+ - "\n\u0000\u0000\u00d6\u00d7\u0001\u0000\u0000\u0000\u00d7\u00d8\u0006\u000b"+ - "\u0002\u0000\u00d8\u001b\u0001\u0000\u0000\u0000\u00d9\u00da\u0005\n\u0000"+ - "\u0000\u00da\u00db\u0001\u0000\u0000\u0000\u00db\u00dc\u0006\f\u0002\u0000"+ - "\u00dc\u001d\u0001\u0000\u0000\u0000\u00dd\u00e0\u0003 \u000e\u0000\u00de"+ - "\u00e0\u0007\u0003\u0000\u0000\u00df\u00dd\u0001\u0000\u0000\u0000\u00df"+ - "\u00de\u0001\u0000\u0000\u0000\u00e0\u001f\u0001\u0000\u0000\u0000\u00e1"+ - "\u00e6\u0007\u0004\u0000\u0000\u00e2\u00e6\b\u0005\u0000\u0000\u00e3\u00e4"+ - "\u0007\u0006\u0000\u0000\u00e4\u00e6\u0007\u0007\u0000\u0000\u00e5\u00e1"+ - "\u0001\u0000\u0000\u0000\u00e5\u00e2\u0001\u0000\u0000\u0000\u00e5\u00e3"+ - "\u0001\u0000\u0000\u0000\u00e6!\u0001\u0000\u0000\u0000\u00e7\u00e8\u0005"+ - "\\\u0000\u0000\u00e8\u00fa\u0007\b\u0000\u0000\u00e9\u00ea\u0005\\\u0000"+ - "\u0000\u00ea\u00eb\u0003$\u0010\u0000\u00eb\u00ec\u0003$\u0010\u0000\u00ec"+ - "\u00ed\u0003$\u0010\u0000\u00ed\u00ee\u0003$\u0010\u0000\u00ee\u00fa\u0001"+ - "\u0000\u0000\u0000\u00ef\u00f0\u0005\\\u0000\u0000\u00f0\u00f1\u0003$"+ - "\u0010\u0000\u00f1\u00f2\u0003$\u0010\u0000\u00f2\u00f3\u0003$\u0010\u0000"+ - "\u00f3\u00f4\u0003$\u0010\u0000\u00f4\u00f5\u0003$\u0010\u0000\u00f5\u00f6"+ - "\u0003$\u0010\u0000\u00f6\u00f7\u0003$\u0010\u0000\u00f7\u00f8\u0003$"+ - "\u0010\u0000\u00f8\u00fa\u0001\u0000\u0000\u0000\u00f9\u00e7\u0001\u0000"+ - "\u0000\u0000\u00f9\u00e9\u0001\u0000\u0000\u0000\u00f9\u00ef\u0001\u0000"+ - "\u0000\u0000\u00fa#\u0001\u0000\u0000\u0000\u00fb\u00fc\u0007\t\u0000"+ - "\u0000\u00fc%\u0001\u0000\u0000\u0000\u00fd\u00ff\u0007\u0003\u0000\u0000"+ - "\u00fe\u00fd\u0001\u0000\u0000\u0000\u00ff\u0100\u0001\u0000\u0000\u0000"+ - "\u0100\u00fe\u0001\u0000\u0000\u0000\u0100\u0101\u0001\u0000\u0000\u0000"+ - "\u0101\u0102\u0001\u0000\u0000\u0000\u0102\u0106\u0005.\u0000\u0000\u0103"+ - "\u0105\u0007\u0003\u0000\u0000\u0104\u0103\u0001\u0000\u0000\u0000\u0105"+ - "\u0108\u0001\u0000\u0000\u0000\u0106\u0104\u0001\u0000\u0000\u0000\u0106"+ - "\u0107\u0001\u0000\u0000\u0000\u0107\u010a\u0001\u0000\u0000\u0000\u0108"+ - "\u0106\u0001\u0000\u0000\u0000\u0109\u010b\u0003(\u0012\u0000\u010a\u0109"+ - "\u0001\u0000\u0000\u0000\u010a\u010b\u0001\u0000\u0000\u0000\u010b\u0118"+ - "\u0001\u0000\u0000\u0000\u010c\u010e\u0007\u0003\u0000\u0000\u010d\u010c"+ - "\u0001\u0000\u0000\u0000\u010e\u010f\u0001\u0000\u0000\u0000\u010f\u010d"+ - "\u0001\u0000\u0000\u0000\u010f\u0110\u0001\u0000\u0000\u0000\u0110\u0111"+ - "\u0001\u0000\u0000\u0000\u0111\u0118\u0003(\u0012\u0000\u0112\u0114\u0007"+ - "\u0003\u0000\u0000\u0113\u0112\u0001\u0000\u0000\u0000\u0114\u0115\u0001"+ - "\u0000\u0000\u0000\u0115\u0113\u0001\u0000\u0000\u0000\u0115\u0116\u0001"+ - "\u0000\u0000\u0000\u0116\u0118\u0001\u0000\u0000\u0000\u0117\u00fe\u0001"+ - "\u0000\u0000\u0000\u0117\u010d\u0001\u0000\u0000\u0000\u0117\u0113\u0001"+ - "\u0000\u0000\u0000\u0118\'\u0001\u0000\u0000\u0000\u0119\u011b\u0007\n"+ - "\u0000\u0000\u011a\u011c\u0007\u000b\u0000\u0000\u011b\u011a\u0001\u0000"+ - "\u0000\u0000\u011b\u011c\u0001\u0000\u0000\u0000\u011c\u011e\u0001\u0000"+ - "\u0000\u0000\u011d\u011f\u0007\u0003\u0000\u0000\u011e\u011d\u0001\u0000"+ - "\u0000\u0000\u011f\u0120\u0001\u0000\u0000\u0000\u0120\u011e\u0001\u0000"+ - "\u0000\u0000\u0120\u0121\u0001\u0000\u0000\u0000\u0121)\u0001\u0000\u0000"+ - "\u0000\u0122\u0123\u0005t\u0000\u0000\u0123\u0124\u0005r\u0000\u0000\u0124"+ - "\u0125\u0005u\u0000\u0000\u0125\u012c\u0005e\u0000\u0000\u0126\u0127\u0005"+ - "f\u0000\u0000\u0127\u0128\u0005a\u0000\u0000\u0128\u0129\u0005l\u0000"+ - "\u0000\u0129\u012a\u0005s\u0000\u0000\u012a\u012c\u0005e\u0000\u0000\u012b"+ - "\u0122\u0001\u0000\u0000\u0000\u012b\u0126\u0001\u0000\u0000\u0000\u012c"+ - "+\u0001\u0000\u0000\u0000\u012d\u012e\u0005\"\u0000\u0000\u012e\u012f"+ - "\u0001\u0000\u0000\u0000\u012f\u0130\u0006\u0014\u0003\u0000\u0130-\u0001"+ - "\u0000\u0000\u0000\u0131\u0132\u0005n\u0000\u0000\u0132\u0133\u0005u\u0000"+ - "\u0000\u0133\u0134\u0005l\u0000\u0000\u0134\u0135\u0005l\u0000\u0000\u0135"+ - "/\u0001\u0000\u0000\u0000\u0136\u0137\u0005<\u0000\u0000\u0137\u0138\u0005"+ - "<\u0000\u0000\u0138\u013a\u0001\u0000\u0000\u0000\u0139\u013b\u0005-\u0000"+ - "\u0000\u013a\u0139\u0001\u0000\u0000\u0000\u013a\u013b\u0001\u0000\u0000"+ - "\u0000\u013b\u013c\u0001\u0000\u0000\u0000\u013c\u013d\u0006\u0016\u0004"+ - "\u0000\u013d1\u0001\u0000\u0000\u0000\u013e\u013f\u0005+\u0000\u0000\u013f"+ - "3\u0001\u0000\u0000\u0000\u0140\u0141\u0005&\u0000\u0000\u0141\u0142\u0005"+ - "&\u0000\u0000\u01425\u0001\u0000\u0000\u0000\u0143\u0144\u0005=\u0000"+ - "\u0000\u0144\u0145\u0005=\u0000\u0000\u01457\u0001\u0000\u0000\u0000\u0146"+ - "\u0147\u0005<\u0000\u0000\u01479\u0001\u0000\u0000\u0000\u0148\u0149\u0005"+ - ":\u0000\u0000\u0149;\u0001\u0000\u0000\u0000\u014a\u014b\u0005[\u0000"+ - "\u0000\u014b=\u0001\u0000\u0000\u0000\u014c\u014d\u0005(\u0000\u0000\u014d"+ - "?\u0001\u0000\u0000\u0000\u014e\u014f\u0005-\u0000\u0000\u014fA\u0001"+ - "\u0000\u0000\u0000\u0150\u0151\u0005|\u0000\u0000\u0151\u0152\u0005|\u0000"+ - "\u0000\u0152C\u0001\u0000\u0000\u0000\u0153\u0154\u0005!\u0000\u0000\u0154"+ - "\u0155\u0005=\u0000\u0000\u0155E\u0001\u0000\u0000\u0000\u0156\u0157\u0005"+ - ">\u0000\u0000\u0157G\u0001\u0000\u0000\u0000\u0158\u0159\u0005?\u0000"+ - "\u0000\u0159I\u0001\u0000\u0000\u0000\u015a\u015b\u0005]\u0000\u0000\u015b"+ - "K\u0001\u0000\u0000\u0000\u015c\u015d\u0005)\u0000\u0000\u015dM\u0001"+ - "\u0000\u0000\u0000\u015e\u015f\u0005*\u0000\u0000\u015fO\u0001\u0000\u0000"+ - "\u0000\u0160\u0161\u0005!\u0000\u0000\u0161Q\u0001\u0000\u0000\u0000\u0162"+ - "\u0163\u0005<\u0000\u0000\u0163\u0164\u0005=\u0000\u0000\u0164S\u0001"+ - "\u0000\u0000\u0000\u0165\u0166\u0005.\u0000\u0000\u0166U\u0001\u0000\u0000"+ - "\u0000\u0167\u0168\u0005/\u0000\u0000\u0168W\u0001\u0000\u0000\u0000\u0169"+ - "\u016a\u0005>\u0000\u0000\u016a\u016b\u0005=\u0000\u0000\u016bY\u0001"+ - "\u0000\u0000\u0000\u016c\u016d\u0005=\u0000\u0000\u016d\u016e\u0005>\u0000"+ - "\u0000\u016e[\u0001\u0000\u0000\u0000\u016f\u0170\u0005,\u0000\u0000\u0170"+ - "]\u0001\u0000\u0000\u0000\u0171\u0172\u0005%\u0000\u0000\u0172_\u0001"+ - "\u0000\u0000\u0000\u0173\u0174\u0005.\u0000\u0000\u0174\u0175\u0005.\u0000"+ - "\u0000\u0175\u0176\u0005.\u0000\u0000\u0176a\u0001\u0000\u0000\u0000\u0177"+ - "\u0178\u0005~\u0000\u0000\u0178c\u0001\u0000\u0000\u0000\u0179\u017a\u0005"+ - "$\u0000\u0000\u017a\u017b\u0005{\u0000\u0000\u017b\u017c\u0001\u0000\u0000"+ - "\u0000\u017c\u017d\u00060\u0005\u0000\u017d\u017e\u0001\u0000\u0000\u0000"+ - "\u017e\u017f\u00060\u0006\u0000\u017fe\u0001\u0000\u0000\u0000\u0180\u0182"+ - "\u0003h2\u0000\u0181\u0180\u0001\u0000\u0000\u0000\u0182\u0183\u0001\u0000"+ - "\u0000\u0000\u0183\u0181\u0001\u0000\u0000\u0000\u0183\u0184\u0001\u0000"+ - "\u0000\u0000\u0184g\u0001\u0000\u0000\u0000\u0185\u0190\b\u0000\u0000"+ - "\u0000\u0186\u0187\u0005$\u0000\u0000\u0187\u0190\u0005$\u0000\u0000\u0188"+ - "\u0189\u0005$\u0000\u0000\u0189\u0190\u00042\u0000\u0000\u018a\u018b\u0005"+ - "%\u0000\u0000\u018b\u0190\u0005%\u0000\u0000\u018c\u018d\u0005%\u0000"+ - "\u0000\u018d\u0190\u00042\u0001\u0000\u018e\u0190\u0003\"\u000f\u0000"+ - "\u018f\u0185\u0001\u0000\u0000\u0000\u018f\u0186\u0001\u0000\u0000\u0000"+ - "\u018f\u0188\u0001\u0000\u0000\u0000\u018f\u018a\u0001\u0000\u0000\u0000"+ - "\u018f\u018c\u0001\u0000\u0000\u0000\u018f\u018e\u0001\u0000\u0000\u0000"+ - "\u0190i\u0001\u0000\u0000\u0000\u0191\u0192\u0005\"\u0000\u0000\u0192"+ - "\u0193\u0001\u0000\u0000\u0000\u0193\u0194\u00063\u0007\u0000\u0194\u0195"+ - "\u00063\b\u0000\u0195k\u0001\u0000\u0000\u0000\u0196\u0197\u0005\n\u0000"+ - "\u0000\u0197\u0198\u0001\u0000\u0000\u0000\u0198\u0199\u00064\t\u0000"+ - "\u0199\u019a\u00064\n\u0000\u019am\u0001\u0000\u0000\u0000\u019b\u01a0"+ - "\u0003 \u000e\u0000\u019c\u019f\u0003\u001e\r\u0000\u019d\u019f\u0005"+ - "-\u0000\u0000\u019e\u019c\u0001\u0000\u0000\u0000\u019e\u019d\u0001\u0000"+ - "\u0000\u0000\u019f\u01a2\u0001\u0000\u0000\u0000\u01a0\u019e\u0001\u0000"+ - "\u0000\u0000\u01a0\u01a1\u0001\u0000\u0000\u0000\u01a1\u01a3\u0001\u0000"+ - "\u0000\u0000\u01a2\u01a0\u0001\u0000\u0000\u0000\u01a3\u01a4\u00065\u000b"+ - "\u0000\u01a4\u01a5\u0001\u0000\u0000\u0000\u01a5\u01a6\u00065\f\u0000"+ - "\u01a6o\u0001\u0000\u0000\u0000\u01a7\u01a8\u0005\n\u0000\u0000\u01a8"+ - "\u01a9\u0001\u0000\u0000\u0000\u01a9\u01aa\u00066\t\u0000\u01aaq\u0001"+ - "\u0000\u0000\u0000\u01ab\u01ac\u0005$\u0000\u0000\u01ac\u01ad\u0005{\u0000"+ - "\u0000\u01ad\u01ae\u0001\u0000\u0000\u0000\u01ae\u01af\u00067\r\u0000"+ - "\u01af\u01b0\u0001\u0000\u0000\u0000\u01b0\u01b1\u00067\u000e\u0000\u01b1"+ - "\u01b2\u00067\u0006\u0000\u01b2s\u0001\u0000\u0000\u0000\u01b3\u01b5\u0003"+ - "v9\u0000\u01b4\u01b3\u0001\u0000\u0000\u0000\u01b5\u01b6\u0001\u0000\u0000"+ - "\u0000\u01b6\u01b4\u0001\u0000\u0000\u0000\u01b6\u01b7\u0001\u0000\u0000"+ - "\u0000\u01b7\u01b8\u0001\u0000\u0000\u0000\u01b8\u01b9\u00068\u000f\u0000"+ - "\u01b9u\u0001\u0000\u0000\u0000\u01ba\u01c1\b\f\u0000\u0000\u01bb\u01bc"+ - "\u0005$\u0000\u0000\u01bc\u01c1\b\r\u0000\u0000\u01bd\u01be\u0005%\u0000"+ - "\u0000\u01be\u01c1\b\r\u0000\u0000\u01bf\u01c1\u0003\"\u000f\u0000\u01c0"+ - "\u01ba\u0001\u0000\u0000\u0000\u01c0\u01bb\u0001\u0000\u0000\u0000\u01c0"+ - "\u01bd\u0001\u0000\u0000\u0000\u01c0\u01bf\u0001\u0000\u0000\u0000\u01c1"+ - "w\u0001\u0000\u0000\u0000#\u0000\u0001\u0002\u0003}\u007f\u008d\u008f"+ - "\u00a8\u00ad\u00af\u00b5\u00bf\u00ca\u00cf\u00d3\u00df\u00e5\u00f9\u0100"+ - "\u0106\u010a\u010f\u0115\u0117\u011b\u0120\u012b\u013a\u0183\u018f\u019e"+ - "\u01a0\u01b6\u01c0\u0010\u0001\u0004\u0000\u0001\u0005\u0001\u0000\u0001"+ - "\u0000\u0005\u0001\u0000\u0005\u0002\u0000\u00010\u0002\u0005\u0000\u0000"+ - "\u0007\u000f\u0000\u0004\u0000\u0000\u0007\f\u0000\u0002\u0003\u0000\u0001"+ - "5\u0003\u0007\b\u0000\u00017\u0004\u0007+\u0000\u00018\u0005"; + "\u0003\u000f\u0004\u0000\n\n\r\r\"\"$%\u0003\u0000\t\t\f\r \u0002\u0000"+ + "\n\n\r\r\u0001\u0001\n\n\u0001\u000009\u0004\u0000$$AZ__az\u0002\u0000"+ + "\u0000\u007f\u8000\ud800\u8000\udbff\u0001\u0000\u8000\ud800\u8000\udbff"+ + "\u0001\u0000\u8000\udc00\u8000\udfff\u0005\u0000\"\"\\\\nnrrtt\u0003\u0000"+ + "09AFaf\u0002\u0000EEee\u0002\u0000++--\u0003\u0000\n\n\r\r$%\u0001\u0000"+ + "{{\u01e5\u0000\u0004\u0001\u0000\u0000\u0000\u0000\u0006\u0001\u0000\u0000"+ + "\u0000\u0000\b\u0001\u0000\u0000\u0000\u0000\n\u0001\u0000\u0000\u0000"+ + "\u0000\f\u0001\u0000\u0000\u0000\u0000\u000e\u0001\u0000\u0000\u0000\u0000"+ + "\u0010\u0001\u0000\u0000\u0000\u0000\u0014\u0001\u0000\u0000\u0000\u0000"+ + "\u0016\u0001\u0000\u0000\u0000\u0000\u0018\u0001\u0000\u0000\u0000\u0000"+ + "\u001a\u0001\u0000\u0000\u0000\u0000\u001c\u0001\u0000\u0000\u0000\u0000"+ + "&\u0001\u0000\u0000\u0000\u0000*\u0001\u0000\u0000\u0000\u0000,\u0001"+ + "\u0000\u0000\u0000\u0000.\u0001\u0000\u0000\u0000\u00000\u0001\u0000\u0000"+ + "\u0000\u00002\u0001\u0000\u0000\u0000\u00004\u0001\u0000\u0000\u0000\u0000"+ + "6\u0001\u0000\u0000\u0000\u00008\u0001\u0000\u0000\u0000\u0000:\u0001"+ + "\u0000\u0000\u0000\u0000<\u0001\u0000\u0000\u0000\u0000>\u0001\u0000\u0000"+ + "\u0000\u0000@\u0001\u0000\u0000\u0000\u0000B\u0001\u0000\u0000\u0000\u0000"+ + "D\u0001\u0000\u0000\u0000\u0000F\u0001\u0000\u0000\u0000\u0000H\u0001"+ + "\u0000\u0000\u0000\u0000J\u0001\u0000\u0000\u0000\u0000L\u0001\u0000\u0000"+ + "\u0000\u0000N\u0001\u0000\u0000\u0000\u0000P\u0001\u0000\u0000\u0000\u0000"+ + "R\u0001\u0000\u0000\u0000\u0000T\u0001\u0000\u0000\u0000\u0000V\u0001"+ + "\u0000\u0000\u0000\u0000X\u0001\u0000\u0000\u0000\u0000Z\u0001\u0000\u0000"+ + "\u0000\u0000\\\u0001\u0000\u0000\u0000\u0000^\u0001\u0000\u0000\u0000"+ + "\u0000`\u0001\u0000\u0000\u0000\u0000b\u0001\u0000\u0000\u0000\u0001d"+ + "\u0001\u0000\u0000\u0000\u0001f\u0001\u0000\u0000\u0000\u0001h\u0001\u0000"+ + "\u0000\u0000\u0001j\u0001\u0000\u0000\u0000\u0002l\u0001\u0000\u0000\u0000"+ + "\u0002n\u0001\u0000\u0000\u0000\u0003p\u0001\u0000\u0000\u0000\u0003r"+ + "\u0001\u0000\u0000\u0000\u0003t\u0001\u0000\u0000\u0000\u0003v\u0001\u0000"+ + "\u0000\u0000\u0004x\u0001\u0000\u0000\u0000\u0006\u0088\u0001\u0000\u0000"+ + "\u0000\b\u0098\u0001\u0000\u0000\u0000\n\u009b\u0001\u0000\u0000\u0000"+ + "\f\u009e\u0001\u0000\u0000\u0000\u000e\u00a1\u0001\u0000\u0000\u0000\u0010"+ + "\u00a4\u0001\u0000\u0000\u0000\u0012\u00a8\u0001\u0000\u0000\u0000\u0014"+ + "\u00aa\u0001\u0000\u0000\u0000\u0016\u00b3\u0001\u0000\u0000\u0000\u0018"+ + "\u00b9\u0001\u0000\u0000\u0000\u001a\u00ca\u0001\u0000\u0000\u0000\u001c"+ + "\u00da\u0001\u0000\u0000\u0000\u001e\u00e0\u0001\u0000\u0000\u0000 \u00e6"+ + "\u0001\u0000\u0000\u0000\"\u00fa\u0001\u0000\u0000\u0000$\u00fc\u0001"+ + "\u0000\u0000\u0000&\u0118\u0001\u0000\u0000\u0000(\u011a\u0001\u0000\u0000"+ + "\u0000*\u012c\u0001\u0000\u0000\u0000,\u012e\u0001\u0000\u0000\u0000."+ + "\u0132\u0001\u0000\u0000\u00000\u0137\u0001\u0000\u0000\u00002\u013f\u0001"+ + "\u0000\u0000\u00004\u0141\u0001\u0000\u0000\u00006\u0144\u0001\u0000\u0000"+ + "\u00008\u0147\u0001\u0000\u0000\u0000:\u0149\u0001\u0000\u0000\u0000<"+ + "\u014b\u0001\u0000\u0000\u0000>\u014d\u0001\u0000\u0000\u0000@\u014f\u0001"+ + "\u0000\u0000\u0000B\u0151\u0001\u0000\u0000\u0000D\u0154\u0001\u0000\u0000"+ + "\u0000F\u0157\u0001\u0000\u0000\u0000H\u0159\u0001\u0000\u0000\u0000J"+ + "\u015b\u0001\u0000\u0000\u0000L\u015d\u0001\u0000\u0000\u0000N\u015f\u0001"+ + "\u0000\u0000\u0000P\u0161\u0001\u0000\u0000\u0000R\u0163\u0001\u0000\u0000"+ + "\u0000T\u0166\u0001\u0000\u0000\u0000V\u0168\u0001\u0000\u0000\u0000X"+ + "\u016a\u0001\u0000\u0000\u0000Z\u016d\u0001\u0000\u0000\u0000\\\u0170"+ + "\u0001\u0000\u0000\u0000^\u0172\u0001\u0000\u0000\u0000`\u0174\u0001\u0000"+ + "\u0000\u0000b\u0178\u0001\u0000\u0000\u0000d\u017a\u0001\u0000\u0000\u0000"+ + "f\u0182\u0001\u0000\u0000\u0000h\u0190\u0001\u0000\u0000\u0000j\u0192"+ + "\u0001\u0000\u0000\u0000l\u0197\u0001\u0000\u0000\u0000n\u019c\u0001\u0000"+ + "\u0000\u0000p\u01a8\u0001\u0000\u0000\u0000r\u01ac\u0001\u0000\u0000\u0000"+ + "t\u01b5\u0001\u0000\u0000\u0000v\u01c1\u0001\u0000\u0000\u0000x\u007f"+ + "\u0005{\u0000\u0000y~\u0003\u0016\t\u0000z~\u0003\u001c\f\u0000{~\u0003"+ + "\u0018\n\u0000|~\u0003\u001a\u000b\u0000}y\u0001\u0000\u0000\u0000}z\u0001"+ + "\u0000\u0000\u0000}{\u0001\u0000\u0000\u0000}|\u0001\u0000\u0000\u0000"+ + "~\u0081\u0001\u0000\u0000\u0000\u007f}\u0001\u0000\u0000\u0000\u007f\u0080"+ + "\u0001\u0000\u0000\u0000\u0080\u0082\u0001\u0000\u0000\u0000\u0081\u007f"+ + "\u0001\u0000\u0000\u0000\u0082\u0083\u0005f\u0000\u0000\u0083\u0084\u0005"+ + "o\u0000\u0000\u0084\u0085\u0005r\u0000\u0000\u0085\u0086\u0001\u0000\u0000"+ + "\u0000\u0086\u0087\u0003\u0016\t\u0000\u0087\u0005\u0001\u0000\u0000\u0000"+ + "\u0088\u008f\u0005[\u0000\u0000\u0089\u008e\u0003\u0016\t\u0000\u008a"+ + "\u008e\u0003\u001c\f\u0000\u008b\u008e\u0003\u0018\n\u0000\u008c\u008e"+ + "\u0003\u001a\u000b\u0000\u008d\u0089\u0001\u0000\u0000\u0000\u008d\u008a"+ + "\u0001\u0000\u0000\u0000\u008d\u008b\u0001\u0000\u0000\u0000\u008d\u008c"+ + "\u0001\u0000\u0000\u0000\u008e\u0091\u0001\u0000\u0000\u0000\u008f\u008d"+ + "\u0001\u0000\u0000\u0000\u008f\u0090\u0001\u0000\u0000\u0000\u0090\u0092"+ + "\u0001\u0000\u0000\u0000\u0091\u008f\u0001\u0000\u0000\u0000\u0092\u0093"+ + "\u0005f\u0000\u0000\u0093\u0094\u0005o\u0000\u0000\u0094\u0095\u0005r"+ + "\u0000\u0000\u0095\u0096\u0001\u0000\u0000\u0000\u0096\u0097\u0003\u0016"+ + "\t\u0000\u0097\u0007\u0001\u0000\u0000\u0000\u0098\u0099\u0005i\u0000"+ + "\u0000\u0099\u009a\u0005f\u0000\u0000\u009a\t\u0001\u0000\u0000\u0000"+ + "\u009b\u009c\u0005i\u0000\u0000\u009c\u009d\u0005n\u0000\u0000\u009d\u000b"+ + "\u0001\u0000\u0000\u0000\u009e\u009f\u0005{\u0000\u0000\u009f\u00a0\u0006"+ + "\u0004\u0000\u0000\u00a0\r\u0001\u0000\u0000\u0000\u00a1\u00a2\u0005}"+ + "\u0000\u0000\u00a2\u00a3\u0006\u0005\u0001\u0000\u00a3\u000f\u0001\u0000"+ + "\u0000\u0000\u00a4\u00a5\u0005=\u0000\u0000\u00a5\u0011\u0001\u0000\u0000"+ + "\u0000\u00a6\u00a9\b\u0000\u0000\u0000\u00a7\u00a9\u0003\"\u000f\u0000"+ + "\u00a8\u00a6\u0001\u0000\u0000\u0000\u00a8\u00a7\u0001\u0000\u0000\u0000"+ + "\u00a9\u0013\u0001\u0000\u0000\u0000\u00aa\u00af\u0003 \u000e\u0000\u00ab"+ + "\u00ae\u0003\u001e\r\u0000\u00ac\u00ae\u0005-\u0000\u0000\u00ad\u00ab"+ + "\u0001\u0000\u0000\u0000\u00ad\u00ac\u0001\u0000\u0000\u0000\u00ae\u00b1"+ + "\u0001\u0000\u0000\u0000\u00af\u00ad\u0001\u0000\u0000\u0000\u00af\u00b0"+ + "\u0001\u0000\u0000\u0000\u00b0\u0015\u0001\u0000\u0000\u0000\u00b1\u00af"+ + "\u0001\u0000\u0000\u0000\u00b2\u00b4\u0007\u0001\u0000\u0000\u00b3\u00b2"+ + "\u0001\u0000\u0000\u0000\u00b4\u00b5\u0001\u0000\u0000\u0000\u00b5\u00b3"+ + "\u0001\u0000\u0000\u0000\u00b5\u00b6\u0001\u0000\u0000\u0000\u00b6\u00b7"+ + "\u0001\u0000\u0000\u0000\u00b7\u00b8\u0006\t\u0002\u0000\u00b8\u0017\u0001"+ + "\u0000\u0000\u0000\u00b9\u00ba\u0005/\u0000\u0000\u00ba\u00bb\u0005*\u0000"+ + "\u0000\u00bb\u00bf\u0001\u0000\u0000\u0000\u00bc\u00be\t\u0000\u0000\u0000"+ + "\u00bd\u00bc\u0001\u0000\u0000\u0000\u00be\u00c1\u0001\u0000\u0000\u0000"+ + "\u00bf\u00c0\u0001\u0000\u0000\u0000\u00bf\u00bd\u0001\u0000\u0000\u0000"+ + "\u00c0\u00c2\u0001\u0000\u0000\u0000\u00c1\u00bf\u0001\u0000\u0000\u0000"+ + "\u00c2\u00c3\u0005*\u0000\u0000\u00c3\u00c4\u0005/\u0000\u0000\u00c4\u00c5"+ + "\u0001\u0000\u0000\u0000\u00c5\u00c6\u0006\n\u0002\u0000\u00c6\u0019\u0001"+ + "\u0000\u0000\u0000\u00c7\u00c8\u0005/\u0000\u0000\u00c8\u00cb\u0005/\u0000"+ + "\u0000\u00c9\u00cb\u0005#\u0000\u0000\u00ca\u00c7\u0001\u0000\u0000\u0000"+ + "\u00ca\u00c9\u0001\u0000\u0000\u0000\u00cb\u00cf\u0001\u0000\u0000\u0000"+ + "\u00cc\u00ce\b\u0002\u0000\u0000\u00cd\u00cc\u0001\u0000\u0000\u0000\u00ce"+ + "\u00d1\u0001\u0000\u0000\u0000\u00cf\u00cd\u0001\u0000\u0000\u0000\u00cf"+ + "\u00d0\u0001\u0000\u0000\u0000\u00d0\u00d3\u0001\u0000\u0000\u0000\u00d1"+ + "\u00cf\u0001\u0000\u0000\u0000\u00d2\u00d4\u0005\r\u0000\u0000\u00d3\u00d2"+ + "\u0001\u0000\u0000\u0000\u00d3\u00d4\u0001\u0000\u0000\u0000\u00d4\u00d6"+ + "\u0001\u0000\u0000\u0000\u00d5\u00d7\u0007\u0003\u0000\u0000\u00d6\u00d5"+ + "\u0001\u0000\u0000\u0000\u00d7\u00d8\u0001\u0000\u0000\u0000\u00d8\u00d9"+ + "\u0006\u000b\u0002\u0000\u00d9\u001b\u0001\u0000\u0000\u0000\u00da\u00db"+ + "\u0005\n\u0000\u0000\u00db\u00dc\u0001\u0000\u0000\u0000\u00dc\u00dd\u0006"+ + "\f\u0002\u0000\u00dd\u001d\u0001\u0000\u0000\u0000\u00de\u00e1\u0003 "+ + "\u000e\u0000\u00df\u00e1\u0007\u0004\u0000\u0000\u00e0\u00de\u0001\u0000"+ + "\u0000\u0000\u00e0\u00df\u0001\u0000\u0000\u0000\u00e1\u001f\u0001\u0000"+ + "\u0000\u0000\u00e2\u00e7\u0007\u0005\u0000\u0000\u00e3\u00e7\b\u0006\u0000"+ + "\u0000\u00e4\u00e5\u0007\u0007\u0000\u0000\u00e5\u00e7\u0007\b\u0000\u0000"+ + "\u00e6\u00e2\u0001\u0000\u0000\u0000\u00e6\u00e3\u0001\u0000\u0000\u0000"+ + "\u00e6\u00e4\u0001\u0000\u0000\u0000\u00e7!\u0001\u0000\u0000\u0000\u00e8"+ + "\u00e9\u0005\\\u0000\u0000\u00e9\u00fb\u0007\t\u0000\u0000\u00ea\u00eb"+ + "\u0005\\\u0000\u0000\u00eb\u00ec\u0003$\u0010\u0000\u00ec\u00ed\u0003"+ + "$\u0010\u0000\u00ed\u00ee\u0003$\u0010\u0000\u00ee\u00ef\u0003$\u0010"+ + "\u0000\u00ef\u00fb\u0001\u0000\u0000\u0000\u00f0\u00f1\u0005\\\u0000\u0000"+ + "\u00f1\u00f2\u0003$\u0010\u0000\u00f2\u00f3\u0003$\u0010\u0000\u00f3\u00f4"+ + "\u0003$\u0010\u0000\u00f4\u00f5\u0003$\u0010\u0000\u00f5\u00f6\u0003$"+ + "\u0010\u0000\u00f6\u00f7\u0003$\u0010\u0000\u00f7\u00f8\u0003$\u0010\u0000"+ + "\u00f8\u00f9\u0003$\u0010\u0000\u00f9\u00fb\u0001\u0000\u0000\u0000\u00fa"+ + "\u00e8\u0001\u0000\u0000\u0000\u00fa\u00ea\u0001\u0000\u0000\u0000\u00fa"+ + "\u00f0\u0001\u0000\u0000\u0000\u00fb#\u0001\u0000\u0000\u0000\u00fc\u00fd"+ + "\u0007\n\u0000\u0000\u00fd%\u0001\u0000\u0000\u0000\u00fe\u0100\u0007"+ + "\u0004\u0000\u0000\u00ff\u00fe\u0001\u0000\u0000\u0000\u0100\u0101\u0001"+ + "\u0000\u0000\u0000\u0101\u00ff\u0001\u0000\u0000\u0000\u0101\u0102\u0001"+ + "\u0000\u0000\u0000\u0102\u0103\u0001\u0000\u0000\u0000\u0103\u0107\u0005"+ + ".\u0000\u0000\u0104\u0106\u0007\u0004\u0000\u0000\u0105\u0104\u0001\u0000"+ + "\u0000\u0000\u0106\u0109\u0001\u0000\u0000\u0000\u0107\u0105\u0001\u0000"+ + "\u0000\u0000\u0107\u0108\u0001\u0000\u0000\u0000\u0108\u010b\u0001\u0000"+ + "\u0000\u0000\u0109\u0107\u0001\u0000\u0000\u0000\u010a\u010c\u0003(\u0012"+ + "\u0000\u010b\u010a\u0001\u0000\u0000\u0000\u010b\u010c\u0001\u0000\u0000"+ + "\u0000\u010c\u0119\u0001\u0000\u0000\u0000\u010d\u010f\u0007\u0004\u0000"+ + "\u0000\u010e\u010d\u0001\u0000\u0000\u0000\u010f\u0110\u0001\u0000\u0000"+ + "\u0000\u0110\u010e\u0001\u0000\u0000\u0000\u0110\u0111\u0001\u0000\u0000"+ + "\u0000\u0111\u0112\u0001\u0000\u0000\u0000\u0112\u0119\u0003(\u0012\u0000"+ + "\u0113\u0115\u0007\u0004\u0000\u0000\u0114\u0113\u0001\u0000\u0000\u0000"+ + "\u0115\u0116\u0001\u0000\u0000\u0000\u0116\u0114\u0001\u0000\u0000\u0000"+ + "\u0116\u0117\u0001\u0000\u0000\u0000\u0117\u0119\u0001\u0000\u0000\u0000"+ + "\u0118\u00ff\u0001\u0000\u0000\u0000\u0118\u010e\u0001\u0000\u0000\u0000"+ + "\u0118\u0114\u0001\u0000\u0000\u0000\u0119\'\u0001\u0000\u0000\u0000\u011a"+ + "\u011c\u0007\u000b\u0000\u0000\u011b\u011d\u0007\f\u0000\u0000\u011c\u011b"+ + "\u0001\u0000\u0000\u0000\u011c\u011d\u0001\u0000\u0000\u0000\u011d\u011f"+ + "\u0001\u0000\u0000\u0000\u011e\u0120\u0007\u0004\u0000\u0000\u011f\u011e"+ + "\u0001\u0000\u0000\u0000\u0120\u0121\u0001\u0000\u0000\u0000\u0121\u011f"+ + "\u0001\u0000\u0000\u0000\u0121\u0122\u0001\u0000\u0000\u0000\u0122)\u0001"+ + "\u0000\u0000\u0000\u0123\u0124\u0005t\u0000\u0000\u0124\u0125\u0005r\u0000"+ + "\u0000\u0125\u0126\u0005u\u0000\u0000\u0126\u012d\u0005e\u0000\u0000\u0127"+ + "\u0128\u0005f\u0000\u0000\u0128\u0129\u0005a\u0000\u0000\u0129\u012a\u0005"+ + "l\u0000\u0000\u012a\u012b\u0005s\u0000\u0000\u012b\u012d\u0005e\u0000"+ + "\u0000\u012c\u0123\u0001\u0000\u0000\u0000\u012c\u0127\u0001\u0000\u0000"+ + "\u0000\u012d+\u0001\u0000\u0000\u0000\u012e\u012f\u0005\"\u0000\u0000"+ + "\u012f\u0130\u0001\u0000\u0000\u0000\u0130\u0131\u0006\u0014\u0003\u0000"+ + "\u0131-\u0001\u0000\u0000\u0000\u0132\u0133\u0005n\u0000\u0000\u0133\u0134"+ + "\u0005u\u0000\u0000\u0134\u0135\u0005l\u0000\u0000\u0135\u0136\u0005l"+ + "\u0000\u0000\u0136/\u0001\u0000\u0000\u0000\u0137\u0138\u0005<\u0000\u0000"+ + "\u0138\u0139\u0005<\u0000\u0000\u0139\u013b\u0001\u0000\u0000\u0000\u013a"+ + "\u013c\u0005-\u0000\u0000\u013b\u013a\u0001\u0000\u0000\u0000\u013b\u013c"+ + "\u0001\u0000\u0000\u0000\u013c\u013d\u0001\u0000\u0000\u0000\u013d\u013e"+ + "\u0006\u0016\u0004\u0000\u013e1\u0001\u0000\u0000\u0000\u013f\u0140\u0005"+ + "+\u0000\u0000\u01403\u0001\u0000\u0000\u0000\u0141\u0142\u0005&\u0000"+ + "\u0000\u0142\u0143\u0005&\u0000\u0000\u01435\u0001\u0000\u0000\u0000\u0144"+ + "\u0145\u0005=\u0000\u0000\u0145\u0146\u0005=\u0000\u0000\u01467\u0001"+ + "\u0000\u0000\u0000\u0147\u0148\u0005<\u0000\u0000\u01489\u0001\u0000\u0000"+ + "\u0000\u0149\u014a\u0005:\u0000\u0000\u014a;\u0001\u0000\u0000\u0000\u014b"+ + "\u014c\u0005[\u0000\u0000\u014c=\u0001\u0000\u0000\u0000\u014d\u014e\u0005"+ + "(\u0000\u0000\u014e?\u0001\u0000\u0000\u0000\u014f\u0150\u0005-\u0000"+ + "\u0000\u0150A\u0001\u0000\u0000\u0000\u0151\u0152\u0005|\u0000\u0000\u0152"+ + "\u0153\u0005|\u0000\u0000\u0153C\u0001\u0000\u0000\u0000\u0154\u0155\u0005"+ + "!\u0000\u0000\u0155\u0156\u0005=\u0000\u0000\u0156E\u0001\u0000\u0000"+ + "\u0000\u0157\u0158\u0005>\u0000\u0000\u0158G\u0001\u0000\u0000\u0000\u0159"+ + "\u015a\u0005?\u0000\u0000\u015aI\u0001\u0000\u0000\u0000\u015b\u015c\u0005"+ + "]\u0000\u0000\u015cK\u0001\u0000\u0000\u0000\u015d\u015e\u0005)\u0000"+ + "\u0000\u015eM\u0001\u0000\u0000\u0000\u015f\u0160\u0005*\u0000\u0000\u0160"+ + "O\u0001\u0000\u0000\u0000\u0161\u0162\u0005!\u0000\u0000\u0162Q\u0001"+ + "\u0000\u0000\u0000\u0163\u0164\u0005<\u0000\u0000\u0164\u0165\u0005=\u0000"+ + "\u0000\u0165S\u0001\u0000\u0000\u0000\u0166\u0167\u0005.\u0000\u0000\u0167"+ + "U\u0001\u0000\u0000\u0000\u0168\u0169\u0005/\u0000\u0000\u0169W\u0001"+ + "\u0000\u0000\u0000\u016a\u016b\u0005>\u0000\u0000\u016b\u016c\u0005=\u0000"+ + "\u0000\u016cY\u0001\u0000\u0000\u0000\u016d\u016e\u0005=\u0000\u0000\u016e"+ + "\u016f\u0005>\u0000\u0000\u016f[\u0001\u0000\u0000\u0000\u0170\u0171\u0005"+ + ",\u0000\u0000\u0171]\u0001\u0000\u0000\u0000\u0172\u0173\u0005%\u0000"+ + "\u0000\u0173_\u0001\u0000\u0000\u0000\u0174\u0175\u0005.\u0000\u0000\u0175"+ + "\u0176\u0005.\u0000\u0000\u0176\u0177\u0005.\u0000\u0000\u0177a\u0001"+ + "\u0000\u0000\u0000\u0178\u0179\u0005~\u0000\u0000\u0179c\u0001\u0000\u0000"+ + "\u0000\u017a\u017b\u0005$\u0000\u0000\u017b\u017c\u0005{\u0000\u0000\u017c"+ + "\u017d\u0001\u0000\u0000\u0000\u017d\u017e\u00060\u0005\u0000\u017e\u017f"+ + "\u0001\u0000\u0000\u0000\u017f\u0180\u00060\u0006\u0000\u0180e\u0001\u0000"+ + "\u0000\u0000\u0181\u0183\u0003h2\u0000\u0182\u0181\u0001\u0000\u0000\u0000"+ + "\u0183\u0184\u0001\u0000\u0000\u0000\u0184\u0182\u0001\u0000\u0000\u0000"+ + "\u0184\u0185\u0001\u0000\u0000\u0000\u0185g\u0001\u0000\u0000\u0000\u0186"+ + "\u0191\b\u0000\u0000\u0000\u0187\u0188\u0005$\u0000\u0000\u0188\u0191"+ + "\u0005$\u0000\u0000\u0189\u018a\u0005$\u0000\u0000\u018a\u0191\u00042"+ + "\u0000\u0000\u018b\u018c\u0005%\u0000\u0000\u018c\u0191\u0005%\u0000\u0000"+ + "\u018d\u018e\u0005%\u0000\u0000\u018e\u0191\u00042\u0001\u0000\u018f\u0191"+ + "\u0003\"\u000f\u0000\u0190\u0186\u0001\u0000\u0000\u0000\u0190\u0187\u0001"+ + "\u0000\u0000\u0000\u0190\u0189\u0001\u0000\u0000\u0000\u0190\u018b\u0001"+ + "\u0000\u0000\u0000\u0190\u018d\u0001\u0000\u0000\u0000\u0190\u018f\u0001"+ + "\u0000\u0000\u0000\u0191i\u0001\u0000\u0000\u0000\u0192\u0193\u0005\""+ + "\u0000\u0000\u0193\u0194\u0001\u0000\u0000\u0000\u0194\u0195\u00063\u0007"+ + "\u0000\u0195\u0196\u00063\b\u0000\u0196k\u0001\u0000\u0000\u0000\u0197"+ + "\u0198\u0005\n\u0000\u0000\u0198\u0199\u0001\u0000\u0000\u0000\u0199\u019a"+ + "\u00064\t\u0000\u019a\u019b\u00064\n\u0000\u019bm\u0001\u0000\u0000\u0000"+ + "\u019c\u01a1\u0003 \u000e\u0000\u019d\u01a0\u0003\u001e\r\u0000\u019e"+ + "\u01a0\u0005-\u0000\u0000\u019f\u019d\u0001\u0000\u0000\u0000\u019f\u019e"+ + "\u0001\u0000\u0000\u0000\u01a0\u01a3\u0001\u0000\u0000\u0000\u01a1\u019f"+ + "\u0001\u0000\u0000\u0000\u01a1\u01a2\u0001\u0000\u0000\u0000\u01a2\u01a4"+ + "\u0001\u0000\u0000\u0000\u01a3\u01a1\u0001\u0000\u0000\u0000\u01a4\u01a5"+ + "\u00065\u000b\u0000\u01a5\u01a6\u0001\u0000\u0000\u0000\u01a6\u01a7\u0006"+ + "5\f\u0000\u01a7o\u0001\u0000\u0000\u0000\u01a8\u01a9\u0005\n\u0000\u0000"+ + "\u01a9\u01aa\u0001\u0000\u0000\u0000\u01aa\u01ab\u00066\t\u0000\u01ab"+ + "q\u0001\u0000\u0000\u0000\u01ac\u01ad\u0005$\u0000\u0000\u01ad\u01ae\u0005"+ + "{\u0000\u0000\u01ae\u01af\u0001\u0000\u0000\u0000\u01af\u01b0\u00067\r"+ + "\u0000\u01b0\u01b1\u0001\u0000\u0000\u0000\u01b1\u01b2\u00067\u000e\u0000"+ + "\u01b2\u01b3\u00067\u0006\u0000\u01b3s\u0001\u0000\u0000\u0000\u01b4\u01b6"+ + "\u0003v9\u0000\u01b5\u01b4\u0001\u0000\u0000\u0000\u01b6\u01b7\u0001\u0000"+ + "\u0000\u0000\u01b7\u01b5\u0001\u0000\u0000\u0000\u01b7\u01b8\u0001\u0000"+ + "\u0000\u0000\u01b8\u01b9\u0001\u0000\u0000\u0000\u01b9\u01ba\u00068\u000f"+ + "\u0000\u01bau\u0001\u0000\u0000\u0000\u01bb\u01c2\b\r\u0000\u0000\u01bc"+ + "\u01bd\u0005$\u0000\u0000\u01bd\u01c2\b\u000e\u0000\u0000\u01be\u01bf"+ + "\u0005%\u0000\u0000\u01bf\u01c2\b\u000e\u0000\u0000\u01c0\u01c2\u0003"+ + "\"\u000f\u0000\u01c1\u01bb\u0001\u0000\u0000\u0000\u01c1\u01bc\u0001\u0000"+ + "\u0000\u0000\u01c1\u01be\u0001\u0000\u0000\u0000\u01c1\u01c0\u0001\u0000"+ + "\u0000\u0000\u01c2w\u0001\u0000\u0000\u0000$\u0000\u0001\u0002\u0003}"+ + "\u007f\u008d\u008f\u00a8\u00ad\u00af\u00b5\u00bf\u00ca\u00cf\u00d3\u00d6"+ + "\u00e0\u00e6\u00fa\u0101\u0107\u010b\u0110\u0116\u0118\u011c\u0121\u012c"+ + "\u013b\u0184\u0190\u019f\u01a1\u01b7\u01c1\u0010\u0001\u0004\u0000\u0001"+ + "\u0005\u0001\u0000\u0001\u0000\u0005\u0001\u0000\u0005\u0002\u0000\u0001"+ + "0\u0002\u0005\u0000\u0000\u0007\u000f\u0000\u0004\u0000\u0000\u0007\f"+ + "\u0000\u0002\u0003\u0000\u00015\u0003\u0007\b\u0000\u00017\u0004\u0007"+ + "+\u0000\u00018\u0005"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java index 1b4c56e5bdc..854b9299aee 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java @@ -225,6 +225,11 @@ public static Space format(String formatting) { last = c; } + if ((comment.length() > 0)) { + comments.add(new Comment(inLineSlashOrHashComment, comment.toString(), prefix.toString(), Markers.EMPTY)); + prefix = new StringBuilder(); + } + // Shift the whitespace on each comment forward to be a suffix of the comment before it, and the // whitespace on the first comment to be the whitespace of the tree element. The remaining prefix is the suffix // of the last comment. diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java index 391964d5319..3a6d872b02d 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java @@ -16,7 +16,6 @@ package org.openrewrite.hcl.tree; import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.ExpectedToFail; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -101,7 +100,6 @@ void inLineCommentsNextLineAttribute() { ); } - @ExpectedToFail @Issue("https://github.com/openrewrite/rewrite/issues/4611") @Test void commentAsTheLastLine() { @@ -116,4 +114,20 @@ void commentAsTheLastLine() { ) ); } + + @Issue("https://github.com/openrewrite/rewrite/issues/4611") + @Test + void commentsAsTheFinalLines() { + rewriteRun( + hcl( + """ + locals { + a = 3 + } + # Nice code, right? + # Isn't it? + """ + ) + ); + } } From c2e5624c457e3d61830b47c75f9f895e5f4149f4 Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Wed, 8 Jan 2025 08:04:08 +0100 Subject: [PATCH 115/179] Replacing dependency on commons-compress with commons-lang3 (#4863) --- rewrite-core/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewrite-core/build.gradle.kts b/rewrite-core/build.gradle.kts index e3a59325a5f..cce20ae54f8 100644 --- a/rewrite-core/build.gradle.kts +++ b/rewrite-core/build.gradle.kts @@ -15,7 +15,7 @@ dependencies { api("org.jspecify:jspecify:latest.release") - implementation("org.apache.commons:commons-compress:latest.release") + implementation("org.apache.commons:commons-lang3:latest.release") implementation("io.micrometer:micrometer-core:1.9.+") implementation("io.github.classgraph:classgraph:latest.release") From 789ac5ffaadde114b9b5254e7a9351f0029f364a Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Wed, 8 Jan 2025 08:04:30 +0100 Subject: [PATCH 116/179] Fixing handing of # or // within multiline comments (#4864) --- .../java/org/openrewrite/hcl/tree/Space.java | 14 +++--- .../openrewrite/hcl/tree/HclCommentTest.java | 45 +++++++++++++++++++ 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java index 854b9299aee..31d5fa2f4e8 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java @@ -158,14 +158,14 @@ public static Space format(String formatting) { case '#': if (Comment.Style.LINE_SLASH == inLineSlashOrHashComment) { comment.append(c); + } else if (inSingleLineComment) { + comment.append(c); + } else if (inMultiLineComment) { + comment.append(c); } else { - if (inSingleLineComment) { - comment.append(c); - } else { - inSingleLineComment = true; - inLineSlashOrHashComment = Comment.Style.LINE_HASH; - comment = new StringBuilder(); - } + inSingleLineComment = true; + inLineSlashOrHashComment = Comment.Style.LINE_HASH; + comment = new StringBuilder(); } break; case '/': diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java index 3a6d872b02d..7750b722d14 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java @@ -130,4 +130,49 @@ void commentsAsTheFinalLines() { ) ); } + + @Test + void singeLineWithinMultiLineHash() { + rewriteRun( + hcl( + """ + /* + # It's important + */ + locals { + Anwil = "Wloclawek" + } + """ + ) + ); + } + + @Test + void singeLineWithinMultiLineSlash() { + rewriteRun( + hcl( + """ + /* + // It's important + */ + locals { + Anwil = "Wloclawek" + } + """ + ) + ); + } + + @Test + void multilineNotStartingInTheFirstCharacter() { + rewriteRun( + hcl( + """ + /* An indented comment + */ + """ + ) + ); + } + } From 6bfac941901f4b774fa21bb2996043d40f6bb2fd Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Wed, 8 Jan 2025 08:22:28 +0100 Subject: [PATCH 117/179] Mark `PlainText` all-args constructor as private Add back the previous constructor without the `SoftReference` as public. --- .../java/org/openrewrite/text/PlainText.java | 16 +++++++++++++- .../org/openrewrite/text/PlainTextParser.java | 22 ++++++------------- .../org/openrewrite/protobuf/ProtoParser.java | 22 ++++++------------- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/text/PlainText.java b/rewrite-core/src/main/java/org/openrewrite/text/PlainText.java index cf538bca0ec..623122d9921 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/PlainText.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/PlainText.java @@ -38,7 +38,7 @@ */ @Value @Builder -@AllArgsConstructor +@AllArgsConstructor(access = AccessLevel.PRIVATE) public class PlainText implements SourceFileWithReferences, Tree { @Builder.Default @@ -82,6 +82,7 @@ public SourceFile withCharset(Charset charset) { @Builder.Default String text = ""; + @Nullable List snippets; @Nullable @@ -89,6 +90,19 @@ public SourceFile withCharset(Charset charset) { @ToString.Exclude transient SoftReference references; + public PlainText(UUID id, Path sourcePath, Markers markers, @Nullable String charsetName, boolean charsetBomMarked, + @Nullable FileAttributes fileAttributes, @Nullable Checksum checksum, String text, @Nullable List snippets) { + this.id = id; + this.sourcePath = sourcePath; + this.markers = markers; + this.charsetName = charsetName; + this.charsetBomMarked = charsetBomMarked; + this.fileAttributes = fileAttributes; + this.checksum = checksum; + this.text = text; + this.snippets = snippets; + } + @Override public References getReferences() { this.references = build(this.references); diff --git a/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java b/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java index eb0d6281f0a..a1a105e9331 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/PlainTextParser.java @@ -20,7 +20,6 @@ import org.openrewrite.Parser; import org.openrewrite.SourceFile; import org.openrewrite.internal.EncodingDetectingInputStream; -import org.openrewrite.marker.Markers; import org.openrewrite.tree.ParseError; import org.openrewrite.tree.ParsingEventListener; import org.openrewrite.tree.ParsingExecutionContextView; @@ -34,8 +33,6 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -import static org.openrewrite.Tree.randomId; - public class PlainTextParser implements Parser { /** @@ -73,18 +70,13 @@ public Stream parseInputs(Iterable sources, @Nullable Path re try { EncodingDetectingInputStream is = input.getSource(ctx); String sourceStr = is.readFully(); - PlainText plainText = new PlainText( - randomId(), - path, - Markers.EMPTY, - is.getCharset().name(), - is.isCharsetBomMarked(), - input.getFileAttributes(), - null, - sourceStr, - null, - null - ); + PlainText plainText = PlainText.builder() + .sourcePath(path) + .charsetName(is.getCharset().name()) + .charsetBomMarked(is.isCharsetBomMarked()) + .fileAttributes(input.getFileAttributes()) + .text(sourceStr) + .build(); parsingListener.parsed(input, plainText); return plainText; } catch (Throwable t) { diff --git a/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java b/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java index d491f8506f4..acae7b05ab3 100644 --- a/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java +++ b/rewrite-protobuf/src/main/java/org/openrewrite/protobuf/ProtoParser.java @@ -23,7 +23,6 @@ import org.openrewrite.Parser; import org.openrewrite.SourceFile; import org.openrewrite.internal.EncodingDetectingInputStream; -import org.openrewrite.marker.Markers; import org.openrewrite.protobuf.internal.ProtoParserVisitor; import org.openrewrite.protobuf.internal.grammar.Protobuf2Lexer; import org.openrewrite.protobuf.internal.grammar.Protobuf2Parser; @@ -36,8 +35,6 @@ import java.nio.file.Path; import java.util.stream.Stream; -import static org.openrewrite.Tree.randomId; - public class ProtoParser implements Parser { @Override @@ -57,18 +54,13 @@ public Stream parseInputs(Iterable sourceFiles, @Nullable Pat if (sourceStr.contains("proto3")) { // Pending Proto3 support, the best we can do is plain text & not skip files - return new PlainText( - randomId(), - path, - Markers.EMPTY, - is.getCharset().name(), - is.isCharsetBomMarked(), - input.getFileAttributes(), - null, - sourceStr, - null, - null - ); + return PlainText.builder() + .sourcePath(path) + .charsetName(is.getCharset().name()) + .charsetBomMarked(is.isCharsetBomMarked()) + .fileAttributes(input.getFileAttributes()) + .text(sourceStr) + .build(); } Proto.Document document = new ProtoParserVisitor( From 3b3a56cfc9986827b2301f3d39745e067ece4ac1 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Wed, 8 Jan 2025 09:38:59 +0100 Subject: [PATCH 118/179] Check for `null` in `TabsAndIndentsVisitor#visitContainer()` In case the caller doesn't have a guard on this. --- .../org/openrewrite/java/format/TabsAndIndentsVisitor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/format/TabsAndIndentsVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/format/TabsAndIndentsVisitor.java index a69183dd763..3a51e8c3617 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/format/TabsAndIndentsVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/format/TabsAndIndentsVisitor.java @@ -354,7 +354,11 @@ public Space visitSpace(Space space, Space.Location loc, P p) { } @Override - public JContainer visitContainer(JContainer container, JContainer.Location loc, P p) { + public @Nullable JContainer visitContainer(@Nullable JContainer container, JContainer.Location loc, P p) { + if (container == null) { + return null; + } + setCursor(new Cursor(getCursor(), container)); Space before; From 13b61683b7f07a46431712326cd3b3f1018e8ba3 Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Wed, 8 Jan 2025 12:23:16 +0100 Subject: [PATCH 119/179] fixing comment nesting in positionOfNext() (#4866) --- .../hcl/internal/HclParserVisitor.java | 6 ++++-- .../org/openrewrite/hcl/tree/HclCommentTest.java | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java index d729bdffc15..1f3e317eaf0 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java @@ -742,8 +742,10 @@ private int positionOfNext(String untilDelim, @Nullable Character stop) { int delimIndex = cursor; for (; delimIndex < source.length() - untilDelim.length() + 1; delimIndex++) { - if (inSingleLineComment && source.charAt(delimIndex) == '\n') { - inSingleLineComment = false; + if (inSingleLineComment) { + if (source.charAt(delimIndex) == '\n') { + inSingleLineComment = false; + } } else { if (source.length() - untilDelim.length() > delimIndex + 1) { if ('#' == source.charAt(delimIndex)) { diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java index 7750b722d14..e67ff4ad5e6 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java @@ -175,4 +175,20 @@ void multilineNotStartingInTheFirstCharacter() { ); } + @Test + void commentedOutLinesInListLiteral() { + rewriteRun( + hcl( + """ + locals { + resources = [ + "arn:aws:s3:::${var.my_precious_bucket}", + "arn:aws:s3:::${var.waste_bucket}", + # "arn:aws:s3:::just-some-bucket/*", + ] + } + """ + ) + ); + } } From 1bb9da0645fae7cb23e8850115bd60632cba1ed9 Mon Sep 17 00:00:00 2001 From: Nate Danner Date: Thu, 9 Jan 2025 03:17:44 -0800 Subject: [PATCH 120/179] fix: create dependencyResourceLoaders in 2 passes (#4870) * fix: create dependencyResourceLoaders in 2 passes * Inline variables used once --------- Co-authored-by: Tim te Beek --- .../org/openrewrite/config/Environment.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/config/Environment.java b/rewrite-core/src/main/java/org/openrewrite/config/Environment.java index 3cabc8c209a..64179d985ab 100644 --- a/rewrite-core/src/main/java/org/openrewrite/config/Environment.java +++ b/rewrite-core/src/main/java/org/openrewrite/config/Environment.java @@ -249,12 +249,23 @@ public Builder scanYamlResources() { */ @SuppressWarnings("unused") public Builder scanJar(Path jar, Collection dependencies, ClassLoader classLoader) { - List list = new ArrayList<>(); + List firstPassLoaderList = new ArrayList<>(); for (Path dep : dependencies) { - ClasspathScanningLoader classpathScanningLoader = new ClasspathScanningLoader(dep, properties, emptyList(), classLoader); - list.add(classpathScanningLoader); + firstPassLoaderList.add(new ClasspathScanningLoader(dep, properties, emptyList(), classLoader)); } - return load(new ClasspathScanningLoader(jar, properties, list, classLoader), list); + + /* + * Second loader creation pass where the firstPassLoaderList is passed as the + * dependencyResourceLoaders list to ensure that we can resolve transitive + * dependencies using the loaders we just created. This is necessary because + * the first pass may have missing recipes since the full list of loaders was + * not provided. + */ + List secondPassLoaderList = new ArrayList<>(); + for (Path dep : dependencies) { + secondPassLoaderList.add(new ClasspathScanningLoader(dep, properties, firstPassLoaderList, classLoader)); + } + return load(new ClasspathScanningLoader(jar, properties, secondPassLoaderList, classLoader), secondPassLoaderList); } @SuppressWarnings("unused") From 7566b00e462f60f148a69beee3aab839d23c2471 Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Thu, 9 Jan 2025 13:24:29 +0100 Subject: [PATCH 121/179] HCL - Fixing empty comment handling (#4871) * Fixing empty comment handling * Newline Co-authored-by: Tim te Beek --------- Co-authored-by: Tim te Beek --- .../hcl/internal/HclParserVisitor.java | 7 ++-- .../openrewrite/hcl/tree/HclCommentTest.java | 36 +++++++++++++++++-- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java index 1f3e317eaf0..00aa2b37f4f 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java @@ -750,19 +750,18 @@ private int positionOfNext(String untilDelim, @Nullable Character stop) { if (source.length() - untilDelim.length() > delimIndex + 1) { if ('#' == source.charAt(delimIndex)) { inSingleLineComment = true; - delimIndex++; } else switch (source.substring(delimIndex, delimIndex + 2)) { case "//": inSingleLineComment = true; - delimIndex += 2; + delimIndex += 1; break; case "/*": inMultiLineComment = true; - delimIndex += 2; + delimIndex += 1; break; case "*/": inMultiLineComment = false; - delimIndex += 2; + delimIndex += 1; break; } } diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java index e67ff4ad5e6..bf72c18586c 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclCommentTest.java @@ -132,7 +132,7 @@ void commentsAsTheFinalLines() { } @Test - void singeLineWithinMultiLineHash() { + void singleLineWithinMultiLineHash() { rewriteRun( hcl( """ @@ -148,7 +148,7 @@ void singeLineWithinMultiLineHash() { } @Test - void singeLineWithinMultiLineSlash() { + void singleLineWithinMultiLineSlash() { rewriteRun( hcl( """ @@ -191,4 +191,36 @@ void commentedOutLinesInListLiteral() { ) ); } + + @Test + void emptyHashCommentJustBeforeCurlyBraceEnd() { + rewriteRun( + hcl( + """ + locals { + # + } + module "something" { + source = "../else/" + } + """ + ) + ); + } + + @Test + void emptyDoubleSlashCommentJustBeforeCurlyBraceEnd() { + rewriteRun( + hcl( + """ + locals { + // + } + module "something" { + source = "../else/" + } + """ + ) + ); + } } From 0826417f314d88c67bd136f8785bfe94ee5faefd Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 9 Jan 2025 13:24:34 +0100 Subject: [PATCH 122/179] RemoveUnusedProperties should not fail on Quarks Fixes #4873 Fixes #4872 --- .../org/openrewrite/maven/RemoveUnusedProperties.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveUnusedProperties.java b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveUnusedProperties.java index 59fc3fc889a..913a3f4bf39 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveUnusedProperties.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/RemoveUnusedProperties.java @@ -19,11 +19,14 @@ import lombok.Value; import org.jspecify.annotations.Nullable; import org.openrewrite.*; +import org.openrewrite.binary.Binary; import org.openrewrite.java.tree.JavaSourceFile; import org.openrewrite.maven.internal.MavenPomDownloader; import org.openrewrite.maven.tree.MavenResolutionResult; import org.openrewrite.maven.tree.ResolvedGroupArtifactVersion; import org.openrewrite.maven.tree.ResolvedPom; +import org.openrewrite.quark.Quark; +import org.openrewrite.remote.Remote; import org.openrewrite.text.PlainText; import org.openrewrite.text.PlainTextParser; import org.openrewrite.text.PlainTextVisitor; @@ -97,6 +100,9 @@ public TreeVisitor getScanner(RemoveUnusedProperties.Accumu return new TreeVisitor() { @Override public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) { + if (tree instanceof Quark || tree instanceof Remote || tree instanceof Binary) { + return tree; + } if (tree instanceof SourceFile) { SourceFile sf = (SourceFile) tree; if (findPomUsagesVisitor.isAcceptable(sf, ctx)) { // ie: is a pom @@ -232,7 +238,7 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { if (resourceMatcher.matches(getCursor())) { String directory = tag.getChildValue("directory").orElse(null); if (tag.getChildValue("filtering").map(Boolean::valueOf).orElse(false) && - directory != null) { + directory != null) { Path path = getCursor().firstEnclosingOrThrow(SourceFile.class).getSourcePath(); try { acc.filteredResourcePathsToDeclaringPoms.put(path.getParent().resolve(directory), getResolutionResult()); From d11eae939d91309a414e3028bd800457c84ef30c Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 9 Jan 2025 15:53:56 +0100 Subject: [PATCH 123/179] ExplicitPluginGroupId should only add groupId if artifactId is present Fixes #4875 --- .../org/openrewrite/maven/cleanup/ExplicitPluginGroupId.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/cleanup/ExplicitPluginGroupId.java b/rewrite-maven/src/main/java/org/openrewrite/maven/cleanup/ExplicitPluginGroupId.java index 25e50422922..452c01b7eb2 100755 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/cleanup/ExplicitPluginGroupId.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/cleanup/ExplicitPluginGroupId.java @@ -44,7 +44,7 @@ public TreeVisitor getVisitor() { @Override public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) { Xml.Tag t = (Xml.Tag) super.visitTag(tag, ctx); - if (isPluginTag() && !t.getChild("groupId").isPresent()) { + if (isPluginTag() && !t.getChild("groupId").isPresent() && t.getChild("artifactId").isPresent()) { Xml.Tag groupIdTag = Xml.Tag.build("org.apache.maven.plugins"); t = (Xml.Tag) new AddToTagVisitor<>(t, groupIdTag, new MavenTagInsertionComparator(t.getChildren())) .visitNonNull(t, ctx, getCursor().getParentOrThrow()); From 82b61dea078ea32a4686e91362c91ccae9a4ddef Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 9 Jan 2025 17:06:23 +0100 Subject: [PATCH 124/179] Map trailing commas as `TrailingComma` `Marker`, to fix `J.Erroneous` issues seen (#4869) * Do not allow J.Erroneous LST nodes by default in tests * Allow erroneous nodes in FindCompileErrorsTest * Use `TrailingComma` marker for enum values and array initializers Add an overload for `ReloadableJava17ParserVisitor#convert()` which allows supplying a `Markers` function, so that we can capture trailing commas using a `TrailingComma` marker and then also avoid the issue with the `J.Erroneous` getting constructed. * Update whitespace handling for last enum constant The last enum constant should only be right-padded if it has a trailing comma or semicolon. This is important because the whitespace after it belongs to the prefix of the next statement or the `J.Block#end`. * Allow errorneous nodes in specific tests * Update JavaDoc for typeValidation.erroneous after feedback * Use overloaded method * Apply to Java 21 parser as well * Format Java 21 parser * Apply to Java 11 parser as well * Apply to Java 8 parser as well * Fix failing tests * Minimize diff between versions to make it easier to compare --------- Co-authored-by: Knut Wannheden Co-authored-by: Laurens Westerlaken --- .../ReloadableJava11ParserVisitor.java | 98 +++++++++++++------ .../ReloadableJava17ParserVisitor.java | 89 ++++++++++++----- .../ReloadableJava21ParserVisitor.java | 91 ++++++++++++----- .../java/ReloadableJava8ParserVisitor.java | 75 ++++++++++---- .../openrewrite/java/tree/AnnotationTest.java | 15 +++ .../org/openrewrite/java/tree/EnumTest.java | 31 ++++-- .../openrewrite/java/tree/NewArrayTest.java | 2 - .../org/openrewrite/java/JavaParserTest.java | 6 +- .../org/openrewrite/java/JavaVisitorTest.java | 33 ++++--- .../java/org/openrewrite/java/Assertions.java | 22 ++++- .../org/openrewrite/java/JavaPrinter.java | 11 +++ .../java/org/openrewrite/java/tree/Space.java | 21 ++-- .../java/search/FindCompileErrorsTest.java | 3 +- .../org/openrewrite/test/TypeValidation.java | 9 +- 14 files changed, 363 insertions(+), 143 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index b8dd7a5d14f..a9972f1e672 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -38,6 +38,7 @@ import org.openrewrite.java.JavaPrinter; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.OmitParentheses; +import org.openrewrite.java.marker.TrailingComma; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; import org.openrewrite.style.NamedStyles; @@ -327,7 +328,7 @@ public J visitBreak(BreakTree node, Space fmt) { J.Identifier label = node.getLabel() == null ? null : new J.Identifier(randomId(), sourceBefore(node.getLabel().toString()), Markers.EMPTY, - emptyList(), skip(node.getLabel().toString()), null, null); + emptyList(), node.getLabel().toString(), null, null); return new J.Break(randomId(), fmt, Markers.EMPTY, label); } @@ -420,13 +421,31 @@ public J visitClass(ClassTree node, Space fmt) { JRightPadded enumSet = null; if (!jcEnums.isEmpty()) { - AtomicBoolean semicolonPresent = new AtomicBoolean(false); - + Tree lastConstant = jcEnums.get(jcEnums.size() - 1); List> enumValues = convertAll(jcEnums, commaDelim, t -> { - // this semicolon is required when there are non-value members, but can still - // be present when there are not - semicolonPresent.set(positionOfNext(";", '}') > 0); - return semicolonPresent.get() ? sourceBefore(";", '}') : EMPTY; + if (t != lastConstant) { + return whitespace(); + } + int savedCursor = cursor; + Space suffix = whitespace(); + if (source.charAt(cursor) == ',' || source.charAt(cursor) == ';') { + return suffix; + } + // Whitespace should be assigned to prefix of next statement or `J.Block#end` + cursor = savedCursor; + return EMPTY; + }, t -> { + if (t == lastConstant && skip(",") != null) { + int savedCursor = cursor; + Space suffix = whitespace(); + if (source.charAt(cursor) == ';') { + return Markers.build(singletonList(new TrailingComma(randomId(), suffix))); + } + // Whitespace should be assigned to prefix of next statement or `J.Block#end` + cursor = savedCursor; + return Markers.build(singletonList(new TrailingComma(randomId(), EMPTY))); + } + return Markers.EMPTY; }); enumSet = padRight( @@ -435,7 +454,7 @@ public J visitClass(ClassTree node, Space fmt) { EMPTY, Markers.EMPTY, enumValues, - semicolonPresent.get() + skip(";") != null ), EMPTY ); @@ -1010,7 +1029,14 @@ public J visitNewArray(NewArrayTree node, Space fmt) { JContainer initializer = node.getInitializers() == null ? null : JContainer.build(sourceBefore("{"), node.getInitializers().isEmpty() ? singletonList(padRight(new J.Empty(randomId(), sourceBefore("}"), Markers.EMPTY), EMPTY)) : - convertAll(node.getInitializers(), commaDelim, t -> sourceBefore("}")), Markers.EMPTY); + convertAll(node.getInitializers(), commaDelim, t -> whitespace(), t -> { + if (t == node.getInitializers().get(node.getInitializers().size() - 1) && source.charAt(cursor) == ',') { + cursor++; + return Markers.build(singletonList(new TrailingComma(randomId(), whitespace()))); + } + return Markers.EMPTY; + }), Markers.EMPTY); + skip("}"); return new J.NewArray(randomId(), fmt, Markers.EMPTY, typeExpr, dimensions, initializer, typeMapping.type(node)); @@ -1622,7 +1648,6 @@ public J visitWildcard(WildcardTree node, Space fmt) { * Conversion utilities * -------------- */ - private @Nullable J2 convert(@Nullable Tree t) { if (t == null) { return null; @@ -1667,20 +1692,24 @@ private static int getActualStartPosition(JCTree t) { } private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix) { + return convert(t, suffix, j -> Markers.EMPTY); + } + + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix, Function markers) { if (t == null) { return null; } J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : - new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); + new JRightPadded<>(j, suffix.apply(t), markers.apply(t)); int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace()); if (idx >= 0) { rightPadded = (JRightPadded) JRightPadded.build(getErroneous(List.of(rightPadded))); } // Cursor hasn't been updated but points at the end of erroneous node already // This means that error node start position == end position - // Therefore ensure that cursor has moved to the end of erroneous node bu adding its length to the cursor - // Example `/pet` results in 2 erroeneous nodes: `/` and `pet`. The `/` node would have start and end position the + // Therefore ensure that cursor has moved to the end of erroneous node but adding its length to the cursor + // Example `/pet` results in 2 erroneous nodes: `/` and `pet`. The `/` node would have start and end position the // same from the JC compiler. if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) { cursor += ((J.Erroneous) rightPadded.getElement()).getText().length(); @@ -1691,8 +1720,8 @@ private static int getActualStartPosition(JCTree t) { } private J.Erroneous getErroneous(List> converted) { - PrintOutputCapture p = new PrintOutputCapture<>(0); - new JavaPrinter<>().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); + PrintOutputCapture p = new PrintOutputCapture<>(0); + new JavaPrinter().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); return new J.Erroneous( org.openrewrite.Tree.randomId(), EMPTY, @@ -1725,13 +1754,20 @@ private List convertAll(List trees) { private List> convertAll(List trees, Function innerSuffix, Function suffix) { + return convertAll(trees, innerSuffix, suffix, t -> Markers.EMPTY); + } + + private List> convertAll(List trees, + Function innerSuffix, + Function suffix, + Function markers) { int size = trees.size(); if (size == 0) { return emptyList(); } List> converted = new ArrayList<>(size); for (int i = 0; i < size; i++) { - converted.add(convert(trees.get(i), i == size - 1 ? suffix : innerSuffix)); + converted.add(convert(trees.get(i), i == size - 1 ? suffix : innerSuffix, markers)); } return converted; } @@ -1756,17 +1792,17 @@ private List> convertAll(List tr private Space statementDelim(@Nullable Tree t) { if (t instanceof JCAssert || - t instanceof JCAssign || - t instanceof JCAssignOp || - t instanceof JCBreak || - t instanceof JCContinue || - t instanceof JCDoWhileLoop || - t instanceof JCImport || - t instanceof JCMethodInvocation || - t instanceof JCNewClass || - t instanceof JCReturn || - t instanceof JCThrow || - t instanceof JCUnary) { + t instanceof JCAssign || + t instanceof JCAssignOp || + t instanceof JCBreak || + t instanceof JCContinue || + t instanceof JCDoWhileLoop || + t instanceof JCImport || + t instanceof JCMethodInvocation || + t instanceof JCNewClass || + t instanceof JCReturn || + t instanceof JCThrow || + t instanceof JCUnary) { return sourceBefore(";"); } @@ -1933,6 +1969,7 @@ private Space sourceBefore(String untilDelim, @Nullable Character stop) { cursor += untilDelim.length(); return EMPTY; } + Space space = format(source, cursor, delimIndex); cursor = delimIndex + untilDelim.length(); // advance past the delimiter return space; @@ -2011,15 +2048,16 @@ private Space whitespace() { return space; } - private String skip(@Nullable String token) { + private @Nullable String skip(@Nullable String token) { if (token == null) { //noinspection ConstantConditions return null; } if (source.startsWith(token, cursor)) { cursor += token.length(); + return token; } - return token; + return null; } // Only exists as a function to make it easier to debug unexpected cursor shifts @@ -2040,7 +2078,7 @@ private List listFlags(long flags) { try { // FIXME instanceof probably not right here... return field.get(null) instanceof Long && - field.getName().matches("[A-Z_]+"); + field.getName().matches("[A-Z_]+"); } catch (IllegalAccessException e) { throw new RuntimeException(e); } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 9f56bfb0b3c..738a3fe7c23 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -39,6 +39,7 @@ import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.CompactConstructor; import org.openrewrite.java.marker.OmitParentheses; +import org.openrewrite.java.marker.TrailingComma; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; import org.openrewrite.style.NamedStyles; @@ -51,7 +52,6 @@ import java.nio.charset.Charset; import java.nio.file.Path; import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.regex.Matcher; @@ -334,7 +334,7 @@ public J visitBreak(BreakTree node, Space fmt) { J.Identifier label = node.getLabel() == null ? null : new J.Identifier(randomId(), sourceBefore(node.getLabel().toString()), Markers.EMPTY, - emptyList(), skip(node.getLabel().toString()), null, null); + emptyList(), node.getLabel().toString(), null, null); return new J.Break(randomId(), fmt, Markers.EMPTY, label); } @@ -476,13 +476,31 @@ public J visitClass(ClassTree node, Space fmt) { JRightPadded enumSet = null; if (!jcEnums.isEmpty()) { - AtomicBoolean semicolonPresent = new AtomicBoolean(false); - + Tree lastConstant = jcEnums.get(jcEnums.size() - 1); List> enumValues = convertAll(jcEnums, commaDelim, t -> { - // this semicolon is required when there are non-value members, but can still - // be present when there are not - semicolonPresent.set(positionOfNext(";", '}') > 0); - return semicolonPresent.get() ? sourceBefore(";", '}') : EMPTY; + if (t != lastConstant) { + return whitespace(); + } + int savedCursor = cursor; + Space suffix = whitespace(); + if (source.charAt(cursor) == ',' || source.charAt(cursor) == ';') { + return suffix; + } + // Whitespace should be assigned to prefix of next statement or `J.Block#end` + cursor = savedCursor; + return EMPTY; + }, t -> { + if (t == lastConstant && skip(",") != null) { + int savedCursor = cursor; + Space suffix = whitespace(); + if (source.charAt(cursor) == ';') { + return Markers.build(singletonList(new TrailingComma(randomId(), suffix))); + } + // Whitespace should be assigned to prefix of next statement or `J.Block#end` + cursor = savedCursor; + return Markers.build(singletonList(new TrailingComma(randomId(), EMPTY))); + } + return Markers.EMPTY; }); enumSet = padRight( @@ -491,7 +509,7 @@ public J visitClass(ClassTree node, Space fmt) { EMPTY, Markers.EMPTY, enumValues, - semicolonPresent.get() + skip(";") != null ), EMPTY ); @@ -1079,7 +1097,14 @@ public J visitNewArray(NewArrayTree node, Space fmt) { JContainer initializer = node.getInitializers() == null ? null : JContainer.build(sourceBefore("{"), node.getInitializers().isEmpty() ? singletonList(padRight(new J.Empty(randomId(), sourceBefore("}"), Markers.EMPTY), EMPTY)) : - convertAll(node.getInitializers(), commaDelim, t -> sourceBefore("}")), Markers.EMPTY); + convertAll(node.getInitializers(), commaDelim, t -> whitespace(), t -> { + if (t == node.getInitializers().get(node.getInitializers().size() - 1) && source.charAt(cursor) == ',') { + cursor++; + return Markers.build(singletonList(new TrailingComma(randomId(), whitespace()))); + } + return Markers.EMPTY; + }), Markers.EMPTY); + skip("}"); return new J.NewArray(randomId(), fmt, Markers.EMPTY, typeExpr, dimensions, initializer, typeMapping.type(node)); @@ -1722,14 +1747,6 @@ public J visitWildcard(WildcardTree node, Space fmt) { } } - private static int getActualStartPosition(JCTree t) { - // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation - if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { - return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); - } - return t.getStartPosition(); - } - private void reportJavaParsingException(Throwable ex) { // this SHOULD never happen, but is here simply as a diagnostic measure in the event of unexpected exceptions StringBuilder message = new StringBuilder("Failed to convert for the following cursor stack:"); @@ -1754,21 +1771,33 @@ private void reportJavaParsingException(Throwable ex) { ctx.getOnError().accept(new JavaParsingException(message.toString(), ex)); } + private static int getActualStartPosition(JCTree t) { + // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation + if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { + return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); + } + return t.getStartPosition(); + } + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix) { + return convert(t, suffix, j -> Markers.EMPTY); + } + + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix, Function markers) { if (t == null) { return null; } J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : - new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); + new JRightPadded<>(j, suffix.apply(t), markers.apply(t)); int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace()); if (idx >= 0) { rightPadded = (JRightPadded) JRightPadded.build(getErroneous(List.of(rightPadded))); } // Cursor hasn't been updated but points at the end of erroneous node already // This means that error node start position == end position - // Therefore ensure that cursor has moved to the end of erroneous node bu adding its length to the cursor - // Example `/pet` results in 2 erroeneous nodes: `/` and `pet`. The `/` node would have start and end position the + // Therefore ensure that cursor has moved to the end of erroneous node but adding its length to the cursor + // Example `/pet` results in 2 erroneous nodes: `/` and `pet`. The `/` node would have start and end position the // same from the JC compiler. if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) { cursor += ((J.Erroneous) rightPadded.getElement()).getText().length(); @@ -1779,8 +1808,8 @@ private void reportJavaParsingException(Throwable ex) { } private J.Erroneous getErroneous(List> converted) { - PrintOutputCapture p = new PrintOutputCapture<>(0); - new JavaPrinter<>().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); + PrintOutputCapture p = new PrintOutputCapture<>(0); + new JavaPrinter().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); return new J.Erroneous( org.openrewrite.Tree.randomId(), EMPTY, @@ -1813,13 +1842,20 @@ private List convertAll(List trees) { private List> convertAll(List trees, Function innerSuffix, Function suffix) { + return convertAll(trees, innerSuffix, suffix, t -> Markers.EMPTY); + } + + private List> convertAll(List trees, + Function innerSuffix, + Function suffix, + Function markers) { int size = trees.size(); if (size == 0) { return emptyList(); } List> converted = new ArrayList<>(size); for (int i = 0; i < size; i++) { - converted.add(convert(trees.get(i), i == size - 1 ? suffix : innerSuffix)); + converted.add(convert(trees.get(i), i == size - 1 ? suffix : innerSuffix, markers)); } return converted; } @@ -2093,15 +2129,16 @@ private Space whitespace() { return space; } - private String skip(@Nullable String token) { + private @Nullable String skip(@Nullable String token) { if (token == null) { //noinspection ConstantConditions return null; } if (source.startsWith(token, cursor)) { cursor += token.length(); + return token; } - return token; + return null; } // Only exists as a function to make it easier to debug unexpected cursor shifts diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index c1c20fd3ff4..b49c1f1563a 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -39,6 +39,7 @@ import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.marker.CompactConstructor; import org.openrewrite.java.marker.OmitParentheses; +import org.openrewrite.java.marker.TrailingComma; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; import org.openrewrite.style.NamedStyles; @@ -51,7 +52,6 @@ import java.nio.charset.Charset; import java.nio.file.Path; import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.regex.Matcher; @@ -334,7 +334,7 @@ public J visitBreak(BreakTree node, Space fmt) { J.Identifier label = node.getLabel() == null ? null : new J.Identifier(randomId(), sourceBefore(node.getLabel().toString()), Markers.EMPTY, - emptyList(), skip(node.getLabel().toString()), null, null); + emptyList(), node.getLabel().toString(), null, null); return new J.Break(randomId(), fmt, Markers.EMPTY, label); } @@ -476,13 +476,31 @@ public J visitClass(ClassTree node, Space fmt) { JRightPadded enumSet = null; if (!jcEnums.isEmpty()) { - AtomicBoolean semicolonPresent = new AtomicBoolean(false); - + Tree lastConstant = jcEnums.get(jcEnums.size() - 1); List> enumValues = convertAll(jcEnums, commaDelim, t -> { - // this semicolon is required when there are non-value members, but can still - // be present when there are not - semicolonPresent.set(positionOfNext(";", '}') > 0); - return semicolonPresent.get() ? sourceBefore(";", '}') : EMPTY; + if (t != lastConstant) { + return whitespace(); + } + int savedCursor = cursor; + Space suffix = whitespace(); + if (source.charAt(cursor) == ',' || source.charAt(cursor) == ';') { + return suffix; + } + // Whitespace should be assigned to prefix of next statement or `J.Block#end` + cursor = savedCursor; + return EMPTY; + }, t -> { + if (t == lastConstant && skip(",") != null) { + int savedCursor = cursor; + Space suffix = whitespace(); + if (source.charAt(cursor) == ';') { + return Markers.build(singletonList(new TrailingComma(randomId(), suffix))); + } + // Whitespace should be assigned to prefix of next statement or `J.Block#end` + cursor = savedCursor; + return Markers.build(singletonList(new TrailingComma(randomId(), EMPTY))); + } + return Markers.EMPTY; }); enumSet = padRight( @@ -491,7 +509,7 @@ public J visitClass(ClassTree node, Space fmt) { EMPTY, Markers.EMPTY, enumValues, - semicolonPresent.get() + skip(";") != null ), EMPTY ); @@ -1079,7 +1097,14 @@ public J visitNewArray(NewArrayTree node, Space fmt) { JContainer initializer = node.getInitializers() == null ? null : JContainer.build(sourceBefore("{"), node.getInitializers().isEmpty() ? singletonList(padRight(new J.Empty(randomId(), sourceBefore("}"), Markers.EMPTY), EMPTY)) : - convertAll(node.getInitializers(), commaDelim, t -> sourceBefore("}")), Markers.EMPTY); + convertAll(node.getInitializers(), commaDelim, t -> whitespace(), t -> { + if (t == node.getInitializers().get(node.getInitializers().size() - 1) && source.charAt(cursor) == ',') { + cursor++; + return Markers.build(singletonList(new TrailingComma(randomId(), whitespace()))); + } + return Markers.EMPTY; + }), Markers.EMPTY); + skip("}"); return new J.NewArray(randomId(), fmt, Markers.EMPTY, typeExpr, dimensions, initializer, typeMapping.type(node)); @@ -1722,14 +1747,6 @@ public J visitWildcard(WildcardTree node, Space fmt) { } } - private static int getActualStartPosition(JCTree t) { - // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation - if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { - return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); - } - return t.getStartPosition(); - } - private void reportJavaParsingException(Throwable ex) { // this SHOULD never happen, but is here simply as a diagnostic measure in the event of unexpected exceptions StringBuilder message = new StringBuilder("Failed to convert for the following cursor stack:"); @@ -1754,21 +1771,33 @@ private void reportJavaParsingException(Throwable ex) { ctx.getOnError().accept(new JavaParsingException(message.toString(), ex)); } + private static int getActualStartPosition(JCTree t) { + // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation + if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { + return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); + } + return t.getStartPosition(); + } + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix) { + return convert(t, suffix, j -> Markers.EMPTY); + } + + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix, Function markers) { if (t == null) { return null; } J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : - new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); + new JRightPadded<>(j, suffix.apply(t), markers.apply(t)); int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace()); if (idx >= 0) { rightPadded = (JRightPadded) JRightPadded.build(getErroneous(List.of(rightPadded))); } // Cursor hasn't been updated but points at the end of erroneous node already // This means that error node start position == end position - // Therefore ensure that cursor has moved to the end of erroneous node bu adding its length to the cursor - // Example `/pet` results in 2 erroeneous nodes: `/` and `pet`. The `/` node would have start and end position the + // Therefore ensure that cursor has moved to the end of erroneous node but adding its length to the cursor + // Example `/pet` results in 2 erroneous nodes: `/` and `pet`. The `/` node would have start and end position the // same from the JC compiler. if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) { cursor += ((J.Erroneous) rightPadded.getElement()).getText().length(); @@ -1779,8 +1808,8 @@ private void reportJavaParsingException(Throwable ex) { } private J.Erroneous getErroneous(List> converted) { - PrintOutputCapture p = new PrintOutputCapture<>(0); - new JavaPrinter<>().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); + PrintOutputCapture p = new PrintOutputCapture<>(0); + new JavaPrinter().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); return new J.Erroneous( org.openrewrite.Tree.randomId(), EMPTY, @@ -1813,13 +1842,20 @@ private List convertAll(List trees) { private List> convertAll(List trees, Function innerSuffix, Function suffix) { + return convertAll(trees, innerSuffix, suffix, t -> Markers.EMPTY); + } + + private List> convertAll(List trees, + Function innerSuffix, + Function suffix, + Function markers) { int size = trees.size(); if (size == 0) { return emptyList(); } List> converted = new ArrayList<>(size); for (int i = 0; i < size; i++) { - converted.add(convert(trees.get(i), i == size - 1 ? suffix : innerSuffix)); + converted.add(convert(trees.get(i), i == size - 1 ? suffix : innerSuffix, markers)); } return converted; } @@ -1858,7 +1894,7 @@ private Space statementDelim(@Nullable Tree t) { case EXPRESSION_STATEMENT: ExpressionTree expTree = ((ExpressionStatementTree) t).getExpression(); if (expTree instanceof ErroneousTree) { - return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable),((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); + return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable), ((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); } else { return sourceBefore(";"); } @@ -2093,15 +2129,16 @@ private Space whitespace() { return space; } - private String skip(@Nullable String token) { + private @Nullable String skip(@Nullable String token) { if (token == null) { //noinspection ConstantConditions return null; } if (source.startsWith(token, cursor)) { cursor += token.length(); + return token; } - return token; + return null; } // Only exists as a function to make it easier to debug unexpected cursor shifts diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index 8a502fd31b8..6b944cff74a 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -35,6 +35,7 @@ import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.JavaPrinter; import org.openrewrite.java.marker.OmitParentheses; +import org.openrewrite.java.marker.TrailingComma; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; import org.openrewrite.style.NamedStyles; @@ -324,7 +325,7 @@ public J visitBreak(BreakTree node, Space fmt) { J.Identifier label = node.getLabel() == null ? null : new J.Identifier(randomId(), sourceBefore(node.getLabel().toString()), Markers.EMPTY, - emptyList(), skip(node.getLabel().toString()), null, null); + emptyList(), node.getLabel().toString(), null, null); return new J.Break(randomId(), fmt, Markers.EMPTY, label); } @@ -418,13 +419,31 @@ public J visitClass(ClassTree node, Space fmt) { JRightPadded enumSet = null; if (!jcEnums.isEmpty()) { - AtomicBoolean semicolonPresent = new AtomicBoolean(false); - + Tree lastConstant = jcEnums.get(jcEnums.size() - 1); List> enumValues = convertAll(jcEnums, commaDelim, t -> { - // this semicolon is required when there are non-value members, but can still - // be present when there are not - semicolonPresent.set(positionOfNext(";", '}') > 0); - return semicolonPresent.get() ? sourceBefore(";", '}') : EMPTY; + if (t != lastConstant) { + return whitespace(); + } + int savedCursor = cursor; + Space suffix = whitespace(); + if (source.charAt(cursor) == ',' || source.charAt(cursor) == ';') { + return suffix; + } + // Whitespace should be assigned to prefix of next statement or `J.Block#end` + cursor = savedCursor; + return EMPTY; + }, t -> { + if (t == lastConstant && skip(",") != null) { + int savedCursor = cursor; + Space suffix = whitespace(); + if (source.charAt(cursor) == ';') { + return Markers.build(singletonList(new TrailingComma(randomId(), suffix))); + } + // Whitespace should be assigned to prefix of next statement or `J.Block#end` + cursor = savedCursor; + return Markers.build(singletonList(new TrailingComma(randomId(), EMPTY))); + } + return Markers.EMPTY; }); enumSet = padRight( @@ -433,7 +452,7 @@ public J visitClass(ClassTree node, Space fmt) { EMPTY, Markers.EMPTY, enumValues, - semicolonPresent.get() + skip(";") != null ), EMPTY ); @@ -990,7 +1009,7 @@ public J visitNewArray(NewArrayTree node, Space fmt) { convert(dim, t -> sourceBefore("]")))); } - while(true) { + while (true) { int beginBracket = indexOfNextNonWhitespace(cursor, source); if (source.charAt(beginBracket) == '[') { int endBracket = indexOfNextNonWhitespace(beginBracket + 1, source); @@ -1008,7 +1027,14 @@ public J visitNewArray(NewArrayTree node, Space fmt) { JContainer initializer = node.getInitializers() == null ? null : JContainer.build(sourceBefore("{"), node.getInitializers().isEmpty() ? singletonList(padRight(new J.Empty(randomId(), sourceBefore("}"), Markers.EMPTY), EMPTY)) : - convertAll(node.getInitializers(), commaDelim, t -> sourceBefore("}")), Markers.EMPTY); + convertAll(node.getInitializers(), commaDelim, t -> whitespace(), t -> { + if (t == node.getInitializers().get(node.getInitializers().size() - 1) && source.charAt(cursor) == ',') { + cursor++; + return Markers.build(singletonList(new TrailingComma(randomId(), whitespace()))); + } + return Markers.EMPTY; + }), Markers.EMPTY); + skip("}"); return new J.NewArray(randomId(), fmt, Markers.EMPTY, typeExpr, dimensions, initializer, typeMapping.type(node)); @@ -1597,7 +1623,6 @@ public J visitWildcard(WildcardTree node, Space fmt) { * Conversion utilities * -------------- */ - private J2 convert(Tree t) { try { String prefix = source.substring(cursor, max(((JCTree) t).getStartPosition(), cursor)); @@ -1631,17 +1656,21 @@ private J2 convert(Tree t) { } private JRightPadded convert(Tree t, Function suffix) { + return convert(t, suffix, j -> Markers.EMPTY); + } + + private JRightPadded convert(Tree t, Function suffix, Function markers) { J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : - new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); + new JRightPadded<>(j, suffix.apply(t), markers.apply(t)); int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace()); if (idx >= 0) { rightPadded = (JRightPadded) JRightPadded.build(getErroneous(Collections.singletonList(rightPadded))); } // Cursor hasn't been updated but points at the end of erroneous node already // This means that error node start position == end position - // Therefore ensure that cursor has moved to the end of erroneous node bu adding its length to the cursor - // Example `/pet` results in 2 erroeneous nodes: `/` and `pet`. The `/` node would have start and end position the + // Therefore ensure that cursor has moved to the end of erroneous node but adding its length to the cursor + // Example `/pet` results in 2 erroneous nodes: `/` and `pet`. The `/` node would have start and end position the // same from the JC compiler. if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) { cursor += ((J.Erroneous) rightPadded.getElement()).getText().length(); @@ -1652,8 +1681,8 @@ private JRightPadded convert(Tree t, Function su } private J.Erroneous getErroneous(List> converted) { - PrintOutputCapture p = new PrintOutputCapture<>(0); - new JavaPrinter<>().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); + PrintOutputCapture p = new PrintOutputCapture<>(0); + new JavaPrinter().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p); return new J.Erroneous( org.openrewrite.Tree.randomId(), EMPTY, @@ -1700,13 +1729,20 @@ private List convertAll(List trees) { private List> convertAll(List trees, Function innerSuffix, Function suffix) { + return convertAll(trees, innerSuffix, suffix, t -> Markers.EMPTY); + } + + private List> convertAll(List trees, + Function innerSuffix, + Function suffix, + Function markers) { int size = trees.size(); if (size == 0) { return emptyList(); } List> converted = new ArrayList<>(size); for (int i = 0; i < size; i++) { - converted.add(convert(trees.get(i), i == size - 1 ? suffix : innerSuffix)); + converted.add(convert(trees.get(i), i == size - 1 ? suffix : innerSuffix, markers)); } return converted; } @@ -1936,15 +1972,16 @@ private Space whitespace() { return format(prefix); } - private String skip(@Nullable String token) { + private @Nullable String skip(@Nullable String token) { if (token == null) { //noinspection ConstantConditions return null; } if (source.startsWith(token, cursor)) { cursor += token.length(); + return token; } - return token; + return null; } // Only exists as a function to make it easier to debug unexpected cursor shifts diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java index 9a89ce50b27..51e56507716 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/AnnotationTest.java @@ -82,6 +82,21 @@ void newArrayArgument() { ); } + @Test + void newArrayArgumentTrailingComma() { + rewriteRun( + java( + """ + import java.lang.annotation.Target; + import static java.lang.annotation.ElementType.*; + + @Target({ FIELD, PARAMETER , }) + public @interface Annotation {} + """ + ) + ); + } + @SuppressWarnings("FinalMethodInFinalClass") @Test void annotationsInManyLocations() { diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/EnumTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/EnumTest.java index 03787bb3816..90dc6a8d5c1 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/EnumTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/EnumTest.java @@ -16,7 +16,6 @@ package org.openrewrite.java.tree; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; @@ -35,7 +34,7 @@ void enumWithAnnotations() { public enum Test { @Deprecated(since = "now") One, - + @Deprecated(since = "now") Two; } @@ -56,7 +55,7 @@ void foo() {} }; A(int n) {} - + abstract void foo(); } """ @@ -74,7 +73,7 @@ public enum A { @Override void foo() {} }; - + abstract void foo(); } """ @@ -90,10 +89,10 @@ void enumConstructor() { public class Outer { public enum A { A1(1); - + A(int n) {} } - + private static final class ContextFailedToStart { private static Object[] combineArguments(String context, Throwable ex, Object[] arguments) { return new Object[arguments.length + 2]; @@ -126,7 +125,7 @@ void enumWithParameters() { public enum A { ONE(1), TWO(2); - + A(int n) {} } """ @@ -150,7 +149,6 @@ void enumUnnecessarilyTerminatedWithSemicolon() { } @Test - @Disabled("enum A { ONE~~(non-whitespace)~~>, <~~}") void enumValuesTerminatedWithComma() { rewriteRun( java("enum A { ONE, }") @@ -163,4 +161,21 @@ void enumWithEmptyParameters() { java("public enum A { ONE ( ), TWO ( ) }") ); } + + @Test + void enumWithParametersAndTrailingComma() { + rewriteRun( + java( + """ + public enum A { + ONE(1), + TWO(2), + ; + + A(int n) {} + } + """ + ) + ); + } } diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/NewArrayTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/NewArrayTest.java index 48c0972ce7e..e504de17cb2 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/NewArrayTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/NewArrayTest.java @@ -15,7 +15,6 @@ */ package org.openrewrite.java.tree; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openrewrite.test.RewriteTest; @@ -50,7 +49,6 @@ class Test { } @Test - @Disabled("int[] n = new int[] { 0, 1, 2~~(non-whitespace)~~>, <~~};") void initializersWithTrailingComma() { rewriteRun( java( diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java index 4314094918f..25a75622a02 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaParserTest.java @@ -40,6 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.test.TypeValidation.all; /** * @author Alex Boyko @@ -49,6 +50,7 @@ class JavaParserTest implements RewriteTest { @Test void incompleteAssignment() { rewriteRun( + spec -> spec.typeValidationOptions(all().erroneous(false)), java( """ @Deprecated(since=) @@ -238,6 +240,7 @@ public void test(int param ) { }) void erroneousExpressionStatements(@Language("java") String source) { rewriteRun( + spec -> spec.typeValidationOptions(all().erroneous(false)), java(source) ); } @@ -245,7 +248,8 @@ void erroneousExpressionStatements(@Language("java") String source) { @Test void erroneousVariableDeclarations() { rewriteRun( - spec -> spec.recipe(new FindCompileErrors()), + spec -> spec.recipe(new FindCompileErrors()) + .typeValidationOptions(all().erroneous(false)), java( """ package com.example.demo; diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaVisitorTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaVisitorTest.java index de0f9daa151..a906fb84249 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/JavaVisitorTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/JavaVisitorTest.java @@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.fail; import static org.openrewrite.java.Assertions.java; import static org.openrewrite.test.RewriteTest.toRecipe; +import static org.openrewrite.test.TypeValidation.all; class JavaVisitorTest implements RewriteTest { @@ -116,20 +117,21 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, Ex }) ), java( - """ - class A { - public void method1() { - } - - @Deprecated - public String myMethod() { - return "hello"; - } - - public void method2() { - } - } - """) + """ + class A { + public void method1() { + } + + @Deprecated + public String myMethod() { + return "hello"; + } + + public void method2() { + } + } + """ + ) ); } @@ -149,7 +151,8 @@ public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, Ex return method; } }) - ), + ) + .typeValidationOptions(all().erroneous(false)), java( """ class A { diff --git a/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java b/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java index 27ae9b4ec08..1524c72188e 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java @@ -38,6 +38,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; +import static java.util.stream.Collectors.joining; import static org.openrewrite.test.SourceSpecs.dir; @SuppressWarnings("unused") @@ -58,13 +59,28 @@ static void customizeExecutionContext(ExecutionContext ctx) { public static SourceFile validateTypes(SourceFile source, TypeValidation typeValidation) { if (source instanceof JavaSourceFile) { assertValidTypes(typeValidation, (JavaSourceFile) source); + if (typeValidation.erroneous()) { + List allErroneous = new JavaIsoVisitor>() { + @Override + public J.Erroneous visitErroneous(J.Erroneous erroneous, List list) { + J.Erroneous err = super.visitErroneous(erroneous, list); + list.add(err); + return err; + } + }.reduce(source, new ArrayList<>()); + if (!allErroneous.isEmpty()) { + throw new IllegalStateException("LST contains erroneous nodes\n" + allErroneous.stream() + .map(J.Erroneous::getText) + .collect(joining("\n\n"))); + } + } } return source; } private static void assertValidTypes(TypeValidation typeValidation, J sf) { if (typeValidation.identifiers() || typeValidation.methodInvocations() || typeValidation.methodDeclarations() || typeValidation.classDeclarations() || - typeValidation.constructorInvocations()) { + typeValidation.constructorInvocations()) { List missingTypeResults = FindMissingTypes.findMissingTypes(sf); missingTypeResults = missingTypeResults.stream() .filter(missingType -> { @@ -89,10 +105,10 @@ private static void assertValidTypes(TypeValidation typeValidation, J sf) { if (!missingTypeResults.isEmpty()) { String missingTypes = missingTypeResults.stream() .map(v -> v.getPath() + "\n" + v.getPrintedTree()) - .collect(Collectors.joining("\n\n")); + .collect(joining("\n\n")); throw new IllegalStateException( "LST contains missing or invalid type information\n" + missingTypes + - "\nhttps://docs.openrewrite.org/reference/faq#im-seeing-lst-contains-missing-or-invalid-type-information-in-my-recipe-unit-tests-how-to-resolve"); + "\nhttps://docs.openrewrite.org/reference/faq#im-seeing-lst-contains-missing-or-invalid-type-information-in-my-recipe-unit-tests-how-to-resolve"); } } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java index 71a1d56ccac..9743bb1abcd 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java @@ -21,6 +21,7 @@ import org.openrewrite.Tree; import org.openrewrite.java.marker.CompactConstructor; import org.openrewrite.java.marker.OmitParentheses; +import org.openrewrite.java.marker.TrailingComma; import org.openrewrite.java.tree.*; import org.openrewrite.java.tree.J.*; import org.openrewrite.marker.Marker; @@ -94,6 +95,16 @@ protected void visitRightPadded(@Nullable JRightPadded rightPadded, } } + @Override + public M visitMarker(Marker marker, PrintOutputCapture

p) { + if (marker instanceof TrailingComma) { + p.append(','); + visitSpace(((TrailingComma) marker).getSuffix(), Space.Location.TRAILING_COMMA_SUFFIX, p); + } + //noinspection unchecked + return (M) marker; + } + @Override public J visitModifier(Modifier mod, PrintOutputCapture

p) { visit(mod.getAnnotations(), p); diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java index fc40698f5d9..a334eafa601 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java @@ -300,21 +300,21 @@ public String toString() { } public enum Location { - ANY, ANNOTATED_TYPE_PREFIX, + ANNOTATIONS, ANNOTATION_ARGUMENTS, ANNOTATION_ARGUMENT_SUFFIX, - ANNOTATIONS, ANNOTATION_PREFIX, + ANY, ARRAY_ACCESS_PREFIX, ARRAY_INDEX_SUFFIX, ARRAY_TYPE_PREFIX, - ASSERT_PREFIX, ASSERT_DETAIL, ASSERT_DETAIL_PREFIX, + ASSERT_PREFIX, ASSIGNMENT, - ASSIGNMENT_OPERATION_PREFIX, ASSIGNMENT_OPERATION_OPERATOR, + ASSIGNMENT_OPERATION_PREFIX, ASSIGNMENT_PREFIX, BINARY_OPERATOR, BINARY_PREFIX, @@ -323,9 +323,9 @@ public enum Location { BLOCK_STATEMENT_SUFFIX, BREAK_PREFIX, CASE, - CASE_PREFIX, CASE_BODY, CASE_EXPRESSION, + CASE_PREFIX, CASE_SUFFIX, CATCH_ALTERNATIVE_SUFFIX, CATCH_PREFIX, @@ -335,8 +335,8 @@ public enum Location { COMPILATION_UNIT_PREFIX, CONTINUE_PREFIX, CONTROL_PARENTHESES_PREFIX, - DIMENSION_PREFIX, DIMENSION, + DIMENSION_PREFIX, DIMENSION_SUFFIX, DO_WHILE_PREFIX, ELSE_PREFIX, @@ -364,9 +364,8 @@ public enum Location { IF_PREFIX, IF_THEN_SUFFIX, IMPLEMENTS, - IMPORT_ALIAS_PREFIX, - PERMITS, IMPLEMENTS_SUFFIX, + IMPORT_ALIAS_PREFIX, IMPORT_PREFIX, IMPORT_SUFFIX, INSTANCEOF_PREFIX, @@ -383,9 +382,9 @@ public enum Location { MEMBER_REFERENCE_CONTAINING, MEMBER_REFERENCE_NAME, MEMBER_REFERENCE_PREFIX, + METHOD_DECLARATION_DEFAULT_VALUE, METHOD_DECLARATION_PARAMETERS, METHOD_DECLARATION_PARAMETER_SUFFIX, - METHOD_DECLARATION_DEFAULT_VALUE, METHOD_DECLARATION_PREFIX, METHOD_INVOCATION_ARGUMENTS, METHOD_INVOCATION_ARGUMENT_SUFFIX, @@ -410,6 +409,7 @@ public enum Location { PARAMETERIZED_TYPE_PREFIX, PARENTHESES_PREFIX, PARENTHESES_SUFFIX, + PERMITS, PERMITS_SUFFIX, PRIMITIVE_PREFIX, RECORD_STATE_VECTOR, @@ -418,8 +418,8 @@ public enum Location { STATEMENT_PREFIX, STATIC_IMPORT, STATIC_INIT_SUFFIX, - SWITCH_PREFIX, SWITCH_EXPRESSION_PREFIX, + SWITCH_PREFIX, SYNCHRONIZED_PREFIX, TERNARY_FALSE, TERNARY_PREFIX, @@ -427,6 +427,7 @@ public enum Location { THROWS, THROWS_SUFFIX, THROW_PREFIX, + TRAILING_COMMA_SUFFIX, TRY_FINALLY, TRY_PREFIX, TRY_RESOURCE, diff --git a/rewrite-java/src/test/java/org/openrewrite/java/search/FindCompileErrorsTest.java b/rewrite-java/src/test/java/org/openrewrite/java/search/FindCompileErrorsTest.java index 168e88ee0ec..36fc57b9637 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/search/FindCompileErrorsTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/search/FindCompileErrorsTest.java @@ -23,6 +23,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.test.TypeValidation.all; class FindCompileErrorsTest implements RewriteTest { @@ -39,7 +40,7 @@ void javaVisitorHandlesErroneousNodes() { rows -> assertThat(rows).singleElement().satisfies(row -> { assertThat(row.getSourceFile()).isEqualTo("A.java"); assertThat(row.getCode()).isEqualTo("\n owner"); - })), + })).typeValidationOptions(all().erroneous(false)), java( """ class A { diff --git a/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java b/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java index e4df172f017..9d78cd0a33a 100644 --- a/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java +++ b/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java @@ -96,6 +96,13 @@ public class TypeValidation { @Builder.Default private Function allowMissingType = o -> false; + + /** + * Controls whether the LST is validated not to contain any `J.Erroneous` elements. + */ + @Builder.Default + private boolean erroneous = true; + /** * Enable all invariant validation checks. */ @@ -107,7 +114,7 @@ public static TypeValidation all() { * Skip all invariant validation checks. */ public static TypeValidation none() { - return new TypeValidation(false, false, false, false, false, false, false, false, o -> false); + return new TypeValidation(false, false, false, false, false, false, false, false, o -> false, false); } static TypeValidation before(RecipeSpec testMethodSpec, RecipeSpec testClassSpec) { From 4c901ff348bf1b94e92f33d1ed7a325f75ff2e69 Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Thu, 9 Jan 2025 14:51:45 -0800 Subject: [PATCH 125/179] Don't cache filePatterns at Recipe class level... caused strange behavior on the saas. At least I think that's why I was matching too many things with FindSourceFiles on the saas but couldn't reproduce locally. --- .../java/org/openrewrite/FindSourceFiles.java | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java b/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java index 20cf360f697..05362e7c79b 100644 --- a/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java +++ b/rewrite-core/src/main/java/org/openrewrite/FindSourceFiles.java @@ -42,21 +42,6 @@ public class FindSourceFiles extends Recipe { @Nullable String filePattern; - @EqualsAndHashCode.Exclude - transient String[] filePatterns; - - public FindSourceFiles(@Nullable String filePattern) { - this.filePattern = filePattern; - this.filePatterns = Optional.ofNullable(filePattern) - .map(it -> it.split(";")) - .map(Arrays::stream) - .orElseGet(Stream::empty) - .map(String::trim) - .filter(StringUtils::isNotEmpty) - .map(FindSourceFiles::normalize) - .toArray(String[]::new); - } - @Override public String getDisplayName() { return "Find files"; @@ -84,6 +69,22 @@ public TreeVisitor getVisitor() { } return tree; } + + String @Nullable[] filePatterns; + + private boolean matches(Path sourcePath) { + if (filePatterns == null) { + filePatterns = Optional.ofNullable(filePattern) + .map(it -> it.split(";")) + .map(Arrays::stream) + .orElseGet(Stream::empty) + .map(String::trim) + .filter(StringUtils::isNotEmpty) + .map(FindSourceFiles::normalize) + .toArray(String[]::new); + } + return filePatterns.length == 0 || Arrays.stream(filePatterns).anyMatch(pattern -> PathUtils.matchesGlob(sourcePath, pattern)); + } }; } @@ -96,7 +97,4 @@ private static String normalize(String filePattern) { return filePattern; } - private boolean matches(Path sourcePath) { - return filePatterns.length == 0 || Arrays.stream(filePatterns).anyMatch(pattern -> PathUtils.matchesGlob(sourcePath, pattern)); - } } From e69e8ca2aaa5cc16c9f002ad45a74ad77c47d7b9 Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Thu, 9 Jan 2025 17:24:34 -0800 Subject: [PATCH 126/179] Fix broken RSPEC links --- .../java/org/openrewrite/java/format/TabsAndIndentsTest.java | 2 +- rewrite-java/src/main/java/org/openrewrite/java/tree/J.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/format/TabsAndIndentsTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/format/TabsAndIndentsTest.java index 2bb6531f15c..e4cb56a7a11 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/format/TabsAndIndentsTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/format/TabsAndIndentsTest.java @@ -194,7 +194,7 @@ class Foo { ); } - // https://rules.sonarsource.com/java/tag/confusing/RSPEC-S3973 + // https://rules.sonarsource.com/java/tag/confusing/RSPEC-3973 @DocumentExample @SuppressWarnings("SuspiciousIndentAfterControlStatement") @Test diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java index 417db943f5f..3c6f581bb8a 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java @@ -4062,7 +4062,7 @@ public String toString() { /** * These types are sorted in order of their recommended appearance in a list of modifiers, as defined in the - * JLS. + * JLS. */ public enum Type { Default, From fa1fc5626c3f78909903656756eb17e70b908104 Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Thu, 9 Jan 2025 17:25:54 -0800 Subject: [PATCH 127/179] Fix #4877 where the groovy parser would fail to parse variables whose names started with "def" --- .../groovy/GroovyParserVisitor.java | 53 +++++++++++++------ .../groovy/tree/VariableDeclarationsTest.java | 10 ++++ 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index bbed7c6c14b..2e5cc8467f5 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -1383,7 +1383,7 @@ public void visitNotExpression(NotExpression expression) { public void visitDeclarationExpression(DeclarationExpression expression) { Space prefix = whitespace(); Optional multiVariable = maybeMultiVariable(); - List modifiers = getModifiers(); + List modifiers = getModifiers(expression.getVariableExpression()); TypeTree typeExpr = visitVariableExpressionType(expression.getVariableExpression()); J.VariableDeclarations.NamedVariable namedVariable; @@ -1438,25 +1438,28 @@ private Optional maybeMultiVariable() { return Optional.empty(); } - private List getModifiers() { + private List getModifiers(Variable variable) { + String varName = variable.getName(); List modifiers = new ArrayList<>(); int saveCursor = cursor; Space prefix = whitespace(); - while (source.startsWith("def", cursor) || source.startsWith("var", cursor) || source.startsWith("final", cursor)) { - if (source.startsWith("var", cursor)) { - modifiers.add(new J.Modifier(randomId(), prefix, Markers.EMPTY, "var", J.Modifier.Type.LanguageExtension, emptyList())); - skip("var"); - } else if (source.startsWith("def", cursor)) { - modifiers.add(new J.Modifier(randomId(), prefix, Markers.EMPTY, "def", J.Modifier.Type.LanguageExtension, emptyList())); - skip("def"); - } else if (source.startsWith("final", cursor)) { - modifiers.add(new J.Modifier(randomId(), prefix, Markers.EMPTY, "final", J.Modifier.Type.LanguageExtension, emptyList())); - skip("final"); - } else { - break; - } + Set possibleModifiers = new LinkedHashSet<>(modifierNameToType.keySet()); + String currentModifier = possibleModifiers.stream().filter(modifierName -> source.startsWith(modifierName, cursor)) + .findFirst() + .orElse(null); + while (currentModifier != null) { + possibleModifiers.remove(currentModifier); + modifiers.add(new J.Modifier(randomId(), prefix, Markers.EMPTY, currentModifier, modifierNameToType.get(currentModifier), emptyList())); + skip(currentModifier); saveCursor = cursor; prefix = whitespace(); + currentModifier = possibleModifiers.stream() + .filter(modifierName -> + // Try to avoid confusing a variable name with an incidentally similar modifier keyword + (varName.length() < modifierName.length() || !source.startsWith(varName, cursor)) && + source.startsWith(modifierName, cursor)) + .findFirst() + .orElse(null); } cursor = saveCursor; return modifiers; @@ -1513,7 +1516,7 @@ public void visitForLoop(ForStatement forLoop) { } else { Parameter param = forLoop.getVariable(); Space paramFmt = whitespace(); - List modifiers = getModifiers(); + List modifiers = getModifiers(param); TypeTree paramType = param.getOriginType().getColumnNumber() >= 0 ? visitTypeTree(param.getOriginType()) : null; JRightPadded paramName = JRightPadded.build( new J.VariableDeclarations.NamedVariable(randomId(), whitespace(), Markers.EMPTY, @@ -2773,4 +2776,22 @@ private static ClassNode staticType(Parameter parameter) { return inferred; } } + + private static final Map modifierNameToType; + static { + modifierNameToType = new LinkedHashMap<>(); + modifierNameToType.put("def", J.Modifier.Type.LanguageExtension); + modifierNameToType.put("var", J.Modifier.Type.LanguageExtension); + modifierNameToType.put("public", J.Modifier.Type.Public); + modifierNameToType.put("protected", J.Modifier.Type.Protected); + modifierNameToType.put("private", J.Modifier.Type.Private); + modifierNameToType.put("abstract", J.Modifier.Type.Abstract); + modifierNameToType.put("static", J.Modifier.Type.Static); + modifierNameToType.put("final", J.Modifier.Type.Final); + modifierNameToType.put("volatile", J.Modifier.Type.Volatile); + modifierNameToType.put("synchronized", J.Modifier.Type.Synchronized); + modifierNameToType.put("native", J.Modifier.Type.Native); + modifierNameToType.put("default", J.Modifier.Type.Default); + modifierNameToType.put("strictfp", J.Modifier.Type.Strictfp); + } } diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java index 9a2efcf03bd..370772cb111 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java @@ -216,4 +216,14 @@ void defAndExplicitReturnType() { ) ); } + + @Issue("https://github.com/openrewrite/rewrite/issues/4877") + @Test + void defVariableStartsWithDef() { + rewriteRun( + groovy(""" + def defaultPublicStaticFinal = 0 + """) + ); + } } From 9fc0dbaa1cef7851afc919a618dc04a385fd0493 Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Thu, 9 Jan 2025 17:41:50 -0800 Subject: [PATCH 128/179] I transiently forgot about transient --- .../main/java/org/openrewrite/groovy/GroovyParserVisitor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index 2e5cc8467f5..d38c154ef76 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -2790,6 +2790,7 @@ private static ClassNode staticType(Parameter parameter) { modifierNameToType.put("final", J.Modifier.Type.Final); modifierNameToType.put("volatile", J.Modifier.Type.Volatile); modifierNameToType.put("synchronized", J.Modifier.Type.Synchronized); + modifierNameToType.put("transient", J.Modifier.Type.Transient); modifierNameToType.put("native", J.Modifier.Type.Native); modifierNameToType.put("default", J.Modifier.Type.Default); modifierNameToType.put("strictfp", J.Modifier.Type.Strictfp); From 50d160e38de6e4f9c1f927699ee1981792485c64 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Fri, 10 Jan 2025 10:07:10 +0100 Subject: [PATCH 129/179] Partial support Lombok for java 8 (mostly done) (#4855) * Support Lombok for java 8 * Support Lombok for java 8 * Support Lombok for java 8 * Add rewrite-java-lombok to classpath * Improve message * Remove `TimedTodo` to be more like the other java parsers * cleanup * Add JavaCompiler `delegate` fix * Support Lomboks `var` and `val` for Java 8 * Cleanup * Cleanup * Cleanup of `isLombokGenerated` methods * Cleanup of `isLombokGenerated` methods * Cleanup of `isLombokGenerated` methods * Cleanup of `isLombokGenerated` methods * Cleanup of `isLombokGenerated` methods * Cleanup * Improve `onConstructor` and `onConstructorNoArgs` args * Fix missing `onConstructor_` check * Cleanup * Apply suggestions from code review Co-authored-by: Knut Wannheden * Improve tests * Merge branch 'main' into lombok-java-8 * Rename JavacAnnotationHandler with no action to XNoOpHandler * Rename JavacAnnotationHandler with no action to XNoOpHandler * Improve lomboks `ExampleException` test --------- Co-authored-by: Knut Wannheden --- .../ReloadableJava11ParserVisitor.java | 69 ++---- .../ReloadableJava17ParserVisitor.java | 81 +++---- .../ReloadableJava21ParserVisitor.java | 81 +++---- rewrite-java-8/build.gradle.kts | 1 + .../java/ReloadableJava8Parser.java | 204 +++++++++++------- .../java/ReloadableJava8ParserVisitor.java | 115 +++++++--- .../org/openrewrite/java/package-info.java | 21 ++ .../lombok/AllArgsConstructorHandler.java | 1 - ...r.java => ExtensionMethodNoOpHandler.java} | 2 +- ...perHandler.java => HelperNoOpHandler.java} | 2 +- ...ndler.java => JacksonizedNoOpHandler.java} | 2 +- .../java/lombok/NoArgsConstructorHandler.java | 3 +- .../RequiredArgsConstructorHandler.java | 3 +- .../lombok.javac.JavacAnnotationHandler | 6 +- .../org/openrewrite/java/tree/LombokTest.java | 201 ++++++++++++++--- 15 files changed, 491 insertions(+), 301 deletions(-) create mode 100644 rewrite-java-8/src/main/java/org/openrewrite/java/package-info.java rename rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/{ExtensionMethodHandler.java => ExtensionMethodNoOpHandler.java} (91%) rename rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/{HelperHandler.java => HelperNoOpHandler.java} (93%) rename rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/{JacksonizedHandler.java => JacksonizedNoOpHandler.java} (93%) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index a9972f1e672..8c434c84edd 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -18,7 +18,6 @@ import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; -import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DCTree; @@ -27,6 +26,7 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Context; +import lombok.Generated; import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; @@ -1519,9 +1519,11 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm // this is a lambda parameter with an inferred type expression typeExpr = null; } else { - boolean lombokVal = isLombokVal(node); + Space space = whitespace(); + boolean lombokVal = source.startsWith("val", cursor); + cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), - sourceBefore(lombokVal ? "val" : "var"), + space, Markers.build(singletonList(JavaVarKeyword.build())), emptyList(), lombokVal ? "val" : "var", @@ -1684,8 +1686,8 @@ public J visitWildcard(WildcardTree node, Space fmt) { } private static int getActualStartPosition(JCTree t) { - // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation - if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { + // The variable's start position in the source is wrongly after lombok's `@val` annotation + if (t instanceof JCVariableDecl && isLombokGenerated(t)) { return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); } return t.getStartPosition(); @@ -1861,7 +1863,7 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { - if (isLombokGenerated(t)) { + if (!(t instanceof JCVariableDecl) && isLombokGenerated(t)) { continue; } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); @@ -1893,51 +1895,23 @@ private List> convertStatements(@Nullable List "lombok.val".equals(a.type.toString())); } - return isLombokGenerated(sym); - } - private static boolean isLombokGenerated(@Nullable Symbol sym) { - if (sym == null) { - return false; - } - // Lombok val is represented as a @lombok.val on a "final" modifier, neither which appear in source - if ("lombok.val".equals(sym.getQualifiedName().toString())) { - return true; - } - if (sym.getMetadata() == null) { - return false; - } - for (Attribute.Compound a : sym.getDeclarationAttributes()) { - if ("lombok.Generated".equals(a.type.toString())) { - return true; - } - } - return false; + //noinspection ConstantConditions + return sym != null && ("lombok.val".equals(sym.getQualifiedName().toString()) || sym.getAnnotation(Generated.class) != null); } /** @@ -2117,7 +2091,6 @@ private ReloadableJava11ModifierResults sortedModifiersAndAnnotations(ModifiersT for (int i = cursor; i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { JCAnnotation jcAnnotation = annotationPosTable.get(i); - // Skip over lombok's "@val" annotation which does not actually appear in source if (isLombokGenerated(jcAnnotation.getAnnotationType())) { continue; } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 738a3fe7c23..90ba684cfd1 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -19,7 +19,6 @@ import com.sun.source.doctree.DocCommentTree; import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; -import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DocCommentTable; @@ -27,6 +26,7 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Context; +import lombok.Generated; import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; @@ -1597,9 +1597,11 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm // this is a lambda parameter with an inferred type expression typeExpr = null; } else { - boolean lombokVal = isLombokVal(node); + Space space = whitespace(); + boolean lombokVal = source.startsWith("val", cursor); + cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), - sourceBefore(lombokVal ? "val" : "var"), + space, Markers.build(singletonList(JavaVarKeyword.build())), emptyList(), lombokVal ? "val" : "var", @@ -1747,6 +1749,14 @@ public J visitWildcard(WildcardTree node, Space fmt) { } } + private static int getActualStartPosition(JCTree t) { + // The variable's start position in the source is wrongly after lombok's `@val` annotation + if (t instanceof JCVariableDecl && isLombokGenerated(t)) { + return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); + } + return t.getStartPosition(); + } + private void reportJavaParsingException(Throwable ex) { // this SHOULD never happen, but is here simply as a diagnostic measure in the event of unexpected exceptions StringBuilder message = new StringBuilder("Failed to convert for the following cursor stack:"); @@ -1771,14 +1781,6 @@ private void reportJavaParsingException(Throwable ex) { ctx.getOnError().accept(new JavaParsingException(message.toString(), ex)); } - private static int getActualStartPosition(JCTree t) { - // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation - if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { - return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); - } - return t.getStartPosition(); - } - private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix) { return convert(t, suffix, j -> Markers.EMPTY); } @@ -1942,7 +1944,7 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { - if (isLombokGenerated(t)) { + if (!(t instanceof JCVariableDecl) && isLombokGenerated(t)) { continue; } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); @@ -1974,51 +1976,23 @@ private List> convertStatements(@Nullable List "lombok.val".equals(a.type.toString())); } - return isLombokGenerated(sym); - } - private static boolean isLombokGenerated(@Nullable Symbol sym) { - if (sym == null) { - return false; - } - // Lombok val is represented as a @lombok.val on a "final" modifier, neither which appear in source - if ("lombok.val".equals(sym.getQualifiedName().toString())) { - return true; - } - if (sym.getMetadata() == null) { - return false; - } - for (Attribute.Compound a : sym.getDeclarationAttributes()) { - if ("lombok.Generated".equals(a.type.toString())) { - return true; - } - } - return false; + //noinspection ConstantConditions + return sym != null && ("lombok.val".equals(sym.getQualifiedName().toString()) || sym.getAnnotation(Generated.class) != null); } /** @@ -2199,7 +2173,6 @@ private ReloadableJava17ModifierResults sortedModifiersAndAnnotations(ModifiersT for (int i = cursor; i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { JCAnnotation jcAnnotation = annotationPosTable.get(i); - // Skip over lombok's "@val" annotation which does not actually appear in source if (isLombokGenerated(jcAnnotation.getAnnotationType())) { continue; } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index b49c1f1563a..da4ad8b8acd 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -19,7 +19,6 @@ import com.sun.source.doctree.DocCommentTree; import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; -import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DocCommentTable; @@ -27,6 +26,7 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Context; +import lombok.Generated; import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; @@ -1597,9 +1597,11 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm // this is a lambda parameter with an inferred type expression typeExpr = null; } else { - boolean lombokVal = isLombokVal(node); + Space space = whitespace(); + boolean lombokVal = source.startsWith("val", cursor); + cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), - sourceBefore(lombokVal ? "val" : "var"), + space, Markers.build(singletonList(JavaVarKeyword.build())), emptyList(), lombokVal ? "val" : "var", @@ -1747,6 +1749,14 @@ public J visitWildcard(WildcardTree node, Space fmt) { } } + private static int getActualStartPosition(JCTree t) { + // The variable's start position in the source is wrongly after lombok's `@val` annotation + if (t instanceof JCVariableDecl && isLombokGenerated(t)) { + return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); + } + return t.getStartPosition(); + } + private void reportJavaParsingException(Throwable ex) { // this SHOULD never happen, but is here simply as a diagnostic measure in the event of unexpected exceptions StringBuilder message = new StringBuilder("Failed to convert for the following cursor stack:"); @@ -1771,14 +1781,6 @@ private void reportJavaParsingException(Throwable ex) { ctx.getOnError().accept(new JavaParsingException(message.toString(), ex)); } - private static int getActualStartPosition(JCTree t) { - // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation - if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { - return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); - } - return t.getStartPosition(); - } - private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix) { return convert(t, suffix, j -> Markers.EMPTY); } @@ -1942,7 +1944,7 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { - if (isLombokGenerated(t)) { + if (!(t instanceof JCVariableDecl) && isLombokGenerated(t)) { continue; } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); @@ -1974,51 +1976,23 @@ private List> convertStatements(@Nullable List "lombok.val".equals(a.type.toString())); } - return isLombokGenerated(sym); - } - private static boolean isLombokGenerated(@Nullable Symbol sym) { - if (sym == null) { - return false; - } - // Lombok val is represented as a @lombok.val on a "final" modifier, neither which appear in source - if ("lombok.val".equals(sym.getQualifiedName().toString())) { - return true; - } - if (sym.getMetadata() == null) { - return false; - } - for (Attribute.Compound a : sym.getDeclarationAttributes()) { - if ("lombok.Generated".equals(a.type.toString())) { - return true; - } - } - return false; + //noinspection ConstantConditions + return sym != null && ("lombok.val".equals(sym.getQualifiedName().toString()) || sym.getAnnotation(Generated.class) != null); } /** @@ -2199,7 +2173,6 @@ private ReloadableJava21ModifierResults sortedModifiersAndAnnotations(ModifiersT for (int i = cursor; i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { JCAnnotation jcAnnotation = annotationPosTable.get(i); - // Skip over lombok's "@val" annotation which does not actually appear in source if (isLombokGenerated(jcAnnotation.getAnnotationType())) { continue; } diff --git a/rewrite-java-8/build.gradle.kts b/rewrite-java-8/build.gradle.kts index 5f92a5f85dd..e07e976892e 100644 --- a/rewrite-java-8/build.gradle.kts +++ b/rewrite-java-8/build.gradle.kts @@ -17,6 +17,7 @@ dependencies { compileOnly("org.slf4j:slf4j-api:1.7.+") implementation(project(":rewrite-java")) + runtimeOnly(project(":rewrite-java-lombok")) implementation("org.ow2.asm:asm:latest.release") implementation("io.micrometer:micrometer-core:1.9.+") diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java index de46c937d0a..bad6fc19a4d 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java @@ -18,12 +18,12 @@ import com.sun.tools.javac.comp.*; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.JavaCompiler; +import com.sun.tools.javac.main.Option; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Options; -import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Timer; +import lombok.Getter; import org.jspecify.annotations.Nullable; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -31,7 +31,6 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.SourceFile; -import org.openrewrite.internal.MetricsHelper; import org.openrewrite.internal.StringUtils; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.tree.J; @@ -40,19 +39,25 @@ import org.openrewrite.tree.ParseError; import org.openrewrite.tree.ParsingEventListener; import org.openrewrite.tree.ParsingExecutionContextView; +import org.slf4j.LoggerFactory; +import javax.annotation.processing.Processor; import javax.tools.*; import java.io.*; +import java.lang.reflect.Constructor; import java.net.URI; +import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import static com.sun.tools.javac.util.List.nil; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; class ReloadableJava8Parser implements JavaParser { @@ -70,6 +75,7 @@ class ReloadableJava8Parser implements JavaParser { private final JavaCompiler compiler; private final ResettableLog compilerLog; private final Collection styles; + private final List annotationProcessors; ReloadableJava8Parser(@Nullable Collection classpath, Collection classBytesClasspath, @@ -100,6 +106,70 @@ class ReloadableJava8Parser implements JavaParser { Options.instance(context).put("-g", "-g"); Options.instance(context).put("-proc", "none"); + // Ensure type attribution continues despite errors in individual files or nodes. + // If an error occurs in a single file or node, type attribution should still proceed + // for all other source files and unaffected nodes within the same file. + Options.instance(context).put("should-stop.ifError", "GENERATE"); + + LOMBOK: + if (System.getenv().getOrDefault("REWRITE_LOMBOK", System.getProperty("rewrite.lombok")) != null && + classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) { + Processor lombokProcessor = null; + try { + // https://projectlombok.org/contributing/lombok-execution-path + List overrideClasspath = new ArrayList<>(); + for (Path part : classpath) { + if (part.toString().contains("lombok")) { + overrideClasspath.add(part.toString()); + } + } + // make sure the rewrite-java-lombok dependency comes first + boolean found = false; + for (int i = 0; i < overrideClasspath.size(); i++) { + if (overrideClasspath.get(i).contains("rewrite-java-lombok")) { + overrideClasspath.add(0, overrideClasspath.remove(i)); + found = true; + } + } + if (!found) { + // try to find `rewrite-java-lombok` using class loader + URL resource = getClass().getClassLoader().getResource("org/openrewrite/java/lombok/OpenRewriteConfigurationKeysLoader.class"); + if (resource != null && resource.getProtocol().equals("jar") && resource.getPath().startsWith("file:")) { + String path = Paths.get(URI.create(resource.getPath().substring(0, resource.getPath().indexOf("!")))).toString(); + overrideClasspath.add(0, path); + } else { + break LOMBOK; + } + } + System.setProperty("shadow.override.lombok", String.join(File.pathSeparator, overrideClasspath)); + + Class shadowLoaderClass = Class.forName("lombok.launch.ShadowClassLoader", true, getClass().getClassLoader()); + Constructor shadowLoaderConstructor = shadowLoaderClass.getDeclaredConstructor( + Class.forName("java.lang.ClassLoader"), + Class.forName("java.lang.String"), + Class.forName("java.lang.String"), + Class.forName("java.util.List"), + Class.forName("java.util.List")); + shadowLoaderConstructor.setAccessible(true); + + ClassLoader lombokShadowLoader = (ClassLoader) shadowLoaderConstructor.newInstance( + getClass().getClassLoader(), + "lombok", + null, + emptyList(), + singletonList("lombok.patcher.Symbols") + ); + lombokProcessor = (Processor) lombokShadowLoader.loadClass("lombok.core.AnnotationProcessor").getDeclaredConstructor().newInstance(); + Options.instance(context).put(Option.PROCESSOR, "lombok.launch.AnnotationProcessorHider$AnnotationProcessor"); + } catch (ReflectiveOperationException ignore) { + // Lombok was not found or could not be initialized + } finally { + annotationProcessors = lombokProcessor != null ? singletonList(lombokProcessor) : emptyList(); + } + } else { + annotationProcessors = emptyList(); + } + // MUST be created (registered with the context) after pfm and compilerLog compiler = new JavaCompiler(context); @@ -118,7 +188,7 @@ public void write(char[] cbuf, int off, int len) { if (logCompilationWarningsAndErrors) { String log = new String(Arrays.copyOfRange(cbuf, off, len)); if (!StringUtils.isBlank(log)) { - org.slf4j.LoggerFactory.getLogger(ReloadableJava8Parser.class).warn(log); + LoggerFactory.getLogger(ReloadableJava8Parser.class).warn(log); } } } @@ -138,45 +208,7 @@ public void close() { @Override public Stream parseInputs(Iterable sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); - if (classpath != null) { // override classpath - if (context.get(JavaFileManager.class) != pfm) { - throw new IllegalStateException("JavaFileManager has been forked unexpectedly"); - } - - try { - pfm.setLocation(StandardLocation.CLASS_PATH, classpath.stream().map(Path::toFile).collect(toList())); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @SuppressWarnings("ConstantConditions") LinkedHashMap cus = acceptedInputs(sourceFiles) - .collect(Collectors.toMap( - Function.identity(), - input -> { - try { - return compiler.parse(new Java8ParserInputFileObject(input, ctx)); - } catch (IllegalStateException e) { - if ("endPosTable already set".equals(e.getMessage())) { - throw new IllegalStateException( - "Call reset() on JavaParser before parsing another set of source files that " + - "have some of the same fully qualified names. Source file [" + - input.getPath() + "]\n[\n" + StringUtils.readFully(input.getSource(ctx), getCharset(ctx)) + "\n]", e); - } - throw e; - } - }, - (e2, e1) -> e1, LinkedHashMap::new)); - - try { - enterAll(cus.values()); - compiler.attribute(new TimedTodo(compiler.todo)); - } catch (Throwable t) { - // when symbol entering fails on problems like missing types, attribution can often times proceed - // unhindered, but it sometimes cannot (so attribution is always a BEST EFFORT in the presence of errors) - ctx.getOnError().accept(new JavaParsingException("Failed symbol entering or attribution", t)); - } - + LinkedHashMap cus = parseInputsToCompilerAst(sourceFiles, ctx); return cus.entrySet().stream().map(cuByPath -> { Input input = cuByPath.getKey(); parsingListener.startedParsing(input); @@ -190,6 +222,7 @@ public Stream parseInputs(Iterable sourceFiles, @Nullable Pat ctx, context); J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); + //noinspection DataFlowIssue cuByPath.setValue(null); // allow memory used by this JCCompilationUnit to be released parsingListener.parsed(input, cu); return requirePrintEqualsInput(cu, input, relativeTo, ctx); @@ -200,6 +233,53 @@ public Stream parseInputs(Iterable sourceFiles, @Nullable Pat }); } + LinkedHashMap parseInputsToCompilerAst(Iterable sourceFiles, ExecutionContext ctx) { + if (classpath != null) { // override classpath + if (context.get(JavaFileManager.class) != pfm) { + throw new IllegalStateException("JavaFileManager has been forked unexpectedly"); + } + + try { + pfm.setLocation(StandardLocation.CLASS_PATH, classpath.stream().map(Path::toFile).collect(toList())); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + LinkedHashMap cus = new LinkedHashMap<>(); + List inputFileObjects = acceptedInputs(sourceFiles) + .map(input -> new Java8ParserInputFileObject(input, ctx)) + .collect(toList()); + if (!annotationProcessors.isEmpty()) { + compiler.initProcessAnnotations(annotationProcessors); + } + try { + //noinspection unchecked + com.sun.tools.javac.util.List jcCompilationUnits = compiler.parseFiles((List) (List) inputFileObjects); + for (int i = 0; i < inputFileObjects.size(); i++) { + cus.put(inputFileObjects.get(i).getInput(), jcCompilationUnits.get(i)); + } + try { + enterAll(cus.values()); + JavaCompiler delegate = annotationProcessors.isEmpty() ? compiler : compiler.processAnnotations(jcCompilationUnits, nil()); + delegate.attribute(delegate.todo); + } catch (Throwable t) { + // when symbol entering fails on problems like missing types, attribution can often times proceed + // unhindered, but it sometimes cannot (so attribution is always best-effort in the presence of errors) + ctx.getOnError().accept(new JavaParsingException("Failed symbol entering or attribution", t)); + } + } catch (IllegalStateException e) { + if ("endPosTable already set".equals(e.getMessage())) { + throw new IllegalStateException( + "Call reset() on JavaParser before parsing another set of source files that " + + "have some of the same fully qualified names.", e); + } + throw e; + } + + return cus; + } + @Override public ReloadableJava8Parser reset() { typeCache.clear(); @@ -261,35 +341,6 @@ public void reset(Collection uris) { } } - private static class TimedTodo extends Todo { - private final Todo todo; - private Timer.@Nullable Sample sample; - - private TimedTodo(Todo todo) { - super(new Context()); - this.todo = todo; - } - - @Override - public boolean isEmpty() { - if (sample != null) { - sample.stop(MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent by the JDK in type attributing the source file") - .tag("file.type", "Java") - .tag("step", "(2) Type attribution")) - .register(Metrics.globalRegistry)); - } - return todo.isEmpty(); - } - - @Override - public Env remove() { - this.sample = Timer.start(); - return todo.remove(); - } - } - private static class ByteArrayCapableJavacFileManager extends JavacFileManager { private final List classByteClasspath; @@ -332,6 +383,7 @@ public Iterable list(Location location, String packageName, Set< private static class PackageAwareJavaFileObject extends SimpleJavaFileObject { private final String pkg; + @Getter private final String className; private final byte[] classBytes; @@ -365,10 +417,6 @@ public String getPackage() { return pkg; } - public String getClassName() { - return className; - } - @Override public InputStream openInputStream() { return new ByteArrayInputStream(classBytes); diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index 6b944cff74a..0d6cf8309fc 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -25,6 +25,7 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Context; +import lombok.Generated; import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; @@ -33,7 +34,6 @@ import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.JavaPrinter; import org.openrewrite.java.marker.OmitParentheses; import org.openrewrite.java.marker.TrailingComma; import org.openrewrite.java.tree.*; @@ -339,7 +339,7 @@ public J visitCase(CaseTree node, Space fmt) { node.getExpression() == null ? EMPTY : sourceBefore("case"), singletonList(node.getExpression() == null ? JRightPadded.build(new J.Identifier(randomId(), Space.EMPTY, Markers.EMPTY, emptyList(), skip("default"), null, null)) : - JRightPadded.build(convertOrNull(node.getExpression())) + JRightPadded.build(convert(node.getExpression())) ), Markers.EMPTY ), @@ -391,7 +391,7 @@ public J visitClass(ClassTree node, Space fmt) { Markers.EMPTY); JLeftPadded extendings = node.getExtendsClause() == null ? null : - padLeft(sourceBefore("extends"), convertOrNull(node.getExtendsClause())); + padLeft(sourceBefore("extends"), convert(node.getExtendsClause())); JContainer implementings = null; if (node.getImplementsClause() != null && !node.getImplementsClause().isEmpty()) { @@ -659,7 +659,7 @@ public J visitForLoop(ForLoopTree node, Space fmt) { commaDelim.apply(t) ); - JRightPadded condition = convertOrNull(node.getCondition(), semiDelim); + JRightPadded condition = convert(node.getCondition(), semiDelim); if (condition == null) { condition = padRight(new J.Empty(randomId(), sourceBefore(";"), Markers.EMPTY), EMPTY); } @@ -927,7 +927,7 @@ public J visitMethod(MethodTree node, Space fmt) { } List returnTypeAnnotations = collectAnnotations(annotationPosTable); - TypeTree returnType = convertOrNull(node.getReturnType()); + TypeTree returnType = convert(node.getReturnType()); if (returnType != null && !returnTypeAnnotations.isEmpty()) { returnType = new J.AnnotatedType(randomId(), Space.EMPTY, Markers.EMPTY, returnTypeAnnotations, returnType); @@ -970,7 +970,7 @@ public J visitMethod(MethodTree node, Space fmt) { JContainer.build(sourceBefore("throws"), convertAll(node.getThrows(), commaDelim, noDelim), Markers.EMPTY); - J.Block body = convertOrNull(node.getBody()); + J.Block body = convert(node.getBody()); JLeftPadded defaultValue = node.getDefaultValue() == null ? null : padLeft(sourceBefore("default"), convert(node.getDefaultValue())); @@ -994,9 +994,9 @@ public J visitNewArray(NewArrayTree node, Space fmt) { while (elementType instanceof JCArrayTypeTree) { elementType = ((JCArrayTypeTree) elementType).elemtype; } - typeExpr = convertOrNull(elementType); + typeExpr = convert(elementType); } else { - typeExpr = convertOrNull(jcVarType); + typeExpr = convert(jcVarType); } List nodeDimensions = node.getDimensions(); @@ -1053,7 +1053,7 @@ public J visitNewClass(NewClassTree node, Space fmt) { } // for enum definitions with anonymous class initializers, endPos of node identifier will be -1 - TypeTree clazz = endPos(node.getIdentifier()) >= 0 ? convertOrNull(node.getIdentifier()) : null; + TypeTree clazz = endPos(node.getIdentifier()) >= 0 ? convert(node.getIdentifier()) : null; JContainer args; if (positionOfNext("(", '{') > -1) { @@ -1161,7 +1161,8 @@ public J visitPrimitiveType(PrimitiveTypeTree node, Space fmt) { @Override public J visitReturn(ReturnTree node, Space fmt) { skip("return"); - return new J.Return(randomId(), fmt, Markers.EMPTY, convertOrNull(node.getExpression())); + Expression expression = convert(node.getExpression()); + return new J.Return(randomId(), fmt, Markers.EMPTY, expression); } @Override @@ -1506,6 +1507,17 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm TypeTree typeExpr; if (vartype == null || endPos(vartype) < 0 || vartype instanceof JCErroneous) { typeExpr = null; // this is a lambda parameter with an inferred type expression + } else if (isLombokGenerated(node)) { + Space space = whitespace(); + boolean lombokVal = source.startsWith("val", cursor); + cursor += 3; // skip `val` or `var` + typeExpr = new J.Identifier(randomId(), + space, + Markers.build(singletonList(JavaVarKeyword.build())), + emptyList(), + lombokVal ? "val" : "var", + typeMapping.type(vartype), + null); } else if (vartype instanceof JCArrayTypeTree) { JCExpression elementType = vartype; while (elementType instanceof JCArrayTypeTree || elementType instanceof JCAnnotatedType) { @@ -1542,10 +1554,9 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm List> vars = new ArrayList<>(nodes.size()); for (int i = 0; i < nodes.size(); i++) { - VariableTree n = nodes.get(i); + JCVariableDecl n = (JCVariableDecl) nodes.get(i); Space namedVarPrefix = sourceBefore(n.getName().toString()); - JCVariableDecl vd = (JCVariableDecl) n; JavaType type = typeMapping.type(n); J.Identifier name = new J.Identifier(randomId(), EMPTY, Markers.EMPTY, emptyList(), n.getName().toString(), @@ -1558,7 +1569,7 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm new J.VariableDeclarations.NamedVariable(randomId(), namedVarPrefix, Markers.EMPTY, name, dimensionsAfterName, - vd.init != null ? padLeft(sourceBefore("="), convertOrNull(vd.init)) : null, + n.init != null ? padLeft(sourceBefore("="), convert(n.init)) : null, (JavaType.Variable) typeMapping.type(n) ), i == nodes.size() - 1 ? EMPTY : sourceBefore(",") @@ -1615,7 +1626,7 @@ public J visitWildcard(WildcardTree node, Space fmt) { bound = null; } - return new J.Wildcard(randomId(), fmt, Markers.EMPTY, bound, convertOrNull(wildcard.inner)); + return new J.Wildcard(randomId(), fmt, Markers.EMPTY, bound, convert(wildcard.inner)); } /** @@ -1623,9 +1634,12 @@ public J visitWildcard(WildcardTree node, Space fmt) { * Conversion utilities * -------------- */ - private J2 convert(Tree t) { + private @Nullable J2 convert(@Nullable Tree t) { + if (t == null) { + return null; + } try { - String prefix = source.substring(cursor, max(((JCTree) t).getStartPosition(), cursor)); + String prefix = source.substring(cursor, Math.max(cursor, getActualStartPosition((JCTree) t))); cursor += prefix.length(); @SuppressWarnings("unchecked") J2 j = (J2) scan(t, formatWithCommentTree(prefix, (JCTree) t, docCommentTable.getCommentTree((JCTree) t))); return j; @@ -1655,11 +1669,25 @@ private J2 convert(Tree t) { } } - private JRightPadded convert(Tree t, Function suffix) { + private static int getActualStartPosition(JCTree t) { + // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation + if (t instanceof JCVariableDecl && isLombokGenerated(t)) { + return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); + } + return t.getStartPosition(); + } + + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix) { + if (t == null) { + return null; + } return convert(t, suffix, j -> Markers.EMPTY); } - private JRightPadded convert(Tree t, Function suffix, Function markers) { + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix, Function markers) { + if (t == null) { + return null; + } J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : new JRightPadded<>(j, suffix.apply(t), markers.apply(t)); @@ -1710,14 +1738,6 @@ private long lineNumber(Tree tree) { return lineNumber; } - private @Nullable T convertOrNull(@Nullable Tree t) { - return t == null ? null : convert(t); - } - - private @Nullable JRightPadded convertOrNull(@Nullable Tree t, Function suffix) { - return t == null ? null : convert(t, suffix); - } - private List convertAll(List trees) { List converted = new ArrayList<>(trees.size()); for (Tree tree : trees) { @@ -1836,6 +1856,9 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { + if (!(t instanceof JCVariableDecl) && isLombokGenerated(t)) { + continue; + } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); } @@ -1865,6 +1888,32 @@ private List> convertStatements(@Nullable List "@lombok.Generated()".equals(a.toString())); + } + } else if (tree instanceof JCTree.JCClassDecl) { + sym = ((JCClassDecl) tree).sym; + } else if (tree instanceof JCTree.JCVariableDecl) { + sym = ((JCVariableDecl) tree).sym; + return sym != null && sym.getDeclarationAttributes().stream().anyMatch(a -> "lombok.val".equals(a.type.toString()) || "lombok.var".equals(a.type.toString())); + } + + //noinspection ConstantConditions + return sym != null && ( + "lombok.val".equals(sym.getQualifiedName().toString()) || "lombok.var".equals(sym.getQualifiedName().toString()) || + sym.getAnnotation(Generated.class) != null + ); + } + /** * -------------- * Other convenience utilities @@ -2040,13 +2089,17 @@ private Java8ModifierResults sortedModifiersAndAnnotations(ModifiersTree modifie int lastAnnotationPosition = cursor; for (int i = cursor; i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { - J.Annotation annotation = convert(annotationPosTable.get(i)); + JCAnnotation jcAnnotation = annotationPosTable.get(i); + if (isLombokGenerated(jcAnnotation.getAnnotationType())) { + continue; + } + J.Annotation annotation = convert(jcAnnotation); if (afterFirstModifier) { currentAnnotations.add(annotation); } else { leadingAnnotations.add(annotation); } - i = cursor -1; + i = cursor - 1; lastAnnotationPosition = cursor; continue; } @@ -2160,7 +2213,11 @@ private List collectAnnotations(Map annotat boolean inMultilineComment = false; for (int i = cursor; i <= maxAnnotationPosition && i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { - annotations.add(convert(annotationPosTable.get(i))); + JCAnnotation jcAnnotation = annotationPosTable.get(i); + if (isLombokGenerated(jcAnnotation)) { + continue; + } + annotations.add(convert(jcAnnotation)); i = cursor; continue; } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/package-info.java b/rewrite-java-8/src/main/java/org/openrewrite/java/package-info.java new file mode 100644 index 00000000000..e697a3e66c4 --- /dev/null +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2020 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +@NonNullFields +package org.openrewrite.java; + +import org.jspecify.annotations.NullMarked; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/AllArgsConstructorHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/AllArgsConstructorHandler.java index b629bee724a..b4b04d39c1d 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/AllArgsConstructorHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/AllArgsConstructorHandler.java @@ -40,7 +40,6 @@ public void handle(AnnotationValues annotationValues, JCTree JCTree.JCIdent ident = (JCTree.JCIdent) assign.getVariable(); String name = ident.getName().toString(); if (name.equals("onConstructor") || name.equals("onConstructor_")) { - // In Java 1.8+ the parameter is `onConstructor_` continue; } } diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodNoOpHandler.java similarity index 91% rename from rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodHandler.java rename to rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodNoOpHandler.java index 68b5543da96..dbc6be1dcf4 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodNoOpHandler.java @@ -21,7 +21,7 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; -public class ExtensionMethodHandler extends JavacAnnotationHandler { +public class ExtensionMethodNoOpHandler extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotationValues, JCTree.JCAnnotation jcAnnotation, JavacNode javacNode) { } diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperNoOpHandler.java similarity index 93% rename from rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperHandler.java rename to rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperNoOpHandler.java index d1ef2b9fa59..6b7a1be1085 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperNoOpHandler.java @@ -21,7 +21,7 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; -public class HelperHandler extends JavacAnnotationHandler { +public class HelperNoOpHandler extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCTree.JCAnnotation ast, JavacNode annotationNode) { } diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedNoOpHandler.java similarity index 93% rename from rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedHandler.java rename to rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedNoOpHandler.java index a9ce02cd671..bd66517d6ff 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedNoOpHandler.java @@ -24,7 +24,7 @@ @SuppressWarnings("SpellCheckingInspection") @HandlerPriority(-512) -public class JacksonizedHandler extends JavacAnnotationHandler { +public class JacksonizedNoOpHandler extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCTree.JCAnnotation ast, JavacNode annotationNode) { } diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/NoArgsConstructorHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/NoArgsConstructorHandler.java index b5942688f46..1acfcfb96a1 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/NoArgsConstructorHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/NoArgsConstructorHandler.java @@ -38,7 +38,8 @@ public void handle(AnnotationValues annotationValues, JCTree. if (originalArg instanceof JCTree.JCAssign && ((JCTree.JCAssign) originalArg).getVariable() instanceof JCTree.JCIdent) { JCTree.JCAssign assign = (JCTree.JCAssign) originalArg; JCTree.JCIdent ident = (JCTree.JCIdent) assign.getVariable(); - if ("onConstructor".equals(ident.getName().toString())) { + String name = ident.getName().toString(); + if (name.equals("onConstructor") || name.equals("onConstructor_")) { continue; } } diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/RequiredArgsConstructorHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/RequiredArgsConstructorHandler.java index e20877acf3d..c376de6bf22 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/RequiredArgsConstructorHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/RequiredArgsConstructorHandler.java @@ -38,7 +38,8 @@ public void handle(AnnotationValues annotationValues, J if (originalArg instanceof JCTree.JCAssign && ((JCTree.JCAssign) originalArg).getVariable() instanceof JCTree.JCIdent) { JCTree.JCAssign assign = (JCTree.JCAssign) originalArg; JCTree.JCIdent ident = (JCTree.JCIdent) assign.getVariable(); - if ("onConstructor".equals(ident.getName().toString())) { + String name = ident.getName().toString(); + if (name.equals("onConstructor") || name.equals("onConstructor_")) { continue; } } diff --git a/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler b/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler index 322964dfb1b..b556f06f95e 100644 --- a/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler +++ b/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler @@ -17,10 +17,10 @@ org.openrewrite.java.lombok.AllArgsConstructorHandler org.openrewrite.java.lombok.BuilderHandler org.openrewrite.java.lombok.BuilderDefaultNoOpHandler org.openrewrite.java.lombok.CleanupNoOpHandler -org.openrewrite.java.lombok.ExtensionMethodHandler +org.openrewrite.java.lombok.ExtensionMethodNoOpHandler org.openrewrite.java.lombok.GetterHandler -org.openrewrite.java.lombok.HelperHandler -org.openrewrite.java.lombok.JacksonizedHandler +org.openrewrite.java.lombok.HelperNoOpHandler +org.openrewrite.java.lombok.JacksonizedNoOpHandler org.openrewrite.java.lombok.LockedNoOpHandler org.openrewrite.java.lombok.LockedReadNoOpHandler org.openrewrite.java.lombok.LockedWriteNoOpHandler diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index 6a355210012..aab176f0a7f 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -19,9 +19,8 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledOnJre; -import org.junit.jupiter.api.condition.JRE; import org.openrewrite.java.JavaParser; +import org.openrewrite.java.MinimumJava11; import org.openrewrite.java.search.FindMissingTypes; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; @@ -34,7 +33,6 @@ import static org.openrewrite.java.Assertions.java; @SuppressWarnings({"CaughtExceptionImmediatelyRethrown", "LombokGetterMayBeUsed", "LombokSetterMayBeUsed", "DefaultAnnotationParam", "NotNullFieldNotInitialized", "ProtectedMemberInFinalClass", "WriteOnlyObject", "ConcatenationWithEmptyString"}) -@EnabledOnJre({JRE.JAVA_11, JRE.JAVA_17, JRE.JAVA_21}) class LombokTest implements RewriteTest { @BeforeAll @@ -248,6 +246,12 @@ public class ConstructorExample { public static class NoArgsExample { @NonNull private String field; } + + public void test() { + ConstructorExample x = ConstructorExample.of("desc"); + ConstructorExample y = new ConstructorExample<>("1L"); + ConstructorExample.NoArgsExample z = new ConstructorExample.NoArgsExample(); + } } """ ) @@ -437,7 +441,7 @@ public class SingularExample { } @Test - void jul() { + void log() { rewriteRun( java( """ @@ -459,6 +463,23 @@ void m() { ); } + @Test + void var() { + rewriteRun( + java( + """ + import lombok.var; + + class Test { + void test() { + var s = "foo"; + } + } + """ + ) + ); + } + @Test void val() { rewriteRun( @@ -696,6 +717,7 @@ public void both(String s) { } @Test + @MinimumJava11 void jacksonized() { rewriteRun( spec -> spec.parser(JavaParser.fromJavaVersion().classpath("jackson-annotations", "lombok")), @@ -725,6 +747,11 @@ void standardException() { @StandardException public class ExampleException extends Exception { + public void test() { + new ExampleException("message"); + new ExampleException(new RuntimeException("message")); + new ExampleException("message", new RuntimeException("message")); + } } """ ) @@ -732,29 +759,27 @@ public class ExampleException extends Exception { } @Test + @MinimumJava11 void onConstructor() { rewriteRun( - spec -> spec.typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { - assert o instanceof FindMissingTypes.MissingTypeResult; - FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; - // type attribution is missing for annotation args, as it was intentionally removed for processing. - return result.getPath().startsWith("Identifier->Annotation->"); - }).build()), + java( + """ + public @interface Inject {} + public @interface Id {} + public @interface Column { String name(); } + public @interface Max { long value(); } + """ + ), java( """ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; - import javax.inject.Inject; - import javax.persistence.Id; - import javax.persistence.Column; - import javax.validation.constraints.Max; - - @AllArgsConstructor(onConstructor=@__(@Inject)) + @AllArgsConstructor(onConstructor_=@Inject) public class OnXExample { - @Getter(onMethod_={@Id, @Column(name="unique-id")}) //JDK8 - @Setter(onParam_=@Max(10000)) //JDK8 + @Getter(onMethod_={@Id, @Column(name="unique-id")}) + @Setter(onParam_=@Max(10000)) private long unid; public void test() { @@ -769,17 +794,14 @@ public void test() { } @Test + @MinimumJava11 void onConstructorNoArgs() { rewriteRun( - spec -> spec.typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { - assert o instanceof FindMissingTypes.MissingTypeResult; - FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; - if (result.getJ() instanceof J.Identifier identifier) { - // type attribution is missing for annotation args, as it was intentionally removed for processing. - return identifier.getSimpleName().equals("__") || identifier.getSimpleName().equals("Inject"); - } - return false; - }).build()), + java( + """ + public @interface Inject {} + """ + ), java( """ import lombok.NoArgsConstructor; @@ -788,8 +810,8 @@ void onConstructorNoArgs() { import javax.inject.Inject; - @NoArgsConstructor(onConstructor = @__(@Inject)) - @RequiredArgsConstructor(onConstructor = @__(@Inject)) + @NoArgsConstructor(onConstructor_ = @Inject) + @RequiredArgsConstructor(onConstructor_ = @Inject) public class OnXExample { @NonNull private Long unid; @@ -810,6 +832,127 @@ public void test() { @SuppressWarnings("MismatchedReadAndWriteOfArray") @Nested class LessSupported { + /* + java 8 cannot figure out all type checking: + - When the @AllArgsConstructorHandler, @NoArgsConstructorHandler and @NoArgsConstructorHandler annotations are + used with the `onConstructor_` param, Lombok does not call the JavacAnnotationHandlers. + - The @Jacksonized annotation does somehow turns into `ClassDeclaration->CompilationUni` error + */ + + @Test + // TODO: Find solution and remove this test + void jacksonizedForJava8() { + rewriteRun( + spec -> spec + .parser(JavaParser.fromJavaVersion().classpath("jackson-annotations", "lombok")) + .typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { + assert o instanceof FindMissingTypes.MissingTypeResult; + FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; + // Using the @Jacksonized annotation in java 8 just breaks it all + return result.getPath().startsWith("ClassDeclaration->CompilationUnit") || + result.getPath().startsWith("Identifier->Annotation")|| + result.getPath().startsWith("Identifier->ParameterizedType"); + }).build()), + java( + """ + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import lombok.Builder; + import lombok.extern.jackson.Jacksonized; + + @Jacksonized + @Builder + @JsonIgnoreProperties(ignoreUnknown = true) + public class JacksonExample { + private List strings; + } + """ + ) + ); + } + + @Test + // TODO: Find solution and remove this test + void onConstructorForJava8() { + rewriteRun( + spec -> spec.typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { + assert o instanceof FindMissingTypes.MissingTypeResult; + FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; + // The AllArgsConstructorHandler, GetterHandler and SetterHandler do not run at all for java 8, + // so no generated constructors and methods, thus no types. + return result.getPath().startsWith("NewClass->") || result.getPath().startsWith("MethodInvocation->"); + }).build()), + java( + """ + public @interface Inject {} + public @interface Id {} + public @interface Column { String name(); } + public @interface Max { long value(); } + """ + ), + java( + """ + import lombok.AllArgsConstructor; + import lombok.Getter; + import lombok.Setter; + + @AllArgsConstructor(onConstructor_=@Inject) + public class OnXExample { + @Getter(onMethod_={@Id, @Column(name="unique-id")}) + @Setter(onParam_=@Max(10000)) + private long unid; + + public void test() { + OnXExample x = new OnXExample(1L); + x.setUnid(2L); + System.out.println(x.getUnid()); + } + } + """ + ) + ); + } + + @Test + // TODO: Find solution and remove this test + void onConstructorNoArgsForJava8() { + rewriteRun( + spec -> spec.typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { + assert o instanceof FindMissingTypes.MissingTypeResult; + FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; + // The NoArgsConstructor and RequiredArgsConstructor do not run at all for java 8, + // so no generated constructors, thus no types. + return result.getPath().startsWith("NewClass->"); + }).build()), + java( + """ + public @interface Inject {} + public @interface Ignore {} // somehow we need this, to prevent `ClassDeclaration->CompilationUnit` errors + """ + ), + java( + """ + import lombok.NoArgsConstructor; + import lombok.NonNull; + import lombok.RequiredArgsConstructor; + + import javax.inject.Inject; + + @NoArgsConstructor(onConstructor_=@Inject) + @RequiredArgsConstructor(onConstructor_=@Inject) + public class OnXExample { + @NonNull private Long unid; + + public void test() { + new OnXExample(); + new OnXExample(1L); + } + } + """ + ) + ); + } + + @Test void extensionMethod() { rewriteRun( From 6609c8c5818f2a5d80fb71aa507ccc8b4b82bb4a Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Fri, 10 Jan 2025 14:11:47 +0100 Subject: [PATCH 130/179] Update VariableDeclarationsTest.java --- .../openrewrite/groovy/tree/VariableDeclarationsTest.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java index 370772cb111..37eac3efad3 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/tree/VariableDeclarationsTest.java @@ -221,9 +221,11 @@ void defAndExplicitReturnType() { @Test void defVariableStartsWithDef() { rewriteRun( - groovy(""" - def defaultPublicStaticFinal = 0 - """) + groovy( + """ + def defaultPublicStaticFinal = 0 + """ + ) ); } } From 6ff7a03d80a988b1751664697f7e51e5e97035df Mon Sep 17 00:00:00 2001 From: Niels de Bruin Date: Fri, 10 Jan 2025 14:37:14 +0100 Subject: [PATCH 131/179] Add recipe to enable Develocity build cache for Gradle (#4859) * Add enable buildcache recipe for gradle * Fix description * Update test cases and rename config * Add initial version of visitor * Update rewrite-gradle/src/main/java/org/openrewrite/gradle/EnableDevelocityBuildCache.java Co-authored-by: Jacob van Lingen * Indent fix * Polish * Change validation * Remove linebreaks * Simplify how build cache is created and extracted * Only look for develocity at the root, and buildCache within that * Show a richer example for `remotePushEnabled` --------- Co-authored-by: Jacob van Lingen Co-authored-by: Tim te Beek --- .../gradle/EnableDevelocityBuildCache.java | 118 +++++++++++++++ .../EnableDevelocityBuildCacheTest.java | 142 ++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 rewrite-gradle/src/main/java/org/openrewrite/gradle/EnableDevelocityBuildCache.java create mode 100644 rewrite-gradle/src/test/java/org/openrewrite/gradle/EnableDevelocityBuildCacheTest.java diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/EnableDevelocityBuildCache.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/EnableDevelocityBuildCache.java new file mode 100644 index 00000000000..f15ab6ac8cc --- /dev/null +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/EnableDevelocityBuildCache.java @@ -0,0 +1,118 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.gradle; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.jspecify.annotations.Nullable; +import org.openrewrite.*; +import org.openrewrite.groovy.GroovyIsoVisitor; +import org.openrewrite.groovy.tree.G; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.java.tree.J; + +import java.util.concurrent.atomic.AtomicBoolean; + +@Value +@EqualsAndHashCode(callSuper = false) +public class EnableDevelocityBuildCache extends Recipe { + + @Override + public String getDisplayName() { + return "Enable Develocity build cache"; + } + + @Override + public String getDescription() { + return "Adds `buildCache` configuration to `develocity` where not yet present."; + } + + @Option(displayName = "Enable remote build cache", + description = "Value for `//develocity/buildCache/remote/enabled`.", + example = "true", + required = false) + @Nullable + String remoteEnabled; + + @Option(displayName = "Enable remote build cache push", + description = "Value for `//develocity/buildCache/remote/storeEnabled`.", + example = "System.getenv(\"CI\") != null", + required = false) + @Nullable + String remotePushEnabled; + + @Override + public Validated validate(ExecutionContext ctx) { + return super.validate(ctx) + .and(Validated.notBlank("remoteEnabled", remoteEnabled) + .or(Validated.notBlank("remotePushEnabled", remotePushEnabled))); + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new IsSettingsGradle<>(), new GroovyIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + if ("develocity".equals(method.getSimpleName()) && !hasBuildCache(method)) { + J.MethodInvocation buildCache = createBuildCache(); + return maybeAutoFormat(method, method.withArguments(ListUtils.mapFirst(method.getArguments(), arg -> { + if (arg instanceof J.Lambda) { + J.Lambda lambda = (J.Lambda) arg; + J.Block block = (J.Block) lambda.getBody(); + return lambda.withBody(block.withStatements(ListUtils.concat(block.getStatements(), buildCache))); + } + return arg; + })), ctx); + } + return method; + } + + private boolean hasBuildCache(J.MethodInvocation m) { + return new GroovyIsoVisitor() { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, AtomicBoolean atomicBoolean) { + if ("buildCache".equals(method.getSimpleName())) { + atomicBoolean.set(true); + return method; + } + return super.visitMethodInvocation(method, atomicBoolean); + } + }.reduce(m, new AtomicBoolean(false), getCursor().getParentTreeCursor()).get(); + } + }); + } + + private J.MethodInvocation createBuildCache() { + String conf = "buildCache {\n" + + " remote(develocity.buildCache) {\n"; + if (!StringUtils.isBlank(remoteEnabled)) { + conf += " enabled = " + remoteEnabled + "\n"; + } + if (!StringUtils.isBlank(remotePushEnabled)) { + conf += " push = " + remotePushEnabled + "\n"; + } + conf += " }" + + "}"; + return (J.MethodInvocation) GradleParser.builder().build() + .parse(conf) + .map(G.CompilationUnit.class::cast) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Could not parse as Gradle")) + .getStatements() + .get(0); + } +} diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/EnableDevelocityBuildCacheTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/EnableDevelocityBuildCacheTest.java new file mode 100644 index 00000000000..6e725db524f --- /dev/null +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/EnableDevelocityBuildCacheTest.java @@ -0,0 +1,142 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.gradle; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.gradle.Assertions.settingsGradle; + +class EnableDevelocityBuildCacheTest implements RewriteTest { + + @Test + @DocumentExample + void addBuildCacheRemoteConfig() { + rewriteRun(spec -> spec.recipe(new EnableDevelocityBuildCache("true", "System.getenv(\"CI\") != null")), + settingsGradle( + """ + plugins { + id 'com.gradle.develocity' version '3.17.6' + } + develocity { + server = 'https://dev.example.com/' + } + """, + """ + plugins { + id 'com.gradle.develocity' version '3.17.6' + } + develocity { + server = 'https://dev.example.com/' + buildCache { + remote(develocity.buildCache) { + enabled = true + push = System.getenv("CI") != null + } + } + } + """ + ) + ); + } + + @Test + void addBuildCacheRemoteConfigExtendedConfig() { + rewriteRun(spec -> spec.recipe(new EnableDevelocityBuildCache("true", "System.getenv(\"CI\") != null")), + settingsGradle( + """ + plugins { + id 'com.gradle.develocity' version '3.17.6' + } + develocity { + server = 'https://dev.example.com/' + buildScan { + uploadInBackground = true + } + } + """, + """ + plugins { + id 'com.gradle.develocity' version '3.17.6' + } + develocity { + server = 'https://dev.example.com/' + buildScan { + uploadInBackground = true + } + buildCache { + remote(develocity.buildCache) { + enabled = true + push = System.getenv("CI") != null + } + } + } + """ + ) + ); + } + + @Test + void addBuildCacheRemoteConfigWithOnlyPush() { + rewriteRun(spec -> spec.recipe(new EnableDevelocityBuildCache(null, "true")), + settingsGradle( + """ + plugins { + id 'com.gradle.develocity' version '3.17.6' + } + develocity { + server = 'https://dev.example.com/' + } + """, + """ + plugins { + id 'com.gradle.develocity' version '3.17.6' + } + develocity { + server = 'https://dev.example.com/' + buildCache { + remote(develocity.buildCache) { + push = true + } + } + } + """ + ) + ); + } + + @Test + void shouldNotModifyBuildCacheConfig() { + rewriteRun(spec -> spec.recipe(new EnableDevelocityBuildCache(null, "#{isTrue(env['CI'])}")), + settingsGradle( + """ + plugins { + id 'com.gradle.develocity' version '3.17.6' + } + develocity { + server = 'https://dev.example.com/' + buildCache { + remote(develocity.buildCache) { + push = false + } + } + } + """ + ) + ); + } +} From cd013f483ea5c224698a05635d6915ebcd25ac99 Mon Sep 17 00:00:00 2001 From: "$(git --no-pager log --format=format:'%an' -n 1)" Date: Fri, 10 Jan 2025 08:29:13 -0800 Subject: [PATCH 132/179] Add dark/light svg logo For updating various readmes in the future --- doc/logo-oss-dark.svg | 10 ++++++++++ doc/logo-oss-light.svg | 3 +++ 2 files changed, 13 insertions(+) create mode 100644 doc/logo-oss-dark.svg create mode 100644 doc/logo-oss-light.svg diff --git a/doc/logo-oss-dark.svg b/doc/logo-oss-dark.svg new file mode 100644 index 00000000000..28c6e76e49e --- /dev/null +++ b/doc/logo-oss-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/doc/logo-oss-light.svg b/doc/logo-oss-light.svg new file mode 100644 index 00000000000..d462da46bd9 --- /dev/null +++ b/doc/logo-oss-light.svg @@ -0,0 +1,3 @@ + + + From 882291babf9517f80f5e57af47b90274bebbd199 Mon Sep 17 00:00:00 2001 From: "$(git --no-pager log --format=format:'%an' -n 1)" Date: Fri, 10 Jan 2025 08:49:44 -0800 Subject: [PATCH 133/179] Swap name of dark/light logo --- doc/logo-oss-dark.svg | 11 ++--------- doc/logo-oss-light.svg | 11 +++++++++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/logo-oss-dark.svg b/doc/logo-oss-dark.svg index 28c6e76e49e..d462da46bd9 100644 --- a/doc/logo-oss-dark.svg +++ b/doc/logo-oss-dark.svg @@ -1,10 +1,3 @@ - - - - - - - - - + + diff --git a/doc/logo-oss-light.svg b/doc/logo-oss-light.svg index d462da46bd9..28c6e76e49e 100644 --- a/doc/logo-oss-light.svg +++ b/doc/logo-oss-light.svg @@ -1,3 +1,10 @@ - - + + + + + + + + + From cb5a05955373dd36432e0f64ac2e92093d4efe18 Mon Sep 17 00:00:00 2001 From: "$(git --no-pager log --format=format:'%an' -n 1)" Date: Fri, 10 Jan 2025 08:53:58 -0800 Subject: [PATCH 134/179] Update readme with new logo --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ff6438cf8a..fd3be8c71bc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@

- OpenRewrite + + + + + OpenRewrite Logo + +

From dd67fe6273f972946826d3acf7c090ee215df207 Mon Sep 17 00:00:00 2001 From: Daniel Shamis <62334660+danielshamis@users.noreply.github.com> Date: Fri, 10 Jan 2025 19:34:24 +0100 Subject: [PATCH 135/179] Add test for inner annotations and fix (#4885) --- .../AddOrUpdateAnnotationAttributeTest.java | 46 +++++++++++++++++++ .../java/AddOrUpdateAnnotationAttribute.java | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java index ac1b1bc8117..63f16fb0ef1 100755 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java @@ -892,4 +892,50 @@ public class A { ) ); } + + @Test + void addAttributeToNestedAnnotationArray() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute( + "org.example.Bar", + "attribute", + "", + null, + false)), + java( + """ + package org.example; + public @interface Foo { + Bar[] array() default {}; + } + """ + ), + java( + """ + package org.example; + public @interface Bar { + String attribute() default ""; + } + """ + ), + java( + """ + import org.example.Foo; + import org.example.Bar; + + @Foo(array = { @Bar() }) + public class A { + } + """, + """ + import org.example.Foo; + import org.example.Bar; + + @Foo(array = { @Bar(attribute = "") }) + public class A { + } + """ + ) + ); + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java b/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java index a62f0be4967..05257701bfd 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java @@ -87,7 +87,7 @@ public TreeVisitor getVisitor() { public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { J.Annotation original = super.visitAnnotation(a, ctx); if (!TypeUtils.isOfClassType(a.getType(), annotationType)) { - return a; + return original; } String newAttributeValue = maybeQuoteStringArgument(attributeName, attributeValue, a); From 4a8a38b4dcda1a6c4044cb332bc29511b196263f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Sun, 12 Jan 2025 17:41:09 +0100 Subject: [PATCH 136/179] Enable `AnnotationMatcher` to match values in `J.NewArray` (#4889) * improve `AnnotationMatcher` to match on values in `J.NewArray` initializers values * update java doc --- .../openrewrite/java/AnnotationMatcher.java | 18 ++++++--- .../openrewrite/java/trait/AnnotatedTest.java | 40 +++++++++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/AnnotationMatcher.java b/rewrite-java/src/main/java/org/openrewrite/java/AnnotationMatcher.java index e37d088fe21..94b138738d1 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/AnnotationMatcher.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/AnnotationMatcher.java @@ -47,7 +47,7 @@ * {@literal @}java.lang.SuppressWarnings - Matches java.lang.SuppressWarnings with no parameters. * {@literal @}myhttp.Get(serviceName="payments", path="recentPayments") - Matches references to myhttp.Get where the parameters are also matched. * {@literal @}myhttp.Get(path="recentPayments", serviceName="payments") - Exactly the same results from the previous example, order of parameters does not matter. - * {@literal @}java.lang.SuppressWarnings("deprecation") - Matches java.langSuppressWarning with a single parameter. + * {@literal @}java.lang.SuppressWarnings("deprecation") - Matches java.langSuppressWarning with a parameter "deprecation", values in array initializer match as well. * {@literal @}org.junit.runner.RunWith(org.junit.runners.JUnit4.class) - Matches JUnit4's @RunWith(JUnit4.class) * */ @@ -76,8 +76,8 @@ public AnnotationMatcher(String signature) { public boolean matches(J.Annotation annotation) { return matchesAnnotationName(annotation) && - matchesSingleParameter(annotation) && - matchesNamedParameters(annotation); + matchesSingleParameter(annotation) && + matchesNamedParameters(annotation); } private boolean matchesAnnotationName(J.Annotation annotation) { @@ -99,7 +99,7 @@ private boolean matchesAnnotationOrMetaAnnotation(JavaType.@Nullable FullyQualif seenAnnotations = new HashSet<>(); } if (seenAnnotations.add(annotation.getFullyQualifiedName()) && - matchesAnnotationOrMetaAnnotation(annotation, seenAnnotations)) { + matchesAnnotationOrMetaAnnotation(annotation, seenAnnotations)) { return true; } } @@ -168,10 +168,16 @@ private boolean argumentValueMatches(String matchOnArgumentName, Expression arg, } if (arg instanceof J.NewArray) { J.NewArray na = (J.NewArray) arg; - if (na.getInitializer() == null || na.getInitializer().size() != 1) { + if (na.getInitializer() == null) { return false; } - return argumentValueMatches("value", na.getInitializer().get(0), matchText); + // recursively check each initializer of the array initializer + for (Expression expression : na.getInitializer()) { + if (argumentValueMatches(matchOnArgumentName, expression, matchText)) { + return true; + } + } + return false; } } diff --git a/rewrite-java/src/test/java/org/openrewrite/java/trait/AnnotatedTest.java b/rewrite-java/src/test/java/org/openrewrite/java/trait/AnnotatedTest.java index 4f55f333154..e928803d389 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/trait/AnnotatedTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/trait/AnnotatedTest.java @@ -62,4 +62,44 @@ class Test { ) ); } + + @Test + void checkOnArray() { + rewriteRun( + spec -> + spec.recipe(RewriteTest.toRecipe(() -> + annotated("@Example(other=\"World\")") + .asVisitor(a -> SearchResult.found(a.getTree())) + )), + java( + //language=java + """ + import java.lang.annotation.ElementType; + import java.lang.annotation.Retention; + import java.lang.annotation.RetentionPolicy; + import java.lang.annotation.Target; + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @interface Example { + String[] other; + } + """ + ), + java( + //language=java + """ + @Example(other = {"Hello", "World"}) + class Test { + } + """, + //language=java + """ + /*~~>*/@Example(other = {"Hello", "World"}) + class Test { + } + """ + ) + ); + } } From 6a818cf9a46d90237c08ab4953fb6c59cbe4efc9 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Mon, 13 Jan 2025 11:55:26 +0100 Subject: [PATCH 137/179] Print cursor when tests fail to run a recipe (#4891) * Print cursor when tests fail to run a recipe * Fail with the original exception, not a new one --- .../main/java/org/openrewrite/test/RewriteTest.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java b/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java index cad40ee819e..11c218c6495 100644 --- a/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java +++ b/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java @@ -23,10 +23,7 @@ import org.openrewrite.config.CompositeRecipe; import org.openrewrite.config.Environment; import org.openrewrite.config.OptionDescriptor; -import org.openrewrite.internal.InMemoryDiffEntry; -import org.openrewrite.internal.RecipeIntrospectionUtils; -import org.openrewrite.internal.StringUtils; -import org.openrewrite.internal.WhitespaceValidationService; +import org.openrewrite.internal.*; import org.openrewrite.marker.Marker; import org.openrewrite.marker.Markers; import org.openrewrite.quark.Quark; @@ -633,7 +630,12 @@ default void rewriteRun(SourceSpec... sources) { } default ExecutionContext defaultExecutionContext(SourceSpec[] sourceSpecs) { - InMemoryExecutionContext ctx = new InMemoryExecutionContext(t -> fail("Failed to parse sources or run recipe", t)); + InMemoryExecutionContext ctx = new InMemoryExecutionContext(t -> { + if (t instanceof RecipeRunException){ + fail("Failed to run recipe at " + ((RecipeRunException) t).getCursor(), t); + } + fail("Failed to parse sources or run recipe", t); + }); ParsingExecutionContextView.view(ctx).setCharset(StandardCharsets.UTF_8); return ctx; } From 6f3416fdc692d5e96c2969413e86390a5e41fcec Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Mon, 13 Jan 2025 11:56:22 +0100 Subject: [PATCH 138/179] Add TomlVisitorTest after seeing ClassCastException in arrays (#4892) * Add TomlVisitorTest after seeing ClassCastException in arrays * Have Toml.Literal implement TomlValue * Drop unnecessary cast instead --- .../org/openrewrite/toml/TomlVisitor.java | 2 +- rewrite-toml/src/test/java/.editorconfig | 5 + .../org/openrewrite/toml/TomlParserTest.java | 252 +++++++++--------- .../org/openrewrite/toml/TomlVisitorTest.java | 67 +++++ 4 files changed, 199 insertions(+), 127 deletions(-) create mode 100644 rewrite-toml/src/test/java/.editorconfig create mode 100644 rewrite-toml/src/test/java/org/openrewrite/toml/TomlVisitorTest.java diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/TomlVisitor.java b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlVisitor.java index b3707132e10..940d46db59c 100644 --- a/rewrite-toml/src/main/java/org/openrewrite/toml/TomlVisitor.java +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlVisitor.java @@ -38,7 +38,7 @@ public Toml visitArray(Toml.Array array, P p) { Toml.Array a = array; a = a.withPrefix(visitSpace(a.getPrefix(), p)); a = a.withMarkers(visitMarkers(a.getMarkers(), p)); - a = a.withValues(ListUtils.map(a.getValues(), v -> (TomlValue) visit(v, p))); + a = a.withValues(ListUtils.map(a.getValues(), v -> visit(v, p))); return a; } diff --git a/rewrite-toml/src/test/java/.editorconfig b/rewrite-toml/src/test/java/.editorconfig new file mode 100644 index 00000000000..a4824935e4f --- /dev/null +++ b/rewrite-toml/src/test/java/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*.java] +indent_size = 4 +ij_continuation_indent_size = 2 diff --git a/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java b/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java index fefa837ee9b..2693151c649 100644 --- a/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java +++ b/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java @@ -26,8 +26,8 @@ void keyValueString() { rewriteRun( toml( """ - str = "I'm a string. \\"You can quote me\\". Name\\tJos\\u00E9\\nLocation\\tSF." - """ + str = "I'm a string. \\"You can quote me\\". Name\\tJos\\u00E9\\nLocation\\tSF." + """ ) ); } @@ -37,23 +37,23 @@ void keyValueInteger() { rewriteRun( toml( """ - int1 = +99 - int2 = 42 - int3 = 0 - int4 = -17 - int5 = 1_000 - - # hexadecimal with prefix `0x` - hex1 = 0xDEADBEEF - hex2 = 0xdeadbeef - hex3 = 0xdead_beef - # octal with prefix `0o` - oct1 = 0o01234567 - oct2 = 0o755 # useful for Unix file permissions - - # binary with prefix `0b` - bin1 = 0b11010110 - """ + int1 = +99 + int2 = 42 + int3 = 0 + int4 = -17 + int5 = 1_000 + + # hexadecimal with prefix `0x` + hex1 = 0xDEADBEEF + hex2 = 0xdeadbeef + hex3 = 0xdead_beef + # octal with prefix `0o` + oct1 = 0o01234567 + oct2 = 0o755 # useful for Unix file permissions + + # binary with prefix `0b` + bin1 = 0b11010110 + """ ) ); } @@ -63,31 +63,31 @@ void keyValueFloat() { rewriteRun( toml( """ - # fractional - flt1 = +1.0 - flt2 = 3.1415 - flt3 = -0.01 - - # exponent - flt4 = 5e+22 - flt5 = 1e06 - flt6 = -2E-2 - - # both - flt7 = 6.626e-34 - - flt8 = 224_617.445_991_228 - - # infinity - sf1 = inf # positive infinity - sf2 = +inf # positive infinity - sf3 = -inf # negative infinity - - # not a number - sf4 = nan # actual sNaN/qNaN encoding is implementation-specific - sf5 = +nan # same as `nan` - sf6 = -nan # valid, actual encoding is implementation-specific - """ + # fractional + flt1 = +1.0 + flt2 = 3.1415 + flt3 = -0.01 + + # exponent + flt4 = 5e+22 + flt5 = 1e06 + flt6 = -2E-2 + + # both + flt7 = 6.626e-34 + + flt8 = 224_617.445_991_228 + + # infinity + sf1 = inf # positive infinity + sf2 = +inf # positive infinity + sf3 = -inf # negative infinity + + # not a number + sf4 = nan # actual sNaN/qNaN encoding is implementation-specific + sf5 = +nan # same as `nan` + sf6 = -nan # valid, actual encoding is implementation-specific + """ ) ); } @@ -97,9 +97,9 @@ void keyValueBool() { rewriteRun( toml( """ - bool1 = true - bool2 = false - """ + bool1 = true + bool2 = false + """ ) ); } @@ -109,11 +109,11 @@ void keyValueOffsetDateTime() { rewriteRun( toml( """ - odt1 = 1979-05-27T07:32:00Z - odt2 = 1979-05-27T00:32:00-07:00 - odt3 = 1979-05-27T00:32:00.999999-07:00 - odt4 = 1979-05-27 07:32:00Z - """ + odt1 = 1979-05-27T07:32:00Z + odt2 = 1979-05-27T00:32:00-07:00 + odt3 = 1979-05-27T00:32:00.999999-07:00 + odt4 = 1979-05-27 07:32:00Z + """ ) ); } @@ -123,9 +123,9 @@ void keyValueLocalDateTime() { rewriteRun( toml( """ - ldt1 = 1979-05-27T07:32:00 - ldt2 = 1979-05-27T00:32:00.999999 - """ + ldt1 = 1979-05-27T07:32:00 + ldt2 = 1979-05-27T00:32:00.999999 + """ ) ); } @@ -135,8 +135,8 @@ void keyValueLocalDate() { rewriteRun( toml( """ - ld1 = 1979-05-27 - """ + ld1 = 1979-05-27 + """ ) ); } @@ -146,9 +146,9 @@ void keyValueLocalTime() { rewriteRun( toml( """ - lt1 = 07:32:00 - lt2 = 00:32:00.999999 - """ + lt1 = 07:32:00 + lt2 = 00:32:00.999999 + """ ) ); } @@ -158,27 +158,27 @@ void keyValueArray() { rewriteRun( toml( """ - integers = [ 1, 2, 3 ] - colors = [ "red", "yellow", "green" ] - nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ] - nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ] - string_array = [ "all", 'strings', ""\"are the same""\", '''type''' ] - - # Mixed-type arrays are allowed - numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ] - contributors = [ - "Foo Bar ", - { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" } - ] - integers2 = [ - 1, 2, 3 - ] - - integers3 = [ - 1, - 2, # this is ok - ] - """ + integers = [ 1, 2, 3 ] + colors = [ "red", "yellow", "green" ] + nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ] + nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ] + string_array = [ "all", 'strings', ""\"are the same""\", '''type''' ] + + # Mixed-type arrays are allowed + numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ] + contributors = [ + "Foo Bar ", + { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" } + ] + integers2 = [ + 1, 2, 3 + ] + + integers3 = [ + 1, + 2, # this is ok + ] + """ ) ); } @@ -188,17 +188,17 @@ void table() { rewriteRun( toml( """ - [table-1] - key1 = "some string" - key2 = 123 - - [table-2] - key1 = "another string" - key2 = 456 - - [dog."tater.man"] - type.name = "pug" - """ + [table-1] + key1 = "some string" + key2 = 123 + + [table-2] + key1 = "another string" + key2 = 456 + + [dog."tater.man"] + type.name = "pug" + """ ) ); } @@ -208,18 +208,18 @@ void arrayTable() { rewriteRun( toml( """ - [[products]] - name = "Hammer" - sku = 738594937 - - [[products]] # empty table within the array - - [[products]] - name = "Nail" - sku = 284758393 - - color = "gray" - """ + [[products]] + name = "Hammer" + sku = 738594937 + + [[products]] # empty table within the array + + [[products]] + name = "Nail" + sku = 284758393 + + color = "gray" + """ ) ); } @@ -229,11 +229,11 @@ void bareKeys() { rewriteRun( toml( """ - key = "value" - bare_key = "value" - bare-key = "value" - 1234 = "value" - """ + key = "value" + bare_key = "value" + bare-key = "value" + 1234 = "value" + """ ) ); } @@ -243,12 +243,12 @@ void quotedKeys() { rewriteRun( toml( """ - "127.0.0.1" = "value" - "character encoding" = "value" - "ʎǝʞ" = "value" - 'key2' = "value" - 'quoted "value"' = "value" - """ + "127.0.0.1" = "value" + "character encoding" = "value" + "ʎǝʞ" = "value" + 'key2' = "value" + 'quoted "value"' = "value" + """ ) ); } @@ -258,10 +258,10 @@ void dottedKeys() { rewriteRun( toml( """ - physical.color = "orange" - physical.shape = "round" - site."google.com" = true - """ + physical.color = "orange" + physical.shape = "round" + site."google.com" = true + """ ) ); } @@ -271,10 +271,10 @@ void extraWhitespaceDottedKeys() { rewriteRun( toml( """ - fruit.name = "banana" # this is best practice - fruit. color = "yellow" # same as fruit.color - fruit . flavor = "banana" # same as fruit.flavor - """ + fruit.name = "banana" # this is best practice + fruit. color = "yellow" # same as fruit.color + fruit . flavor = "banana" # same as fruit.flavor + """ ) ); } @@ -321,9 +321,9 @@ void trailingComment() { rewriteRun( toml( """ - str = "I'm a string. \\"You can quote me\\". Name\\tJos\\u00E9\\nLocation\\tSF." - # trailing comment - """ + str = "I'm a string. \\"You can quote me\\". Name\\tJos\\u00E9\\nLocation\\tSF." + # trailing comment + """ ) ); } diff --git a/rewrite-toml/src/test/java/org/openrewrite/toml/TomlVisitorTest.java b/rewrite-toml/src/test/java/org/openrewrite/toml/TomlVisitorTest.java new file mode 100644 index 00000000000..f7698844a20 --- /dev/null +++ b/rewrite-toml/src/test/java/org/openrewrite/toml/TomlVisitorTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.toml; + +import org.junit.jupiter.api.Test; +import org.openrewrite.*; +import org.openrewrite.marker.Markup; +import org.openrewrite.test.RewriteTest; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.openrewrite.test.RewriteTest.toRecipe; +import static org.openrewrite.toml.Assertions.toml; + +class TomlVisitorTest implements RewriteTest { + + @Issue("https://github.com/openrewrite/rewrite-spring/issues/665") + @Test + void visitMarkupErrorMarkers() { + List exceptions = new ArrayList<>(); + rewriteRun( + spec -> spec.recipe(toRecipe(() -> new TreeVisitor<>() { + @Override + public Tree preVisit(Tree tree, ExecutionContext ctx) { + // Mimics what we do in the rewrite-gradle-plugin + tree.getMarkers().findFirst(Markup.Error.class).ifPresent(e -> { + Optional sourceFile = Optional.ofNullable(getCursor().firstEnclosing(SourceFile.class)); + String sourcePath = sourceFile.map(SourceFile::getSourcePath).map(Path::toString).orElse(""); + exceptions.add(new RuntimeException("Error while visiting " + sourcePath + ": " + e.getDetail())); + }); + return tree; + } + })), + toml( + """ + [versions] + jackson = '2.14.2' + + [libraries] + jackson-annotations = { module = 'com.fasterxml.jackson.core:jackson-annotations', version.ref = 'jackson' } + jackson-core = { module = 'com.fasterxml.jackson.core:jackson-core', version.ref = 'jackson' } + + [bundles] + jackson = ['jackson-annotations', 'jackson-core'] + """ + ) + ); + assertThat(exceptions).isEmpty(); + } +} From aeb5bf2f156a6e12b3451415ab3a70d48cd3463f Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Mon, 13 Jan 2025 14:20:26 +0100 Subject: [PATCH 139/179] Lombok's generated @With method misses type information; fix for Java 17+ (#4882) * Resolve type information for lombok @With for Java 17+ --------- Co-authored-by: Laurens Westerlaken --- .../isolated/ReloadableJava11TypeMapping.java | 5 +- .../ReloadableJava17ParserVisitor.java | 16 ++-- .../isolated/ReloadableJava17TypeMapping.java | 21 ++++- .../ReloadableJava21ParserVisitor.java | 14 +-- .../isolated/ReloadableJava21TypeMapping.java | 21 ++++- .../java/ReloadableJava8TypeMapping.java | 5 +- .../org/openrewrite/java/tree/LombokTest.java | 87 +++++++++++++++++++ 7 files changed, 152 insertions(+), 17 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java index 0fb15f638be..0a7edbbfc46 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java @@ -22,7 +22,6 @@ import org.jspecify.annotations.Nullable; import org.openrewrite.java.JavaTypeMapping; import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.tree.Flag; import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.TypeUtils; @@ -461,6 +460,10 @@ public JavaType.Primitive primitive(TypeTag tag) { * @return Method type attribution. */ public JavaType.@Nullable Method methodInvocationType(com.sun.tools.javac.code.@Nullable Type selectType, @Nullable Symbol symbol) { + /* + TODO: AttrRecover class does not exist for java 11; there is JCNoType + in the Type.class, so maybe it is possible to retrieve this information... + */ if (selectType == null || selectType instanceof Type.ErrorType || symbol == null || symbol.kind == Kinds.Kind.ERR || symbol.type instanceof Type.UnknownType) { return null; } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 90ba684cfd1..7fbd874ed01 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -962,11 +962,15 @@ public J visitMethodInvocation(MethodInvocationTree node, Space fmt) { singletonList(padRight(new J.Empty(randomId(), sourceBefore(")"), Markers.EMPTY), EMPTY)) : convertAll(node.getArguments(), commaDelim, t -> sourceBefore(")")), Markers.EMPTY); - Symbol methodSymbol = (jcSelect instanceof JCFieldAccess) ? ((JCFieldAccess) jcSelect).sym : - ((JCIdent) jcSelect).sym; + JavaType.Method methodType; + if (name.getType() instanceof JavaType.Method) { + methodType = (JavaType.Method) name.getType(); + } else { + Symbol methodSymbol = (jcSelect instanceof JCFieldAccess) ? ((JCFieldAccess) jcSelect).sym : ((JCIdent) jcSelect).sym; + methodType = typeMapping.methodInvocationType(jcSelect.type, methodSymbol); + } - return new J.MethodInvocation(randomId(), fmt, Markers.EMPTY, select, typeParams, name, args, - typeMapping.methodInvocationType(jcSelect.type, methodSymbol)); + return new J.MethodInvocation(randomId(), fmt, Markers.EMPTY, select, typeParams, name, args, methodType); } @Override @@ -1804,7 +1808,7 @@ private void reportJavaParsingException(Throwable ex) { if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) { cursor += ((J.Erroneous) rightPadded.getElement()).getText().length(); } else { - cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it + cursor(max(endPos(t), cursor)); // if there is a non-empty suffix or a lombok generated method, the cursor can be already moved past it } return rightPadded; } @@ -1896,7 +1900,7 @@ private Space statementDelim(@Nullable Tree t) { case EXPRESSION_STATEMENT: ExpressionTree expTree = ((ExpressionStatementTree) t).getExpression(); if (expTree instanceof ErroneousTree) { - return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable),((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); + return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable), ((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); } else { return sourceBefore(";"); } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java index d4252e1bc0e..2a4ba541752 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java @@ -17,12 +17,12 @@ import com.sun.source.tree.Tree; import com.sun.tools.javac.code.*; +import com.sun.tools.javac.comp.AttrRecover; import com.sun.tools.javac.tree.JCTree; import lombok.RequiredArgsConstructor; import org.jspecify.annotations.Nullable; import org.openrewrite.java.JavaTypeMapping; import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.tree.Flag; import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.TypeUtils; @@ -30,6 +30,7 @@ import javax.lang.model.type.TypeMirror; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -370,7 +371,7 @@ private JavaType.FullyQualified.Kind getKind(Symbol.ClassSymbol sym) { if (type == null && symbol != null) { type = symbol.type; } - if (type instanceof Type.MethodType || type instanceof Type.ForAll) { + if (type instanceof Type.MethodType || type instanceof Type.ForAll || (type instanceof Type.ErrorType && type.getOriginalType() instanceof Type.MethodType)) { return methodInvocationType(type, symbol); } return type(type); @@ -459,6 +460,22 @@ public JavaType.Primitive primitive(TypeTag tag) { * @return Method type attribution. */ public JavaType.@Nullable Method methodInvocationType(com.sun.tools.javac.code.@Nullable Type selectType, @Nullable Symbol symbol) { + if (selectType instanceof Type.ErrorType) { + try { + // Ugly reflection solution, because AttrRecover$RecoveryErrorType is private inner class + for (Class targetClass : Class.forName(AttrRecover.class.getCanonicalName()).getDeclaredClasses()) { + if (targetClass.getSimpleName().equals("RecoveryErrorType")) { + Field field = targetClass.getDeclaredField("candidateSymbol"); + field.setAccessible(true); + Symbol originalSymbol = (Symbol) field.get(selectType); + return methodInvocationType(selectType.getOriginalType(), originalSymbol); + } + } + } catch (Exception e) { + // ignore + } + } + if (selectType == null || selectType instanceof Type.ErrorType || symbol == null || symbol.kind == Kinds.Kind.ERR || symbol.type instanceof Type.UnknownType) { return null; } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index da4ad8b8acd..4a6973da177 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -962,11 +962,15 @@ public J visitMethodInvocation(MethodInvocationTree node, Space fmt) { singletonList(padRight(new J.Empty(randomId(), sourceBefore(")"), Markers.EMPTY), EMPTY)) : convertAll(node.getArguments(), commaDelim, t -> sourceBefore(")")), Markers.EMPTY); - Symbol methodSymbol = (jcSelect instanceof JCFieldAccess) ? ((JCFieldAccess) jcSelect).sym : - ((JCIdent) jcSelect).sym; + JavaType.Method methodType; + if (name.getType() instanceof JavaType.Method) { + methodType = (JavaType.Method) name.getType(); + } else { + Symbol methodSymbol = (jcSelect instanceof JCFieldAccess) ? ((JCFieldAccess) jcSelect).sym : ((JCIdent) jcSelect).sym; + methodType = typeMapping.methodInvocationType(jcSelect.type, methodSymbol); + } - return new J.MethodInvocation(randomId(), fmt, Markers.EMPTY, select, typeParams, name, args, - typeMapping.methodInvocationType(jcSelect.type, methodSymbol)); + return new J.MethodInvocation(randomId(), fmt, Markers.EMPTY, select, typeParams, name, args, methodType); } @Override @@ -1804,7 +1808,7 @@ private void reportJavaParsingException(Throwable ex) { if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) { cursor += ((J.Erroneous) rightPadded.getElement()).getText().length(); } else { - cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it + cursor(max(endPos(t), cursor)); // if there is a non-empty suffix or a lombok generated method, the cursor can be already moved past it } return rightPadded; } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index a7cbc01a00e..82c92931303 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -17,12 +17,12 @@ import com.sun.source.tree.Tree; import com.sun.tools.javac.code.*; +import com.sun.tools.javac.comp.AttrRecover; import com.sun.tools.javac.tree.JCTree; import lombok.RequiredArgsConstructor; import org.jspecify.annotations.Nullable; import org.openrewrite.java.JavaTypeMapping; import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.tree.Flag; import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.TypeUtils; @@ -30,6 +30,7 @@ import javax.lang.model.type.TypeMirror; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -381,7 +382,7 @@ private JavaType.FullyQualified.Kind getKind(Symbol.ClassSymbol sym) { } private @Nullable JavaType type(Type type, Symbol symbol) { - if (type instanceof Type.MethodType || type instanceof Type.ForAll) { + if (type instanceof Type.MethodType || type instanceof Type.ForAll || (type instanceof Type.ErrorType && type.getOriginalType() instanceof Type.MethodType)) { return methodInvocationType(type, symbol); } return type(type); @@ -470,6 +471,22 @@ public JavaType.Primitive primitive(TypeTag tag) { * @return Method type attribution. */ public JavaType.@Nullable Method methodInvocationType(com.sun.tools.javac.code.@Nullable Type selectType, @Nullable Symbol symbol) { + if (selectType instanceof Type.ErrorType) { + try { + // Ugly reflection solution, because AttrRecover$RecoveryErrorType is private inner class + for (Class targetClass : Class.forName(AttrRecover.class.getCanonicalName()).getDeclaredClasses()) { + if (targetClass.getSimpleName().equals("RecoveryErrorType")) { + Field field = targetClass.getDeclaredField("candidateSymbol"); + field.setAccessible(true); + Symbol originalSymbol = (Symbol) field.get(selectType); + return methodInvocationType(selectType.getOriginalType(), originalSymbol); + } + } + } catch (Exception e) { + // ignore + } + } + if (selectType == null || selectType instanceof Type.ErrorType || symbol == null || symbol.kind == Kinds.Kind.ERR || symbol.type instanceof Type.UnknownType) { return null; } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java index ca5db39ba80..9afe440a506 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java @@ -21,7 +21,6 @@ import lombok.RequiredArgsConstructor; import org.jspecify.annotations.Nullable; import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.tree.Flag; import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.TypeUtils; @@ -455,6 +454,10 @@ public JavaType.Primitive primitive(TypeTag tag) { * @return Method type attribution. */ public JavaType.@Nullable Method methodInvocationType(com.sun.tools.javac.code.@Nullable Type selectType, @Nullable Symbol symbol) { + /* + TODO: AttrRecover class does not exist for java 8; there is JCNoType + in the Type.class, so maybe it is possible to retrieve this information... + */ if (selectType == null || selectType instanceof Type.ErrorType || symbol == null || symbol.kind == Kinds.ERR || symbol.type instanceof Type.UnknownType) { return null; } diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index aab176f0a7f..ede1c202240 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -21,6 +21,7 @@ import org.junit.jupiter.api.Test; import org.openrewrite.java.JavaParser; import org.openrewrite.java.MinimumJava11; +import org.openrewrite.java.MinimumJava17; import org.openrewrite.java.search.FindMissingTypes; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; @@ -373,7 +374,57 @@ public void foo() { } @Test + void gett() { + rewriteRun( + java( + """ + import lombok.Getter; + + public class WithExample { + @Getter int age; + + public WithExample(int age) { + this.age = age; + } + + void test() { + int x = getAge(); + } + } + """ + ) + ); + } + + //TODO fix for Java 8 and 11 + @Test + @MinimumJava17 void with() { + rewriteRun( + java( + """ + import lombok.With; + + public class WithExample { + @With int age; + + public WithExample(int age) { + this.age = age; + } + + void test() { + WithExample x = withAge("name", 23); + } + } + """ + ) + ); + } + + //TODO fix for Java 8 and 11 + @Test + @MinimumJava17 + void withWithParams() { rewriteRun( java( """ @@ -389,6 +440,42 @@ public WithExample(@NonNull String name, int age) { this.name = name; this.age = age; } + + static void test() { + WithExample x = new WithExample("old name", 22); + x.withName("name", 23); + } + } + """ + ) + ); + } + + //TODO fix for Java 8 and 11 + @Test + @MinimumJava17 + void withOnClass() { + rewriteRun( + java( + """ + import lombok.AccessLevel; + import lombok.NonNull; + import lombok.With; + + @With + public class WithExample { + private final String name; + private final int age; + + public WithExample(String name, int age) { + this.name = name; + this.age = age; + } + + void test() { + WithExample x = new WithExample("old name", 22); + x.withName("name", 23); + } } """ ) From 30c9156f68908681dae7192ac66d9a23b6146993 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Mon, 13 Jan 2025 18:41:14 +0100 Subject: [PATCH 140/179] Add `slf4j-nop` transitively through rewrite-test (#4895) * Add `slf4j-nop` transitively through rewrite-test To reduce warnings seen about https://www.slf4j.org/codes.html#StaticLoggerBinder * Prevent new warning about two implementations --- rewrite-gradle/build.gradle.kts | 1 + rewrite-test/build.gradle.kts | 1 + 2 files changed, 2 insertions(+) diff --git a/rewrite-gradle/build.gradle.kts b/rewrite-gradle/build.gradle.kts index 9f18146b3b0..9df2c9c9477 100644 --- a/rewrite-gradle/build.gradle.kts +++ b/rewrite-gradle/build.gradle.kts @@ -57,6 +57,7 @@ dependencies { testImplementation(project(":rewrite-test")) { // because gradle-api fatjars this implementation already exclude("ch.qos.logback", "logback-classic") + exclude("org.slf4j", "slf4j-nop") } testImplementation("org.openrewrite.gradle.tooling:model:$latest") diff --git a/rewrite-test/build.gradle.kts b/rewrite-test/build.gradle.kts index 3e97814c353..7c90aa85483 100644 --- a/rewrite-test/build.gradle.kts +++ b/rewrite-test/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { implementation("org.assertj:assertj-core:latest.release") implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-csv") implementation("org.slf4j:slf4j-api:1.7.36") + implementation("org.slf4j:slf4j-nop:1.7.36") testImplementation(project(":rewrite-groovy")) } From cce9f3e7397d84b4b7de83781f17aa61e22a6a88 Mon Sep 17 00:00:00 2001 From: Daniil Zhyliaiev Date: Mon, 13 Jan 2025 19:42:30 +0200 Subject: [PATCH 141/179] `LatestRelease` should replace `metadataPattern` as regex, as documented (#4894) * Fix version comparator * LatestRelease.metadataPattern should be matched as a regex --------- Co-authored-by: Tim te Beek --- .../src/main/java/org/openrewrite/semver/LatestRelease.java | 5 ++--- .../org/openrewrite/gradle/UpgradeDependencyVersionTest.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/LatestRelease.java b/rewrite-core/src/main/java/org/openrewrite/semver/LatestRelease.java index df8fac8951c..0b1fa2b0095 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/LatestRelease.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/LatestRelease.java @@ -140,9 +140,8 @@ public int compare(@Nullable String currentVersion, String v1, String v2) { // parts are the same: // // HyphenRange [25-28] should include "28-jre" and "28-android" as possible candidates. - String normalized1 = metadataPattern == null ? nv1 : nv1.replace(metadataPattern, ""); - String normalized2 = metadataPattern == null ? nv2 : nv1.replace(metadataPattern, ""); - + String normalized1 = metadataPattern == null ? nv1 : nv1.replaceAll(metadataPattern, ""); + String normalized2 = metadataPattern == null ? nv2 : nv2.replaceAll(metadataPattern, ""); try { for (int i = 1; i <= Math.max(vp1, vp2); i++) { String v1Part = v1Gav.group(i); diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java index e8d6d145923..2626825c559 100644 --- a/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/UpgradeDependencyVersionTest.java @@ -1016,7 +1016,7 @@ void exactVersionWithExactPattern() { @Issue("https://github.com/openrewrite/rewrite/issues/4333") void exactVersionWithRegexPattern() { rewriteRun( - spec -> spec.recipe(new UpgradeDependencyVersion("com.google.guava", "guava", "32.1.1", ".*droid")), + spec -> spec.recipe(new UpgradeDependencyVersion("com.google.guava", "guava", "32.1.1", "-.*?droid")), buildGradle( """ plugins { From 8a060c6264dcc16c8e0fc0b0ab6a523bd0507c5c Mon Sep 17 00:00:00 2001 From: Kyle Scully Date: Tue, 14 Jan 2025 21:04:19 -0800 Subject: [PATCH 142/179] chore: update suppressions (#4903) --- suppressions.xml | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/suppressions.xml b/suppressions.xml index 329d8806f0f..aab8ffb8ba0 100644 --- a/suppressions.xml +++ b/suppressions.xml @@ -1,15 +1,6 @@ - - - ^pkg:maven/com\.squareup\.okio/okio@.*$ - CVE-2023-3635 - - + CVE-2023-45163 CVE-2023-5964 - + @@ -32,13 +23,6 @@ CVE-2020-15773 CVE-2020-15767 - - - ^pkg:maven/org\.glassfish/javax\.json@.*$ - CVE-2023-7272 - Date: Wed, 15 Jan 2025 09:23:53 +0100 Subject: [PATCH 143/179] HCL - support for legacy syntax for attribute expressions (#4901) * Support for LegacyIndexAttributeExpression * licenseFormat * Space.Location.LEGACY_INDEX_ATTRIBUTE_ACCESS * LegacyIndexAttributeAccess.index is int * Padding for LegacyAttributeAccess.base --- rewrite-hcl/src/main/antlr/HCLLexer.g4 | 3 +- rewrite-hcl/src/main/antlr/HCLParser.g4 | 9 + .../org/openrewrite/hcl/HclIsoVisitor.java | 5 + .../java/org/openrewrite/hcl/HclVisitor.java | 17 + .../hcl/internal/HclParserVisitor.java | 19 + .../openrewrite/hcl/internal/HclPrinter.java | 13 + .../hcl/internal/grammar/HCLLexer.interp | 2 +- .../hcl/internal/grammar/HCLLexer.java | 279 +++-- .../hcl/internal/grammar/HCLParser.interp | 3 +- .../hcl/internal/grammar/HCLParser.java | 968 ++++++++++-------- .../grammar/HCLParserBaseListener.java | 24 + .../grammar/HCLParserBaseVisitor.java | 14 + .../internal/grammar/HCLParserListener.java | 22 + .../internal/grammar/HCLParserVisitor.java | 13 + .../java/org/openrewrite/hcl/tree/Hcl.java | 70 ++ .../openrewrite/hcl/tree/HclRightPadded.java | 1 + .../java/org/openrewrite/hcl/tree/Space.java | 2 + .../hcl/tree/HclVariableExpressionTest.java | 15 + 18 files changed, 895 insertions(+), 584 deletions(-) diff --git a/rewrite-hcl/src/main/antlr/HCLLexer.g4 b/rewrite-hcl/src/main/antlr/HCLLexer.g4 index 7bdf3d0c17f..8ae20167657 100644 --- a/rewrite-hcl/src/main/antlr/HCLLexer.g4 +++ b/rewrite-hcl/src/main/antlr/HCLLexer.g4 @@ -81,7 +81,7 @@ fragment HexDigit // https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#numeric-literals NumericLiteral - : [0-9]+ '.' [0-9]* ExponentPart? + : [0-9]+ '.' [0-9]+ ExponentPart? | [0-9]+ ExponentPart | [0-9]+ ; @@ -129,6 +129,7 @@ MOD : '%'; ELLIPSIS : '...'; TILDE : '~'; + // ---------------------------------------------------------------------------------------------- mode TEMPLATE; // ---------------------------------------------------------------------------------------------- diff --git a/rewrite-hcl/src/main/antlr/HCLParser.g4 b/rewrite-hcl/src/main/antlr/HCLParser.g4 index aa2618baa00..5d48086569c 100644 --- a/rewrite-hcl/src/main/antlr/HCLParser.g4 +++ b/rewrite-hcl/src/main/antlr/HCLParser.g4 @@ -52,6 +52,7 @@ exprTerm | functionCall #FunctionCallExpression | exprTerm index #IndexAccessExpression | exprTerm getAttr #AttributeAccessExpression + | exprTerm legacyIndexAttr #LegacyIndexAttributeExpression | exprTerm splat #SplatExpression | LPAREN expression RPAREN #ParentheticalExpression ; @@ -144,6 +145,14 @@ getAttr : DOT Identifier ; +// Legacy Index Access Operator +// https://github.com/hashicorp/hcl/blob/923b06b5d6adf61a647101c605f7463a1bd56cbf/hclsyntax/spec.md#L547 +// Interestingly not mentioned in hcl2 syntax specification anymore + +legacyIndexAttr + : DOT NumericLiteral + ; + // Splat Operators // https://github.com/hashicorp/hcl2/blob/master/hcl/hclsyntax/spec.md#splat-operators diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclIsoVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclIsoVisitor.java index 6f5b3d2ceb9..b442182a944 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclIsoVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclIsoVisitor.java @@ -102,6 +102,11 @@ public Hcl.Index.Position visitIndexPosition(Hcl.Index.Position indexPosition, P return (Hcl.Index.Position) super.visitIndexPosition(indexPosition, p); } + @Override + public Hcl.LegacyIndexAttributeAccess visitLegacyIndexAttribute(Hcl.LegacyIndexAttributeAccess legacyIndexAttributeAccess, P p) { + return (Hcl.LegacyIndexAttributeAccess) super.visitLegacyIndexAttribute(legacyIndexAttributeAccess, p); + } + @Override public Hcl.Literal visitLiteral(Hcl.Literal literal, P p) { return (Hcl.Literal) super.visitLiteral(literal, p); diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclVisitor.java index 6c7d095e00a..119e13d06ee 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclVisitor.java @@ -77,6 +77,23 @@ public Hcl visitAttributeAccess(Hcl.AttributeAccess attributeAccess, P p) { return a; } + public Hcl visitLegacyIndexAttribute(Hcl.LegacyIndexAttributeAccess legacyIndexAttributeAccess, P p) { + Hcl.LegacyIndexAttributeAccess li = legacyIndexAttributeAccess; + li = li.withPrefix(visitSpace(li.getPrefix(), Space.Location.LEGACY_INDEX_ATTRIBUTE_ACCESS, p)); + li = li.withMarkers(visitMarkers(li.getMarkers(), p)); + Expression temp = (Expression) visitExpression(li, p); + if (!(temp instanceof Hcl.LegacyIndexAttributeAccess)) { + return temp; + } else { + li = (Hcl.LegacyIndexAttributeAccess) temp; + } + li = li.getPadding().withBase( + visitRightPadded(li.getPadding().getBase(), HclRightPadded.Location.LEGACY_INDEX_ATTRIBUTE_ACCESS_BASE, p)); + li = li.withIndex((Hcl.Literal) visitLiteral(li.getIndex(), p)); + return li; + } + + public Hcl visitBinary(Hcl.Binary binary, P p) { Hcl.Binary b = binary; b = b.withPrefix(visitSpace(b.getPrefix(), Space.Location.BINARY, p)); diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java index 00aa2b37f4f..8e538c32cd9 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclParserVisitor.java @@ -409,6 +409,25 @@ public Hcl visitIndexAccessExpression(HCLParser.IndexAccessExpressionContext ctx )); } + @Override + public Hcl visitLegacyIndexAttributeExpression(HCLParser.LegacyIndexAttributeExpressionContext ctx) { + return convert(ctx, (c, prefix) -> { + String valueSource = c.legacyIndexAttr().NumericLiteral().getText(); + Integer value = Integer.parseInt(valueSource); + return new Hcl.LegacyIndexAttributeAccess( + randomId(), + Space.format(prefix), + Markers.EMPTY, + new HclRightPadded<>( + (Expression) visit(c.exprTerm()), + sourceBefore("."), + Markers.EMPTY + ), + new Hcl.Literal(randomId(), Space.format(prefix(c.legacyIndexAttr().NumericLiteral())), Markers.EMPTY, value, valueSource) + ); + }); + } + @Override public Hcl visitLiteralValue(HCLParser.LiteralValueContext ctx) { return convert(ctx, (c, prefix) -> { diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclPrinter.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclPrinter.java index 125040cbc4f..cd9bc28e7f1 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclPrinter.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/HclPrinter.java @@ -23,6 +23,7 @@ import org.openrewrite.marker.Marker; import org.openrewrite.marker.Markers; +import java.util.Collections; import java.util.List; import java.util.function.UnaryOperator; @@ -288,6 +289,18 @@ public Hcl visitIndexPosition(Hcl.Index.Position indexPosition, PrintOutputCaptu return indexPosition; } + @Override + public Hcl visitLegacyIndexAttribute(Hcl.LegacyIndexAttributeAccess laccess, PrintOutputCapture

p) { + beforeSyntax(laccess, Space.Location.LEGACY_INDEX_ATTRIBUTE_ACCESS, p); + visitRightPadded( + Collections.singletonList(laccess.getPadding().getBase()), + HclRightPadded.Location.LEGACY_INDEX_ATTRIBUTE_ACCESS_BASE, "", p); + p.append("."); + visitLiteral(laccess.getIndex(), p); + afterSyntax(laccess, p); + return laccess; + } + @Override public Hcl visitLiteral(Hcl.Literal literal, PrintOutputCapture

p) { beforeSyntax(literal, Space.Location.LITERAL, p); diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp index 9097230066a..6cbc5b58e15 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.interp @@ -169,4 +169,4 @@ HEREDOC_PREAMBLE HEREDOC atn: -[4, 0, 47, 451, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 126, 8, 0, 10, 0, 12, 0, 129, 9, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 142, 8, 1, 10, 1, 12, 1, 145, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 3, 7, 169, 8, 7, 1, 8, 1, 8, 1, 8, 5, 8, 174, 8, 8, 10, 8, 12, 8, 177, 9, 8, 1, 9, 4, 9, 180, 8, 9, 11, 9, 12, 9, 181, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 190, 8, 10, 10, 10, 12, 10, 193, 9, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 3, 11, 203, 8, 11, 1, 11, 5, 11, 206, 8, 11, 10, 11, 12, 11, 209, 9, 11, 1, 11, 3, 11, 212, 8, 11, 1, 11, 3, 11, 215, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 3, 13, 225, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 231, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 251, 8, 15, 1, 16, 1, 16, 1, 17, 4, 17, 256, 8, 17, 11, 17, 12, 17, 257, 1, 17, 1, 17, 5, 17, 262, 8, 17, 10, 17, 12, 17, 265, 9, 17, 1, 17, 3, 17, 268, 8, 17, 1, 17, 4, 17, 271, 8, 17, 11, 17, 12, 17, 272, 1, 17, 1, 17, 4, 17, 277, 8, 17, 11, 17, 12, 17, 278, 3, 17, 281, 8, 17, 1, 18, 1, 18, 3, 18, 285, 8, 18, 1, 18, 4, 18, 288, 8, 18, 11, 18, 12, 18, 289, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 301, 8, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 316, 8, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 4, 49, 387, 8, 49, 11, 49, 12, 49, 388, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 401, 8, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 5, 53, 416, 8, 53, 10, 53, 12, 53, 419, 9, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 4, 56, 438, 8, 56, 11, 56, 12, 56, 439, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 3, 57, 450, 8, 57, 1, 191, 0, 58, 4, 1, 6, 2, 8, 3, 10, 4, 12, 5, 14, 6, 16, 7, 18, 0, 20, 8, 22, 9, 24, 10, 26, 11, 28, 12, 30, 0, 32, 0, 34, 0, 36, 0, 38, 13, 40, 0, 42, 14, 44, 15, 46, 16, 48, 17, 50, 18, 52, 19, 54, 20, 56, 21, 58, 22, 60, 23, 62, 24, 64, 25, 66, 26, 68, 27, 70, 28, 72, 29, 74, 30, 76, 31, 78, 32, 80, 33, 82, 34, 84, 35, 86, 36, 88, 37, 90, 38, 92, 39, 94, 40, 96, 41, 98, 42, 100, 43, 102, 44, 104, 45, 106, 0, 108, 0, 110, 0, 112, 0, 114, 0, 116, 46, 118, 47, 4, 0, 1, 2, 3, 15, 4, 0, 10, 10, 13, 13, 34, 34, 36, 37, 3, 0, 9, 9, 12, 13, 32, 32, 2, 0, 10, 10, 13, 13, 1, 1, 10, 10, 1, 0, 48, 57, 4, 0, 36, 36, 65, 90, 95, 95, 97, 122, 2, 0, 0, 127, 55296, 56319, 1, 0, 55296, 56319, 1, 0, 56320, 57343, 5, 0, 34, 34, 92, 92, 110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 3, 0, 10, 10, 13, 13, 36, 37, 1, 0, 123, 123, 485, 0, 4, 1, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 10, 1, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 14, 1, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 24, 1, 0, 0, 0, 0, 26, 1, 0, 0, 0, 0, 28, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 44, 1, 0, 0, 0, 0, 46, 1, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 50, 1, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 54, 1, 0, 0, 0, 0, 56, 1, 0, 0, 0, 0, 58, 1, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 62, 1, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 66, 1, 0, 0, 0, 0, 68, 1, 0, 0, 0, 0, 70, 1, 0, 0, 0, 0, 72, 1, 0, 0, 0, 0, 74, 1, 0, 0, 0, 0, 76, 1, 0, 0, 0, 0, 78, 1, 0, 0, 0, 0, 80, 1, 0, 0, 0, 0, 82, 1, 0, 0, 0, 0, 84, 1, 0, 0, 0, 0, 86, 1, 0, 0, 0, 0, 88, 1, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 92, 1, 0, 0, 0, 0, 94, 1, 0, 0, 0, 0, 96, 1, 0, 0, 0, 0, 98, 1, 0, 0, 0, 1, 100, 1, 0, 0, 0, 1, 102, 1, 0, 0, 0, 1, 104, 1, 0, 0, 0, 1, 106, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 3, 112, 1, 0, 0, 0, 3, 114, 1, 0, 0, 0, 3, 116, 1, 0, 0, 0, 3, 118, 1, 0, 0, 0, 4, 120, 1, 0, 0, 0, 6, 136, 1, 0, 0, 0, 8, 152, 1, 0, 0, 0, 10, 155, 1, 0, 0, 0, 12, 158, 1, 0, 0, 0, 14, 161, 1, 0, 0, 0, 16, 164, 1, 0, 0, 0, 18, 168, 1, 0, 0, 0, 20, 170, 1, 0, 0, 0, 22, 179, 1, 0, 0, 0, 24, 185, 1, 0, 0, 0, 26, 202, 1, 0, 0, 0, 28, 218, 1, 0, 0, 0, 30, 224, 1, 0, 0, 0, 32, 230, 1, 0, 0, 0, 34, 250, 1, 0, 0, 0, 36, 252, 1, 0, 0, 0, 38, 280, 1, 0, 0, 0, 40, 282, 1, 0, 0, 0, 42, 300, 1, 0, 0, 0, 44, 302, 1, 0, 0, 0, 46, 306, 1, 0, 0, 0, 48, 311, 1, 0, 0, 0, 50, 319, 1, 0, 0, 0, 52, 321, 1, 0, 0, 0, 54, 324, 1, 0, 0, 0, 56, 327, 1, 0, 0, 0, 58, 329, 1, 0, 0, 0, 60, 331, 1, 0, 0, 0, 62, 333, 1, 0, 0, 0, 64, 335, 1, 0, 0, 0, 66, 337, 1, 0, 0, 0, 68, 340, 1, 0, 0, 0, 70, 343, 1, 0, 0, 0, 72, 345, 1, 0, 0, 0, 74, 347, 1, 0, 0, 0, 76, 349, 1, 0, 0, 0, 78, 351, 1, 0, 0, 0, 80, 353, 1, 0, 0, 0, 82, 355, 1, 0, 0, 0, 84, 358, 1, 0, 0, 0, 86, 360, 1, 0, 0, 0, 88, 362, 1, 0, 0, 0, 90, 365, 1, 0, 0, 0, 92, 368, 1, 0, 0, 0, 94, 370, 1, 0, 0, 0, 96, 372, 1, 0, 0, 0, 98, 376, 1, 0, 0, 0, 100, 378, 1, 0, 0, 0, 102, 386, 1, 0, 0, 0, 104, 400, 1, 0, 0, 0, 106, 402, 1, 0, 0, 0, 108, 407, 1, 0, 0, 0, 110, 412, 1, 0, 0, 0, 112, 424, 1, 0, 0, 0, 114, 428, 1, 0, 0, 0, 116, 437, 1, 0, 0, 0, 118, 449, 1, 0, 0, 0, 120, 127, 5, 123, 0, 0, 121, 126, 3, 22, 9, 0, 122, 126, 3, 28, 12, 0, 123, 126, 3, 24, 10, 0, 124, 126, 3, 26, 11, 0, 125, 121, 1, 0, 0, 0, 125, 122, 1, 0, 0, 0, 125, 123, 1, 0, 0, 0, 125, 124, 1, 0, 0, 0, 126, 129, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 128, 1, 0, 0, 0, 128, 130, 1, 0, 0, 0, 129, 127, 1, 0, 0, 0, 130, 131, 5, 102, 0, 0, 131, 132, 5, 111, 0, 0, 132, 133, 5, 114, 0, 0, 133, 134, 1, 0, 0, 0, 134, 135, 3, 22, 9, 0, 135, 5, 1, 0, 0, 0, 136, 143, 5, 91, 0, 0, 137, 142, 3, 22, 9, 0, 138, 142, 3, 28, 12, 0, 139, 142, 3, 24, 10, 0, 140, 142, 3, 26, 11, 0, 141, 137, 1, 0, 0, 0, 141, 138, 1, 0, 0, 0, 141, 139, 1, 0, 0, 0, 141, 140, 1, 0, 0, 0, 142, 145, 1, 0, 0, 0, 143, 141, 1, 0, 0, 0, 143, 144, 1, 0, 0, 0, 144, 146, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 146, 147, 5, 102, 0, 0, 147, 148, 5, 111, 0, 0, 148, 149, 5, 114, 0, 0, 149, 150, 1, 0, 0, 0, 150, 151, 3, 22, 9, 0, 151, 7, 1, 0, 0, 0, 152, 153, 5, 105, 0, 0, 153, 154, 5, 102, 0, 0, 154, 9, 1, 0, 0, 0, 155, 156, 5, 105, 0, 0, 156, 157, 5, 110, 0, 0, 157, 11, 1, 0, 0, 0, 158, 159, 5, 123, 0, 0, 159, 160, 6, 4, 0, 0, 160, 13, 1, 0, 0, 0, 161, 162, 5, 125, 0, 0, 162, 163, 6, 5, 1, 0, 163, 15, 1, 0, 0, 0, 164, 165, 5, 61, 0, 0, 165, 17, 1, 0, 0, 0, 166, 169, 8, 0, 0, 0, 167, 169, 3, 34, 15, 0, 168, 166, 1, 0, 0, 0, 168, 167, 1, 0, 0, 0, 169, 19, 1, 0, 0, 0, 170, 175, 3, 32, 14, 0, 171, 174, 3, 30, 13, 0, 172, 174, 5, 45, 0, 0, 173, 171, 1, 0, 0, 0, 173, 172, 1, 0, 0, 0, 174, 177, 1, 0, 0, 0, 175, 173, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 21, 1, 0, 0, 0, 177, 175, 1, 0, 0, 0, 178, 180, 7, 1, 0, 0, 179, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 181, 182, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 184, 6, 9, 2, 0, 184, 23, 1, 0, 0, 0, 185, 186, 5, 47, 0, 0, 186, 187, 5, 42, 0, 0, 187, 191, 1, 0, 0, 0, 188, 190, 9, 0, 0, 0, 189, 188, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 194, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 194, 195, 5, 42, 0, 0, 195, 196, 5, 47, 0, 0, 196, 197, 1, 0, 0, 0, 197, 198, 6, 10, 2, 0, 198, 25, 1, 0, 0, 0, 199, 200, 5, 47, 0, 0, 200, 203, 5, 47, 0, 0, 201, 203, 5, 35, 0, 0, 202, 199, 1, 0, 0, 0, 202, 201, 1, 0, 0, 0, 203, 207, 1, 0, 0, 0, 204, 206, 8, 2, 0, 0, 205, 204, 1, 0, 0, 0, 206, 209, 1, 0, 0, 0, 207, 205, 1, 0, 0, 0, 207, 208, 1, 0, 0, 0, 208, 211, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 210, 212, 5, 13, 0, 0, 211, 210, 1, 0, 0, 0, 211, 212, 1, 0, 0, 0, 212, 214, 1, 0, 0, 0, 213, 215, 7, 3, 0, 0, 214, 213, 1, 0, 0, 0, 215, 216, 1, 0, 0, 0, 216, 217, 6, 11, 2, 0, 217, 27, 1, 0, 0, 0, 218, 219, 5, 10, 0, 0, 219, 220, 1, 0, 0, 0, 220, 221, 6, 12, 2, 0, 221, 29, 1, 0, 0, 0, 222, 225, 3, 32, 14, 0, 223, 225, 7, 4, 0, 0, 224, 222, 1, 0, 0, 0, 224, 223, 1, 0, 0, 0, 225, 31, 1, 0, 0, 0, 226, 231, 7, 5, 0, 0, 227, 231, 8, 6, 0, 0, 228, 229, 7, 7, 0, 0, 229, 231, 7, 8, 0, 0, 230, 226, 1, 0, 0, 0, 230, 227, 1, 0, 0, 0, 230, 228, 1, 0, 0, 0, 231, 33, 1, 0, 0, 0, 232, 233, 5, 92, 0, 0, 233, 251, 7, 9, 0, 0, 234, 235, 5, 92, 0, 0, 235, 236, 3, 36, 16, 0, 236, 237, 3, 36, 16, 0, 237, 238, 3, 36, 16, 0, 238, 239, 3, 36, 16, 0, 239, 251, 1, 0, 0, 0, 240, 241, 5, 92, 0, 0, 241, 242, 3, 36, 16, 0, 242, 243, 3, 36, 16, 0, 243, 244, 3, 36, 16, 0, 244, 245, 3, 36, 16, 0, 245, 246, 3, 36, 16, 0, 246, 247, 3, 36, 16, 0, 247, 248, 3, 36, 16, 0, 248, 249, 3, 36, 16, 0, 249, 251, 1, 0, 0, 0, 250, 232, 1, 0, 0, 0, 250, 234, 1, 0, 0, 0, 250, 240, 1, 0, 0, 0, 251, 35, 1, 0, 0, 0, 252, 253, 7, 10, 0, 0, 253, 37, 1, 0, 0, 0, 254, 256, 7, 4, 0, 0, 255, 254, 1, 0, 0, 0, 256, 257, 1, 0, 0, 0, 257, 255, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 263, 5, 46, 0, 0, 260, 262, 7, 4, 0, 0, 261, 260, 1, 0, 0, 0, 262, 265, 1, 0, 0, 0, 263, 261, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 267, 1, 0, 0, 0, 265, 263, 1, 0, 0, 0, 266, 268, 3, 40, 18, 0, 267, 266, 1, 0, 0, 0, 267, 268, 1, 0, 0, 0, 268, 281, 1, 0, 0, 0, 269, 271, 7, 4, 0, 0, 270, 269, 1, 0, 0, 0, 271, 272, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 274, 1, 0, 0, 0, 274, 281, 3, 40, 18, 0, 275, 277, 7, 4, 0, 0, 276, 275, 1, 0, 0, 0, 277, 278, 1, 0, 0, 0, 278, 276, 1, 0, 0, 0, 278, 279, 1, 0, 0, 0, 279, 281, 1, 0, 0, 0, 280, 255, 1, 0, 0, 0, 280, 270, 1, 0, 0, 0, 280, 276, 1, 0, 0, 0, 281, 39, 1, 0, 0, 0, 282, 284, 7, 11, 0, 0, 283, 285, 7, 12, 0, 0, 284, 283, 1, 0, 0, 0, 284, 285, 1, 0, 0, 0, 285, 287, 1, 0, 0, 0, 286, 288, 7, 4, 0, 0, 287, 286, 1, 0, 0, 0, 288, 289, 1, 0, 0, 0, 289, 287, 1, 0, 0, 0, 289, 290, 1, 0, 0, 0, 290, 41, 1, 0, 0, 0, 291, 292, 5, 116, 0, 0, 292, 293, 5, 114, 0, 0, 293, 294, 5, 117, 0, 0, 294, 301, 5, 101, 0, 0, 295, 296, 5, 102, 0, 0, 296, 297, 5, 97, 0, 0, 297, 298, 5, 108, 0, 0, 298, 299, 5, 115, 0, 0, 299, 301, 5, 101, 0, 0, 300, 291, 1, 0, 0, 0, 300, 295, 1, 0, 0, 0, 301, 43, 1, 0, 0, 0, 302, 303, 5, 34, 0, 0, 303, 304, 1, 0, 0, 0, 304, 305, 6, 20, 3, 0, 305, 45, 1, 0, 0, 0, 306, 307, 5, 110, 0, 0, 307, 308, 5, 117, 0, 0, 308, 309, 5, 108, 0, 0, 309, 310, 5, 108, 0, 0, 310, 47, 1, 0, 0, 0, 311, 312, 5, 60, 0, 0, 312, 313, 5, 60, 0, 0, 313, 315, 1, 0, 0, 0, 314, 316, 5, 45, 0, 0, 315, 314, 1, 0, 0, 0, 315, 316, 1, 0, 0, 0, 316, 317, 1, 0, 0, 0, 317, 318, 6, 22, 4, 0, 318, 49, 1, 0, 0, 0, 319, 320, 5, 43, 0, 0, 320, 51, 1, 0, 0, 0, 321, 322, 5, 38, 0, 0, 322, 323, 5, 38, 0, 0, 323, 53, 1, 0, 0, 0, 324, 325, 5, 61, 0, 0, 325, 326, 5, 61, 0, 0, 326, 55, 1, 0, 0, 0, 327, 328, 5, 60, 0, 0, 328, 57, 1, 0, 0, 0, 329, 330, 5, 58, 0, 0, 330, 59, 1, 0, 0, 0, 331, 332, 5, 91, 0, 0, 332, 61, 1, 0, 0, 0, 333, 334, 5, 40, 0, 0, 334, 63, 1, 0, 0, 0, 335, 336, 5, 45, 0, 0, 336, 65, 1, 0, 0, 0, 337, 338, 5, 124, 0, 0, 338, 339, 5, 124, 0, 0, 339, 67, 1, 0, 0, 0, 340, 341, 5, 33, 0, 0, 341, 342, 5, 61, 0, 0, 342, 69, 1, 0, 0, 0, 343, 344, 5, 62, 0, 0, 344, 71, 1, 0, 0, 0, 345, 346, 5, 63, 0, 0, 346, 73, 1, 0, 0, 0, 347, 348, 5, 93, 0, 0, 348, 75, 1, 0, 0, 0, 349, 350, 5, 41, 0, 0, 350, 77, 1, 0, 0, 0, 351, 352, 5, 42, 0, 0, 352, 79, 1, 0, 0, 0, 353, 354, 5, 33, 0, 0, 354, 81, 1, 0, 0, 0, 355, 356, 5, 60, 0, 0, 356, 357, 5, 61, 0, 0, 357, 83, 1, 0, 0, 0, 358, 359, 5, 46, 0, 0, 359, 85, 1, 0, 0, 0, 360, 361, 5, 47, 0, 0, 361, 87, 1, 0, 0, 0, 362, 363, 5, 62, 0, 0, 363, 364, 5, 61, 0, 0, 364, 89, 1, 0, 0, 0, 365, 366, 5, 61, 0, 0, 366, 367, 5, 62, 0, 0, 367, 91, 1, 0, 0, 0, 368, 369, 5, 44, 0, 0, 369, 93, 1, 0, 0, 0, 370, 371, 5, 37, 0, 0, 371, 95, 1, 0, 0, 0, 372, 373, 5, 46, 0, 0, 373, 374, 5, 46, 0, 0, 374, 375, 5, 46, 0, 0, 375, 97, 1, 0, 0, 0, 376, 377, 5, 126, 0, 0, 377, 99, 1, 0, 0, 0, 378, 379, 5, 36, 0, 0, 379, 380, 5, 123, 0, 0, 380, 381, 1, 0, 0, 0, 381, 382, 6, 48, 5, 0, 382, 383, 1, 0, 0, 0, 383, 384, 6, 48, 6, 0, 384, 101, 1, 0, 0, 0, 385, 387, 3, 104, 50, 0, 386, 385, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 386, 1, 0, 0, 0, 388, 389, 1, 0, 0, 0, 389, 103, 1, 0, 0, 0, 390, 401, 8, 0, 0, 0, 391, 392, 5, 36, 0, 0, 392, 401, 5, 36, 0, 0, 393, 394, 5, 36, 0, 0, 394, 401, 4, 50, 0, 0, 395, 396, 5, 37, 0, 0, 396, 401, 5, 37, 0, 0, 397, 398, 5, 37, 0, 0, 398, 401, 4, 50, 1, 0, 399, 401, 3, 34, 15, 0, 400, 390, 1, 0, 0, 0, 400, 391, 1, 0, 0, 0, 400, 393, 1, 0, 0, 0, 400, 395, 1, 0, 0, 0, 400, 397, 1, 0, 0, 0, 400, 399, 1, 0, 0, 0, 401, 105, 1, 0, 0, 0, 402, 403, 5, 34, 0, 0, 403, 404, 1, 0, 0, 0, 404, 405, 6, 51, 7, 0, 405, 406, 6, 51, 8, 0, 406, 107, 1, 0, 0, 0, 407, 408, 5, 10, 0, 0, 408, 409, 1, 0, 0, 0, 409, 410, 6, 52, 9, 0, 410, 411, 6, 52, 10, 0, 411, 109, 1, 0, 0, 0, 412, 417, 3, 32, 14, 0, 413, 416, 3, 30, 13, 0, 414, 416, 5, 45, 0, 0, 415, 413, 1, 0, 0, 0, 415, 414, 1, 0, 0, 0, 416, 419, 1, 0, 0, 0, 417, 415, 1, 0, 0, 0, 417, 418, 1, 0, 0, 0, 418, 420, 1, 0, 0, 0, 419, 417, 1, 0, 0, 0, 420, 421, 6, 53, 11, 0, 421, 422, 1, 0, 0, 0, 422, 423, 6, 53, 12, 0, 423, 111, 1, 0, 0, 0, 424, 425, 5, 10, 0, 0, 425, 426, 1, 0, 0, 0, 426, 427, 6, 54, 9, 0, 427, 113, 1, 0, 0, 0, 428, 429, 5, 36, 0, 0, 429, 430, 5, 123, 0, 0, 430, 431, 1, 0, 0, 0, 431, 432, 6, 55, 13, 0, 432, 433, 1, 0, 0, 0, 433, 434, 6, 55, 14, 0, 434, 435, 6, 55, 6, 0, 435, 115, 1, 0, 0, 0, 436, 438, 3, 118, 57, 0, 437, 436, 1, 0, 0, 0, 438, 439, 1, 0, 0, 0, 439, 437, 1, 0, 0, 0, 439, 440, 1, 0, 0, 0, 440, 441, 1, 0, 0, 0, 441, 442, 6, 56, 15, 0, 442, 117, 1, 0, 0, 0, 443, 450, 8, 13, 0, 0, 444, 445, 5, 36, 0, 0, 445, 450, 8, 14, 0, 0, 446, 447, 5, 37, 0, 0, 447, 450, 8, 14, 0, 0, 448, 450, 3, 34, 15, 0, 449, 443, 1, 0, 0, 0, 449, 444, 1, 0, 0, 0, 449, 446, 1, 0, 0, 0, 449, 448, 1, 0, 0, 0, 450, 119, 1, 0, 0, 0, 36, 0, 1, 2, 3, 125, 127, 141, 143, 168, 173, 175, 181, 191, 202, 207, 211, 214, 224, 230, 250, 257, 263, 267, 272, 278, 280, 284, 289, 300, 315, 388, 400, 415, 417, 439, 449, 16, 1, 4, 0, 1, 5, 1, 0, 1, 0, 5, 1, 0, 5, 2, 0, 1, 48, 2, 5, 0, 0, 7, 15, 0, 4, 0, 0, 7, 12, 0, 2, 3, 0, 1, 53, 3, 7, 8, 0, 1, 55, 4, 7, 43, 0, 1, 56, 5] \ No newline at end of file +[4, 0, 47, 450, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 126, 8, 0, 10, 0, 12, 0, 129, 9, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 142, 8, 1, 10, 1, 12, 1, 145, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 3, 7, 169, 8, 7, 1, 8, 1, 8, 1, 8, 5, 8, 174, 8, 8, 10, 8, 12, 8, 177, 9, 8, 1, 9, 4, 9, 180, 8, 9, 11, 9, 12, 9, 181, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 5, 10, 190, 8, 10, 10, 10, 12, 10, 193, 9, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 3, 11, 203, 8, 11, 1, 11, 5, 11, 206, 8, 11, 10, 11, 12, 11, 209, 9, 11, 1, 11, 3, 11, 212, 8, 11, 1, 11, 3, 11, 215, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 3, 13, 225, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 3, 14, 231, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 251, 8, 15, 1, 16, 1, 16, 1, 17, 4, 17, 256, 8, 17, 11, 17, 12, 17, 257, 1, 17, 1, 17, 4, 17, 262, 8, 17, 11, 17, 12, 17, 263, 1, 17, 3, 17, 267, 8, 17, 1, 17, 4, 17, 270, 8, 17, 11, 17, 12, 17, 271, 1, 17, 1, 17, 4, 17, 276, 8, 17, 11, 17, 12, 17, 277, 3, 17, 280, 8, 17, 1, 18, 1, 18, 3, 18, 284, 8, 18, 1, 18, 4, 18, 287, 8, 18, 11, 18, 12, 18, 288, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 3, 19, 300, 8, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 3, 22, 315, 8, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 27, 1, 27, 1, 28, 1, 28, 1, 29, 1, 29, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 4, 49, 386, 8, 49, 11, 49, 12, 49, 387, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 3, 50, 400, 8, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 5, 53, 415, 8, 53, 10, 53, 12, 53, 418, 9, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 4, 56, 437, 8, 56, 11, 56, 12, 56, 438, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 3, 57, 449, 8, 57, 1, 191, 0, 58, 4, 1, 6, 2, 8, 3, 10, 4, 12, 5, 14, 6, 16, 7, 18, 0, 20, 8, 22, 9, 24, 10, 26, 11, 28, 12, 30, 0, 32, 0, 34, 0, 36, 0, 38, 13, 40, 0, 42, 14, 44, 15, 46, 16, 48, 17, 50, 18, 52, 19, 54, 20, 56, 21, 58, 22, 60, 23, 62, 24, 64, 25, 66, 26, 68, 27, 70, 28, 72, 29, 74, 30, 76, 31, 78, 32, 80, 33, 82, 34, 84, 35, 86, 36, 88, 37, 90, 38, 92, 39, 94, 40, 96, 41, 98, 42, 100, 43, 102, 44, 104, 45, 106, 0, 108, 0, 110, 0, 112, 0, 114, 0, 116, 46, 118, 47, 4, 0, 1, 2, 3, 15, 4, 0, 10, 10, 13, 13, 34, 34, 36, 37, 3, 0, 9, 9, 12, 13, 32, 32, 2, 0, 10, 10, 13, 13, 1, 1, 10, 10, 1, 0, 48, 57, 4, 0, 36, 36, 65, 90, 95, 95, 97, 122, 2, 0, 0, 127, 55296, 56319, 1, 0, 55296, 56319, 1, 0, 56320, 57343, 5, 0, 34, 34, 92, 92, 110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 3, 0, 10, 10, 13, 13, 36, 37, 1, 0, 123, 123, 484, 0, 4, 1, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 10, 1, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 14, 1, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 24, 1, 0, 0, 0, 0, 26, 1, 0, 0, 0, 0, 28, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 44, 1, 0, 0, 0, 0, 46, 1, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 50, 1, 0, 0, 0, 0, 52, 1, 0, 0, 0, 0, 54, 1, 0, 0, 0, 0, 56, 1, 0, 0, 0, 0, 58, 1, 0, 0, 0, 0, 60, 1, 0, 0, 0, 0, 62, 1, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 66, 1, 0, 0, 0, 0, 68, 1, 0, 0, 0, 0, 70, 1, 0, 0, 0, 0, 72, 1, 0, 0, 0, 0, 74, 1, 0, 0, 0, 0, 76, 1, 0, 0, 0, 0, 78, 1, 0, 0, 0, 0, 80, 1, 0, 0, 0, 0, 82, 1, 0, 0, 0, 0, 84, 1, 0, 0, 0, 0, 86, 1, 0, 0, 0, 0, 88, 1, 0, 0, 0, 0, 90, 1, 0, 0, 0, 0, 92, 1, 0, 0, 0, 0, 94, 1, 0, 0, 0, 0, 96, 1, 0, 0, 0, 0, 98, 1, 0, 0, 0, 1, 100, 1, 0, 0, 0, 1, 102, 1, 0, 0, 0, 1, 104, 1, 0, 0, 0, 1, 106, 1, 0, 0, 0, 2, 108, 1, 0, 0, 0, 2, 110, 1, 0, 0, 0, 3, 112, 1, 0, 0, 0, 3, 114, 1, 0, 0, 0, 3, 116, 1, 0, 0, 0, 3, 118, 1, 0, 0, 0, 4, 120, 1, 0, 0, 0, 6, 136, 1, 0, 0, 0, 8, 152, 1, 0, 0, 0, 10, 155, 1, 0, 0, 0, 12, 158, 1, 0, 0, 0, 14, 161, 1, 0, 0, 0, 16, 164, 1, 0, 0, 0, 18, 168, 1, 0, 0, 0, 20, 170, 1, 0, 0, 0, 22, 179, 1, 0, 0, 0, 24, 185, 1, 0, 0, 0, 26, 202, 1, 0, 0, 0, 28, 218, 1, 0, 0, 0, 30, 224, 1, 0, 0, 0, 32, 230, 1, 0, 0, 0, 34, 250, 1, 0, 0, 0, 36, 252, 1, 0, 0, 0, 38, 279, 1, 0, 0, 0, 40, 281, 1, 0, 0, 0, 42, 299, 1, 0, 0, 0, 44, 301, 1, 0, 0, 0, 46, 305, 1, 0, 0, 0, 48, 310, 1, 0, 0, 0, 50, 318, 1, 0, 0, 0, 52, 320, 1, 0, 0, 0, 54, 323, 1, 0, 0, 0, 56, 326, 1, 0, 0, 0, 58, 328, 1, 0, 0, 0, 60, 330, 1, 0, 0, 0, 62, 332, 1, 0, 0, 0, 64, 334, 1, 0, 0, 0, 66, 336, 1, 0, 0, 0, 68, 339, 1, 0, 0, 0, 70, 342, 1, 0, 0, 0, 72, 344, 1, 0, 0, 0, 74, 346, 1, 0, 0, 0, 76, 348, 1, 0, 0, 0, 78, 350, 1, 0, 0, 0, 80, 352, 1, 0, 0, 0, 82, 354, 1, 0, 0, 0, 84, 357, 1, 0, 0, 0, 86, 359, 1, 0, 0, 0, 88, 361, 1, 0, 0, 0, 90, 364, 1, 0, 0, 0, 92, 367, 1, 0, 0, 0, 94, 369, 1, 0, 0, 0, 96, 371, 1, 0, 0, 0, 98, 375, 1, 0, 0, 0, 100, 377, 1, 0, 0, 0, 102, 385, 1, 0, 0, 0, 104, 399, 1, 0, 0, 0, 106, 401, 1, 0, 0, 0, 108, 406, 1, 0, 0, 0, 110, 411, 1, 0, 0, 0, 112, 423, 1, 0, 0, 0, 114, 427, 1, 0, 0, 0, 116, 436, 1, 0, 0, 0, 118, 448, 1, 0, 0, 0, 120, 127, 5, 123, 0, 0, 121, 126, 3, 22, 9, 0, 122, 126, 3, 28, 12, 0, 123, 126, 3, 24, 10, 0, 124, 126, 3, 26, 11, 0, 125, 121, 1, 0, 0, 0, 125, 122, 1, 0, 0, 0, 125, 123, 1, 0, 0, 0, 125, 124, 1, 0, 0, 0, 126, 129, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 128, 1, 0, 0, 0, 128, 130, 1, 0, 0, 0, 129, 127, 1, 0, 0, 0, 130, 131, 5, 102, 0, 0, 131, 132, 5, 111, 0, 0, 132, 133, 5, 114, 0, 0, 133, 134, 1, 0, 0, 0, 134, 135, 3, 22, 9, 0, 135, 5, 1, 0, 0, 0, 136, 143, 5, 91, 0, 0, 137, 142, 3, 22, 9, 0, 138, 142, 3, 28, 12, 0, 139, 142, 3, 24, 10, 0, 140, 142, 3, 26, 11, 0, 141, 137, 1, 0, 0, 0, 141, 138, 1, 0, 0, 0, 141, 139, 1, 0, 0, 0, 141, 140, 1, 0, 0, 0, 142, 145, 1, 0, 0, 0, 143, 141, 1, 0, 0, 0, 143, 144, 1, 0, 0, 0, 144, 146, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 146, 147, 5, 102, 0, 0, 147, 148, 5, 111, 0, 0, 148, 149, 5, 114, 0, 0, 149, 150, 1, 0, 0, 0, 150, 151, 3, 22, 9, 0, 151, 7, 1, 0, 0, 0, 152, 153, 5, 105, 0, 0, 153, 154, 5, 102, 0, 0, 154, 9, 1, 0, 0, 0, 155, 156, 5, 105, 0, 0, 156, 157, 5, 110, 0, 0, 157, 11, 1, 0, 0, 0, 158, 159, 5, 123, 0, 0, 159, 160, 6, 4, 0, 0, 160, 13, 1, 0, 0, 0, 161, 162, 5, 125, 0, 0, 162, 163, 6, 5, 1, 0, 163, 15, 1, 0, 0, 0, 164, 165, 5, 61, 0, 0, 165, 17, 1, 0, 0, 0, 166, 169, 8, 0, 0, 0, 167, 169, 3, 34, 15, 0, 168, 166, 1, 0, 0, 0, 168, 167, 1, 0, 0, 0, 169, 19, 1, 0, 0, 0, 170, 175, 3, 32, 14, 0, 171, 174, 3, 30, 13, 0, 172, 174, 5, 45, 0, 0, 173, 171, 1, 0, 0, 0, 173, 172, 1, 0, 0, 0, 174, 177, 1, 0, 0, 0, 175, 173, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 21, 1, 0, 0, 0, 177, 175, 1, 0, 0, 0, 178, 180, 7, 1, 0, 0, 179, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 181, 182, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 184, 6, 9, 2, 0, 184, 23, 1, 0, 0, 0, 185, 186, 5, 47, 0, 0, 186, 187, 5, 42, 0, 0, 187, 191, 1, 0, 0, 0, 188, 190, 9, 0, 0, 0, 189, 188, 1, 0, 0, 0, 190, 193, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 194, 1, 0, 0, 0, 193, 191, 1, 0, 0, 0, 194, 195, 5, 42, 0, 0, 195, 196, 5, 47, 0, 0, 196, 197, 1, 0, 0, 0, 197, 198, 6, 10, 2, 0, 198, 25, 1, 0, 0, 0, 199, 200, 5, 47, 0, 0, 200, 203, 5, 47, 0, 0, 201, 203, 5, 35, 0, 0, 202, 199, 1, 0, 0, 0, 202, 201, 1, 0, 0, 0, 203, 207, 1, 0, 0, 0, 204, 206, 8, 2, 0, 0, 205, 204, 1, 0, 0, 0, 206, 209, 1, 0, 0, 0, 207, 205, 1, 0, 0, 0, 207, 208, 1, 0, 0, 0, 208, 211, 1, 0, 0, 0, 209, 207, 1, 0, 0, 0, 210, 212, 5, 13, 0, 0, 211, 210, 1, 0, 0, 0, 211, 212, 1, 0, 0, 0, 212, 214, 1, 0, 0, 0, 213, 215, 7, 3, 0, 0, 214, 213, 1, 0, 0, 0, 215, 216, 1, 0, 0, 0, 216, 217, 6, 11, 2, 0, 217, 27, 1, 0, 0, 0, 218, 219, 5, 10, 0, 0, 219, 220, 1, 0, 0, 0, 220, 221, 6, 12, 2, 0, 221, 29, 1, 0, 0, 0, 222, 225, 3, 32, 14, 0, 223, 225, 7, 4, 0, 0, 224, 222, 1, 0, 0, 0, 224, 223, 1, 0, 0, 0, 225, 31, 1, 0, 0, 0, 226, 231, 7, 5, 0, 0, 227, 231, 8, 6, 0, 0, 228, 229, 7, 7, 0, 0, 229, 231, 7, 8, 0, 0, 230, 226, 1, 0, 0, 0, 230, 227, 1, 0, 0, 0, 230, 228, 1, 0, 0, 0, 231, 33, 1, 0, 0, 0, 232, 233, 5, 92, 0, 0, 233, 251, 7, 9, 0, 0, 234, 235, 5, 92, 0, 0, 235, 236, 3, 36, 16, 0, 236, 237, 3, 36, 16, 0, 237, 238, 3, 36, 16, 0, 238, 239, 3, 36, 16, 0, 239, 251, 1, 0, 0, 0, 240, 241, 5, 92, 0, 0, 241, 242, 3, 36, 16, 0, 242, 243, 3, 36, 16, 0, 243, 244, 3, 36, 16, 0, 244, 245, 3, 36, 16, 0, 245, 246, 3, 36, 16, 0, 246, 247, 3, 36, 16, 0, 247, 248, 3, 36, 16, 0, 248, 249, 3, 36, 16, 0, 249, 251, 1, 0, 0, 0, 250, 232, 1, 0, 0, 0, 250, 234, 1, 0, 0, 0, 250, 240, 1, 0, 0, 0, 251, 35, 1, 0, 0, 0, 252, 253, 7, 10, 0, 0, 253, 37, 1, 0, 0, 0, 254, 256, 7, 4, 0, 0, 255, 254, 1, 0, 0, 0, 256, 257, 1, 0, 0, 0, 257, 255, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 261, 5, 46, 0, 0, 260, 262, 7, 4, 0, 0, 261, 260, 1, 0, 0, 0, 262, 263, 1, 0, 0, 0, 263, 261, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 266, 1, 0, 0, 0, 265, 267, 3, 40, 18, 0, 266, 265, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 267, 280, 1, 0, 0, 0, 268, 270, 7, 4, 0, 0, 269, 268, 1, 0, 0, 0, 270, 271, 1, 0, 0, 0, 271, 269, 1, 0, 0, 0, 271, 272, 1, 0, 0, 0, 272, 273, 1, 0, 0, 0, 273, 280, 3, 40, 18, 0, 274, 276, 7, 4, 0, 0, 275, 274, 1, 0, 0, 0, 276, 277, 1, 0, 0, 0, 277, 275, 1, 0, 0, 0, 277, 278, 1, 0, 0, 0, 278, 280, 1, 0, 0, 0, 279, 255, 1, 0, 0, 0, 279, 269, 1, 0, 0, 0, 279, 275, 1, 0, 0, 0, 280, 39, 1, 0, 0, 0, 281, 283, 7, 11, 0, 0, 282, 284, 7, 12, 0, 0, 283, 282, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 286, 1, 0, 0, 0, 285, 287, 7, 4, 0, 0, 286, 285, 1, 0, 0, 0, 287, 288, 1, 0, 0, 0, 288, 286, 1, 0, 0, 0, 288, 289, 1, 0, 0, 0, 289, 41, 1, 0, 0, 0, 290, 291, 5, 116, 0, 0, 291, 292, 5, 114, 0, 0, 292, 293, 5, 117, 0, 0, 293, 300, 5, 101, 0, 0, 294, 295, 5, 102, 0, 0, 295, 296, 5, 97, 0, 0, 296, 297, 5, 108, 0, 0, 297, 298, 5, 115, 0, 0, 298, 300, 5, 101, 0, 0, 299, 290, 1, 0, 0, 0, 299, 294, 1, 0, 0, 0, 300, 43, 1, 0, 0, 0, 301, 302, 5, 34, 0, 0, 302, 303, 1, 0, 0, 0, 303, 304, 6, 20, 3, 0, 304, 45, 1, 0, 0, 0, 305, 306, 5, 110, 0, 0, 306, 307, 5, 117, 0, 0, 307, 308, 5, 108, 0, 0, 308, 309, 5, 108, 0, 0, 309, 47, 1, 0, 0, 0, 310, 311, 5, 60, 0, 0, 311, 312, 5, 60, 0, 0, 312, 314, 1, 0, 0, 0, 313, 315, 5, 45, 0, 0, 314, 313, 1, 0, 0, 0, 314, 315, 1, 0, 0, 0, 315, 316, 1, 0, 0, 0, 316, 317, 6, 22, 4, 0, 317, 49, 1, 0, 0, 0, 318, 319, 5, 43, 0, 0, 319, 51, 1, 0, 0, 0, 320, 321, 5, 38, 0, 0, 321, 322, 5, 38, 0, 0, 322, 53, 1, 0, 0, 0, 323, 324, 5, 61, 0, 0, 324, 325, 5, 61, 0, 0, 325, 55, 1, 0, 0, 0, 326, 327, 5, 60, 0, 0, 327, 57, 1, 0, 0, 0, 328, 329, 5, 58, 0, 0, 329, 59, 1, 0, 0, 0, 330, 331, 5, 91, 0, 0, 331, 61, 1, 0, 0, 0, 332, 333, 5, 40, 0, 0, 333, 63, 1, 0, 0, 0, 334, 335, 5, 45, 0, 0, 335, 65, 1, 0, 0, 0, 336, 337, 5, 124, 0, 0, 337, 338, 5, 124, 0, 0, 338, 67, 1, 0, 0, 0, 339, 340, 5, 33, 0, 0, 340, 341, 5, 61, 0, 0, 341, 69, 1, 0, 0, 0, 342, 343, 5, 62, 0, 0, 343, 71, 1, 0, 0, 0, 344, 345, 5, 63, 0, 0, 345, 73, 1, 0, 0, 0, 346, 347, 5, 93, 0, 0, 347, 75, 1, 0, 0, 0, 348, 349, 5, 41, 0, 0, 349, 77, 1, 0, 0, 0, 350, 351, 5, 42, 0, 0, 351, 79, 1, 0, 0, 0, 352, 353, 5, 33, 0, 0, 353, 81, 1, 0, 0, 0, 354, 355, 5, 60, 0, 0, 355, 356, 5, 61, 0, 0, 356, 83, 1, 0, 0, 0, 357, 358, 5, 46, 0, 0, 358, 85, 1, 0, 0, 0, 359, 360, 5, 47, 0, 0, 360, 87, 1, 0, 0, 0, 361, 362, 5, 62, 0, 0, 362, 363, 5, 61, 0, 0, 363, 89, 1, 0, 0, 0, 364, 365, 5, 61, 0, 0, 365, 366, 5, 62, 0, 0, 366, 91, 1, 0, 0, 0, 367, 368, 5, 44, 0, 0, 368, 93, 1, 0, 0, 0, 369, 370, 5, 37, 0, 0, 370, 95, 1, 0, 0, 0, 371, 372, 5, 46, 0, 0, 372, 373, 5, 46, 0, 0, 373, 374, 5, 46, 0, 0, 374, 97, 1, 0, 0, 0, 375, 376, 5, 126, 0, 0, 376, 99, 1, 0, 0, 0, 377, 378, 5, 36, 0, 0, 378, 379, 5, 123, 0, 0, 379, 380, 1, 0, 0, 0, 380, 381, 6, 48, 5, 0, 381, 382, 1, 0, 0, 0, 382, 383, 6, 48, 6, 0, 383, 101, 1, 0, 0, 0, 384, 386, 3, 104, 50, 0, 385, 384, 1, 0, 0, 0, 386, 387, 1, 0, 0, 0, 387, 385, 1, 0, 0, 0, 387, 388, 1, 0, 0, 0, 388, 103, 1, 0, 0, 0, 389, 400, 8, 0, 0, 0, 390, 391, 5, 36, 0, 0, 391, 400, 5, 36, 0, 0, 392, 393, 5, 36, 0, 0, 393, 400, 4, 50, 0, 0, 394, 395, 5, 37, 0, 0, 395, 400, 5, 37, 0, 0, 396, 397, 5, 37, 0, 0, 397, 400, 4, 50, 1, 0, 398, 400, 3, 34, 15, 0, 399, 389, 1, 0, 0, 0, 399, 390, 1, 0, 0, 0, 399, 392, 1, 0, 0, 0, 399, 394, 1, 0, 0, 0, 399, 396, 1, 0, 0, 0, 399, 398, 1, 0, 0, 0, 400, 105, 1, 0, 0, 0, 401, 402, 5, 34, 0, 0, 402, 403, 1, 0, 0, 0, 403, 404, 6, 51, 7, 0, 404, 405, 6, 51, 8, 0, 405, 107, 1, 0, 0, 0, 406, 407, 5, 10, 0, 0, 407, 408, 1, 0, 0, 0, 408, 409, 6, 52, 9, 0, 409, 410, 6, 52, 10, 0, 410, 109, 1, 0, 0, 0, 411, 416, 3, 32, 14, 0, 412, 415, 3, 30, 13, 0, 413, 415, 5, 45, 0, 0, 414, 412, 1, 0, 0, 0, 414, 413, 1, 0, 0, 0, 415, 418, 1, 0, 0, 0, 416, 414, 1, 0, 0, 0, 416, 417, 1, 0, 0, 0, 417, 419, 1, 0, 0, 0, 418, 416, 1, 0, 0, 0, 419, 420, 6, 53, 11, 0, 420, 421, 1, 0, 0, 0, 421, 422, 6, 53, 12, 0, 422, 111, 1, 0, 0, 0, 423, 424, 5, 10, 0, 0, 424, 425, 1, 0, 0, 0, 425, 426, 6, 54, 9, 0, 426, 113, 1, 0, 0, 0, 427, 428, 5, 36, 0, 0, 428, 429, 5, 123, 0, 0, 429, 430, 1, 0, 0, 0, 430, 431, 6, 55, 13, 0, 431, 432, 1, 0, 0, 0, 432, 433, 6, 55, 14, 0, 433, 434, 6, 55, 6, 0, 434, 115, 1, 0, 0, 0, 435, 437, 3, 118, 57, 0, 436, 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 436, 1, 0, 0, 0, 438, 439, 1, 0, 0, 0, 439, 440, 1, 0, 0, 0, 440, 441, 6, 56, 15, 0, 441, 117, 1, 0, 0, 0, 442, 449, 8, 13, 0, 0, 443, 444, 5, 36, 0, 0, 444, 449, 8, 14, 0, 0, 445, 446, 5, 37, 0, 0, 446, 449, 8, 14, 0, 0, 447, 449, 3, 34, 15, 0, 448, 442, 1, 0, 0, 0, 448, 443, 1, 0, 0, 0, 448, 445, 1, 0, 0, 0, 448, 447, 1, 0, 0, 0, 449, 119, 1, 0, 0, 0, 36, 0, 1, 2, 3, 125, 127, 141, 143, 168, 173, 175, 181, 191, 202, 207, 211, 214, 224, 230, 250, 257, 263, 266, 271, 277, 279, 283, 288, 299, 314, 387, 399, 414, 416, 438, 448, 16, 1, 4, 0, 1, 5, 1, 0, 1, 0, 5, 1, 0, 5, 2, 0, 1, 48, 2, 5, 0, 0, 7, 15, 0, 4, 0, 0, 7, 12, 0, 2, 3, 0, 1, 53, 3, 7, 8, 0, 1, 55, 4, 7, 43, 0, 1, 56, 5] \ No newline at end of file diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java index d35cc37fe7c..30ec52013ec 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLLexer.java @@ -257,7 +257,7 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre } public static final String _serializedATN = - "\u0004\u0000/\u01c3\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ + "\u0004\u0000/\u01c2\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ "\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ @@ -294,17 +294,17 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+ "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0003"+ "\u000f\u00fb\b\u000f\u0001\u0010\u0001\u0010\u0001\u0011\u0004\u0011\u0100"+ - "\b\u0011\u000b\u0011\f\u0011\u0101\u0001\u0011\u0001\u0011\u0005\u0011"+ - "\u0106\b\u0011\n\u0011\f\u0011\u0109\t\u0011\u0001\u0011\u0003\u0011\u010c"+ - "\b\u0011\u0001\u0011\u0004\u0011\u010f\b\u0011\u000b\u0011\f\u0011\u0110"+ - "\u0001\u0011\u0001\u0011\u0004\u0011\u0115\b\u0011\u000b\u0011\f\u0011"+ - "\u0116\u0003\u0011\u0119\b\u0011\u0001\u0012\u0001\u0012\u0003\u0012\u011d"+ - "\b\u0012\u0001\u0012\u0004\u0012\u0120\b\u0012\u000b\u0012\f\u0012\u0121"+ + "\b\u0011\u000b\u0011\f\u0011\u0101\u0001\u0011\u0001\u0011\u0004\u0011"+ + "\u0106\b\u0011\u000b\u0011\f\u0011\u0107\u0001\u0011\u0003\u0011\u010b"+ + "\b\u0011\u0001\u0011\u0004\u0011\u010e\b\u0011\u000b\u0011\f\u0011\u010f"+ + "\u0001\u0011\u0001\u0011\u0004\u0011\u0114\b\u0011\u000b\u0011\f\u0011"+ + "\u0115\u0003\u0011\u0118\b\u0011\u0001\u0012\u0001\u0012\u0003\u0012\u011c"+ + "\b\u0012\u0001\u0012\u0004\u0012\u011f\b\u0012\u000b\u0012\f\u0012\u0120"+ "\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013"+ - "\u0001\u0013\u0001\u0013\u0001\u0013\u0003\u0013\u012d\b\u0013\u0001\u0014"+ + "\u0001\u0013\u0001\u0013\u0001\u0013\u0003\u0013\u012c\b\u0013\u0001\u0014"+ "\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0015"+ "\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016"+ - "\u0003\u0016\u013c\b\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017"+ + "\u0003\u0016\u013b\b\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017"+ "\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001\u0019"+ "\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c"+ "\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001f\u0001\u001f"+ @@ -312,14 +312,14 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre "#\u0001#\u0001$\u0001$\u0001%\u0001%\u0001&\u0001&\u0001\'\u0001\'\u0001"+ "\'\u0001(\u0001(\u0001)\u0001)\u0001*\u0001*\u0001*\u0001+\u0001+\u0001"+ "+\u0001,\u0001,\u0001-\u0001-\u0001.\u0001.\u0001.\u0001.\u0001/\u0001"+ - "/\u00010\u00010\u00010\u00010\u00010\u00010\u00010\u00011\u00041\u0183"+ - "\b1\u000b1\f1\u0184\u00012\u00012\u00012\u00012\u00012\u00012\u00012\u0001"+ - "2\u00012\u00012\u00032\u0191\b2\u00013\u00013\u00013\u00013\u00013\u0001"+ - "4\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u00055\u01a0\b5\n5"+ - "\f5\u01a3\t5\u00015\u00015\u00015\u00015\u00016\u00016\u00016\u00016\u0001"+ - "7\u00017\u00017\u00017\u00017\u00017\u00017\u00017\u00018\u00048\u01b6"+ - "\b8\u000b8\f8\u01b7\u00018\u00018\u00019\u00019\u00019\u00019\u00019\u0001"+ - "9\u00039\u01c2\b9\u0001\u00bf\u0000:\u0004\u0001\u0006\u0002\b\u0003\n"+ + "/\u00010\u00010\u00010\u00010\u00010\u00010\u00010\u00011\u00041\u0182"+ + "\b1\u000b1\f1\u0183\u00012\u00012\u00012\u00012\u00012\u00012\u00012\u0001"+ + "2\u00012\u00012\u00032\u0190\b2\u00013\u00013\u00013\u00013\u00013\u0001"+ + "4\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u00055\u019f\b5\n5"+ + "\f5\u01a2\t5\u00015\u00015\u00015\u00015\u00016\u00016\u00016\u00016\u0001"+ + "7\u00017\u00017\u00017\u00017\u00017\u00017\u00017\u00018\u00048\u01b5"+ + "\b8\u000b8\f8\u01b6\u00018\u00018\u00019\u00019\u00019\u00019\u00019\u0001"+ + "9\u00039\u01c1\b9\u0001\u00bf\u0000:\u0004\u0001\u0006\u0002\b\u0003\n"+ "\u0004\f\u0005\u000e\u0006\u0010\u0007\u0012\u0000\u0014\b\u0016\t\u0018"+ "\n\u001a\u000b\u001c\f\u001e\u0000 \u0000\"\u0000$\u0000&\r(\u0000*\u000e"+ ",\u000f.\u00100\u00112\u00124\u00136\u00148\u0015:\u0016<\u0017>\u0018"+ @@ -330,7 +330,7 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre "\u0000\u007f\u8000\ud800\u8000\udbff\u0001\u0000\u8000\ud800\u8000\udbff"+ "\u0001\u0000\u8000\udc00\u8000\udfff\u0005\u0000\"\"\\\\nnrrtt\u0003\u0000"+ "09AFaf\u0002\u0000EEee\u0002\u0000++--\u0003\u0000\n\n\r\r$%\u0001\u0000"+ - "{{\u01e5\u0000\u0004\u0001\u0000\u0000\u0000\u0000\u0006\u0001\u0000\u0000"+ + "{{\u01e4\u0000\u0004\u0001\u0000\u0000\u0000\u0000\u0006\u0001\u0000\u0000"+ "\u0000\u0000\b\u0001\u0000\u0000\u0000\u0000\n\u0001\u0000\u0000\u0000"+ "\u0000\f\u0001\u0000\u0000\u0000\u0000\u000e\u0001\u0000\u0000\u0000\u0000"+ "\u0010\u0001\u0000\u0000\u0000\u0000\u0014\u0001\u0000\u0000\u0000\u0000"+ @@ -361,24 +361,24 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre "\u00b9\u0001\u0000\u0000\u0000\u001a\u00ca\u0001\u0000\u0000\u0000\u001c"+ "\u00da\u0001\u0000\u0000\u0000\u001e\u00e0\u0001\u0000\u0000\u0000 \u00e6"+ "\u0001\u0000\u0000\u0000\"\u00fa\u0001\u0000\u0000\u0000$\u00fc\u0001"+ - "\u0000\u0000\u0000&\u0118\u0001\u0000\u0000\u0000(\u011a\u0001\u0000\u0000"+ - "\u0000*\u012c\u0001\u0000\u0000\u0000,\u012e\u0001\u0000\u0000\u0000."+ - "\u0132\u0001\u0000\u0000\u00000\u0137\u0001\u0000\u0000\u00002\u013f\u0001"+ - "\u0000\u0000\u00004\u0141\u0001\u0000\u0000\u00006\u0144\u0001\u0000\u0000"+ - "\u00008\u0147\u0001\u0000\u0000\u0000:\u0149\u0001\u0000\u0000\u0000<"+ - "\u014b\u0001\u0000\u0000\u0000>\u014d\u0001\u0000\u0000\u0000@\u014f\u0001"+ - "\u0000\u0000\u0000B\u0151\u0001\u0000\u0000\u0000D\u0154\u0001\u0000\u0000"+ - "\u0000F\u0157\u0001\u0000\u0000\u0000H\u0159\u0001\u0000\u0000\u0000J"+ - "\u015b\u0001\u0000\u0000\u0000L\u015d\u0001\u0000\u0000\u0000N\u015f\u0001"+ - "\u0000\u0000\u0000P\u0161\u0001\u0000\u0000\u0000R\u0163\u0001\u0000\u0000"+ - "\u0000T\u0166\u0001\u0000\u0000\u0000V\u0168\u0001\u0000\u0000\u0000X"+ - "\u016a\u0001\u0000\u0000\u0000Z\u016d\u0001\u0000\u0000\u0000\\\u0170"+ - "\u0001\u0000\u0000\u0000^\u0172\u0001\u0000\u0000\u0000`\u0174\u0001\u0000"+ - "\u0000\u0000b\u0178\u0001\u0000\u0000\u0000d\u017a\u0001\u0000\u0000\u0000"+ - "f\u0182\u0001\u0000\u0000\u0000h\u0190\u0001\u0000\u0000\u0000j\u0192"+ - "\u0001\u0000\u0000\u0000l\u0197\u0001\u0000\u0000\u0000n\u019c\u0001\u0000"+ - "\u0000\u0000p\u01a8\u0001\u0000\u0000\u0000r\u01ac\u0001\u0000\u0000\u0000"+ - "t\u01b5\u0001\u0000\u0000\u0000v\u01c1\u0001\u0000\u0000\u0000x\u007f"+ + "\u0000\u0000\u0000&\u0117\u0001\u0000\u0000\u0000(\u0119\u0001\u0000\u0000"+ + "\u0000*\u012b\u0001\u0000\u0000\u0000,\u012d\u0001\u0000\u0000\u0000."+ + "\u0131\u0001\u0000\u0000\u00000\u0136\u0001\u0000\u0000\u00002\u013e\u0001"+ + "\u0000\u0000\u00004\u0140\u0001\u0000\u0000\u00006\u0143\u0001\u0000\u0000"+ + "\u00008\u0146\u0001\u0000\u0000\u0000:\u0148\u0001\u0000\u0000\u0000<"+ + "\u014a\u0001\u0000\u0000\u0000>\u014c\u0001\u0000\u0000\u0000@\u014e\u0001"+ + "\u0000\u0000\u0000B\u0150\u0001\u0000\u0000\u0000D\u0153\u0001\u0000\u0000"+ + "\u0000F\u0156\u0001\u0000\u0000\u0000H\u0158\u0001\u0000\u0000\u0000J"+ + "\u015a\u0001\u0000\u0000\u0000L\u015c\u0001\u0000\u0000\u0000N\u015e\u0001"+ + "\u0000\u0000\u0000P\u0160\u0001\u0000\u0000\u0000R\u0162\u0001\u0000\u0000"+ + "\u0000T\u0165\u0001\u0000\u0000\u0000V\u0167\u0001\u0000\u0000\u0000X"+ + "\u0169\u0001\u0000\u0000\u0000Z\u016c\u0001\u0000\u0000\u0000\\\u016f"+ + "\u0001\u0000\u0000\u0000^\u0171\u0001\u0000\u0000\u0000`\u0173\u0001\u0000"+ + "\u0000\u0000b\u0177\u0001\u0000\u0000\u0000d\u0179\u0001\u0000\u0000\u0000"+ + "f\u0181\u0001\u0000\u0000\u0000h\u018f\u0001\u0000\u0000\u0000j\u0191"+ + "\u0001\u0000\u0000\u0000l\u0196\u0001\u0000\u0000\u0000n\u019b\u0001\u0000"+ + "\u0000\u0000p\u01a7\u0001\u0000\u0000\u0000r\u01ab\u0001\u0000\u0000\u0000"+ + "t\u01b4\u0001\u0000\u0000\u0000v\u01c0\u0001\u0000\u0000\u0000x\u007f"+ "\u0005{\u0000\u0000y~\u0003\u0016\t\u0000z~\u0003\u001c\f\u0000{~\u0003"+ "\u0018\n\u0000|~\u0003\u001a\u000b\u0000}y\u0001\u0000\u0000\u0000}z\u0001"+ "\u0000\u0000\u0000}{\u0001\u0000\u0000\u0000}|\u0001\u0000\u0000\u0000"+ @@ -453,111 +453,110 @@ private boolean TemplateStringLiteralChar_sempred(RuleContext _localctx, int pre "\u0007\n\u0000\u0000\u00fd%\u0001\u0000\u0000\u0000\u00fe\u0100\u0007"+ "\u0004\u0000\u0000\u00ff\u00fe\u0001\u0000\u0000\u0000\u0100\u0101\u0001"+ "\u0000\u0000\u0000\u0101\u00ff\u0001\u0000\u0000\u0000\u0101\u0102\u0001"+ - "\u0000\u0000\u0000\u0102\u0103\u0001\u0000\u0000\u0000\u0103\u0107\u0005"+ + "\u0000\u0000\u0000\u0102\u0103\u0001\u0000\u0000\u0000\u0103\u0105\u0005"+ ".\u0000\u0000\u0104\u0106\u0007\u0004\u0000\u0000\u0105\u0104\u0001\u0000"+ - "\u0000\u0000\u0106\u0109\u0001\u0000\u0000\u0000\u0107\u0105\u0001\u0000"+ - "\u0000\u0000\u0107\u0108\u0001\u0000\u0000\u0000\u0108\u010b\u0001\u0000"+ - "\u0000\u0000\u0109\u0107\u0001\u0000\u0000\u0000\u010a\u010c\u0003(\u0012"+ - "\u0000\u010b\u010a\u0001\u0000\u0000\u0000\u010b\u010c\u0001\u0000\u0000"+ - "\u0000\u010c\u0119\u0001\u0000\u0000\u0000\u010d\u010f\u0007\u0004\u0000"+ - "\u0000\u010e\u010d\u0001\u0000\u0000\u0000\u010f\u0110\u0001\u0000\u0000"+ - "\u0000\u0110\u010e\u0001\u0000\u0000\u0000\u0110\u0111\u0001\u0000\u0000"+ - "\u0000\u0111\u0112\u0001\u0000\u0000\u0000\u0112\u0119\u0003(\u0012\u0000"+ - "\u0113\u0115\u0007\u0004\u0000\u0000\u0114\u0113\u0001\u0000\u0000\u0000"+ - "\u0115\u0116\u0001\u0000\u0000\u0000\u0116\u0114\u0001\u0000\u0000\u0000"+ - "\u0116\u0117\u0001\u0000\u0000\u0000\u0117\u0119\u0001\u0000\u0000\u0000"+ - "\u0118\u00ff\u0001\u0000\u0000\u0000\u0118\u010e\u0001\u0000\u0000\u0000"+ - "\u0118\u0114\u0001\u0000\u0000\u0000\u0119\'\u0001\u0000\u0000\u0000\u011a"+ - "\u011c\u0007\u000b\u0000\u0000\u011b\u011d\u0007\f\u0000\u0000\u011c\u011b"+ - "\u0001\u0000\u0000\u0000\u011c\u011d\u0001\u0000\u0000\u0000\u011d\u011f"+ - "\u0001\u0000\u0000\u0000\u011e\u0120\u0007\u0004\u0000\u0000\u011f\u011e"+ - "\u0001\u0000\u0000\u0000\u0120\u0121\u0001\u0000\u0000\u0000\u0121\u011f"+ - "\u0001\u0000\u0000\u0000\u0121\u0122\u0001\u0000\u0000\u0000\u0122)\u0001"+ - "\u0000\u0000\u0000\u0123\u0124\u0005t\u0000\u0000\u0124\u0125\u0005r\u0000"+ - "\u0000\u0125\u0126\u0005u\u0000\u0000\u0126\u012d\u0005e\u0000\u0000\u0127"+ - "\u0128\u0005f\u0000\u0000\u0128\u0129\u0005a\u0000\u0000\u0129\u012a\u0005"+ - "l\u0000\u0000\u012a\u012b\u0005s\u0000\u0000\u012b\u012d\u0005e\u0000"+ - "\u0000\u012c\u0123\u0001\u0000\u0000\u0000\u012c\u0127\u0001\u0000\u0000"+ - "\u0000\u012d+\u0001\u0000\u0000\u0000\u012e\u012f\u0005\"\u0000\u0000"+ - "\u012f\u0130\u0001\u0000\u0000\u0000\u0130\u0131\u0006\u0014\u0003\u0000"+ - "\u0131-\u0001\u0000\u0000\u0000\u0132\u0133\u0005n\u0000\u0000\u0133\u0134"+ - "\u0005u\u0000\u0000\u0134\u0135\u0005l\u0000\u0000\u0135\u0136\u0005l"+ - "\u0000\u0000\u0136/\u0001\u0000\u0000\u0000\u0137\u0138\u0005<\u0000\u0000"+ - "\u0138\u0139\u0005<\u0000\u0000\u0139\u013b\u0001\u0000\u0000\u0000\u013a"+ - "\u013c\u0005-\u0000\u0000\u013b\u013a\u0001\u0000\u0000\u0000\u013b\u013c"+ - "\u0001\u0000\u0000\u0000\u013c\u013d\u0001\u0000\u0000\u0000\u013d\u013e"+ - "\u0006\u0016\u0004\u0000\u013e1\u0001\u0000\u0000\u0000\u013f\u0140\u0005"+ - "+\u0000\u0000\u01403\u0001\u0000\u0000\u0000\u0141\u0142\u0005&\u0000"+ - "\u0000\u0142\u0143\u0005&\u0000\u0000\u01435\u0001\u0000\u0000\u0000\u0144"+ - "\u0145\u0005=\u0000\u0000\u0145\u0146\u0005=\u0000\u0000\u01467\u0001"+ - "\u0000\u0000\u0000\u0147\u0148\u0005<\u0000\u0000\u01489\u0001\u0000\u0000"+ - "\u0000\u0149\u014a\u0005:\u0000\u0000\u014a;\u0001\u0000\u0000\u0000\u014b"+ - "\u014c\u0005[\u0000\u0000\u014c=\u0001\u0000\u0000\u0000\u014d\u014e\u0005"+ - "(\u0000\u0000\u014e?\u0001\u0000\u0000\u0000\u014f\u0150\u0005-\u0000"+ - "\u0000\u0150A\u0001\u0000\u0000\u0000\u0151\u0152\u0005|\u0000\u0000\u0152"+ - "\u0153\u0005|\u0000\u0000\u0153C\u0001\u0000\u0000\u0000\u0154\u0155\u0005"+ - "!\u0000\u0000\u0155\u0156\u0005=\u0000\u0000\u0156E\u0001\u0000\u0000"+ - "\u0000\u0157\u0158\u0005>\u0000\u0000\u0158G\u0001\u0000\u0000\u0000\u0159"+ - "\u015a\u0005?\u0000\u0000\u015aI\u0001\u0000\u0000\u0000\u015b\u015c\u0005"+ - "]\u0000\u0000\u015cK\u0001\u0000\u0000\u0000\u015d\u015e\u0005)\u0000"+ - "\u0000\u015eM\u0001\u0000\u0000\u0000\u015f\u0160\u0005*\u0000\u0000\u0160"+ - "O\u0001\u0000\u0000\u0000\u0161\u0162\u0005!\u0000\u0000\u0162Q\u0001"+ - "\u0000\u0000\u0000\u0163\u0164\u0005<\u0000\u0000\u0164\u0165\u0005=\u0000"+ - "\u0000\u0165S\u0001\u0000\u0000\u0000\u0166\u0167\u0005.\u0000\u0000\u0167"+ - "U\u0001\u0000\u0000\u0000\u0168\u0169\u0005/\u0000\u0000\u0169W\u0001"+ - "\u0000\u0000\u0000\u016a\u016b\u0005>\u0000\u0000\u016b\u016c\u0005=\u0000"+ - "\u0000\u016cY\u0001\u0000\u0000\u0000\u016d\u016e\u0005=\u0000\u0000\u016e"+ - "\u016f\u0005>\u0000\u0000\u016f[\u0001\u0000\u0000\u0000\u0170\u0171\u0005"+ - ",\u0000\u0000\u0171]\u0001\u0000\u0000\u0000\u0172\u0173\u0005%\u0000"+ - "\u0000\u0173_\u0001\u0000\u0000\u0000\u0174\u0175\u0005.\u0000\u0000\u0175"+ - "\u0176\u0005.\u0000\u0000\u0176\u0177\u0005.\u0000\u0000\u0177a\u0001"+ - "\u0000\u0000\u0000\u0178\u0179\u0005~\u0000\u0000\u0179c\u0001\u0000\u0000"+ - "\u0000\u017a\u017b\u0005$\u0000\u0000\u017b\u017c\u0005{\u0000\u0000\u017c"+ - "\u017d\u0001\u0000\u0000\u0000\u017d\u017e\u00060\u0005\u0000\u017e\u017f"+ - "\u0001\u0000\u0000\u0000\u017f\u0180\u00060\u0006\u0000\u0180e\u0001\u0000"+ - "\u0000\u0000\u0181\u0183\u0003h2\u0000\u0182\u0181\u0001\u0000\u0000\u0000"+ - "\u0183\u0184\u0001\u0000\u0000\u0000\u0184\u0182\u0001\u0000\u0000\u0000"+ - "\u0184\u0185\u0001\u0000\u0000\u0000\u0185g\u0001\u0000\u0000\u0000\u0186"+ - "\u0191\b\u0000\u0000\u0000\u0187\u0188\u0005$\u0000\u0000\u0188\u0191"+ - "\u0005$\u0000\u0000\u0189\u018a\u0005$\u0000\u0000\u018a\u0191\u00042"+ - "\u0000\u0000\u018b\u018c\u0005%\u0000\u0000\u018c\u0191\u0005%\u0000\u0000"+ - "\u018d\u018e\u0005%\u0000\u0000\u018e\u0191\u00042\u0001\u0000\u018f\u0191"+ - "\u0003\"\u000f\u0000\u0190\u0186\u0001\u0000\u0000\u0000\u0190\u0187\u0001"+ - "\u0000\u0000\u0000\u0190\u0189\u0001\u0000\u0000\u0000\u0190\u018b\u0001"+ - "\u0000\u0000\u0000\u0190\u018d\u0001\u0000\u0000\u0000\u0190\u018f\u0001"+ - "\u0000\u0000\u0000\u0191i\u0001\u0000\u0000\u0000\u0192\u0193\u0005\""+ - "\u0000\u0000\u0193\u0194\u0001\u0000\u0000\u0000\u0194\u0195\u00063\u0007"+ - "\u0000\u0195\u0196\u00063\b\u0000\u0196k\u0001\u0000\u0000\u0000\u0197"+ - "\u0198\u0005\n\u0000\u0000\u0198\u0199\u0001\u0000\u0000\u0000\u0199\u019a"+ - "\u00064\t\u0000\u019a\u019b\u00064\n\u0000\u019bm\u0001\u0000\u0000\u0000"+ - "\u019c\u01a1\u0003 \u000e\u0000\u019d\u01a0\u0003\u001e\r\u0000\u019e"+ - "\u01a0\u0005-\u0000\u0000\u019f\u019d\u0001\u0000\u0000\u0000\u019f\u019e"+ - "\u0001\u0000\u0000\u0000\u01a0\u01a3\u0001\u0000\u0000\u0000\u01a1\u019f"+ - "\u0001\u0000\u0000\u0000\u01a1\u01a2\u0001\u0000\u0000\u0000\u01a2\u01a4"+ - "\u0001\u0000\u0000\u0000\u01a3\u01a1\u0001\u0000\u0000\u0000\u01a4\u01a5"+ - "\u00065\u000b\u0000\u01a5\u01a6\u0001\u0000\u0000\u0000\u01a6\u01a7\u0006"+ - "5\f\u0000\u01a7o\u0001\u0000\u0000\u0000\u01a8\u01a9\u0005\n\u0000\u0000"+ - "\u01a9\u01aa\u0001\u0000\u0000\u0000\u01aa\u01ab\u00066\t\u0000\u01ab"+ - "q\u0001\u0000\u0000\u0000\u01ac\u01ad\u0005$\u0000\u0000\u01ad\u01ae\u0005"+ - "{\u0000\u0000\u01ae\u01af\u0001\u0000\u0000\u0000\u01af\u01b0\u00067\r"+ - "\u0000\u01b0\u01b1\u0001\u0000\u0000\u0000\u01b1\u01b2\u00067\u000e\u0000"+ - "\u01b2\u01b3\u00067\u0006\u0000\u01b3s\u0001\u0000\u0000\u0000\u01b4\u01b6"+ - "\u0003v9\u0000\u01b5\u01b4\u0001\u0000\u0000\u0000\u01b6\u01b7\u0001\u0000"+ - "\u0000\u0000\u01b7\u01b5\u0001\u0000\u0000\u0000\u01b7\u01b8\u0001\u0000"+ - "\u0000\u0000\u01b8\u01b9\u0001\u0000\u0000\u0000\u01b9\u01ba\u00068\u000f"+ - "\u0000\u01bau\u0001\u0000\u0000\u0000\u01bb\u01c2\b\r\u0000\u0000\u01bc"+ - "\u01bd\u0005$\u0000\u0000\u01bd\u01c2\b\u000e\u0000\u0000\u01be\u01bf"+ - "\u0005%\u0000\u0000\u01bf\u01c2\b\u000e\u0000\u0000\u01c0\u01c2\u0003"+ - "\"\u000f\u0000\u01c1\u01bb\u0001\u0000\u0000\u0000\u01c1\u01bc\u0001\u0000"+ - "\u0000\u0000\u01c1\u01be\u0001\u0000\u0000\u0000\u01c1\u01c0\u0001\u0000"+ - "\u0000\u0000\u01c2w\u0001\u0000\u0000\u0000$\u0000\u0001\u0002\u0003}"+ - "\u007f\u008d\u008f\u00a8\u00ad\u00af\u00b5\u00bf\u00ca\u00cf\u00d3\u00d6"+ - "\u00e0\u00e6\u00fa\u0101\u0107\u010b\u0110\u0116\u0118\u011c\u0121\u012c"+ - "\u013b\u0184\u0190\u019f\u01a1\u01b7\u01c1\u0010\u0001\u0004\u0000\u0001"+ - "\u0005\u0001\u0000\u0001\u0000\u0005\u0001\u0000\u0005\u0002\u0000\u0001"+ - "0\u0002\u0005\u0000\u0000\u0007\u000f\u0000\u0004\u0000\u0000\u0007\f"+ - "\u0000\u0002\u0003\u0000\u00015\u0003\u0007\b\u0000\u00017\u0004\u0007"+ - "+\u0000\u00018\u0005"; + "\u0000\u0000\u0106\u0107\u0001\u0000\u0000\u0000\u0107\u0105\u0001\u0000"+ + "\u0000\u0000\u0107\u0108\u0001\u0000\u0000\u0000\u0108\u010a\u0001\u0000"+ + "\u0000\u0000\u0109\u010b\u0003(\u0012\u0000\u010a\u0109\u0001\u0000\u0000"+ + "\u0000\u010a\u010b\u0001\u0000\u0000\u0000\u010b\u0118\u0001\u0000\u0000"+ + "\u0000\u010c\u010e\u0007\u0004\u0000\u0000\u010d\u010c\u0001\u0000\u0000"+ + "\u0000\u010e\u010f\u0001\u0000\u0000\u0000\u010f\u010d\u0001\u0000\u0000"+ + "\u0000\u010f\u0110\u0001\u0000\u0000\u0000\u0110\u0111\u0001\u0000\u0000"+ + "\u0000\u0111\u0118\u0003(\u0012\u0000\u0112\u0114\u0007\u0004\u0000\u0000"+ + "\u0113\u0112\u0001\u0000\u0000\u0000\u0114\u0115\u0001\u0000\u0000\u0000"+ + "\u0115\u0113\u0001\u0000\u0000\u0000\u0115\u0116\u0001\u0000\u0000\u0000"+ + "\u0116\u0118\u0001\u0000\u0000\u0000\u0117\u00ff\u0001\u0000\u0000\u0000"+ + "\u0117\u010d\u0001\u0000\u0000\u0000\u0117\u0113\u0001\u0000\u0000\u0000"+ + "\u0118\'\u0001\u0000\u0000\u0000\u0119\u011b\u0007\u000b\u0000\u0000\u011a"+ + "\u011c\u0007\f\u0000\u0000\u011b\u011a\u0001\u0000\u0000\u0000\u011b\u011c"+ + "\u0001\u0000\u0000\u0000\u011c\u011e\u0001\u0000\u0000\u0000\u011d\u011f"+ + "\u0007\u0004\u0000\u0000\u011e\u011d\u0001\u0000\u0000\u0000\u011f\u0120"+ + "\u0001\u0000\u0000\u0000\u0120\u011e\u0001\u0000\u0000\u0000\u0120\u0121"+ + "\u0001\u0000\u0000\u0000\u0121)\u0001\u0000\u0000\u0000\u0122\u0123\u0005"+ + "t\u0000\u0000\u0123\u0124\u0005r\u0000\u0000\u0124\u0125\u0005u\u0000"+ + "\u0000\u0125\u012c\u0005e\u0000\u0000\u0126\u0127\u0005f\u0000\u0000\u0127"+ + "\u0128\u0005a\u0000\u0000\u0128\u0129\u0005l\u0000\u0000\u0129\u012a\u0005"+ + "s\u0000\u0000\u012a\u012c\u0005e\u0000\u0000\u012b\u0122\u0001\u0000\u0000"+ + "\u0000\u012b\u0126\u0001\u0000\u0000\u0000\u012c+\u0001\u0000\u0000\u0000"+ + "\u012d\u012e\u0005\"\u0000\u0000\u012e\u012f\u0001\u0000\u0000\u0000\u012f"+ + "\u0130\u0006\u0014\u0003\u0000\u0130-\u0001\u0000\u0000\u0000\u0131\u0132"+ + "\u0005n\u0000\u0000\u0132\u0133\u0005u\u0000\u0000\u0133\u0134\u0005l"+ + "\u0000\u0000\u0134\u0135\u0005l\u0000\u0000\u0135/\u0001\u0000\u0000\u0000"+ + "\u0136\u0137\u0005<\u0000\u0000\u0137\u0138\u0005<\u0000\u0000\u0138\u013a"+ + "\u0001\u0000\u0000\u0000\u0139\u013b\u0005-\u0000\u0000\u013a\u0139\u0001"+ + "\u0000\u0000\u0000\u013a\u013b\u0001\u0000\u0000\u0000\u013b\u013c\u0001"+ + "\u0000\u0000\u0000\u013c\u013d\u0006\u0016\u0004\u0000\u013d1\u0001\u0000"+ + "\u0000\u0000\u013e\u013f\u0005+\u0000\u0000\u013f3\u0001\u0000\u0000\u0000"+ + "\u0140\u0141\u0005&\u0000\u0000\u0141\u0142\u0005&\u0000\u0000\u01425"+ + "\u0001\u0000\u0000\u0000\u0143\u0144\u0005=\u0000\u0000\u0144\u0145\u0005"+ + "=\u0000\u0000\u01457\u0001\u0000\u0000\u0000\u0146\u0147\u0005<\u0000"+ + "\u0000\u01479\u0001\u0000\u0000\u0000\u0148\u0149\u0005:\u0000\u0000\u0149"+ + ";\u0001\u0000\u0000\u0000\u014a\u014b\u0005[\u0000\u0000\u014b=\u0001"+ + "\u0000\u0000\u0000\u014c\u014d\u0005(\u0000\u0000\u014d?\u0001\u0000\u0000"+ + "\u0000\u014e\u014f\u0005-\u0000\u0000\u014fA\u0001\u0000\u0000\u0000\u0150"+ + "\u0151\u0005|\u0000\u0000\u0151\u0152\u0005|\u0000\u0000\u0152C\u0001"+ + "\u0000\u0000\u0000\u0153\u0154\u0005!\u0000\u0000\u0154\u0155\u0005=\u0000"+ + "\u0000\u0155E\u0001\u0000\u0000\u0000\u0156\u0157\u0005>\u0000\u0000\u0157"+ + "G\u0001\u0000\u0000\u0000\u0158\u0159\u0005?\u0000\u0000\u0159I\u0001"+ + "\u0000\u0000\u0000\u015a\u015b\u0005]\u0000\u0000\u015bK\u0001\u0000\u0000"+ + "\u0000\u015c\u015d\u0005)\u0000\u0000\u015dM\u0001\u0000\u0000\u0000\u015e"+ + "\u015f\u0005*\u0000\u0000\u015fO\u0001\u0000\u0000\u0000\u0160\u0161\u0005"+ + "!\u0000\u0000\u0161Q\u0001\u0000\u0000\u0000\u0162\u0163\u0005<\u0000"+ + "\u0000\u0163\u0164\u0005=\u0000\u0000\u0164S\u0001\u0000\u0000\u0000\u0165"+ + "\u0166\u0005.\u0000\u0000\u0166U\u0001\u0000\u0000\u0000\u0167\u0168\u0005"+ + "/\u0000\u0000\u0168W\u0001\u0000\u0000\u0000\u0169\u016a\u0005>\u0000"+ + "\u0000\u016a\u016b\u0005=\u0000\u0000\u016bY\u0001\u0000\u0000\u0000\u016c"+ + "\u016d\u0005=\u0000\u0000\u016d\u016e\u0005>\u0000\u0000\u016e[\u0001"+ + "\u0000\u0000\u0000\u016f\u0170\u0005,\u0000\u0000\u0170]\u0001\u0000\u0000"+ + "\u0000\u0171\u0172\u0005%\u0000\u0000\u0172_\u0001\u0000\u0000\u0000\u0173"+ + "\u0174\u0005.\u0000\u0000\u0174\u0175\u0005.\u0000\u0000\u0175\u0176\u0005"+ + ".\u0000\u0000\u0176a\u0001\u0000\u0000\u0000\u0177\u0178\u0005~\u0000"+ + "\u0000\u0178c\u0001\u0000\u0000\u0000\u0179\u017a\u0005$\u0000\u0000\u017a"+ + "\u017b\u0005{\u0000\u0000\u017b\u017c\u0001\u0000\u0000\u0000\u017c\u017d"+ + "\u00060\u0005\u0000\u017d\u017e\u0001\u0000\u0000\u0000\u017e\u017f\u0006"+ + "0\u0006\u0000\u017fe\u0001\u0000\u0000\u0000\u0180\u0182\u0003h2\u0000"+ + "\u0181\u0180\u0001\u0000\u0000\u0000\u0182\u0183\u0001\u0000\u0000\u0000"+ + "\u0183\u0181\u0001\u0000\u0000\u0000\u0183\u0184\u0001\u0000\u0000\u0000"+ + "\u0184g\u0001\u0000\u0000\u0000\u0185\u0190\b\u0000\u0000\u0000\u0186"+ + "\u0187\u0005$\u0000\u0000\u0187\u0190\u0005$\u0000\u0000\u0188\u0189\u0005"+ + "$\u0000\u0000\u0189\u0190\u00042\u0000\u0000\u018a\u018b\u0005%\u0000"+ + "\u0000\u018b\u0190\u0005%\u0000\u0000\u018c\u018d\u0005%\u0000\u0000\u018d"+ + "\u0190\u00042\u0001\u0000\u018e\u0190\u0003\"\u000f\u0000\u018f\u0185"+ + "\u0001\u0000\u0000\u0000\u018f\u0186\u0001\u0000\u0000\u0000\u018f\u0188"+ + "\u0001\u0000\u0000\u0000\u018f\u018a\u0001\u0000\u0000\u0000\u018f\u018c"+ + "\u0001\u0000\u0000\u0000\u018f\u018e\u0001\u0000\u0000\u0000\u0190i\u0001"+ + "\u0000\u0000\u0000\u0191\u0192\u0005\"\u0000\u0000\u0192\u0193\u0001\u0000"+ + "\u0000\u0000\u0193\u0194\u00063\u0007\u0000\u0194\u0195\u00063\b\u0000"+ + "\u0195k\u0001\u0000\u0000\u0000\u0196\u0197\u0005\n\u0000\u0000\u0197"+ + "\u0198\u0001\u0000\u0000\u0000\u0198\u0199\u00064\t\u0000\u0199\u019a"+ + "\u00064\n\u0000\u019am\u0001\u0000\u0000\u0000\u019b\u01a0\u0003 \u000e"+ + "\u0000\u019c\u019f\u0003\u001e\r\u0000\u019d\u019f\u0005-\u0000\u0000"+ + "\u019e\u019c\u0001\u0000\u0000\u0000\u019e\u019d\u0001\u0000\u0000\u0000"+ + "\u019f\u01a2\u0001\u0000\u0000\u0000\u01a0\u019e\u0001\u0000\u0000\u0000"+ + "\u01a0\u01a1\u0001\u0000\u0000\u0000\u01a1\u01a3\u0001\u0000\u0000\u0000"+ + "\u01a2\u01a0\u0001\u0000\u0000\u0000\u01a3\u01a4\u00065\u000b\u0000\u01a4"+ + "\u01a5\u0001\u0000\u0000\u0000\u01a5\u01a6\u00065\f\u0000\u01a6o\u0001"+ + "\u0000\u0000\u0000\u01a7\u01a8\u0005\n\u0000\u0000\u01a8\u01a9\u0001\u0000"+ + "\u0000\u0000\u01a9\u01aa\u00066\t\u0000\u01aaq\u0001\u0000\u0000\u0000"+ + "\u01ab\u01ac\u0005$\u0000\u0000\u01ac\u01ad\u0005{\u0000\u0000\u01ad\u01ae"+ + "\u0001\u0000\u0000\u0000\u01ae\u01af\u00067\r\u0000\u01af\u01b0\u0001"+ + "\u0000\u0000\u0000\u01b0\u01b1\u00067\u000e\u0000\u01b1\u01b2\u00067\u0006"+ + "\u0000\u01b2s\u0001\u0000\u0000\u0000\u01b3\u01b5\u0003v9\u0000\u01b4"+ + "\u01b3\u0001\u0000\u0000\u0000\u01b5\u01b6\u0001\u0000\u0000\u0000\u01b6"+ + "\u01b4\u0001\u0000\u0000\u0000\u01b6\u01b7\u0001\u0000\u0000\u0000\u01b7"+ + "\u01b8\u0001\u0000\u0000\u0000\u01b8\u01b9\u00068\u000f\u0000\u01b9u\u0001"+ + "\u0000\u0000\u0000\u01ba\u01c1\b\r\u0000\u0000\u01bb\u01bc\u0005$\u0000"+ + "\u0000\u01bc\u01c1\b\u000e\u0000\u0000\u01bd\u01be\u0005%\u0000\u0000"+ + "\u01be\u01c1\b\u000e\u0000\u0000\u01bf\u01c1\u0003\"\u000f\u0000\u01c0"+ + "\u01ba\u0001\u0000\u0000\u0000\u01c0\u01bb\u0001\u0000\u0000\u0000\u01c0"+ + "\u01bd\u0001\u0000\u0000\u0000\u01c0\u01bf\u0001\u0000\u0000\u0000\u01c1"+ + "w\u0001\u0000\u0000\u0000$\u0000\u0001\u0002\u0003}\u007f\u008d\u008f"+ + "\u00a8\u00ad\u00af\u00b5\u00bf\u00ca\u00cf\u00d3\u00d6\u00e0\u00e6\u00fa"+ + "\u0101\u0107\u010a\u010f\u0115\u0117\u011b\u0120\u012b\u013a\u0183\u018f"+ + "\u019e\u01a0\u01b6\u01c0\u0010\u0001\u0004\u0000\u0001\u0005\u0001\u0000"+ + "\u0001\u0000\u0005\u0001\u0000\u0005\u0002\u0000\u00010\u0002\u0005\u0000"+ + "\u0000\u0007\u000f\u0000\u0004\u0000\u0000\u0007\f\u0000\u0002\u0003\u0000"+ + "\u00015\u0003\u0007\b\u0000\u00017\u0004\u0007+\u0000\u00018\u0005"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.interp b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.interp index 20b2b39e3b0..b80f4f5904d 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.interp +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.interp @@ -123,6 +123,7 @@ functionCall arguments index getAttr +legacyIndexAttr splat attrSplat fullSplat @@ -142,4 +143,4 @@ templateInterpolation atn: -[4, 1, 47, 362, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 1, 0, 1, 0, 1, 1, 5, 1, 84, 8, 1, 10, 1, 12, 1, 87, 9, 1, 1, 2, 1, 2, 3, 2, 91, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 5, 4, 99, 8, 4, 10, 4, 12, 4, 102, 9, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 111, 8, 5, 1, 6, 1, 6, 1, 6, 3, 6, 116, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 5, 6, 124, 8, 6, 10, 6, 12, 6, 127, 9, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 140, 8, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 5, 7, 148, 8, 7, 10, 7, 12, 7, 151, 9, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 3, 10, 161, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 167, 8, 11, 10, 11, 12, 11, 170, 9, 11, 1, 11, 3, 11, 173, 8, 11, 3, 11, 175, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 5, 12, 181, 8, 12, 10, 12, 12, 12, 184, 9, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 194, 8, 13, 10, 13, 12, 13, 197, 9, 13, 1, 13, 1, 13, 3, 13, 201, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 206, 8, 13, 1, 14, 1, 14, 3, 14, 210, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 217, 8, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 228, 8, 16, 1, 16, 3, 16, 231, 8, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 3, 17, 238, 8, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 3, 20, 251, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 5, 21, 258, 8, 21, 10, 21, 12, 21, 261, 9, 21, 1, 21, 3, 21, 264, 8, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 3, 24, 275, 8, 24, 1, 25, 1, 25, 1, 25, 5, 25, 280, 8, 25, 10, 25, 12, 25, 283, 9, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 5, 26, 290, 8, 26, 10, 26, 12, 26, 293, 9, 26, 1, 27, 1, 27, 3, 27, 297, 8, 27, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 3, 29, 304, 8, 29, 1, 29, 1, 29, 1, 29, 3, 29, 309, 8, 29, 1, 30, 1, 30, 1, 30, 3, 30, 314, 8, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 326, 8, 34, 10, 34, 12, 34, 329, 9, 34, 4, 34, 331, 8, 34, 11, 34, 12, 34, 332, 1, 34, 1, 34, 1, 34, 5, 34, 338, 8, 34, 10, 34, 12, 34, 341, 9, 34, 1, 34, 3, 34, 344, 8, 34, 1, 35, 1, 35, 3, 35, 348, 8, 35, 1, 36, 1, 36, 1, 37, 1, 37, 3, 37, 354, 8, 37, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 0, 2, 12, 14, 40, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 0, 7, 2, 0, 13, 14, 16, 16, 2, 0, 7, 7, 22, 22, 2, 0, 39, 39, 41, 41, 2, 0, 25, 25, 33, 33, 4, 0, 20, 21, 27, 28, 34, 34, 37, 37, 5, 0, 18, 18, 25, 25, 32, 32, 36, 36, 40, 40, 2, 0, 19, 19, 26, 26, 369, 0, 80, 1, 0, 0, 0, 2, 85, 1, 0, 0, 0, 4, 90, 1, 0, 0, 0, 6, 92, 1, 0, 0, 0, 8, 96, 1, 0, 0, 0, 10, 110, 1, 0, 0, 0, 12, 115, 1, 0, 0, 0, 14, 139, 1, 0, 0, 0, 16, 152, 1, 0, 0, 0, 18, 156, 1, 0, 0, 0, 20, 160, 1, 0, 0, 0, 22, 162, 1, 0, 0, 0, 24, 178, 1, 0, 0, 0, 26, 200, 1, 0, 0, 0, 28, 209, 1, 0, 0, 0, 30, 211, 1, 0, 0, 0, 32, 220, 1, 0, 0, 0, 34, 234, 1, 0, 0, 0, 36, 242, 1, 0, 0, 0, 38, 245, 1, 0, 0, 0, 40, 247, 1, 0, 0, 0, 42, 254, 1, 0, 0, 0, 44, 265, 1, 0, 0, 0, 46, 269, 1, 0, 0, 0, 48, 274, 1, 0, 0, 0, 50, 276, 1, 0, 0, 0, 52, 284, 1, 0, 0, 0, 54, 296, 1, 0, 0, 0, 56, 298, 1, 0, 0, 0, 58, 303, 1, 0, 0, 0, 60, 313, 1, 0, 0, 0, 62, 315, 1, 0, 0, 0, 64, 317, 1, 0, 0, 0, 66, 319, 1, 0, 0, 0, 68, 343, 1, 0, 0, 0, 70, 347, 1, 0, 0, 0, 72, 349, 1, 0, 0, 0, 74, 353, 1, 0, 0, 0, 76, 355, 1, 0, 0, 0, 78, 357, 1, 0, 0, 0, 80, 81, 3, 2, 1, 0, 81, 1, 1, 0, 0, 0, 82, 84, 3, 4, 2, 0, 83, 82, 1, 0, 0, 0, 84, 87, 1, 0, 0, 0, 85, 83, 1, 0, 0, 0, 85, 86, 1, 0, 0, 0, 86, 3, 1, 0, 0, 0, 87, 85, 1, 0, 0, 0, 88, 91, 3, 6, 3, 0, 89, 91, 3, 8, 4, 0, 90, 88, 1, 0, 0, 0, 90, 89, 1, 0, 0, 0, 91, 5, 1, 0, 0, 0, 92, 93, 5, 8, 0, 0, 93, 94, 5, 7, 0, 0, 94, 95, 3, 12, 6, 0, 95, 7, 1, 0, 0, 0, 96, 100, 5, 8, 0, 0, 97, 99, 3, 10, 5, 0, 98, 97, 1, 0, 0, 0, 99, 102, 1, 0, 0, 0, 100, 98, 1, 0, 0, 0, 100, 101, 1, 0, 0, 0, 101, 103, 1, 0, 0, 0, 102, 100, 1, 0, 0, 0, 103, 104, 3, 16, 8, 0, 104, 9, 1, 0, 0, 0, 105, 106, 5, 15, 0, 0, 106, 107, 3, 76, 38, 0, 107, 108, 5, 15, 0, 0, 108, 111, 1, 0, 0, 0, 109, 111, 5, 8, 0, 0, 110, 105, 1, 0, 0, 0, 110, 109, 1, 0, 0, 0, 111, 11, 1, 0, 0, 0, 112, 113, 6, 6, -1, 0, 113, 116, 3, 14, 7, 0, 114, 116, 3, 54, 27, 0, 115, 112, 1, 0, 0, 0, 115, 114, 1, 0, 0, 0, 116, 125, 1, 0, 0, 0, 117, 118, 10, 1, 0, 0, 118, 119, 5, 29, 0, 0, 119, 120, 3, 12, 6, 0, 120, 121, 5, 22, 0, 0, 121, 122, 3, 12, 6, 2, 122, 124, 1, 0, 0, 0, 123, 117, 1, 0, 0, 0, 124, 127, 1, 0, 0, 0, 125, 123, 1, 0, 0, 0, 125, 126, 1, 0, 0, 0, 126, 13, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 128, 129, 6, 7, -1, 0, 129, 140, 3, 68, 34, 0, 130, 140, 3, 18, 9, 0, 131, 140, 3, 28, 14, 0, 132, 140, 3, 20, 10, 0, 133, 140, 3, 38, 19, 0, 134, 140, 3, 40, 20, 0, 135, 136, 5, 24, 0, 0, 136, 137, 3, 12, 6, 0, 137, 138, 5, 31, 0, 0, 138, 140, 1, 0, 0, 0, 139, 128, 1, 0, 0, 0, 139, 130, 1, 0, 0, 0, 139, 131, 1, 0, 0, 0, 139, 132, 1, 0, 0, 0, 139, 133, 1, 0, 0, 0, 139, 134, 1, 0, 0, 0, 139, 135, 1, 0, 0, 0, 140, 149, 1, 0, 0, 0, 141, 142, 10, 4, 0, 0, 142, 148, 3, 44, 22, 0, 143, 144, 10, 3, 0, 0, 144, 148, 3, 46, 23, 0, 145, 146, 10, 2, 0, 0, 146, 148, 3, 48, 24, 0, 147, 141, 1, 0, 0, 0, 147, 143, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 148, 151, 1, 0, 0, 0, 149, 147, 1, 0, 0, 0, 149, 150, 1, 0, 0, 0, 150, 15, 1, 0, 0, 0, 151, 149, 1, 0, 0, 0, 152, 153, 5, 5, 0, 0, 153, 154, 3, 2, 1, 0, 154, 155, 5, 6, 0, 0, 155, 17, 1, 0, 0, 0, 156, 157, 7, 0, 0, 0, 157, 19, 1, 0, 0, 0, 158, 161, 3, 22, 11, 0, 159, 161, 3, 24, 12, 0, 160, 158, 1, 0, 0, 0, 160, 159, 1, 0, 0, 0, 161, 21, 1, 0, 0, 0, 162, 174, 5, 23, 0, 0, 163, 168, 3, 12, 6, 0, 164, 165, 5, 39, 0, 0, 165, 167, 3, 12, 6, 0, 166, 164, 1, 0, 0, 0, 167, 170, 1, 0, 0, 0, 168, 166, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 172, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 173, 5, 39, 0, 0, 172, 171, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, 173, 175, 1, 0, 0, 0, 174, 163, 1, 0, 0, 0, 174, 175, 1, 0, 0, 0, 175, 176, 1, 0, 0, 0, 176, 177, 5, 30, 0, 0, 177, 23, 1, 0, 0, 0, 178, 182, 5, 5, 0, 0, 179, 181, 3, 26, 13, 0, 180, 179, 1, 0, 0, 0, 181, 184, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 182, 183, 1, 0, 0, 0, 183, 185, 1, 0, 0, 0, 184, 182, 1, 0, 0, 0, 185, 186, 5, 6, 0, 0, 186, 25, 1, 0, 0, 0, 187, 201, 5, 8, 0, 0, 188, 189, 5, 24, 0, 0, 189, 190, 5, 8, 0, 0, 190, 201, 5, 31, 0, 0, 191, 195, 5, 15, 0, 0, 192, 194, 3, 74, 37, 0, 193, 192, 1, 0, 0, 0, 194, 197, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 198, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 198, 201, 5, 15, 0, 0, 199, 201, 3, 12, 6, 0, 200, 187, 1, 0, 0, 0, 200, 188, 1, 0, 0, 0, 200, 191, 1, 0, 0, 0, 200, 199, 1, 0, 0, 0, 201, 202, 1, 0, 0, 0, 202, 203, 7, 1, 0, 0, 203, 205, 3, 12, 6, 0, 204, 206, 5, 39, 0, 0, 205, 204, 1, 0, 0, 0, 205, 206, 1, 0, 0, 0, 206, 27, 1, 0, 0, 0, 207, 210, 3, 30, 15, 0, 208, 210, 3, 32, 16, 0, 209, 207, 1, 0, 0, 0, 209, 208, 1, 0, 0, 0, 210, 29, 1, 0, 0, 0, 211, 212, 5, 2, 0, 0, 212, 213, 3, 34, 17, 0, 213, 214, 5, 22, 0, 0, 214, 216, 3, 12, 6, 0, 215, 217, 3, 36, 18, 0, 216, 215, 1, 0, 0, 0, 216, 217, 1, 0, 0, 0, 217, 218, 1, 0, 0, 0, 218, 219, 5, 30, 0, 0, 219, 31, 1, 0, 0, 0, 220, 221, 5, 1, 0, 0, 221, 222, 3, 34, 17, 0, 222, 223, 5, 22, 0, 0, 223, 224, 3, 12, 6, 0, 224, 225, 5, 38, 0, 0, 225, 227, 3, 12, 6, 0, 226, 228, 5, 41, 0, 0, 227, 226, 1, 0, 0, 0, 227, 228, 1, 0, 0, 0, 228, 230, 1, 0, 0, 0, 229, 231, 3, 36, 18, 0, 230, 229, 1, 0, 0, 0, 230, 231, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 233, 5, 6, 0, 0, 233, 33, 1, 0, 0, 0, 234, 237, 5, 8, 0, 0, 235, 236, 5, 39, 0, 0, 236, 238, 5, 8, 0, 0, 237, 235, 1, 0, 0, 0, 237, 238, 1, 0, 0, 0, 238, 239, 1, 0, 0, 0, 239, 240, 5, 4, 0, 0, 240, 241, 3, 12, 6, 0, 241, 35, 1, 0, 0, 0, 242, 243, 5, 3, 0, 0, 243, 244, 3, 12, 6, 0, 244, 37, 1, 0, 0, 0, 245, 246, 5, 8, 0, 0, 246, 39, 1, 0, 0, 0, 247, 248, 5, 8, 0, 0, 248, 250, 5, 24, 0, 0, 249, 251, 3, 42, 21, 0, 250, 249, 1, 0, 0, 0, 250, 251, 1, 0, 0, 0, 251, 252, 1, 0, 0, 0, 252, 253, 5, 31, 0, 0, 253, 41, 1, 0, 0, 0, 254, 259, 3, 12, 6, 0, 255, 256, 5, 39, 0, 0, 256, 258, 3, 12, 6, 0, 257, 255, 1, 0, 0, 0, 258, 261, 1, 0, 0, 0, 259, 257, 1, 0, 0, 0, 259, 260, 1, 0, 0, 0, 260, 263, 1, 0, 0, 0, 261, 259, 1, 0, 0, 0, 262, 264, 7, 2, 0, 0, 263, 262, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 43, 1, 0, 0, 0, 265, 266, 5, 23, 0, 0, 266, 267, 3, 12, 6, 0, 267, 268, 5, 30, 0, 0, 268, 45, 1, 0, 0, 0, 269, 270, 5, 35, 0, 0, 270, 271, 5, 8, 0, 0, 271, 47, 1, 0, 0, 0, 272, 275, 3, 50, 25, 0, 273, 275, 3, 52, 26, 0, 274, 272, 1, 0, 0, 0, 274, 273, 1, 0, 0, 0, 275, 49, 1, 0, 0, 0, 276, 277, 5, 35, 0, 0, 277, 281, 5, 32, 0, 0, 278, 280, 3, 46, 23, 0, 279, 278, 1, 0, 0, 0, 280, 283, 1, 0, 0, 0, 281, 279, 1, 0, 0, 0, 281, 282, 1, 0, 0, 0, 282, 51, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 284, 285, 5, 23, 0, 0, 285, 286, 5, 32, 0, 0, 286, 291, 5, 30, 0, 0, 287, 290, 3, 46, 23, 0, 288, 290, 3, 44, 22, 0, 289, 287, 1, 0, 0, 0, 289, 288, 1, 0, 0, 0, 290, 293, 1, 0, 0, 0, 291, 289, 1, 0, 0, 0, 291, 292, 1, 0, 0, 0, 292, 53, 1, 0, 0, 0, 293, 291, 1, 0, 0, 0, 294, 297, 3, 56, 28, 0, 295, 297, 3, 58, 29, 0, 296, 294, 1, 0, 0, 0, 296, 295, 1, 0, 0, 0, 297, 55, 1, 0, 0, 0, 298, 299, 7, 3, 0, 0, 299, 300, 3, 14, 7, 0, 300, 57, 1, 0, 0, 0, 301, 304, 3, 14, 7, 0, 302, 304, 3, 56, 28, 0, 303, 301, 1, 0, 0, 0, 303, 302, 1, 0, 0, 0, 304, 305, 1, 0, 0, 0, 305, 308, 3, 60, 30, 0, 306, 309, 3, 14, 7, 0, 307, 309, 3, 54, 27, 0, 308, 306, 1, 0, 0, 0, 308, 307, 1, 0, 0, 0, 309, 59, 1, 0, 0, 0, 310, 314, 3, 62, 31, 0, 311, 314, 3, 64, 32, 0, 312, 314, 3, 66, 33, 0, 313, 310, 1, 0, 0, 0, 313, 311, 1, 0, 0, 0, 313, 312, 1, 0, 0, 0, 314, 61, 1, 0, 0, 0, 315, 316, 7, 4, 0, 0, 316, 63, 1, 0, 0, 0, 317, 318, 7, 5, 0, 0, 318, 65, 1, 0, 0, 0, 319, 320, 7, 6, 0, 0, 320, 67, 1, 0, 0, 0, 321, 322, 5, 17, 0, 0, 322, 330, 5, 8, 0, 0, 323, 327, 5, 12, 0, 0, 324, 326, 3, 70, 35, 0, 325, 324, 1, 0, 0, 0, 326, 329, 1, 0, 0, 0, 327, 325, 1, 0, 0, 0, 327, 328, 1, 0, 0, 0, 328, 331, 1, 0, 0, 0, 329, 327, 1, 0, 0, 0, 330, 323, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 330, 1, 0, 0, 0, 332, 333, 1, 0, 0, 0, 333, 334, 1, 0, 0, 0, 334, 344, 5, 8, 0, 0, 335, 339, 5, 15, 0, 0, 336, 338, 3, 74, 37, 0, 337, 336, 1, 0, 0, 0, 338, 341, 1, 0, 0, 0, 339, 337, 1, 0, 0, 0, 339, 340, 1, 0, 0, 0, 340, 342, 1, 0, 0, 0, 341, 339, 1, 0, 0, 0, 342, 344, 5, 15, 0, 0, 343, 321, 1, 0, 0, 0, 343, 335, 1, 0, 0, 0, 344, 69, 1, 0, 0, 0, 345, 348, 3, 78, 39, 0, 346, 348, 3, 72, 36, 0, 347, 345, 1, 0, 0, 0, 347, 346, 1, 0, 0, 0, 348, 71, 1, 0, 0, 0, 349, 350, 5, 46, 0, 0, 350, 73, 1, 0, 0, 0, 351, 354, 3, 78, 39, 0, 352, 354, 3, 76, 38, 0, 353, 351, 1, 0, 0, 0, 353, 352, 1, 0, 0, 0, 354, 75, 1, 0, 0, 0, 355, 356, 5, 44, 0, 0, 356, 77, 1, 0, 0, 0, 357, 358, 5, 43, 0, 0, 358, 359, 3, 12, 6, 0, 359, 360, 5, 6, 0, 0, 360, 79, 1, 0, 0, 0, 39, 85, 90, 100, 110, 115, 125, 139, 147, 149, 160, 168, 172, 174, 182, 195, 200, 205, 209, 216, 227, 230, 237, 250, 259, 263, 274, 281, 289, 291, 296, 303, 308, 313, 327, 332, 339, 343, 347, 353] \ No newline at end of file +[4, 1, 47, 369, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 1, 0, 1, 0, 1, 1, 5, 1, 86, 8, 1, 10, 1, 12, 1, 89, 9, 1, 1, 2, 1, 2, 3, 2, 93, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 5, 4, 101, 8, 4, 10, 4, 12, 4, 104, 9, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 113, 8, 5, 1, 6, 1, 6, 1, 6, 3, 6, 118, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 5, 6, 126, 8, 6, 10, 6, 12, 6, 129, 9, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 142, 8, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 5, 7, 152, 8, 7, 10, 7, 12, 7, 155, 9, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 3, 10, 165, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 171, 8, 11, 10, 11, 12, 11, 174, 9, 11, 1, 11, 3, 11, 177, 8, 11, 3, 11, 179, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 5, 12, 185, 8, 12, 10, 12, 12, 12, 188, 9, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 198, 8, 13, 10, 13, 12, 13, 201, 9, 13, 1, 13, 1, 13, 3, 13, 205, 8, 13, 1, 13, 1, 13, 1, 13, 3, 13, 210, 8, 13, 1, 14, 1, 14, 3, 14, 214, 8, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 221, 8, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 232, 8, 16, 1, 16, 3, 16, 235, 8, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 3, 17, 242, 8, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 3, 20, 255, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 5, 21, 262, 8, 21, 10, 21, 12, 21, 265, 9, 21, 1, 21, 3, 21, 268, 8, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 3, 25, 282, 8, 25, 1, 26, 1, 26, 1, 26, 5, 26, 287, 8, 26, 10, 26, 12, 26, 290, 9, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 5, 27, 297, 8, 27, 10, 27, 12, 27, 300, 9, 27, 1, 28, 1, 28, 3, 28, 304, 8, 28, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 3, 30, 311, 8, 30, 1, 30, 1, 30, 1, 30, 3, 30, 316, 8, 30, 1, 31, 1, 31, 1, 31, 3, 31, 321, 8, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 333, 8, 35, 10, 35, 12, 35, 336, 9, 35, 4, 35, 338, 8, 35, 11, 35, 12, 35, 339, 1, 35, 1, 35, 1, 35, 5, 35, 345, 8, 35, 10, 35, 12, 35, 348, 9, 35, 1, 35, 3, 35, 351, 8, 35, 1, 36, 1, 36, 3, 36, 355, 8, 36, 1, 37, 1, 37, 1, 38, 1, 38, 3, 38, 361, 8, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 0, 2, 12, 14, 41, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 0, 7, 2, 0, 13, 14, 16, 16, 2, 0, 7, 7, 22, 22, 2, 0, 39, 39, 41, 41, 2, 0, 25, 25, 33, 33, 4, 0, 20, 21, 27, 28, 34, 34, 37, 37, 5, 0, 18, 18, 25, 25, 32, 32, 36, 36, 40, 40, 2, 0, 19, 19, 26, 26, 376, 0, 82, 1, 0, 0, 0, 2, 87, 1, 0, 0, 0, 4, 92, 1, 0, 0, 0, 6, 94, 1, 0, 0, 0, 8, 98, 1, 0, 0, 0, 10, 112, 1, 0, 0, 0, 12, 117, 1, 0, 0, 0, 14, 141, 1, 0, 0, 0, 16, 156, 1, 0, 0, 0, 18, 160, 1, 0, 0, 0, 20, 164, 1, 0, 0, 0, 22, 166, 1, 0, 0, 0, 24, 182, 1, 0, 0, 0, 26, 204, 1, 0, 0, 0, 28, 213, 1, 0, 0, 0, 30, 215, 1, 0, 0, 0, 32, 224, 1, 0, 0, 0, 34, 238, 1, 0, 0, 0, 36, 246, 1, 0, 0, 0, 38, 249, 1, 0, 0, 0, 40, 251, 1, 0, 0, 0, 42, 258, 1, 0, 0, 0, 44, 269, 1, 0, 0, 0, 46, 273, 1, 0, 0, 0, 48, 276, 1, 0, 0, 0, 50, 281, 1, 0, 0, 0, 52, 283, 1, 0, 0, 0, 54, 291, 1, 0, 0, 0, 56, 303, 1, 0, 0, 0, 58, 305, 1, 0, 0, 0, 60, 310, 1, 0, 0, 0, 62, 320, 1, 0, 0, 0, 64, 322, 1, 0, 0, 0, 66, 324, 1, 0, 0, 0, 68, 326, 1, 0, 0, 0, 70, 350, 1, 0, 0, 0, 72, 354, 1, 0, 0, 0, 74, 356, 1, 0, 0, 0, 76, 360, 1, 0, 0, 0, 78, 362, 1, 0, 0, 0, 80, 364, 1, 0, 0, 0, 82, 83, 3, 2, 1, 0, 83, 1, 1, 0, 0, 0, 84, 86, 3, 4, 2, 0, 85, 84, 1, 0, 0, 0, 86, 89, 1, 0, 0, 0, 87, 85, 1, 0, 0, 0, 87, 88, 1, 0, 0, 0, 88, 3, 1, 0, 0, 0, 89, 87, 1, 0, 0, 0, 90, 93, 3, 6, 3, 0, 91, 93, 3, 8, 4, 0, 92, 90, 1, 0, 0, 0, 92, 91, 1, 0, 0, 0, 93, 5, 1, 0, 0, 0, 94, 95, 5, 8, 0, 0, 95, 96, 5, 7, 0, 0, 96, 97, 3, 12, 6, 0, 97, 7, 1, 0, 0, 0, 98, 102, 5, 8, 0, 0, 99, 101, 3, 10, 5, 0, 100, 99, 1, 0, 0, 0, 101, 104, 1, 0, 0, 0, 102, 100, 1, 0, 0, 0, 102, 103, 1, 0, 0, 0, 103, 105, 1, 0, 0, 0, 104, 102, 1, 0, 0, 0, 105, 106, 3, 16, 8, 0, 106, 9, 1, 0, 0, 0, 107, 108, 5, 15, 0, 0, 108, 109, 3, 78, 39, 0, 109, 110, 5, 15, 0, 0, 110, 113, 1, 0, 0, 0, 111, 113, 5, 8, 0, 0, 112, 107, 1, 0, 0, 0, 112, 111, 1, 0, 0, 0, 113, 11, 1, 0, 0, 0, 114, 115, 6, 6, -1, 0, 115, 118, 3, 14, 7, 0, 116, 118, 3, 56, 28, 0, 117, 114, 1, 0, 0, 0, 117, 116, 1, 0, 0, 0, 118, 127, 1, 0, 0, 0, 119, 120, 10, 1, 0, 0, 120, 121, 5, 29, 0, 0, 121, 122, 3, 12, 6, 0, 122, 123, 5, 22, 0, 0, 123, 124, 3, 12, 6, 2, 124, 126, 1, 0, 0, 0, 125, 119, 1, 0, 0, 0, 126, 129, 1, 0, 0, 0, 127, 125, 1, 0, 0, 0, 127, 128, 1, 0, 0, 0, 128, 13, 1, 0, 0, 0, 129, 127, 1, 0, 0, 0, 130, 131, 6, 7, -1, 0, 131, 142, 3, 70, 35, 0, 132, 142, 3, 18, 9, 0, 133, 142, 3, 28, 14, 0, 134, 142, 3, 20, 10, 0, 135, 142, 3, 38, 19, 0, 136, 142, 3, 40, 20, 0, 137, 138, 5, 24, 0, 0, 138, 139, 3, 12, 6, 0, 139, 140, 5, 31, 0, 0, 140, 142, 1, 0, 0, 0, 141, 130, 1, 0, 0, 0, 141, 132, 1, 0, 0, 0, 141, 133, 1, 0, 0, 0, 141, 134, 1, 0, 0, 0, 141, 135, 1, 0, 0, 0, 141, 136, 1, 0, 0, 0, 141, 137, 1, 0, 0, 0, 142, 153, 1, 0, 0, 0, 143, 144, 10, 5, 0, 0, 144, 152, 3, 44, 22, 0, 145, 146, 10, 4, 0, 0, 146, 152, 3, 46, 23, 0, 147, 148, 10, 3, 0, 0, 148, 152, 3, 48, 24, 0, 149, 150, 10, 2, 0, 0, 150, 152, 3, 50, 25, 0, 151, 143, 1, 0, 0, 0, 151, 145, 1, 0, 0, 0, 151, 147, 1, 0, 0, 0, 151, 149, 1, 0, 0, 0, 152, 155, 1, 0, 0, 0, 153, 151, 1, 0, 0, 0, 153, 154, 1, 0, 0, 0, 154, 15, 1, 0, 0, 0, 155, 153, 1, 0, 0, 0, 156, 157, 5, 5, 0, 0, 157, 158, 3, 2, 1, 0, 158, 159, 5, 6, 0, 0, 159, 17, 1, 0, 0, 0, 160, 161, 7, 0, 0, 0, 161, 19, 1, 0, 0, 0, 162, 165, 3, 22, 11, 0, 163, 165, 3, 24, 12, 0, 164, 162, 1, 0, 0, 0, 164, 163, 1, 0, 0, 0, 165, 21, 1, 0, 0, 0, 166, 178, 5, 23, 0, 0, 167, 172, 3, 12, 6, 0, 168, 169, 5, 39, 0, 0, 169, 171, 3, 12, 6, 0, 170, 168, 1, 0, 0, 0, 171, 174, 1, 0, 0, 0, 172, 170, 1, 0, 0, 0, 172, 173, 1, 0, 0, 0, 173, 176, 1, 0, 0, 0, 174, 172, 1, 0, 0, 0, 175, 177, 5, 39, 0, 0, 176, 175, 1, 0, 0, 0, 176, 177, 1, 0, 0, 0, 177, 179, 1, 0, 0, 0, 178, 167, 1, 0, 0, 0, 178, 179, 1, 0, 0, 0, 179, 180, 1, 0, 0, 0, 180, 181, 5, 30, 0, 0, 181, 23, 1, 0, 0, 0, 182, 186, 5, 5, 0, 0, 183, 185, 3, 26, 13, 0, 184, 183, 1, 0, 0, 0, 185, 188, 1, 0, 0, 0, 186, 184, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 187, 189, 1, 0, 0, 0, 188, 186, 1, 0, 0, 0, 189, 190, 5, 6, 0, 0, 190, 25, 1, 0, 0, 0, 191, 205, 5, 8, 0, 0, 192, 193, 5, 24, 0, 0, 193, 194, 5, 8, 0, 0, 194, 205, 5, 31, 0, 0, 195, 199, 5, 15, 0, 0, 196, 198, 3, 76, 38, 0, 197, 196, 1, 0, 0, 0, 198, 201, 1, 0, 0, 0, 199, 197, 1, 0, 0, 0, 199, 200, 1, 0, 0, 0, 200, 202, 1, 0, 0, 0, 201, 199, 1, 0, 0, 0, 202, 205, 5, 15, 0, 0, 203, 205, 3, 12, 6, 0, 204, 191, 1, 0, 0, 0, 204, 192, 1, 0, 0, 0, 204, 195, 1, 0, 0, 0, 204, 203, 1, 0, 0, 0, 205, 206, 1, 0, 0, 0, 206, 207, 7, 1, 0, 0, 207, 209, 3, 12, 6, 0, 208, 210, 5, 39, 0, 0, 209, 208, 1, 0, 0, 0, 209, 210, 1, 0, 0, 0, 210, 27, 1, 0, 0, 0, 211, 214, 3, 30, 15, 0, 212, 214, 3, 32, 16, 0, 213, 211, 1, 0, 0, 0, 213, 212, 1, 0, 0, 0, 214, 29, 1, 0, 0, 0, 215, 216, 5, 2, 0, 0, 216, 217, 3, 34, 17, 0, 217, 218, 5, 22, 0, 0, 218, 220, 3, 12, 6, 0, 219, 221, 3, 36, 18, 0, 220, 219, 1, 0, 0, 0, 220, 221, 1, 0, 0, 0, 221, 222, 1, 0, 0, 0, 222, 223, 5, 30, 0, 0, 223, 31, 1, 0, 0, 0, 224, 225, 5, 1, 0, 0, 225, 226, 3, 34, 17, 0, 226, 227, 5, 22, 0, 0, 227, 228, 3, 12, 6, 0, 228, 229, 5, 38, 0, 0, 229, 231, 3, 12, 6, 0, 230, 232, 5, 41, 0, 0, 231, 230, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 234, 1, 0, 0, 0, 233, 235, 3, 36, 18, 0, 234, 233, 1, 0, 0, 0, 234, 235, 1, 0, 0, 0, 235, 236, 1, 0, 0, 0, 236, 237, 5, 6, 0, 0, 237, 33, 1, 0, 0, 0, 238, 241, 5, 8, 0, 0, 239, 240, 5, 39, 0, 0, 240, 242, 5, 8, 0, 0, 241, 239, 1, 0, 0, 0, 241, 242, 1, 0, 0, 0, 242, 243, 1, 0, 0, 0, 243, 244, 5, 4, 0, 0, 244, 245, 3, 12, 6, 0, 245, 35, 1, 0, 0, 0, 246, 247, 5, 3, 0, 0, 247, 248, 3, 12, 6, 0, 248, 37, 1, 0, 0, 0, 249, 250, 5, 8, 0, 0, 250, 39, 1, 0, 0, 0, 251, 252, 5, 8, 0, 0, 252, 254, 5, 24, 0, 0, 253, 255, 3, 42, 21, 0, 254, 253, 1, 0, 0, 0, 254, 255, 1, 0, 0, 0, 255, 256, 1, 0, 0, 0, 256, 257, 5, 31, 0, 0, 257, 41, 1, 0, 0, 0, 258, 263, 3, 12, 6, 0, 259, 260, 5, 39, 0, 0, 260, 262, 3, 12, 6, 0, 261, 259, 1, 0, 0, 0, 262, 265, 1, 0, 0, 0, 263, 261, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 267, 1, 0, 0, 0, 265, 263, 1, 0, 0, 0, 266, 268, 7, 2, 0, 0, 267, 266, 1, 0, 0, 0, 267, 268, 1, 0, 0, 0, 268, 43, 1, 0, 0, 0, 269, 270, 5, 23, 0, 0, 270, 271, 3, 12, 6, 0, 271, 272, 5, 30, 0, 0, 272, 45, 1, 0, 0, 0, 273, 274, 5, 35, 0, 0, 274, 275, 5, 8, 0, 0, 275, 47, 1, 0, 0, 0, 276, 277, 5, 35, 0, 0, 277, 278, 5, 13, 0, 0, 278, 49, 1, 0, 0, 0, 279, 282, 3, 52, 26, 0, 280, 282, 3, 54, 27, 0, 281, 279, 1, 0, 0, 0, 281, 280, 1, 0, 0, 0, 282, 51, 1, 0, 0, 0, 283, 284, 5, 35, 0, 0, 284, 288, 5, 32, 0, 0, 285, 287, 3, 46, 23, 0, 286, 285, 1, 0, 0, 0, 287, 290, 1, 0, 0, 0, 288, 286, 1, 0, 0, 0, 288, 289, 1, 0, 0, 0, 289, 53, 1, 0, 0, 0, 290, 288, 1, 0, 0, 0, 291, 292, 5, 23, 0, 0, 292, 293, 5, 32, 0, 0, 293, 298, 5, 30, 0, 0, 294, 297, 3, 46, 23, 0, 295, 297, 3, 44, 22, 0, 296, 294, 1, 0, 0, 0, 296, 295, 1, 0, 0, 0, 297, 300, 1, 0, 0, 0, 298, 296, 1, 0, 0, 0, 298, 299, 1, 0, 0, 0, 299, 55, 1, 0, 0, 0, 300, 298, 1, 0, 0, 0, 301, 304, 3, 58, 29, 0, 302, 304, 3, 60, 30, 0, 303, 301, 1, 0, 0, 0, 303, 302, 1, 0, 0, 0, 304, 57, 1, 0, 0, 0, 305, 306, 7, 3, 0, 0, 306, 307, 3, 14, 7, 0, 307, 59, 1, 0, 0, 0, 308, 311, 3, 14, 7, 0, 309, 311, 3, 58, 29, 0, 310, 308, 1, 0, 0, 0, 310, 309, 1, 0, 0, 0, 311, 312, 1, 0, 0, 0, 312, 315, 3, 62, 31, 0, 313, 316, 3, 14, 7, 0, 314, 316, 3, 56, 28, 0, 315, 313, 1, 0, 0, 0, 315, 314, 1, 0, 0, 0, 316, 61, 1, 0, 0, 0, 317, 321, 3, 64, 32, 0, 318, 321, 3, 66, 33, 0, 319, 321, 3, 68, 34, 0, 320, 317, 1, 0, 0, 0, 320, 318, 1, 0, 0, 0, 320, 319, 1, 0, 0, 0, 321, 63, 1, 0, 0, 0, 322, 323, 7, 4, 0, 0, 323, 65, 1, 0, 0, 0, 324, 325, 7, 5, 0, 0, 325, 67, 1, 0, 0, 0, 326, 327, 7, 6, 0, 0, 327, 69, 1, 0, 0, 0, 328, 329, 5, 17, 0, 0, 329, 337, 5, 8, 0, 0, 330, 334, 5, 12, 0, 0, 331, 333, 3, 72, 36, 0, 332, 331, 1, 0, 0, 0, 333, 336, 1, 0, 0, 0, 334, 332, 1, 0, 0, 0, 334, 335, 1, 0, 0, 0, 335, 338, 1, 0, 0, 0, 336, 334, 1, 0, 0, 0, 337, 330, 1, 0, 0, 0, 338, 339, 1, 0, 0, 0, 339, 337, 1, 0, 0, 0, 339, 340, 1, 0, 0, 0, 340, 341, 1, 0, 0, 0, 341, 351, 5, 8, 0, 0, 342, 346, 5, 15, 0, 0, 343, 345, 3, 76, 38, 0, 344, 343, 1, 0, 0, 0, 345, 348, 1, 0, 0, 0, 346, 344, 1, 0, 0, 0, 346, 347, 1, 0, 0, 0, 347, 349, 1, 0, 0, 0, 348, 346, 1, 0, 0, 0, 349, 351, 5, 15, 0, 0, 350, 328, 1, 0, 0, 0, 350, 342, 1, 0, 0, 0, 351, 71, 1, 0, 0, 0, 352, 355, 3, 80, 40, 0, 353, 355, 3, 74, 37, 0, 354, 352, 1, 0, 0, 0, 354, 353, 1, 0, 0, 0, 355, 73, 1, 0, 0, 0, 356, 357, 5, 46, 0, 0, 357, 75, 1, 0, 0, 0, 358, 361, 3, 80, 40, 0, 359, 361, 3, 78, 39, 0, 360, 358, 1, 0, 0, 0, 360, 359, 1, 0, 0, 0, 361, 77, 1, 0, 0, 0, 362, 363, 5, 44, 0, 0, 363, 79, 1, 0, 0, 0, 364, 365, 5, 43, 0, 0, 365, 366, 3, 12, 6, 0, 366, 367, 5, 6, 0, 0, 367, 81, 1, 0, 0, 0, 39, 87, 92, 102, 112, 117, 127, 141, 151, 153, 164, 172, 176, 178, 186, 199, 204, 209, 213, 220, 231, 234, 241, 254, 263, 267, 281, 288, 296, 298, 303, 310, 315, 320, 334, 339, 346, 350, 354, 360] \ No newline at end of file diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.java index 5d5346463fb..2827484b3c4 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParser.java @@ -46,19 +46,20 @@ public class HCLParser extends Parser { RULE_tuple = 11, RULE_object = 12, RULE_objectelem = 13, RULE_forExpr = 14, RULE_forTupleExpr = 15, RULE_forObjectExpr = 16, RULE_forIntro = 17, RULE_forCond = 18, RULE_variableExpr = 19, RULE_functionCall = 20, RULE_arguments = 21, RULE_index = 22, - RULE_getAttr = 23, RULE_splat = 24, RULE_attrSplat = 25, RULE_fullSplat = 26, - RULE_operation = 27, RULE_unaryOp = 28, RULE_binaryOp = 29, RULE_binaryOperator = 30, - RULE_compareOperator = 31, RULE_arithmeticOperator = 32, RULE_logicOperator = 33, - RULE_templateExpr = 34, RULE_heredocTemplatePart = 35, RULE_heredocLiteral = 36, - RULE_quotedTemplatePart = 37, RULE_stringLiteral = 38, RULE_templateInterpolation = 39; + RULE_getAttr = 23, RULE_legacyIndexAttr = 24, RULE_splat = 25, RULE_attrSplat = 26, + RULE_fullSplat = 27, RULE_operation = 28, RULE_unaryOp = 29, RULE_binaryOp = 30, + RULE_binaryOperator = 31, RULE_compareOperator = 32, RULE_arithmeticOperator = 33, + RULE_logicOperator = 34, RULE_templateExpr = 35, RULE_heredocTemplatePart = 36, + RULE_heredocLiteral = 37, RULE_quotedTemplatePart = 38, RULE_stringLiteral = 39, + RULE_templateInterpolation = 40; private static String[] makeRuleNames() { return new String[] { "configFile", "body", "bodyContent", "attribute", "block", "blockLabel", "expression", "exprTerm", "blockExpr", "literalValue", "collectionValue", "tuple", "object", "objectelem", "forExpr", "forTupleExpr", "forObjectExpr", "forIntro", "forCond", "variableExpr", "functionCall", "arguments", "index", - "getAttr", "splat", "attrSplat", "fullSplat", "operation", "unaryOp", - "binaryOp", "binaryOperator", "compareOperator", "arithmeticOperator", + "getAttr", "legacyIndexAttr", "splat", "attrSplat", "fullSplat", "operation", + "unaryOp", "binaryOp", "binaryOperator", "compareOperator", "arithmeticOperator", "logicOperator", "templateExpr", "heredocTemplatePart", "heredocLiteral", "quotedTemplatePart", "stringLiteral", "templateInterpolation" }; @@ -168,7 +169,7 @@ public final ConfigFileContext configFile() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(80); + setState(82); body(); } } @@ -217,17 +218,17 @@ public final BodyContext body() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(85); + setState(87); _errHandler.sync(this); _la = _input.LA(1); while (_la==Identifier) { { { - setState(82); + setState(84); bodyContent(); } } - setState(87); + setState(89); _errHandler.sync(this); _la = _input.LA(1); } @@ -275,20 +276,20 @@ public final BodyContentContext bodyContent() throws RecognitionException { BodyContentContext _localctx = new BodyContentContext(_ctx, getState()); enterRule(_localctx, 4, RULE_bodyContent); try { - setState(90); + setState(92); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(88); + setState(90); attribute(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(89); + setState(91); block(); } break; @@ -337,11 +338,11 @@ public final AttributeContext attribute() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(92); + setState(94); match(Identifier); - setState(93); + setState(95); match(ASSIGN); - setState(94); + setState(96); expression(0); } } @@ -394,23 +395,23 @@ public final BlockContext block() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(96); + setState(98); match(Identifier); - setState(100); + setState(102); _errHandler.sync(this); _la = _input.LA(1); while (_la==Identifier || _la==QUOTE) { { { - setState(97); + setState(99); blockLabel(); } } - setState(102); + setState(104); _errHandler.sync(this); _la = _input.LA(1); } - setState(103); + setState(105); blockExpr(); } } @@ -458,24 +459,24 @@ public final BlockLabelContext blockLabel() throws RecognitionException { BlockLabelContext _localctx = new BlockLabelContext(_ctx, getState()); enterRule(_localctx, 10, RULE_blockLabel); try { - setState(110); + setState(112); _errHandler.sync(this); switch (_input.LA(1)) { case QUOTE: enterOuterAlt(_localctx, 1); { - setState(105); + setState(107); match(QUOTE); - setState(106); + setState(108); stringLiteral(); - setState(107); + setState(109); match(QUOTE); } break; case Identifier: enterOuterAlt(_localctx, 2); { - setState(109); + setState(111); match(Identifier); } break; @@ -587,7 +588,7 @@ private ExpressionContext expression(int _p) throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(115); + setState(117); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) { case 1: @@ -596,7 +597,7 @@ private ExpressionContext expression(int _p) throws RecognitionException { _ctx = _localctx; _prevctx = _localctx; - setState(113); + setState(115); exprTerm(0); } break; @@ -605,13 +606,13 @@ private ExpressionContext expression(int _p) throws RecognitionException { _localctx = new OperationExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(114); + setState(116); operation(); } break; } _ctx.stop = _input.LT(-1); - setState(125); + setState(127); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,5,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -622,20 +623,20 @@ private ExpressionContext expression(int _p) throws RecognitionException { { _localctx = new ConditionalExpressionContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(117); + setState(119); if (!(precpred(_ctx, 1))) throw new FailedPredicateException(this, "precpred(_ctx, 1)"); - setState(118); + setState(120); match(QUESTION); - setState(119); + setState(121); expression(0); - setState(120); + setState(122); match(COLON); - setState(121); + setState(123); expression(2); } } } - setState(127); + setState(129); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,5,_ctx); } @@ -816,6 +817,29 @@ public T accept(ParseTreeVisitor visitor) { } } @SuppressWarnings("CheckReturnValue") + public static class LegacyIndexAttributeExpressionContext extends ExprTermContext { + public ExprTermContext exprTerm() { + return getRuleContext(ExprTermContext.class,0); + } + public LegacyIndexAttrContext legacyIndexAttr() { + return getRuleContext(LegacyIndexAttrContext.class,0); + } + public LegacyIndexAttributeExpressionContext(ExprTermContext ctx) { copyFrom(ctx); } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof HCLParserListener ) ((HCLParserListener)listener).enterLegacyIndexAttributeExpression(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof HCLParserListener ) ((HCLParserListener)listener).exitLegacyIndexAttributeExpression(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof HCLParserVisitor ) return ((HCLParserVisitor)visitor).visitLegacyIndexAttributeExpression(this); + else return visitor.visitChildren(this); + } + } + @SuppressWarnings("CheckReturnValue") public static class ForExpressionContext extends ExprTermContext { public ForExprContext forExpr() { return getRuleContext(ForExprContext.class,0); @@ -891,7 +915,7 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(139); + setState(141); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,6,_ctx) ) { case 1: @@ -900,7 +924,7 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { _ctx = _localctx; _prevctx = _localctx; - setState(129); + setState(131); templateExpr(); } break; @@ -909,7 +933,7 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { _localctx = new LiteralExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(130); + setState(132); literalValue(); } break; @@ -918,7 +942,7 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { _localctx = new ForExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(131); + setState(133); forExpr(); } break; @@ -927,7 +951,7 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { _localctx = new CollectionValueExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(132); + setState(134); collectionValue(); } break; @@ -936,7 +960,7 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { _localctx = new VariableExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(133); + setState(135); variableExpr(); } break; @@ -945,7 +969,7 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { _localctx = new FunctionCallExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(134); + setState(136); functionCall(); } break; @@ -954,17 +978,17 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { _localctx = new ParentheticalExpressionContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(135); + setState(137); match(LPAREN); - setState(136); + setState(138); expression(0); - setState(137); + setState(139); match(RPAREN); } break; } _ctx.stop = _input.LT(-1); - setState(149); + setState(153); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,8,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { @@ -972,16 +996,16 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(147); + setState(151); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,7,_ctx) ) { case 1: { _localctx = new IndexAccessExpressionContext(new ExprTermContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_exprTerm); - setState(141); - if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)"); - setState(142); + setState(143); + if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)"); + setState(144); index(); } break; @@ -989,26 +1013,36 @@ private ExprTermContext exprTerm(int _p) throws RecognitionException { { _localctx = new AttributeAccessExpressionContext(new ExprTermContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_exprTerm); - setState(143); - if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)"); - setState(144); + setState(145); + if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)"); + setState(146); getAttr(); } break; case 3: + { + _localctx = new LegacyIndexAttributeExpressionContext(new ExprTermContext(_parentctx, _parentState)); + pushNewRecursionContext(_localctx, _startState, RULE_exprTerm); + setState(147); + if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)"); + setState(148); + legacyIndexAttr(); + } + break; + case 4: { _localctx = new SplatExpressionContext(new ExprTermContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_exprTerm); - setState(145); + setState(149); if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)"); - setState(146); + setState(150); splat(); } break; } } } - setState(151); + setState(155); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,8,_ctx); } @@ -1057,11 +1091,11 @@ public final BlockExprContext blockExpr() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(152); + setState(156); match(LBRACE); - setState(153); + setState(157); body(); - setState(154); + setState(158); match(RBRACE); } } @@ -1107,7 +1141,7 @@ public final LiteralValueContext literalValue() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(156); + setState(160); _la = _input.LA(1); if ( !(((_la) & ~0x3f) == 0 && ((1L << _la) & 90112L) != 0) ) { _errHandler.recoverInline(this); @@ -1161,20 +1195,20 @@ public final CollectionValueContext collectionValue() throws RecognitionExceptio CollectionValueContext _localctx = new CollectionValueContext(_ctx, getState()); enterRule(_localctx, 20, RULE_collectionValue); try { - setState(160); + setState(164); _errHandler.sync(this); switch (_input.LA(1)) { case LBRACK: enterOuterAlt(_localctx, 1); { - setState(158); + setState(162); tuple(); } break; case LBRACE: enterOuterAlt(_localctx, 2); { - setState(159); + setState(163); object(); } break; @@ -1234,39 +1268,39 @@ public final TupleContext tuple() throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(162); + setState(166); match(LBRACK); - setState(174); + setState(178); _errHandler.sync(this); _la = _input.LA(1); if (((_la) & ~0x3f) == 0 && ((1L << _la) & 8648909094L) != 0) { { - setState(163); + setState(167); expression(0); - setState(168); + setState(172); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,10,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(164); + setState(168); match(COMMA); - setState(165); + setState(169); expression(0); } } } - setState(170); + setState(174); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,10,_ctx); } - setState(172); + setState(176); _errHandler.sync(this); _la = _input.LA(1); if (_la==COMMA) { { - setState(171); + setState(175); match(COMMA); } } @@ -1274,7 +1308,7 @@ public final TupleContext tuple() throws RecognitionException { } } - setState(176); + setState(180); match(RBRACK); } } @@ -1325,23 +1359,23 @@ public final ObjectContext object() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(178); - match(LBRACE); setState(182); + match(LBRACE); + setState(186); _errHandler.sync(this); _la = _input.LA(1); while (((_la) & ~0x3f) == 0 && ((1L << _la) & 8648909094L) != 0) { { { - setState(179); + setState(183); objectelem(); } } - setState(184); + setState(188); _errHandler.sync(this); _la = _input.LA(1); } - setState(185); + setState(189); match(RBRACE); } } @@ -1406,55 +1440,55 @@ public final ObjectelemContext objectelem() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(200); + setState(204); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,15,_ctx) ) { case 1: { - setState(187); + setState(191); match(Identifier); } break; case 2: { - setState(188); + setState(192); match(LPAREN); - setState(189); + setState(193); match(Identifier); - setState(190); + setState(194); match(RPAREN); } break; case 3: { - setState(191); - match(QUOTE); setState(195); + match(QUOTE); + setState(199); _errHandler.sync(this); _la = _input.LA(1); while (_la==TEMPLATE_INTERPOLATION_START || _la==TemplateStringLiteral) { { { - setState(192); + setState(196); quotedTemplatePart(); } } - setState(197); + setState(201); _errHandler.sync(this); _la = _input.LA(1); } - setState(198); + setState(202); match(QUOTE); } break; case 4: { - setState(199); + setState(203); expression(0); } break; } - setState(202); + setState(206); _la = _input.LA(1); if ( !(_la==ASSIGN || _la==COLON) ) { _errHandler.recoverInline(this); @@ -1464,14 +1498,14 @@ public final ObjectelemContext objectelem() throws RecognitionException { _errHandler.reportMatch(this); consume(); } - setState(203); + setState(207); expression(0); - setState(205); + setState(209); _errHandler.sync(this); _la = _input.LA(1); if (_la==COMMA) { { - setState(204); + setState(208); match(COMMA); } } @@ -1520,20 +1554,20 @@ public final ForExprContext forExpr() throws RecognitionException { ForExprContext _localctx = new ForExprContext(_ctx, getState()); enterRule(_localctx, 28, RULE_forExpr); try { - setState(209); + setState(213); _errHandler.sync(this); switch (_input.LA(1)) { case FOR_BRACK: enterOuterAlt(_localctx, 1); { - setState(207); + setState(211); forTupleExpr(); } break; case FOR_BRACE: enterOuterAlt(_localctx, 2); { - setState(208); + setState(212); forObjectExpr(); } break; @@ -1592,25 +1626,25 @@ public final ForTupleExprContext forTupleExpr() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(211); + setState(215); match(FOR_BRACK); - setState(212); + setState(216); forIntro(); - setState(213); + setState(217); match(COLON); - setState(214); + setState(218); expression(0); - setState(216); + setState(220); _errHandler.sync(this); _la = _input.LA(1); if (_la==IF) { { - setState(215); + setState(219); forCond(); } } - setState(218); + setState(222); match(RBRACK); } } @@ -1670,39 +1704,39 @@ public final ForObjectExprContext forObjectExpr() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(220); + setState(224); match(FOR_BRACE); - setState(221); + setState(225); forIntro(); - setState(222); + setState(226); match(COLON); - setState(223); + setState(227); expression(0); - setState(224); + setState(228); match(ARROW); - setState(225); + setState(229); expression(0); - setState(227); + setState(231); _errHandler.sync(this); _la = _input.LA(1); if (_la==ELLIPSIS) { { - setState(226); + setState(230); match(ELLIPSIS); } } - setState(230); + setState(234); _errHandler.sync(this); _la = _input.LA(1); if (_la==IF) { { - setState(229); + setState(233); forCond(); } } - setState(232); + setState(236); match(RBRACE); } } @@ -1754,23 +1788,23 @@ public final ForIntroContext forIntro() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(234); + setState(238); match(Identifier); - setState(237); + setState(241); _errHandler.sync(this); _la = _input.LA(1); if (_la==COMMA) { { - setState(235); + setState(239); match(COMMA); - setState(236); + setState(240); match(Identifier); } } - setState(239); + setState(243); match(IN); - setState(240); + setState(244); expression(0); } } @@ -1816,9 +1850,9 @@ public final ForCondContext forCond() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(242); + setState(246); match(IF); - setState(243); + setState(247); expression(0); } } @@ -1861,7 +1895,7 @@ public final VariableExprContext variableExpr() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(245); + setState(249); match(Identifier); } } @@ -1910,21 +1944,21 @@ public final FunctionCallContext functionCall() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(247); + setState(251); match(Identifier); - setState(248); + setState(252); match(LPAREN); - setState(250); + setState(254); _errHandler.sync(this); _la = _input.LA(1); if (((_la) & ~0x3f) == 0 && ((1L << _la) & 8648909094L) != 0) { { - setState(249); + setState(253); arguments(); } } - setState(252); + setState(256); match(RPAREN); } } @@ -1979,32 +2013,32 @@ public final ArgumentsContext arguments() throws RecognitionException { int _alt; enterOuterAlt(_localctx, 1); { - setState(254); + setState(258); expression(0); - setState(259); + setState(263); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,23,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(255); + setState(259); match(COMMA); - setState(256); + setState(260); expression(0); } } } - setState(261); + setState(265); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,23,_ctx); } - setState(263); + setState(267); _errHandler.sync(this); _la = _input.LA(1); if (_la==COMMA || _la==ELLIPSIS) { { - setState(262); + setState(266); _la = _input.LA(1); if ( !(_la==COMMA || _la==ELLIPSIS) ) { _errHandler.recoverInline(this); @@ -2062,11 +2096,11 @@ public final IndexContext index() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(265); + setState(269); match(LBRACK); - setState(266); + setState(270); expression(0); - setState(267); + setState(271); match(RBRACK); } } @@ -2110,9 +2144,9 @@ public final GetAttrContext getAttr() throws RecognitionException { try { enterOuterAlt(_localctx, 1); { - setState(269); + setState(273); match(DOT); - setState(270); + setState(274); match(Identifier); } } @@ -2127,6 +2161,52 @@ public final GetAttrContext getAttr() throws RecognitionException { return _localctx; } + @SuppressWarnings("CheckReturnValue") + public static class LegacyIndexAttrContext extends ParserRuleContext { + public TerminalNode DOT() { return getToken(HCLParser.DOT, 0); } + public TerminalNode NumericLiteral() { return getToken(HCLParser.NumericLiteral, 0); } + public LegacyIndexAttrContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_legacyIndexAttr; } + @Override + public void enterRule(ParseTreeListener listener) { + if ( listener instanceof HCLParserListener ) ((HCLParserListener)listener).enterLegacyIndexAttr(this); + } + @Override + public void exitRule(ParseTreeListener listener) { + if ( listener instanceof HCLParserListener ) ((HCLParserListener)listener).exitLegacyIndexAttr(this); + } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof HCLParserVisitor ) return ((HCLParserVisitor)visitor).visitLegacyIndexAttr(this); + else return visitor.visitChildren(this); + } + } + + public final LegacyIndexAttrContext legacyIndexAttr() throws RecognitionException { + LegacyIndexAttrContext _localctx = new LegacyIndexAttrContext(_ctx, getState()); + enterRule(_localctx, 48, RULE_legacyIndexAttr); + try { + enterOuterAlt(_localctx, 1); + { + setState(276); + match(DOT); + setState(277); + match(NumericLiteral); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + @SuppressWarnings("CheckReturnValue") public static class SplatContext extends ParserRuleContext { public AttrSplatContext attrSplat() { @@ -2156,22 +2236,22 @@ public T accept(ParseTreeVisitor visitor) { public final SplatContext splat() throws RecognitionException { SplatContext _localctx = new SplatContext(_ctx, getState()); - enterRule(_localctx, 48, RULE_splat); + enterRule(_localctx, 50, RULE_splat); try { - setState(274); + setState(281); _errHandler.sync(this); switch (_input.LA(1)) { case DOT: enterOuterAlt(_localctx, 1); { - setState(272); + setState(279); attrSplat(); } break; case LBRACK: enterOuterAlt(_localctx, 2); { - setState(273); + setState(280); fullSplat(); } break; @@ -2221,28 +2301,28 @@ public T accept(ParseTreeVisitor visitor) { public final AttrSplatContext attrSplat() throws RecognitionException { AttrSplatContext _localctx = new AttrSplatContext(_ctx, getState()); - enterRule(_localctx, 50, RULE_attrSplat); + enterRule(_localctx, 52, RULE_attrSplat); try { int _alt; enterOuterAlt(_localctx, 1); { - setState(276); + setState(283); match(DOT); - setState(277); + setState(284); match(MUL); - setState(281); + setState(288); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,26,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { { - setState(278); + setState(285); getAttr(); } } } - setState(283); + setState(290); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,26,_ctx); } @@ -2297,35 +2377,35 @@ public T accept(ParseTreeVisitor visitor) { public final FullSplatContext fullSplat() throws RecognitionException { FullSplatContext _localctx = new FullSplatContext(_ctx, getState()); - enterRule(_localctx, 52, RULE_fullSplat); + enterRule(_localctx, 54, RULE_fullSplat); try { int _alt; enterOuterAlt(_localctx, 1); { - setState(284); + setState(291); match(LBRACK); - setState(285); + setState(292); match(MUL); - setState(286); + setState(293); match(RBRACK); - setState(291); + setState(298); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,28,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { { - setState(289); + setState(296); _errHandler.sync(this); switch (_input.LA(1)) { case DOT: { - setState(287); + setState(294); getAttr(); } break; case LBRACK: { - setState(288); + setState(295); index(); } break; @@ -2334,7 +2414,7 @@ public final FullSplatContext fullSplat() throws RecognitionException { } } } - setState(293); + setState(300); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,28,_ctx); } @@ -2380,22 +2460,22 @@ public T accept(ParseTreeVisitor visitor) { public final OperationContext operation() throws RecognitionException { OperationContext _localctx = new OperationContext(_ctx, getState()); - enterRule(_localctx, 54, RULE_operation); + enterRule(_localctx, 56, RULE_operation); try { - setState(296); + setState(303); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,29,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(294); + setState(301); unaryOp(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(295); + setState(302); binaryOp(); } break; @@ -2440,12 +2520,12 @@ public T accept(ParseTreeVisitor visitor) { public final UnaryOpContext unaryOp() throws RecognitionException { UnaryOpContext _localctx = new UnaryOpContext(_ctx, getState()); - enterRule(_localctx, 56, RULE_unaryOp); + enterRule(_localctx, 58, RULE_unaryOp); int _la; try { enterOuterAlt(_localctx, 1); { - setState(298); + setState(305); _la = _input.LA(1); if ( !(_la==MINUS || _la==NOT) ) { _errHandler.recoverInline(this); @@ -2455,7 +2535,7 @@ public final UnaryOpContext unaryOp() throws RecognitionException { _errHandler.reportMatch(this); consume(); } - setState(299); + setState(306); exprTerm(0); } } @@ -2508,11 +2588,11 @@ public T accept(ParseTreeVisitor visitor) { public final BinaryOpContext binaryOp() throws RecognitionException { BinaryOpContext _localctx = new BinaryOpContext(_ctx, getState()); - enterRule(_localctx, 58, RULE_binaryOp); + enterRule(_localctx, 60, RULE_binaryOp); try { enterOuterAlt(_localctx, 1); { - setState(303); + setState(310); _errHandler.sync(this); switch (_input.LA(1)) { case FOR_BRACE: @@ -2527,34 +2607,34 @@ public final BinaryOpContext binaryOp() throws RecognitionException { case LBRACK: case LPAREN: { - setState(301); + setState(308); exprTerm(0); } break; case MINUS: case NOT: { - setState(302); + setState(309); unaryOp(); } break; default: throw new NoViableAltException(this); } - setState(305); + setState(312); binaryOperator(); - setState(308); + setState(315); _errHandler.sync(this); switch ( getInterpreter().adaptivePredict(_input,31,_ctx) ) { case 1: { - setState(306); + setState(313); exprTerm(0); } break; case 2: { - setState(307); + setState(314); operation(); } break; @@ -2604,9 +2684,9 @@ public T accept(ParseTreeVisitor visitor) { public final BinaryOperatorContext binaryOperator() throws RecognitionException { BinaryOperatorContext _localctx = new BinaryOperatorContext(_ctx, getState()); - enterRule(_localctx, 60, RULE_binaryOperator); + enterRule(_localctx, 62, RULE_binaryOperator); try { - setState(313); + setState(320); _errHandler.sync(this); switch (_input.LA(1)) { case EQ: @@ -2617,7 +2697,7 @@ public final BinaryOperatorContext binaryOperator() throws RecognitionException case GEQ: enterOuterAlt(_localctx, 1); { - setState(310); + setState(317); compareOperator(); } break; @@ -2628,7 +2708,7 @@ public final BinaryOperatorContext binaryOperator() throws RecognitionException case MOD: enterOuterAlt(_localctx, 2); { - setState(311); + setState(318); arithmeticOperator(); } break; @@ -2636,7 +2716,7 @@ public final BinaryOperatorContext binaryOperator() throws RecognitionException case OR: enterOuterAlt(_localctx, 3); { - setState(312); + setState(319); logicOperator(); } break; @@ -2684,12 +2764,12 @@ public T accept(ParseTreeVisitor visitor) { public final CompareOperatorContext compareOperator() throws RecognitionException { CompareOperatorContext _localctx = new CompareOperatorContext(_ctx, getState()); - enterRule(_localctx, 62, RULE_compareOperator); + enterRule(_localctx, 64, RULE_compareOperator); int _la; try { enterOuterAlt(_localctx, 1); { - setState(315); + setState(322); _la = _input.LA(1); if ( !(((_la) & ~0x3f) == 0 && ((1L << _la) & 155024621568L) != 0) ) { _errHandler.recoverInline(this); @@ -2740,12 +2820,12 @@ public T accept(ParseTreeVisitor visitor) { public final ArithmeticOperatorContext arithmeticOperator() throws RecognitionException { ArithmeticOperatorContext _localctx = new ArithmeticOperatorContext(_ctx, getState()); - enterRule(_localctx, 64, RULE_arithmeticOperator); + enterRule(_localctx, 66, RULE_arithmeticOperator); int _la; try { enterOuterAlt(_localctx, 1); { - setState(317); + setState(324); _la = _input.LA(1); if ( !(((_la) & ~0x3f) == 0 && ((1L << _la) & 1172559888384L) != 0) ) { _errHandler.recoverInline(this); @@ -2793,12 +2873,12 @@ public T accept(ParseTreeVisitor visitor) { public final LogicOperatorContext logicOperator() throws RecognitionException { LogicOperatorContext _localctx = new LogicOperatorContext(_ctx, getState()); - enterRule(_localctx, 66, RULE_logicOperator); + enterRule(_localctx, 68, RULE_logicOperator); int _la; try { enterOuterAlt(_localctx, 1); { - setState(319); + setState(326); _la = _input.LA(1); if ( !(_la==AND || _la==OR) ) { _errHandler.recoverInline(this); @@ -2895,49 +2975,49 @@ public T accept(ParseTreeVisitor visitor) { public final TemplateExprContext templateExpr() throws RecognitionException { TemplateExprContext _localctx = new TemplateExprContext(_ctx, getState()); - enterRule(_localctx, 68, RULE_templateExpr); + enterRule(_localctx, 70, RULE_templateExpr); int _la; try { - setState(343); + setState(350); _errHandler.sync(this); switch (_input.LA(1)) { case HEREDOC_START: _localctx = new HeredocContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(321); + setState(328); match(HEREDOC_START); - setState(322); + setState(329); match(Identifier); - setState(330); + setState(337); _errHandler.sync(this); _la = _input.LA(1); do { { { - setState(323); + setState(330); match(NEWLINE); - setState(327); + setState(334); _errHandler.sync(this); _la = _input.LA(1); while (_la==TEMPLATE_INTERPOLATION_START || _la==HTemplateLiteral) { { { - setState(324); + setState(331); heredocTemplatePart(); } } - setState(329); + setState(336); _errHandler.sync(this); _la = _input.LA(1); } } } - setState(332); + setState(339); _errHandler.sync(this); _la = _input.LA(1); } while ( _la==NEWLINE ); - setState(334); + setState(341); match(Identifier); } break; @@ -2945,23 +3025,23 @@ public final TemplateExprContext templateExpr() throws RecognitionException { _localctx = new QuotedTemplateContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(335); + setState(342); match(QUOTE); - setState(339); + setState(346); _errHandler.sync(this); _la = _input.LA(1); while (_la==TEMPLATE_INTERPOLATION_START || _la==TemplateStringLiteral) { { { - setState(336); + setState(343); quotedTemplatePart(); } } - setState(341); + setState(348); _errHandler.sync(this); _la = _input.LA(1); } - setState(342); + setState(349); match(QUOTE); } break; @@ -3009,22 +3089,22 @@ public T accept(ParseTreeVisitor visitor) { public final HeredocTemplatePartContext heredocTemplatePart() throws RecognitionException { HeredocTemplatePartContext _localctx = new HeredocTemplatePartContext(_ctx, getState()); - enterRule(_localctx, 70, RULE_heredocTemplatePart); + enterRule(_localctx, 72, RULE_heredocTemplatePart); try { - setState(347); + setState(354); _errHandler.sync(this); switch (_input.LA(1)) { case TEMPLATE_INTERPOLATION_START: enterOuterAlt(_localctx, 1); { - setState(345); + setState(352); templateInterpolation(); } break; case HTemplateLiteral: enterOuterAlt(_localctx, 2); { - setState(346); + setState(353); heredocLiteral(); } break; @@ -3067,11 +3147,11 @@ public T accept(ParseTreeVisitor visitor) { public final HeredocLiteralContext heredocLiteral() throws RecognitionException { HeredocLiteralContext _localctx = new HeredocLiteralContext(_ctx, getState()); - enterRule(_localctx, 72, RULE_heredocLiteral); + enterRule(_localctx, 74, RULE_heredocLiteral); try { enterOuterAlt(_localctx, 1); { - setState(349); + setState(356); match(HTemplateLiteral); } } @@ -3115,22 +3195,22 @@ public T accept(ParseTreeVisitor visitor) { public final QuotedTemplatePartContext quotedTemplatePart() throws RecognitionException { QuotedTemplatePartContext _localctx = new QuotedTemplatePartContext(_ctx, getState()); - enterRule(_localctx, 74, RULE_quotedTemplatePart); + enterRule(_localctx, 76, RULE_quotedTemplatePart); try { - setState(353); + setState(360); _errHandler.sync(this); switch (_input.LA(1)) { case TEMPLATE_INTERPOLATION_START: enterOuterAlt(_localctx, 1); { - setState(351); + setState(358); templateInterpolation(); } break; case TemplateStringLiteral: enterOuterAlt(_localctx, 2); { - setState(352); + setState(359); stringLiteral(); } break; @@ -3173,11 +3253,11 @@ public T accept(ParseTreeVisitor visitor) { public final StringLiteralContext stringLiteral() throws RecognitionException { StringLiteralContext _localctx = new StringLiteralContext(_ctx, getState()); - enterRule(_localctx, 76, RULE_stringLiteral); + enterRule(_localctx, 78, RULE_stringLiteral); try { enterOuterAlt(_localctx, 1); { - setState(355); + setState(362); match(TemplateStringLiteral); } } @@ -3220,15 +3300,15 @@ public T accept(ParseTreeVisitor visitor) { public final TemplateInterpolationContext templateInterpolation() throws RecognitionException { TemplateInterpolationContext _localctx = new TemplateInterpolationContext(_ctx, getState()); - enterRule(_localctx, 78, RULE_templateInterpolation); + enterRule(_localctx, 80, RULE_templateInterpolation); try { enterOuterAlt(_localctx, 1); { - setState(357); + setState(364); match(TEMPLATE_INTERPOLATION_START); - setState(358); + setState(365); expression(0); - setState(359); + setState(366); match(RBRACE); } } @@ -3263,17 +3343,19 @@ private boolean expression_sempred(ExpressionContext _localctx, int predIndex) { private boolean exprTerm_sempred(ExprTermContext _localctx, int predIndex) { switch (predIndex) { case 1: - return precpred(_ctx, 4); + return precpred(_ctx, 5); case 2: - return precpred(_ctx, 3); + return precpred(_ctx, 4); case 3: + return precpred(_ctx, 3); + case 4: return precpred(_ctx, 2); } return true; } public static final String _serializedATN = - "\u0004\u0001/\u016a\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ + "\u0004\u0001/\u0171\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ "\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b\u0007\u000b\u0002"+ @@ -3284,225 +3366,229 @@ private boolean exprTerm_sempred(ExprTermContext _localctx, int predIndex) { "\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002\u001b\u0007\u001b"+ "\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002\u001e\u0007\u001e"+ "\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007!\u0002\"\u0007\"\u0002"+ - "#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007&\u0002\'\u0007\'\u0001"+ - "\u0000\u0001\u0000\u0001\u0001\u0005\u0001T\b\u0001\n\u0001\f\u0001W\t"+ - "\u0001\u0001\u0002\u0001\u0002\u0003\u0002[\b\u0002\u0001\u0003\u0001"+ - "\u0003\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004\u0005\u0004c\b"+ - "\u0004\n\u0004\f\u0004f\t\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001"+ - "\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0003\u0005o\b\u0005\u0001"+ - "\u0006\u0001\u0006\u0001\u0006\u0003\u0006t\b\u0006\u0001\u0006\u0001"+ - "\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0005\u0006|\b"+ - "\u0006\n\u0006\f\u0006\u007f\t\u0006\u0001\u0007\u0001\u0007\u0001\u0007"+ - "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+ - "\u0001\u0007\u0001\u0007\u0003\u0007\u008c\b\u0007\u0001\u0007\u0001\u0007"+ - "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0005\u0007\u0094\b\u0007"+ - "\n\u0007\f\u0007\u0097\t\u0007\u0001\b\u0001\b\u0001\b\u0001\b\u0001\t"+ - "\u0001\t\u0001\n\u0001\n\u0003\n\u00a1\b\n\u0001\u000b\u0001\u000b\u0001"+ - "\u000b\u0001\u000b\u0005\u000b\u00a7\b\u000b\n\u000b\f\u000b\u00aa\t\u000b"+ - "\u0001\u000b\u0003\u000b\u00ad\b\u000b\u0003\u000b\u00af\b\u000b\u0001"+ - "\u000b\u0001\u000b\u0001\f\u0001\f\u0005\f\u00b5\b\f\n\f\f\f\u00b8\t\f"+ - "\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0005"+ - "\r\u00c2\b\r\n\r\f\r\u00c5\t\r\u0001\r\u0001\r\u0003\r\u00c9\b\r\u0001"+ - "\r\u0001\r\u0001\r\u0003\r\u00ce\b\r\u0001\u000e\u0001\u000e\u0003\u000e"+ - "\u00d2\b\u000e\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f"+ - "\u0003\u000f\u00d9\b\u000f\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010"+ - "\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0003\u0010"+ - "\u00e4\b\u0010\u0001\u0010\u0003\u0010\u00e7\b\u0010\u0001\u0010\u0001"+ - "\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0003\u0011\u00ee\b\u0011\u0001"+ - "\u0011\u0001\u0011\u0001\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+ - "\u0013\u0001\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0003\u0014\u00fb"+ - "\b\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0015\u0005"+ - "\u0015\u0102\b\u0015\n\u0015\f\u0015\u0105\t\u0015\u0001\u0015\u0003\u0015"+ - "\u0108\b\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0017"+ - "\u0001\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0003\u0018\u0113\b\u0018"+ - "\u0001\u0019\u0001\u0019\u0001\u0019\u0005\u0019\u0118\b\u0019\n\u0019"+ - "\f\u0019\u011b\t\u0019\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a"+ - "\u0001\u001a\u0005\u001a\u0122\b\u001a\n\u001a\f\u001a\u0125\t\u001a\u0001"+ - "\u001b\u0001\u001b\u0003\u001b\u0129\b\u001b\u0001\u001c\u0001\u001c\u0001"+ - "\u001c\u0001\u001d\u0001\u001d\u0003\u001d\u0130\b\u001d\u0001\u001d\u0001"+ - "\u001d\u0001\u001d\u0003\u001d\u0135\b\u001d\u0001\u001e\u0001\u001e\u0001"+ - "\u001e\u0003\u001e\u013a\b\u001e\u0001\u001f\u0001\u001f\u0001 \u0001"+ - " \u0001!\u0001!\u0001\"\u0001\"\u0001\"\u0001\"\u0005\"\u0146\b\"\n\""+ - "\f\"\u0149\t\"\u0004\"\u014b\b\"\u000b\"\f\"\u014c\u0001\"\u0001\"\u0001"+ - "\"\u0005\"\u0152\b\"\n\"\f\"\u0155\t\"\u0001\"\u0003\"\u0158\b\"\u0001"+ - "#\u0001#\u0003#\u015c\b#\u0001$\u0001$\u0001%\u0001%\u0003%\u0162\b%\u0001"+ - "&\u0001&\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0000\u0002\f\u000e("+ - "\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012\u0014\u0016\u0018\u001a"+ - "\u001c\u001e \"$&(*,.02468:<>@BDFHJLN\u0000\u0007\u0002\u0000\r\u000e"+ - "\u0010\u0010\u0002\u0000\u0007\u0007\u0016\u0016\u0002\u0000\'\'))\u0002"+ - "\u0000\u0019\u0019!!\u0004\u0000\u0014\u0015\u001b\u001c\"\"%%\u0005\u0000"+ - "\u0012\u0012\u0019\u0019 $$((\u0002\u0000\u0013\u0013\u001a\u001a\u0171"+ - "\u0000P\u0001\u0000\u0000\u0000\u0002U\u0001\u0000\u0000\u0000\u0004Z"+ - "\u0001\u0000\u0000\u0000\u0006\\\u0001\u0000\u0000\u0000\b`\u0001\u0000"+ - "\u0000\u0000\nn\u0001\u0000\u0000\u0000\fs\u0001\u0000\u0000\u0000\u000e"+ - "\u008b\u0001\u0000\u0000\u0000\u0010\u0098\u0001\u0000\u0000\u0000\u0012"+ - "\u009c\u0001\u0000\u0000\u0000\u0014\u00a0\u0001\u0000\u0000\u0000\u0016"+ - "\u00a2\u0001\u0000\u0000\u0000\u0018\u00b2\u0001\u0000\u0000\u0000\u001a"+ - "\u00c8\u0001\u0000\u0000\u0000\u001c\u00d1\u0001\u0000\u0000\u0000\u001e"+ - "\u00d3\u0001\u0000\u0000\u0000 \u00dc\u0001\u0000\u0000\u0000\"\u00ea"+ - "\u0001\u0000\u0000\u0000$\u00f2\u0001\u0000\u0000\u0000&\u00f5\u0001\u0000"+ - "\u0000\u0000(\u00f7\u0001\u0000\u0000\u0000*\u00fe\u0001\u0000\u0000\u0000"+ - ",\u0109\u0001\u0000\u0000\u0000.\u010d\u0001\u0000\u0000\u00000\u0112"+ - "\u0001\u0000\u0000\u00002\u0114\u0001\u0000\u0000\u00004\u011c\u0001\u0000"+ - "\u0000\u00006\u0128\u0001\u0000\u0000\u00008\u012a\u0001\u0000\u0000\u0000"+ - ":\u012f\u0001\u0000\u0000\u0000<\u0139\u0001\u0000\u0000\u0000>\u013b"+ - "\u0001\u0000\u0000\u0000@\u013d\u0001\u0000\u0000\u0000B\u013f\u0001\u0000"+ - "\u0000\u0000D\u0157\u0001\u0000\u0000\u0000F\u015b\u0001\u0000\u0000\u0000"+ - "H\u015d\u0001\u0000\u0000\u0000J\u0161\u0001\u0000\u0000\u0000L\u0163"+ - "\u0001\u0000\u0000\u0000N\u0165\u0001\u0000\u0000\u0000PQ\u0003\u0002"+ - "\u0001\u0000Q\u0001\u0001\u0000\u0000\u0000RT\u0003\u0004\u0002\u0000"+ - "SR\u0001\u0000\u0000\u0000TW\u0001\u0000\u0000\u0000US\u0001\u0000\u0000"+ - "\u0000UV\u0001\u0000\u0000\u0000V\u0003\u0001\u0000\u0000\u0000WU\u0001"+ - "\u0000\u0000\u0000X[\u0003\u0006\u0003\u0000Y[\u0003\b\u0004\u0000ZX\u0001"+ - "\u0000\u0000\u0000ZY\u0001\u0000\u0000\u0000[\u0005\u0001\u0000\u0000"+ - "\u0000\\]\u0005\b\u0000\u0000]^\u0005\u0007\u0000\u0000^_\u0003\f\u0006"+ - "\u0000_\u0007\u0001\u0000\u0000\u0000`d\u0005\b\u0000\u0000ac\u0003\n"+ - "\u0005\u0000ba\u0001\u0000\u0000\u0000cf\u0001\u0000\u0000\u0000db\u0001"+ - "\u0000\u0000\u0000de\u0001\u0000\u0000\u0000eg\u0001\u0000\u0000\u0000"+ - "fd\u0001\u0000\u0000\u0000gh\u0003\u0010\b\u0000h\t\u0001\u0000\u0000"+ - "\u0000ij\u0005\u000f\u0000\u0000jk\u0003L&\u0000kl\u0005\u000f\u0000\u0000"+ - "lo\u0001\u0000\u0000\u0000mo\u0005\b\u0000\u0000ni\u0001\u0000\u0000\u0000"+ - "nm\u0001\u0000\u0000\u0000o\u000b\u0001\u0000\u0000\u0000pq\u0006\u0006"+ - "\uffff\uffff\u0000qt\u0003\u000e\u0007\u0000rt\u00036\u001b\u0000sp\u0001"+ - "\u0000\u0000\u0000sr\u0001\u0000\u0000\u0000t}\u0001\u0000\u0000\u0000"+ - "uv\n\u0001\u0000\u0000vw\u0005\u001d\u0000\u0000wx\u0003\f\u0006\u0000"+ - "xy\u0005\u0016\u0000\u0000yz\u0003\f\u0006\u0002z|\u0001\u0000\u0000\u0000"+ - "{u\u0001\u0000\u0000\u0000|\u007f\u0001\u0000\u0000\u0000}{\u0001\u0000"+ - "\u0000\u0000}~\u0001\u0000\u0000\u0000~\r\u0001\u0000\u0000\u0000\u007f"+ - "}\u0001\u0000\u0000\u0000\u0080\u0081\u0006\u0007\uffff\uffff\u0000\u0081"+ - "\u008c\u0003D\"\u0000\u0082\u008c\u0003\u0012\t\u0000\u0083\u008c\u0003"+ - "\u001c\u000e\u0000\u0084\u008c\u0003\u0014\n\u0000\u0085\u008c\u0003&"+ - "\u0013\u0000\u0086\u008c\u0003(\u0014\u0000\u0087\u0088\u0005\u0018\u0000"+ - "\u0000\u0088\u0089\u0003\f\u0006\u0000\u0089\u008a\u0005\u001f\u0000\u0000"+ - "\u008a\u008c\u0001\u0000\u0000\u0000\u008b\u0080\u0001\u0000\u0000\u0000"+ - "\u008b\u0082\u0001\u0000\u0000\u0000\u008b\u0083\u0001\u0000\u0000\u0000"+ - "\u008b\u0084\u0001\u0000\u0000\u0000\u008b\u0085\u0001\u0000\u0000\u0000"+ - "\u008b\u0086\u0001\u0000\u0000\u0000\u008b\u0087\u0001\u0000\u0000\u0000"+ - "\u008c\u0095\u0001\u0000\u0000\u0000\u008d\u008e\n\u0004\u0000\u0000\u008e"+ - "\u0094\u0003,\u0016\u0000\u008f\u0090\n\u0003\u0000\u0000\u0090\u0094"+ - "\u0003.\u0017\u0000\u0091\u0092\n\u0002\u0000\u0000\u0092\u0094\u0003"+ - "0\u0018\u0000\u0093\u008d\u0001\u0000\u0000\u0000\u0093\u008f\u0001\u0000"+ - "\u0000\u0000\u0093\u0091\u0001\u0000\u0000\u0000\u0094\u0097\u0001\u0000"+ - "\u0000\u0000\u0095\u0093\u0001\u0000\u0000\u0000\u0095\u0096\u0001\u0000"+ - "\u0000\u0000\u0096\u000f\u0001\u0000\u0000\u0000\u0097\u0095\u0001\u0000"+ - "\u0000\u0000\u0098\u0099\u0005\u0005\u0000\u0000\u0099\u009a\u0003\u0002"+ - "\u0001\u0000\u009a\u009b\u0005\u0006\u0000\u0000\u009b\u0011\u0001\u0000"+ - "\u0000\u0000\u009c\u009d\u0007\u0000\u0000\u0000\u009d\u0013\u0001\u0000"+ - "\u0000\u0000\u009e\u00a1\u0003\u0016\u000b\u0000\u009f\u00a1\u0003\u0018"+ - "\f\u0000\u00a0\u009e\u0001\u0000\u0000\u0000\u00a0\u009f\u0001\u0000\u0000"+ - "\u0000\u00a1\u0015\u0001\u0000\u0000\u0000\u00a2\u00ae\u0005\u0017\u0000"+ - "\u0000\u00a3\u00a8\u0003\f\u0006\u0000\u00a4\u00a5\u0005\'\u0000\u0000"+ - "\u00a5\u00a7\u0003\f\u0006\u0000\u00a6\u00a4\u0001\u0000\u0000\u0000\u00a7"+ - "\u00aa\u0001\u0000\u0000\u0000\u00a8\u00a6\u0001\u0000\u0000\u0000\u00a8"+ - "\u00a9\u0001\u0000\u0000\u0000\u00a9\u00ac\u0001\u0000\u0000\u0000\u00aa"+ - "\u00a8\u0001\u0000\u0000\u0000\u00ab\u00ad\u0005\'\u0000\u0000\u00ac\u00ab"+ - "\u0001\u0000\u0000\u0000\u00ac\u00ad\u0001\u0000\u0000\u0000\u00ad\u00af"+ - "\u0001\u0000\u0000\u0000\u00ae\u00a3\u0001\u0000\u0000\u0000\u00ae\u00af"+ - "\u0001\u0000\u0000\u0000\u00af\u00b0\u0001\u0000\u0000\u0000\u00b0\u00b1"+ - "\u0005\u001e\u0000\u0000\u00b1\u0017\u0001\u0000\u0000\u0000\u00b2\u00b6"+ - "\u0005\u0005\u0000\u0000\u00b3\u00b5\u0003\u001a\r\u0000\u00b4\u00b3\u0001"+ - "\u0000\u0000\u0000\u00b5\u00b8\u0001\u0000\u0000\u0000\u00b6\u00b4\u0001"+ - "\u0000\u0000\u0000\u00b6\u00b7\u0001\u0000\u0000\u0000\u00b7\u00b9\u0001"+ - "\u0000\u0000\u0000\u00b8\u00b6\u0001\u0000\u0000\u0000\u00b9\u00ba\u0005"+ - "\u0006\u0000\u0000\u00ba\u0019\u0001\u0000\u0000\u0000\u00bb\u00c9\u0005"+ - "\b\u0000\u0000\u00bc\u00bd\u0005\u0018\u0000\u0000\u00bd\u00be\u0005\b"+ - "\u0000\u0000\u00be\u00c9\u0005\u001f\u0000\u0000\u00bf\u00c3\u0005\u000f"+ - "\u0000\u0000\u00c0\u00c2\u0003J%\u0000\u00c1\u00c0\u0001\u0000\u0000\u0000"+ - "\u00c2\u00c5\u0001\u0000\u0000\u0000\u00c3\u00c1\u0001\u0000\u0000\u0000"+ - "\u00c3\u00c4\u0001\u0000\u0000\u0000\u00c4\u00c6\u0001\u0000\u0000\u0000"+ - "\u00c5\u00c3\u0001\u0000\u0000\u0000\u00c6\u00c9\u0005\u000f\u0000\u0000"+ - "\u00c7\u00c9\u0003\f\u0006\u0000\u00c8\u00bb\u0001\u0000\u0000\u0000\u00c8"+ - "\u00bc\u0001\u0000\u0000\u0000\u00c8\u00bf\u0001\u0000\u0000\u0000\u00c8"+ - "\u00c7\u0001\u0000\u0000\u0000\u00c9\u00ca\u0001\u0000\u0000\u0000\u00ca"+ - "\u00cb\u0007\u0001\u0000\u0000\u00cb\u00cd\u0003\f\u0006\u0000\u00cc\u00ce"+ - "\u0005\'\u0000\u0000\u00cd\u00cc\u0001\u0000\u0000\u0000\u00cd\u00ce\u0001"+ - "\u0000\u0000\u0000\u00ce\u001b\u0001\u0000\u0000\u0000\u00cf\u00d2\u0003"+ - "\u001e\u000f\u0000\u00d0\u00d2\u0003 \u0010\u0000\u00d1\u00cf\u0001\u0000"+ - "\u0000\u0000\u00d1\u00d0\u0001\u0000\u0000\u0000\u00d2\u001d\u0001\u0000"+ - "\u0000\u0000\u00d3\u00d4\u0005\u0002\u0000\u0000\u00d4\u00d5\u0003\"\u0011"+ - "\u0000\u00d5\u00d6\u0005\u0016\u0000\u0000\u00d6\u00d8\u0003\f\u0006\u0000"+ - "\u00d7\u00d9\u0003$\u0012\u0000\u00d8\u00d7\u0001\u0000\u0000\u0000\u00d8"+ - "\u00d9\u0001\u0000\u0000\u0000\u00d9\u00da\u0001\u0000\u0000\u0000\u00da"+ - "\u00db\u0005\u001e\u0000\u0000\u00db\u001f\u0001\u0000\u0000\u0000\u00dc"+ - "\u00dd\u0005\u0001\u0000\u0000\u00dd\u00de\u0003\"\u0011\u0000\u00de\u00df"+ - "\u0005\u0016\u0000\u0000\u00df\u00e0\u0003\f\u0006\u0000\u00e0\u00e1\u0005"+ - "&\u0000\u0000\u00e1\u00e3\u0003\f\u0006\u0000\u00e2\u00e4\u0005)\u0000"+ - "\u0000\u00e3\u00e2\u0001\u0000\u0000\u0000\u00e3\u00e4\u0001\u0000\u0000"+ - "\u0000\u00e4\u00e6\u0001\u0000\u0000\u0000\u00e5\u00e7\u0003$\u0012\u0000"+ - "\u00e6\u00e5\u0001\u0000\u0000\u0000\u00e6\u00e7\u0001\u0000\u0000\u0000"+ - "\u00e7\u00e8\u0001\u0000\u0000\u0000\u00e8\u00e9\u0005\u0006\u0000\u0000"+ - "\u00e9!\u0001\u0000\u0000\u0000\u00ea\u00ed\u0005\b\u0000\u0000\u00eb"+ - "\u00ec\u0005\'\u0000\u0000\u00ec\u00ee\u0005\b\u0000\u0000\u00ed\u00eb"+ - "\u0001\u0000\u0000\u0000\u00ed\u00ee\u0001\u0000\u0000\u0000\u00ee\u00ef"+ - "\u0001\u0000\u0000\u0000\u00ef\u00f0\u0005\u0004\u0000\u0000\u00f0\u00f1"+ - "\u0003\f\u0006\u0000\u00f1#\u0001\u0000\u0000\u0000\u00f2\u00f3\u0005"+ - "\u0003\u0000\u0000\u00f3\u00f4\u0003\f\u0006\u0000\u00f4%\u0001\u0000"+ - "\u0000\u0000\u00f5\u00f6\u0005\b\u0000\u0000\u00f6\'\u0001\u0000\u0000"+ - "\u0000\u00f7\u00f8\u0005\b\u0000\u0000\u00f8\u00fa\u0005\u0018\u0000\u0000"+ - "\u00f9\u00fb\u0003*\u0015\u0000\u00fa\u00f9\u0001\u0000\u0000\u0000\u00fa"+ - "\u00fb\u0001\u0000\u0000\u0000\u00fb\u00fc\u0001\u0000\u0000\u0000\u00fc"+ - "\u00fd\u0005\u001f\u0000\u0000\u00fd)\u0001\u0000\u0000\u0000\u00fe\u0103"+ - "\u0003\f\u0006\u0000\u00ff\u0100\u0005\'\u0000\u0000\u0100\u0102\u0003"+ - "\f\u0006\u0000\u0101\u00ff\u0001\u0000\u0000\u0000\u0102\u0105\u0001\u0000"+ - "\u0000\u0000\u0103\u0101\u0001\u0000\u0000\u0000\u0103\u0104\u0001\u0000"+ - "\u0000\u0000\u0104\u0107\u0001\u0000\u0000\u0000\u0105\u0103\u0001\u0000"+ - "\u0000\u0000\u0106\u0108\u0007\u0002\u0000\u0000\u0107\u0106\u0001\u0000"+ - "\u0000\u0000\u0107\u0108\u0001\u0000\u0000\u0000\u0108+\u0001\u0000\u0000"+ - "\u0000\u0109\u010a\u0005\u0017\u0000\u0000\u010a\u010b\u0003\f\u0006\u0000"+ - "\u010b\u010c\u0005\u001e\u0000\u0000\u010c-\u0001\u0000\u0000\u0000\u010d"+ - "\u010e\u0005#\u0000\u0000\u010e\u010f\u0005\b\u0000\u0000\u010f/\u0001"+ - "\u0000\u0000\u0000\u0110\u0113\u00032\u0019\u0000\u0111\u0113\u00034\u001a"+ - "\u0000\u0112\u0110\u0001\u0000\u0000\u0000\u0112\u0111\u0001\u0000\u0000"+ - "\u0000\u01131\u0001\u0000\u0000\u0000\u0114\u0115\u0005#\u0000\u0000\u0115"+ - "\u0119\u0005 \u0000\u0000\u0116\u0118\u0003.\u0017\u0000\u0117\u0116\u0001"+ - "\u0000\u0000\u0000\u0118\u011b\u0001\u0000\u0000\u0000\u0119\u0117\u0001"+ - "\u0000\u0000\u0000\u0119\u011a\u0001\u0000\u0000\u0000\u011a3\u0001\u0000"+ - "\u0000\u0000\u011b\u0119\u0001\u0000\u0000\u0000\u011c\u011d\u0005\u0017"+ - "\u0000\u0000\u011d\u011e\u0005 \u0000\u0000\u011e\u0123\u0005\u001e\u0000"+ - "\u0000\u011f\u0122\u0003.\u0017\u0000\u0120\u0122\u0003,\u0016\u0000\u0121"+ - "\u011f\u0001\u0000\u0000\u0000\u0121\u0120\u0001\u0000\u0000\u0000\u0122"+ - "\u0125\u0001\u0000\u0000\u0000\u0123\u0121\u0001\u0000\u0000\u0000\u0123"+ - "\u0124\u0001\u0000\u0000\u0000\u01245\u0001\u0000\u0000\u0000\u0125\u0123"+ - "\u0001\u0000\u0000\u0000\u0126\u0129\u00038\u001c\u0000\u0127\u0129\u0003"+ - ":\u001d\u0000\u0128\u0126\u0001\u0000\u0000\u0000\u0128\u0127\u0001\u0000"+ - "\u0000\u0000\u01297\u0001\u0000\u0000\u0000\u012a\u012b\u0007\u0003\u0000"+ - "\u0000\u012b\u012c\u0003\u000e\u0007\u0000\u012c9\u0001\u0000\u0000\u0000"+ - "\u012d\u0130\u0003\u000e\u0007\u0000\u012e\u0130\u00038\u001c\u0000\u012f"+ - "\u012d\u0001\u0000\u0000\u0000\u012f\u012e\u0001\u0000\u0000\u0000\u0130"+ - "\u0131\u0001\u0000\u0000\u0000\u0131\u0134\u0003<\u001e\u0000\u0132\u0135"+ - "\u0003\u000e\u0007\u0000\u0133\u0135\u00036\u001b\u0000\u0134\u0132\u0001"+ - "\u0000\u0000\u0000\u0134\u0133\u0001\u0000\u0000\u0000\u0135;\u0001\u0000"+ - "\u0000\u0000\u0136\u013a\u0003>\u001f\u0000\u0137\u013a\u0003@ \u0000"+ - "\u0138\u013a\u0003B!\u0000\u0139\u0136\u0001\u0000\u0000\u0000\u0139\u0137"+ - "\u0001\u0000\u0000\u0000\u0139\u0138\u0001\u0000\u0000\u0000\u013a=\u0001"+ - "\u0000\u0000\u0000\u013b\u013c\u0007\u0004\u0000\u0000\u013c?\u0001\u0000"+ - "\u0000\u0000\u013d\u013e\u0007\u0005\u0000\u0000\u013eA\u0001\u0000\u0000"+ - "\u0000\u013f\u0140\u0007\u0006\u0000\u0000\u0140C\u0001\u0000\u0000\u0000"+ - "\u0141\u0142\u0005\u0011\u0000\u0000\u0142\u014a\u0005\b\u0000\u0000\u0143"+ - "\u0147\u0005\f\u0000\u0000\u0144\u0146\u0003F#\u0000\u0145\u0144\u0001"+ - "\u0000\u0000\u0000\u0146\u0149\u0001\u0000\u0000\u0000\u0147\u0145\u0001"+ - "\u0000\u0000\u0000\u0147\u0148\u0001\u0000\u0000\u0000\u0148\u014b\u0001"+ - "\u0000\u0000\u0000\u0149\u0147\u0001\u0000\u0000\u0000\u014a\u0143\u0001"+ - "\u0000\u0000\u0000\u014b\u014c\u0001\u0000\u0000\u0000\u014c\u014a\u0001"+ - "\u0000\u0000\u0000\u014c\u014d\u0001\u0000\u0000\u0000\u014d\u014e\u0001"+ - "\u0000\u0000\u0000\u014e\u0158\u0005\b\u0000\u0000\u014f\u0153\u0005\u000f"+ - "\u0000\u0000\u0150\u0152\u0003J%\u0000\u0151\u0150\u0001\u0000\u0000\u0000"+ - "\u0152\u0155\u0001\u0000\u0000\u0000\u0153\u0151\u0001\u0000\u0000\u0000"+ - "\u0153\u0154\u0001\u0000\u0000\u0000\u0154\u0156\u0001\u0000\u0000\u0000"+ - "\u0155\u0153\u0001\u0000\u0000\u0000\u0156\u0158\u0005\u000f\u0000\u0000"+ - "\u0157\u0141\u0001\u0000\u0000\u0000\u0157\u014f\u0001\u0000\u0000\u0000"+ - "\u0158E\u0001\u0000\u0000\u0000\u0159\u015c\u0003N\'\u0000\u015a\u015c"+ - "\u0003H$\u0000\u015b\u0159\u0001\u0000\u0000\u0000\u015b\u015a\u0001\u0000"+ - "\u0000\u0000\u015cG\u0001\u0000\u0000\u0000\u015d\u015e\u0005.\u0000\u0000"+ - "\u015eI\u0001\u0000\u0000\u0000\u015f\u0162\u0003N\'\u0000\u0160\u0162"+ - "\u0003L&\u0000\u0161\u015f\u0001\u0000\u0000\u0000\u0161\u0160\u0001\u0000"+ - "\u0000\u0000\u0162K\u0001\u0000\u0000\u0000\u0163\u0164\u0005,\u0000\u0000"+ - "\u0164M\u0001\u0000\u0000\u0000\u0165\u0166\u0005+\u0000\u0000\u0166\u0167"+ - "\u0003\f\u0006\u0000\u0167\u0168\u0005\u0006\u0000\u0000\u0168O\u0001"+ - "\u0000\u0000\u0000\'UZdns}\u008b\u0093\u0095\u00a0\u00a8\u00ac\u00ae\u00b6"+ - "\u00c3\u00c8\u00cd\u00d1\u00d8\u00e3\u00e6\u00ed\u00fa\u0103\u0107\u0112"+ - "\u0119\u0121\u0123\u0128\u012f\u0134\u0139\u0147\u014c\u0153\u0157\u015b"+ - "\u0161"; + "#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007&\u0002\'\u0007\'\u0002"+ + "(\u0007(\u0001\u0000\u0001\u0000\u0001\u0001\u0005\u0001V\b\u0001\n\u0001"+ + "\f\u0001Y\t\u0001\u0001\u0002\u0001\u0002\u0003\u0002]\b\u0002\u0001\u0003"+ + "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004\u0005\u0004"+ + "e\b\u0004\n\u0004\f\u0004h\t\u0004\u0001\u0004\u0001\u0004\u0001\u0005"+ + "\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0003\u0005q\b\u0005"+ + "\u0001\u0006\u0001\u0006\u0001\u0006\u0003\u0006v\b\u0006\u0001\u0006"+ + "\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006\u0005\u0006"+ + "~\b\u0006\n\u0006\f\u0006\u0081\t\u0006\u0001\u0007\u0001\u0007\u0001"+ + "\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001"+ + "\u0007\u0001\u0007\u0001\u0007\u0003\u0007\u008e\b\u0007\u0001\u0007\u0001"+ + "\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001"+ + "\u0007\u0005\u0007\u0098\b\u0007\n\u0007\f\u0007\u009b\t\u0007\u0001\b"+ + "\u0001\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001\n\u0001\n\u0003\n\u00a5"+ + "\b\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b\u0005\u000b\u00ab"+ + "\b\u000b\n\u000b\f\u000b\u00ae\t\u000b\u0001\u000b\u0003\u000b\u00b1\b"+ + "\u000b\u0003\u000b\u00b3\b\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001"+ + "\f\u0005\f\u00b9\b\f\n\f\f\f\u00bc\t\f\u0001\f\u0001\f\u0001\r\u0001\r"+ + "\u0001\r\u0001\r\u0001\r\u0001\r\u0005\r\u00c6\b\r\n\r\f\r\u00c9\t\r\u0001"+ + "\r\u0001\r\u0003\r\u00cd\b\r\u0001\r\u0001\r\u0001\r\u0003\r\u00d2\b\r"+ + "\u0001\u000e\u0001\u000e\u0003\u000e\u00d6\b\u000e\u0001\u000f\u0001\u000f"+ + "\u0001\u000f\u0001\u000f\u0001\u000f\u0003\u000f\u00dd\b\u000f\u0001\u000f"+ + "\u0001\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010"+ + "\u0001\u0010\u0001\u0010\u0003\u0010\u00e8\b\u0010\u0001\u0010\u0003\u0010"+ + "\u00eb\b\u0010\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0011"+ + "\u0003\u0011\u00f2\b\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0012"+ + "\u0001\u0012\u0001\u0012\u0001\u0013\u0001\u0013\u0001\u0014\u0001\u0014"+ + "\u0001\u0014\u0003\u0014\u00ff\b\u0014\u0001\u0014\u0001\u0014\u0001\u0015"+ + "\u0001\u0015\u0001\u0015\u0005\u0015\u0106\b\u0015\n\u0015\f\u0015\u0109"+ + "\t\u0015\u0001\u0015\u0003\u0015\u010c\b\u0015\u0001\u0016\u0001\u0016"+ + "\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0018"+ + "\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0003\u0019\u011a\b\u0019"+ + "\u0001\u001a\u0001\u001a\u0001\u001a\u0005\u001a\u011f\b\u001a\n\u001a"+ + "\f\u001a\u0122\t\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b"+ + "\u0001\u001b\u0005\u001b\u0129\b\u001b\n\u001b\f\u001b\u012c\t\u001b\u0001"+ + "\u001c\u0001\u001c\u0003\u001c\u0130\b\u001c\u0001\u001d\u0001\u001d\u0001"+ + "\u001d\u0001\u001e\u0001\u001e\u0003\u001e\u0137\b\u001e\u0001\u001e\u0001"+ + "\u001e\u0001\u001e\u0003\u001e\u013c\b\u001e\u0001\u001f\u0001\u001f\u0001"+ + "\u001f\u0003\u001f\u0141\b\u001f\u0001 \u0001 \u0001!\u0001!\u0001\"\u0001"+ + "\"\u0001#\u0001#\u0001#\u0001#\u0005#\u014d\b#\n#\f#\u0150\t#\u0004#\u0152"+ + "\b#\u000b#\f#\u0153\u0001#\u0001#\u0001#\u0005#\u0159\b#\n#\f#\u015c\t"+ + "#\u0001#\u0003#\u015f\b#\u0001$\u0001$\u0003$\u0163\b$\u0001%\u0001%\u0001"+ + "&\u0001&\u0003&\u0169\b&\u0001\'\u0001\'\u0001(\u0001(\u0001(\u0001(\u0001"+ + "(\u0000\u0002\f\u000e)\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010\u0012"+ + "\u0014\u0016\u0018\u001a\u001c\u001e \"$&(*,.02468:<>@BDFHJLNP\u0000\u0007"+ + "\u0002\u0000\r\u000e\u0010\u0010\u0002\u0000\u0007\u0007\u0016\u0016\u0002"+ + "\u0000\'\'))\u0002\u0000\u0019\u0019!!\u0004\u0000\u0014\u0015\u001b\u001c"+ + "\"\"%%\u0005\u0000\u0012\u0012\u0019\u0019 $$((\u0002\u0000\u0013\u0013"+ + "\u001a\u001a\u0178\u0000R\u0001\u0000\u0000\u0000\u0002W\u0001\u0000\u0000"+ + "\u0000\u0004\\\u0001\u0000\u0000\u0000\u0006^\u0001\u0000\u0000\u0000"+ + "\bb\u0001\u0000\u0000\u0000\np\u0001\u0000\u0000\u0000\fu\u0001\u0000"+ + "\u0000\u0000\u000e\u008d\u0001\u0000\u0000\u0000\u0010\u009c\u0001\u0000"+ + "\u0000\u0000\u0012\u00a0\u0001\u0000\u0000\u0000\u0014\u00a4\u0001\u0000"+ + "\u0000\u0000\u0016\u00a6\u0001\u0000\u0000\u0000\u0018\u00b6\u0001\u0000"+ + "\u0000\u0000\u001a\u00cc\u0001\u0000\u0000\u0000\u001c\u00d5\u0001\u0000"+ + "\u0000\u0000\u001e\u00d7\u0001\u0000\u0000\u0000 \u00e0\u0001\u0000\u0000"+ + "\u0000\"\u00ee\u0001\u0000\u0000\u0000$\u00f6\u0001\u0000\u0000\u0000"+ + "&\u00f9\u0001\u0000\u0000\u0000(\u00fb\u0001\u0000\u0000\u0000*\u0102"+ + "\u0001\u0000\u0000\u0000,\u010d\u0001\u0000\u0000\u0000.\u0111\u0001\u0000"+ + "\u0000\u00000\u0114\u0001\u0000\u0000\u00002\u0119\u0001\u0000\u0000\u0000"+ + "4\u011b\u0001\u0000\u0000\u00006\u0123\u0001\u0000\u0000\u00008\u012f"+ + "\u0001\u0000\u0000\u0000:\u0131\u0001\u0000\u0000\u0000<\u0136\u0001\u0000"+ + "\u0000\u0000>\u0140\u0001\u0000\u0000\u0000@\u0142\u0001\u0000\u0000\u0000"+ + "B\u0144\u0001\u0000\u0000\u0000D\u0146\u0001\u0000\u0000\u0000F\u015e"+ + "\u0001\u0000\u0000\u0000H\u0162\u0001\u0000\u0000\u0000J\u0164\u0001\u0000"+ + "\u0000\u0000L\u0168\u0001\u0000\u0000\u0000N\u016a\u0001\u0000\u0000\u0000"+ + "P\u016c\u0001\u0000\u0000\u0000RS\u0003\u0002\u0001\u0000S\u0001\u0001"+ + "\u0000\u0000\u0000TV\u0003\u0004\u0002\u0000UT\u0001\u0000\u0000\u0000"+ + "VY\u0001\u0000\u0000\u0000WU\u0001\u0000\u0000\u0000WX\u0001\u0000\u0000"+ + "\u0000X\u0003\u0001\u0000\u0000\u0000YW\u0001\u0000\u0000\u0000Z]\u0003"+ + "\u0006\u0003\u0000[]\u0003\b\u0004\u0000\\Z\u0001\u0000\u0000\u0000\\"+ + "[\u0001\u0000\u0000\u0000]\u0005\u0001\u0000\u0000\u0000^_\u0005\b\u0000"+ + "\u0000_`\u0005\u0007\u0000\u0000`a\u0003\f\u0006\u0000a\u0007\u0001\u0000"+ + "\u0000\u0000bf\u0005\b\u0000\u0000ce\u0003\n\u0005\u0000dc\u0001\u0000"+ + "\u0000\u0000eh\u0001\u0000\u0000\u0000fd\u0001\u0000\u0000\u0000fg\u0001"+ + "\u0000\u0000\u0000gi\u0001\u0000\u0000\u0000hf\u0001\u0000\u0000\u0000"+ + "ij\u0003\u0010\b\u0000j\t\u0001\u0000\u0000\u0000kl\u0005\u000f\u0000"+ + "\u0000lm\u0003N\'\u0000mn\u0005\u000f\u0000\u0000nq\u0001\u0000\u0000"+ + "\u0000oq\u0005\b\u0000\u0000pk\u0001\u0000\u0000\u0000po\u0001\u0000\u0000"+ + "\u0000q\u000b\u0001\u0000\u0000\u0000rs\u0006\u0006\uffff\uffff\u0000"+ + "sv\u0003\u000e\u0007\u0000tv\u00038\u001c\u0000ur\u0001\u0000\u0000\u0000"+ + "ut\u0001\u0000\u0000\u0000v\u007f\u0001\u0000\u0000\u0000wx\n\u0001\u0000"+ + "\u0000xy\u0005\u001d\u0000\u0000yz\u0003\f\u0006\u0000z{\u0005\u0016\u0000"+ + "\u0000{|\u0003\f\u0006\u0002|~\u0001\u0000\u0000\u0000}w\u0001\u0000\u0000"+ + "\u0000~\u0081\u0001\u0000\u0000\u0000\u007f}\u0001\u0000\u0000\u0000\u007f"+ + "\u0080\u0001\u0000\u0000\u0000\u0080\r\u0001\u0000\u0000\u0000\u0081\u007f"+ + "\u0001\u0000\u0000\u0000\u0082\u0083\u0006\u0007\uffff\uffff\u0000\u0083"+ + "\u008e\u0003F#\u0000\u0084\u008e\u0003\u0012\t\u0000\u0085\u008e\u0003"+ + "\u001c\u000e\u0000\u0086\u008e\u0003\u0014\n\u0000\u0087\u008e\u0003&"+ + "\u0013\u0000\u0088\u008e\u0003(\u0014\u0000\u0089\u008a\u0005\u0018\u0000"+ + "\u0000\u008a\u008b\u0003\f\u0006\u0000\u008b\u008c\u0005\u001f\u0000\u0000"+ + "\u008c\u008e\u0001\u0000\u0000\u0000\u008d\u0082\u0001\u0000\u0000\u0000"+ + "\u008d\u0084\u0001\u0000\u0000\u0000\u008d\u0085\u0001\u0000\u0000\u0000"+ + "\u008d\u0086\u0001\u0000\u0000\u0000\u008d\u0087\u0001\u0000\u0000\u0000"+ + "\u008d\u0088\u0001\u0000\u0000\u0000\u008d\u0089\u0001\u0000\u0000\u0000"+ + "\u008e\u0099\u0001\u0000\u0000\u0000\u008f\u0090\n\u0005\u0000\u0000\u0090"+ + "\u0098\u0003,\u0016\u0000\u0091\u0092\n\u0004\u0000\u0000\u0092\u0098"+ + "\u0003.\u0017\u0000\u0093\u0094\n\u0003\u0000\u0000\u0094\u0098\u0003"+ + "0\u0018\u0000\u0095\u0096\n\u0002\u0000\u0000\u0096\u0098\u00032\u0019"+ + "\u0000\u0097\u008f\u0001\u0000\u0000\u0000\u0097\u0091\u0001\u0000\u0000"+ + "\u0000\u0097\u0093\u0001\u0000\u0000\u0000\u0097\u0095\u0001\u0000\u0000"+ + "\u0000\u0098\u009b\u0001\u0000\u0000\u0000\u0099\u0097\u0001\u0000\u0000"+ + "\u0000\u0099\u009a\u0001\u0000\u0000\u0000\u009a\u000f\u0001\u0000\u0000"+ + "\u0000\u009b\u0099\u0001\u0000\u0000\u0000\u009c\u009d\u0005\u0005\u0000"+ + "\u0000\u009d\u009e\u0003\u0002\u0001\u0000\u009e\u009f\u0005\u0006\u0000"+ + "\u0000\u009f\u0011\u0001\u0000\u0000\u0000\u00a0\u00a1\u0007\u0000\u0000"+ + "\u0000\u00a1\u0013\u0001\u0000\u0000\u0000\u00a2\u00a5\u0003\u0016\u000b"+ + "\u0000\u00a3\u00a5\u0003\u0018\f\u0000\u00a4\u00a2\u0001\u0000\u0000\u0000"+ + "\u00a4\u00a3\u0001\u0000\u0000\u0000\u00a5\u0015\u0001\u0000\u0000\u0000"+ + "\u00a6\u00b2\u0005\u0017\u0000\u0000\u00a7\u00ac\u0003\f\u0006\u0000\u00a8"+ + "\u00a9\u0005\'\u0000\u0000\u00a9\u00ab\u0003\f\u0006\u0000\u00aa\u00a8"+ + "\u0001\u0000\u0000\u0000\u00ab\u00ae\u0001\u0000\u0000\u0000\u00ac\u00aa"+ + "\u0001\u0000\u0000\u0000\u00ac\u00ad\u0001\u0000\u0000\u0000\u00ad\u00b0"+ + "\u0001\u0000\u0000\u0000\u00ae\u00ac\u0001\u0000\u0000\u0000\u00af\u00b1"+ + "\u0005\'\u0000\u0000\u00b0\u00af\u0001\u0000\u0000\u0000\u00b0\u00b1\u0001"+ + "\u0000\u0000\u0000\u00b1\u00b3\u0001\u0000\u0000\u0000\u00b2\u00a7\u0001"+ + "\u0000\u0000\u0000\u00b2\u00b3\u0001\u0000\u0000\u0000\u00b3\u00b4\u0001"+ + "\u0000\u0000\u0000\u00b4\u00b5\u0005\u001e\u0000\u0000\u00b5\u0017\u0001"+ + "\u0000\u0000\u0000\u00b6\u00ba\u0005\u0005\u0000\u0000\u00b7\u00b9\u0003"+ + "\u001a\r\u0000\u00b8\u00b7\u0001\u0000\u0000\u0000\u00b9\u00bc\u0001\u0000"+ + "\u0000\u0000\u00ba\u00b8\u0001\u0000\u0000\u0000\u00ba\u00bb\u0001\u0000"+ + "\u0000\u0000\u00bb\u00bd\u0001\u0000\u0000\u0000\u00bc\u00ba\u0001\u0000"+ + "\u0000\u0000\u00bd\u00be\u0005\u0006\u0000\u0000\u00be\u0019\u0001\u0000"+ + "\u0000\u0000\u00bf\u00cd\u0005\b\u0000\u0000\u00c0\u00c1\u0005\u0018\u0000"+ + "\u0000\u00c1\u00c2\u0005\b\u0000\u0000\u00c2\u00cd\u0005\u001f\u0000\u0000"+ + "\u00c3\u00c7\u0005\u000f\u0000\u0000\u00c4\u00c6\u0003L&\u0000\u00c5\u00c4"+ + "\u0001\u0000\u0000\u0000\u00c6\u00c9\u0001\u0000\u0000\u0000\u00c7\u00c5"+ + "\u0001\u0000\u0000\u0000\u00c7\u00c8\u0001\u0000\u0000\u0000\u00c8\u00ca"+ + "\u0001\u0000\u0000\u0000\u00c9\u00c7\u0001\u0000\u0000\u0000\u00ca\u00cd"+ + "\u0005\u000f\u0000\u0000\u00cb\u00cd\u0003\f\u0006\u0000\u00cc\u00bf\u0001"+ + "\u0000\u0000\u0000\u00cc\u00c0\u0001\u0000\u0000\u0000\u00cc\u00c3\u0001"+ + "\u0000\u0000\u0000\u00cc\u00cb\u0001\u0000\u0000\u0000\u00cd\u00ce\u0001"+ + "\u0000\u0000\u0000\u00ce\u00cf\u0007\u0001\u0000\u0000\u00cf\u00d1\u0003"+ + "\f\u0006\u0000\u00d0\u00d2\u0005\'\u0000\u0000\u00d1\u00d0\u0001\u0000"+ + "\u0000\u0000\u00d1\u00d2\u0001\u0000\u0000\u0000\u00d2\u001b\u0001\u0000"+ + "\u0000\u0000\u00d3\u00d6\u0003\u001e\u000f\u0000\u00d4\u00d6\u0003 \u0010"+ + "\u0000\u00d5\u00d3\u0001\u0000\u0000\u0000\u00d5\u00d4\u0001\u0000\u0000"+ + "\u0000\u00d6\u001d\u0001\u0000\u0000\u0000\u00d7\u00d8\u0005\u0002\u0000"+ + "\u0000\u00d8\u00d9\u0003\"\u0011\u0000\u00d9\u00da\u0005\u0016\u0000\u0000"+ + "\u00da\u00dc\u0003\f\u0006\u0000\u00db\u00dd\u0003$\u0012\u0000\u00dc"+ + "\u00db\u0001\u0000\u0000\u0000\u00dc\u00dd\u0001\u0000\u0000\u0000\u00dd"+ + "\u00de\u0001\u0000\u0000\u0000\u00de\u00df\u0005\u001e\u0000\u0000\u00df"+ + "\u001f\u0001\u0000\u0000\u0000\u00e0\u00e1\u0005\u0001\u0000\u0000\u00e1"+ + "\u00e2\u0003\"\u0011\u0000\u00e2\u00e3\u0005\u0016\u0000\u0000\u00e3\u00e4"+ + "\u0003\f\u0006\u0000\u00e4\u00e5\u0005&\u0000\u0000\u00e5\u00e7\u0003"+ + "\f\u0006\u0000\u00e6\u00e8\u0005)\u0000\u0000\u00e7\u00e6\u0001\u0000"+ + "\u0000\u0000\u00e7\u00e8\u0001\u0000\u0000\u0000\u00e8\u00ea\u0001\u0000"+ + "\u0000\u0000\u00e9\u00eb\u0003$\u0012\u0000\u00ea\u00e9\u0001\u0000\u0000"+ + "\u0000\u00ea\u00eb\u0001\u0000\u0000\u0000\u00eb\u00ec\u0001\u0000\u0000"+ + "\u0000\u00ec\u00ed\u0005\u0006\u0000\u0000\u00ed!\u0001\u0000\u0000\u0000"+ + "\u00ee\u00f1\u0005\b\u0000\u0000\u00ef\u00f0\u0005\'\u0000\u0000\u00f0"+ + "\u00f2\u0005\b\u0000\u0000\u00f1\u00ef\u0001\u0000\u0000\u0000\u00f1\u00f2"+ + "\u0001\u0000\u0000\u0000\u00f2\u00f3\u0001\u0000\u0000\u0000\u00f3\u00f4"+ + "\u0005\u0004\u0000\u0000\u00f4\u00f5\u0003\f\u0006\u0000\u00f5#\u0001"+ + "\u0000\u0000\u0000\u00f6\u00f7\u0005\u0003\u0000\u0000\u00f7\u00f8\u0003"+ + "\f\u0006\u0000\u00f8%\u0001\u0000\u0000\u0000\u00f9\u00fa\u0005\b\u0000"+ + "\u0000\u00fa\'\u0001\u0000\u0000\u0000\u00fb\u00fc\u0005\b\u0000\u0000"+ + "\u00fc\u00fe\u0005\u0018\u0000\u0000\u00fd\u00ff\u0003*\u0015\u0000\u00fe"+ + "\u00fd\u0001\u0000\u0000\u0000\u00fe\u00ff\u0001\u0000\u0000\u0000\u00ff"+ + "\u0100\u0001\u0000\u0000\u0000\u0100\u0101\u0005\u001f\u0000\u0000\u0101"+ + ")\u0001\u0000\u0000\u0000\u0102\u0107\u0003\f\u0006\u0000\u0103\u0104"+ + "\u0005\'\u0000\u0000\u0104\u0106\u0003\f\u0006\u0000\u0105\u0103\u0001"+ + "\u0000\u0000\u0000\u0106\u0109\u0001\u0000\u0000\u0000\u0107\u0105\u0001"+ + "\u0000\u0000\u0000\u0107\u0108\u0001\u0000\u0000\u0000\u0108\u010b\u0001"+ + "\u0000\u0000\u0000\u0109\u0107\u0001\u0000\u0000\u0000\u010a\u010c\u0007"+ + "\u0002\u0000\u0000\u010b\u010a\u0001\u0000\u0000\u0000\u010b\u010c\u0001"+ + "\u0000\u0000\u0000\u010c+\u0001\u0000\u0000\u0000\u010d\u010e\u0005\u0017"+ + "\u0000\u0000\u010e\u010f\u0003\f\u0006\u0000\u010f\u0110\u0005\u001e\u0000"+ + "\u0000\u0110-\u0001\u0000\u0000\u0000\u0111\u0112\u0005#\u0000\u0000\u0112"+ + "\u0113\u0005\b\u0000\u0000\u0113/\u0001\u0000\u0000\u0000\u0114\u0115"+ + "\u0005#\u0000\u0000\u0115\u0116\u0005\r\u0000\u0000\u01161\u0001\u0000"+ + "\u0000\u0000\u0117\u011a\u00034\u001a\u0000\u0118\u011a\u00036\u001b\u0000"+ + "\u0119\u0117\u0001\u0000\u0000\u0000\u0119\u0118\u0001\u0000\u0000\u0000"+ + "\u011a3\u0001\u0000\u0000\u0000\u011b\u011c\u0005#\u0000\u0000\u011c\u0120"+ + "\u0005 \u0000\u0000\u011d\u011f\u0003.\u0017\u0000\u011e\u011d\u0001\u0000"+ + "\u0000\u0000\u011f\u0122\u0001\u0000\u0000\u0000\u0120\u011e\u0001\u0000"+ + "\u0000\u0000\u0120\u0121\u0001\u0000\u0000\u0000\u01215\u0001\u0000\u0000"+ + "\u0000\u0122\u0120\u0001\u0000\u0000\u0000\u0123\u0124\u0005\u0017\u0000"+ + "\u0000\u0124\u0125\u0005 \u0000\u0000\u0125\u012a\u0005\u001e\u0000\u0000"+ + "\u0126\u0129\u0003.\u0017\u0000\u0127\u0129\u0003,\u0016\u0000\u0128\u0126"+ + "\u0001\u0000\u0000\u0000\u0128\u0127\u0001\u0000\u0000\u0000\u0129\u012c"+ + "\u0001\u0000\u0000\u0000\u012a\u0128\u0001\u0000\u0000\u0000\u012a\u012b"+ + "\u0001\u0000\u0000\u0000\u012b7\u0001\u0000\u0000\u0000\u012c\u012a\u0001"+ + "\u0000\u0000\u0000\u012d\u0130\u0003:\u001d\u0000\u012e\u0130\u0003<\u001e"+ + "\u0000\u012f\u012d\u0001\u0000\u0000\u0000\u012f\u012e\u0001\u0000\u0000"+ + "\u0000\u01309\u0001\u0000\u0000\u0000\u0131\u0132\u0007\u0003\u0000\u0000"+ + "\u0132\u0133\u0003\u000e\u0007\u0000\u0133;\u0001\u0000\u0000\u0000\u0134"+ + "\u0137\u0003\u000e\u0007\u0000\u0135\u0137\u0003:\u001d\u0000\u0136\u0134"+ + "\u0001\u0000\u0000\u0000\u0136\u0135\u0001\u0000\u0000\u0000\u0137\u0138"+ + "\u0001\u0000\u0000\u0000\u0138\u013b\u0003>\u001f\u0000\u0139\u013c\u0003"+ + "\u000e\u0007\u0000\u013a\u013c\u00038\u001c\u0000\u013b\u0139\u0001\u0000"+ + "\u0000\u0000\u013b\u013a\u0001\u0000\u0000\u0000\u013c=\u0001\u0000\u0000"+ + "\u0000\u013d\u0141\u0003@ \u0000\u013e\u0141\u0003B!\u0000\u013f\u0141"+ + "\u0003D\"\u0000\u0140\u013d\u0001\u0000\u0000\u0000\u0140\u013e\u0001"+ + "\u0000\u0000\u0000\u0140\u013f\u0001\u0000\u0000\u0000\u0141?\u0001\u0000"+ + "\u0000\u0000\u0142\u0143\u0007\u0004\u0000\u0000\u0143A\u0001\u0000\u0000"+ + "\u0000\u0144\u0145\u0007\u0005\u0000\u0000\u0145C\u0001\u0000\u0000\u0000"+ + "\u0146\u0147\u0007\u0006\u0000\u0000\u0147E\u0001\u0000\u0000\u0000\u0148"+ + "\u0149\u0005\u0011\u0000\u0000\u0149\u0151\u0005\b\u0000\u0000\u014a\u014e"+ + "\u0005\f\u0000\u0000\u014b\u014d\u0003H$\u0000\u014c\u014b\u0001\u0000"+ + "\u0000\u0000\u014d\u0150\u0001\u0000\u0000\u0000\u014e\u014c\u0001\u0000"+ + "\u0000\u0000\u014e\u014f\u0001\u0000\u0000\u0000\u014f\u0152\u0001\u0000"+ + "\u0000\u0000\u0150\u014e\u0001\u0000\u0000\u0000\u0151\u014a\u0001\u0000"+ + "\u0000\u0000\u0152\u0153\u0001\u0000\u0000\u0000\u0153\u0151\u0001\u0000"+ + "\u0000\u0000\u0153\u0154\u0001\u0000\u0000\u0000\u0154\u0155\u0001\u0000"+ + "\u0000\u0000\u0155\u015f\u0005\b\u0000\u0000\u0156\u015a\u0005\u000f\u0000"+ + "\u0000\u0157\u0159\u0003L&\u0000\u0158\u0157\u0001\u0000\u0000\u0000\u0159"+ + "\u015c\u0001\u0000\u0000\u0000\u015a\u0158\u0001\u0000\u0000\u0000\u015a"+ + "\u015b\u0001\u0000\u0000\u0000\u015b\u015d\u0001\u0000\u0000\u0000\u015c"+ + "\u015a\u0001\u0000\u0000\u0000\u015d\u015f\u0005\u000f\u0000\u0000\u015e"+ + "\u0148\u0001\u0000\u0000\u0000\u015e\u0156\u0001\u0000\u0000\u0000\u015f"+ + "G\u0001\u0000\u0000\u0000\u0160\u0163\u0003P(\u0000\u0161\u0163\u0003"+ + "J%\u0000\u0162\u0160\u0001\u0000\u0000\u0000\u0162\u0161\u0001\u0000\u0000"+ + "\u0000\u0163I\u0001\u0000\u0000\u0000\u0164\u0165\u0005.\u0000\u0000\u0165"+ + "K\u0001\u0000\u0000\u0000\u0166\u0169\u0003P(\u0000\u0167\u0169\u0003"+ + "N\'\u0000\u0168\u0166\u0001\u0000\u0000\u0000\u0168\u0167\u0001\u0000"+ + "\u0000\u0000\u0169M\u0001\u0000\u0000\u0000\u016a\u016b\u0005,\u0000\u0000"+ + "\u016bO\u0001\u0000\u0000\u0000\u016c\u016d\u0005+\u0000\u0000\u016d\u016e"+ + "\u0003\f\u0006\u0000\u016e\u016f\u0005\u0006\u0000\u0000\u016fQ\u0001"+ + "\u0000\u0000\u0000\'W\\fpu\u007f\u008d\u0097\u0099\u00a4\u00ac\u00b0\u00b2"+ + "\u00ba\u00c7\u00cc\u00d1\u00d5\u00dc\u00e7\u00ea\u00f1\u00fe\u0107\u010b"+ + "\u0119\u0120\u0128\u012a\u012f\u0136\u013b\u0140\u014e\u0153\u015a\u015e"+ + "\u0162\u0168"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseListener.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseListener.java index 955f095e365..0d44480c791 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseListener.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseListener.java @@ -219,6 +219,18 @@ public class HCLParserBaseListener implements HCLParserListener { *

The default implementation does nothing.

*/ @Override public void exitIndexAccessExpression(HCLParser.IndexAccessExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterLegacyIndexAttributeExpression(HCLParser.LegacyIndexAttributeExpressionContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitLegacyIndexAttributeExpression(HCLParser.LegacyIndexAttributeExpressionContext ctx) { } /** * {@inheritDoc} * @@ -447,6 +459,18 @@ public class HCLParserBaseListener implements HCLParserListener { *

The default implementation does nothing.

*/ @Override public void exitGetAttr(HCLParser.GetAttrContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void enterLegacyIndexAttr(HCLParser.LegacyIndexAttrContext ctx) { } + /** + * {@inheritDoc} + * + *

The default implementation does nothing.

+ */ + @Override public void exitLegacyIndexAttr(HCLParser.LegacyIndexAttrContext ctx) { } /** * {@inheritDoc} * diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseVisitor.java index 5add2c1566f..cc3e91b9973 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserBaseVisitor.java @@ -139,6 +139,13 @@ public class HCLParserBaseVisitor extends AbstractParseTreeVisitor impleme * {@link #visitChildren} on {@code ctx}.

*/ @Override public T visitIndexAccessExpression(HCLParser.IndexAccessExpressionContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitLegacyIndexAttributeExpression(HCLParser.LegacyIndexAttributeExpressionContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * @@ -272,6 +279,13 @@ public class HCLParserBaseVisitor extends AbstractParseTreeVisitor impleme * {@link #visitChildren} on {@code ctx}.

*/ @Override public T visitGetAttr(HCLParser.GetAttrContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitLegacyIndexAttr(HCLParser.LegacyIndexAttrContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserListener.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserListener.java index c73e9f70565..6725c41ed20 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserListener.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserListener.java @@ -202,6 +202,18 @@ public interface HCLParserListener extends ParseTreeListener { * @param ctx the parse tree */ void exitIndexAccessExpression(HCLParser.IndexAccessExpressionContext ctx); + /** + * Enter a parse tree produced by the {@code LegacyIndexAttributeExpression} + * labeled alternative in {@link HCLParser#exprTerm}. + * @param ctx the parse tree + */ + void enterLegacyIndexAttributeExpression(HCLParser.LegacyIndexAttributeExpressionContext ctx); + /** + * Exit a parse tree produced by the {@code LegacyIndexAttributeExpression} + * labeled alternative in {@link HCLParser#exprTerm}. + * @param ctx the parse tree + */ + void exitLegacyIndexAttributeExpression(HCLParser.LegacyIndexAttributeExpressionContext ctx); /** * Enter a parse tree produced by the {@code ForExpression} * labeled alternative in {@link HCLParser#exprTerm}. @@ -398,6 +410,16 @@ public interface HCLParserListener extends ParseTreeListener { * @param ctx the parse tree */ void exitGetAttr(HCLParser.GetAttrContext ctx); + /** + * Enter a parse tree produced by {@link HCLParser#legacyIndexAttr}. + * @param ctx the parse tree + */ + void enterLegacyIndexAttr(HCLParser.LegacyIndexAttrContext ctx); + /** + * Exit a parse tree produced by {@link HCLParser#legacyIndexAttr}. + * @param ctx the parse tree + */ + void exitLegacyIndexAttr(HCLParser.LegacyIndexAttrContext ctx); /** * Enter a parse tree produced by {@link HCLParser#splat}. * @param ctx the parse tree diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserVisitor.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserVisitor.java index 531e35db3bc..f1a5f11d588 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserVisitor.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/internal/grammar/HCLParserVisitor.java @@ -131,6 +131,13 @@ public interface HCLParserVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitIndexAccessExpression(HCLParser.IndexAccessExpressionContext ctx); + /** + * Visit a parse tree produced by the {@code LegacyIndexAttributeExpression} + * labeled alternative in {@link HCLParser#exprTerm}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitLegacyIndexAttributeExpression(HCLParser.LegacyIndexAttributeExpressionContext ctx); /** * Visit a parse tree produced by the {@code ForExpression} * labeled alternative in {@link HCLParser#exprTerm}. @@ -248,6 +255,12 @@ public interface HCLParserVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitGetAttr(HCLParser.GetAttrContext ctx); + /** + * Visit a parse tree produced by {@link HCLParser#legacyIndexAttr}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitLegacyIndexAttr(HCLParser.LegacyIndexAttrContext ctx); /** * Visit a parse tree produced by {@link HCLParser#splat}. * @param ctx the parse tree diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Hcl.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Hcl.java index 8ee49114969..5d517cc800a 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Hcl.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Hcl.java @@ -19,6 +19,7 @@ import lombok.*; import lombok.experimental.FieldDefaults; import lombok.experimental.NonFinal; +import org.antlr.v4.runtime.tree.TerminalNode; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.hcl.HclParser; @@ -236,6 +237,75 @@ public AttributeAccess withName(HclLeftPadded name) { } } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) + @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) + @RequiredArgsConstructor + @AllArgsConstructor(access = AccessLevel.PRIVATE) + class LegacyIndexAttributeAccess implements Expression, Label { + @Nullable + @NonFinal + transient WeakReference padding; + + @With + @EqualsAndHashCode.Include + @Getter + UUID id; + + @With + @Getter + Space prefix; + + @With + @Getter + Markers markers; + + @With + @Getter + HclRightPadded base; + + @With + @Getter + Literal index; + + @Override + public

Hcl acceptHcl(HclVisitor

v, P p) { + return v.visitLegacyIndexAttribute(this, p); + } + + @Override + public String toString() { + return "LegacyIndexAttributeAccess{" + base + "." + index + "}"; + } + + public Padding getPadding() { + Padding p; + if (this.padding == null) { + p = new Padding(this); + this.padding = new WeakReference<>(p); + } else { + p = this.padding.get(); + if (p == null || p.t != this) { + p = new Padding(this); + this.padding = new WeakReference<>(p); + } + } + return p; + } + + @RequiredArgsConstructor + public static class Padding { + private final LegacyIndexAttributeAccess t; + + public HclRightPadded getBase() { + return t.base; + } + + public LegacyIndexAttributeAccess withBase(HclRightPadded base) { + return t.base == base ? t : new LegacyIndexAttributeAccess(t.id, t.prefix, t.markers, base, t.index); + } + } + } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true) @RequiredArgsConstructor diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/HclRightPadded.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/HclRightPadded.java index 366b94a2300..3e8c9b9e282 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/HclRightPadded.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/HclRightPadded.java @@ -50,6 +50,7 @@ public enum Location { FOR_VARIABLE_ARGUMENT(Space.Location.FOR_VARIABLE_SUFFIX), FUNCTION_CALL_ARGUMENT(Space.Location.FUNCTION_CALL_ARGUMENT_SUFFIX), INDEX_POSITION(Space.Location.INDEX_POSITION_SUFFIX), + LEGACY_INDEX_ATTRIBUTE_ACCESS_BASE(Space.Location.LEGACY_INDEX_ATTRIBUTE_ACCESS_BASE), OBJECT_VALUE_ARGUMENT(Space.Location.OBJECT_VALUE_ATTRIBUTE_SUFFIX), PARENTHESES(Space.Location.PARENTHESES_SUFFIX), SPLAT_OPERATOR(Space.Location.SPLAT_OPERATOR_SUFFIX), diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java index 31d5fa2f4e8..cf89a2e683d 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/tree/Space.java @@ -328,6 +328,8 @@ public enum Location { INDEX_POSITION, INDEX_POSITION_SUFFIX, IDENTIFIER, + LEGACY_INDEX_ATTRIBUTE_ACCESS, + LEGACY_INDEX_ATTRIBUTE_ACCESS_BASE, LITERAL, OBJECT_VALUE, OBJECT_VALUE_ATTRIBUTES, diff --git a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclVariableExpressionTest.java b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclVariableExpressionTest.java index 353d4c43b86..3353166a97b 100644 --- a/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclVariableExpressionTest.java +++ b/rewrite-hcl/src/test/java/org/openrewrite/hcl/tree/HclVariableExpressionTest.java @@ -33,4 +33,19 @@ void variableExpression() { ) ); } + + @Test + void legacyIndexOperator() { + rewriteRun( + hcl( + """ + locals { + dns_record = aws_acm_certificate.google_dot_com.0.resource_record_name + with_space_before = a.b .0.d + with_space_after = a.b. 0.d + } + """ + ) + ); + } } From 09dfe0633946d5eddf075235c4f5851f139f219e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Wed, 15 Jan 2025 09:31:03 +0100 Subject: [PATCH 144/179] Add new parameter `oldAttributeValue` to `AddOrUpdateAnnotationAttribute` recipe (#4881) * Add new parameter `oldAttributeValue` to `AddOrUpdateAnnotationAttribute` * enhance add test for Enum and class values * implement checks for `oldAttributeValue` * small fixes and a reproducer for adding array values to implicite values * fix handling of implicit and explicit value handling * fix handling of implicit and explicit value handling in arrays * Skip supporting source files, and extract constant * add contract to handle nullability * remove comments from debugging --------- Co-authored-by: Tim te Beek --- .../AddOrUpdateAnnotationAttributeTest.java | 375 +++++++++++++++++- .../java/AddOrUpdateAnnotationAttribute.java | 206 ++++++++-- .../java/recipes/MissingOptionExample.java | 2 +- 3 files changed, 533 insertions(+), 50 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java index 63f16fb0ef1..fc520e7f8ab 100755 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java @@ -15,8 +15,11 @@ */ package org.openrewrite.java; +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.openrewrite.test.RewriteTest; +import org.openrewrite.test.SourceSpec; import static org.openrewrite.java.Assertions.java; @@ -25,7 +28,7 @@ class AddOrUpdateAnnotationAttributeTest implements RewriteTest { @Test void addValueAttribute() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "hello", null, null)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "hello", null, null, null)), java( """ package org.example; @@ -56,7 +59,7 @@ public class A { @Test void addValueAttributeClass() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "Integer.class", null, null)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "Integer.class", null, null, null)), java( """ package org.example; @@ -87,7 +90,7 @@ public class A { @Test void addValueAttributeFullyQualifiedClass() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "java.math.BigDecimal.class", null, null)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "java.math.BigDecimal.class", null, null, null)), java( """ package org.example; @@ -118,7 +121,7 @@ public class A { @Test void updateValueAttribute() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "hello", null, null)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "hello", null, null, null)), java( """ package org.example; @@ -150,7 +153,7 @@ public class A { @Test void updateValueAttributeClass() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "Integer.class", null, null)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "Integer.class", null, null, null)), java( """ package org.example; @@ -182,7 +185,7 @@ public class A { @Test void removeValueAttribute() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, null, null, null)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, null, null, null, null)), java( """ package org.example; @@ -214,7 +217,7 @@ public class A { @Test void removeValueAttributeClass() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, null, null, null)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, null, null, null, null)), java( """ package org.example; @@ -245,7 +248,7 @@ public class A { @Test void addNamedAttribute() { - rewriteRun(spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "timeout", "500", null, null)), + rewriteRun(spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "timeout", "500", null, null, null)), java( """ package org.junit; @@ -282,7 +285,7 @@ void foo() { @Test void replaceAttribute() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "timeout", "500", null, null)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "timeout", "500", null, null, null)), java( """ package org.junit; @@ -319,7 +322,7 @@ void foo() { @Test void removeAttribute() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "timeout", null, null, null)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "timeout", null, null, null, null)), java( """ package org.junit; @@ -356,7 +359,7 @@ void foo() { @Test void preserveExistingAttributes() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "timeout", "500", null, null)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "timeout", "500", null, null, null)), java( """ package org.junit; @@ -394,7 +397,7 @@ void foo() { @Test void implicitValueToExplicitValue() { - rewriteRun(spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "other", "1", null, null)), + rewriteRun(spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "other", "1", null, null, null)), java( """ package org.junit; @@ -431,7 +434,7 @@ void foo() { @Test void implicitValueToExplicitValueClass() { - rewriteRun(spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "other", "1", null, null)), + rewriteRun(spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "other", "1", null, null, null)), java( """ package org.junit; @@ -469,7 +472,7 @@ void foo() { @Test void dontChangeWhenSetToAddOnly() { rewriteRun( - spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "other", "1", true, false)), + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.junit.Test", "other", "1", null, true, false)), java( """ package org.junit; @@ -500,6 +503,7 @@ void arrayInAnnotationAttribute() { "org.example.Foo", "array", "newTest", + null, false, false)), java( @@ -536,6 +540,7 @@ void arrayInputMoreThanOneInAnnotationAttribute() { "org.example.Foo", "array", "newTest1,newTest2", + null, false, false)), java( @@ -572,6 +577,7 @@ void addArrayInputInAnnotationAttribute() { "org.example.Foo", "array", "newTest1,newTest2", + null, false, false)), java( @@ -608,6 +614,7 @@ void addArrayInputInAnnotationAttributeWithAppendTrue() { "org.example.Foo", "array", "newTest1,newTest2", + null, false, true)), java( @@ -644,6 +651,7 @@ void addArrayInputInAnnotationAttributeEmptyBraces() { "org.example.Foo", "array", "newTest1,newTest2", + null, false, null)), java( @@ -681,6 +689,7 @@ void removeArrayInputInAnnotationAttribute() { "array", null, null, + null, false)), java( """ @@ -717,6 +726,7 @@ void addOtherAttributeInArrayAnnotation() { "string", "test", null, + null, false)), java( """ @@ -753,6 +763,7 @@ void appendSingleValueToExistingArrayAttribute() { "org.example.Foo", "array", "b", + null, false, true)), java( @@ -789,6 +800,7 @@ void appendMultipleValuesToExistingArrayAttribute() { "org.example.Foo", "array", "b,c", + null, false, true)), java( @@ -825,6 +837,7 @@ void appendMultipleValuesToExistingArrayAttributeWithOverlap() { "org.example.Foo", "array", "b,c", + null, false, true)), java( @@ -861,6 +874,7 @@ void appendMultipleValuesToExistingArrayAttributeNonSet() { "org.example.Foo", "array", "b,c", + null, true, true)), java( @@ -901,6 +915,7 @@ void addAttributeToNestedAnnotationArray() { "attribute", "", null, + null, false)), java( """ @@ -938,4 +953,336 @@ public class A { ) ); } + + @Nested + class OnMatch { + @Test + void matchValue() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "hello", "goodbye", null, null)), + java( + """ + package org.example; + public @interface Foo { + String value() default ""; + } + """, + SourceSpec::skip + ), + java( + """ + import org.example.Foo; + + @Foo("goodbye") + public class A { + } + """, + """ + import org.example.Foo; + + @Foo("hello") + public class A { + } + """ + ) + ); + } + + @Test + void matchEnumValue() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "Values.TWO", "Values.ONE", null, null)), + java( + """ + package org.example; + public @interface Foo { + Values value() default ""; + } + public enum Values {ONE, TWO} + """, + SourceSpec::skip + ), + java( + """ + import org.example.Foo; + + @Foo(Values.ONE) + public class A { + } + """, + """ + import org.example.Foo; + + @Foo(Values.TWO) + public class A { + } + """ + ) + ); + } + + @Test + void matchValueInArray() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute( + "org.example.Foo", + null, + "hello", + "goodbye", + null, + true)), + java( + """ + package org.example; + public @interface Foo { + String[] value() default ""; + } + """, + SourceSpec::skip + ), + java( + """ + import org.example.Foo; + + @Foo({"goodbye", "hi"}) + public class A { + } + """, + """ + import org.example.Foo; + + @Foo({"hi", "hello"}) + public class A { + } + """ + ) + ); + } + + @Test + void noMatchValue() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "hello", "hi", null, null)), + java( + """ + package org.example; + public @interface Foo { + String value() default ""; + } + """, + SourceSpec::skip + ), + java( + """ + import org.example.Foo; + + @Foo("goodbye") + public class A { + } + """ + ) + ); + } + + @Test + void matchClass() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "Integer.class", "Long.class", null, null)), + java( + """ + package org.example; + public @interface Foo { + Class value(); + } + """, + SourceSpec::skip + ), + java( + """ + import org.example.Foo; + + @Foo(Long.class) + public class A { + } + """, + """ + import org.example.Foo; + + @Foo(Integer.class) + public class A { + } + """ + ) + ); + } + + @Test + void nomatchClass() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", null, "Integer.class", "Double.class", null, null)), + java( + """ + package org.example; + public @interface Foo { + Class value(); + } + """, + SourceSpec::skip + ), + java( + """ + import org.example.Foo; + + @Foo(Long.class) + public class A { + } + """ + ) + ); + } + } + + @Nested + class AsValueAttribute { + + @Language("java") + private static final String FOO_ANNOTATION_WITH_STRING_ARRAY_VALUE = """ + package org.example; + public @interface Foo { + String[] value() default {}; + } + """; + + @Test + void implicitWithNullAttributeName() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute( + "org.example.Foo", + null, + "b", + null, + false, + true)), + java( + FOO_ANNOTATION_WITH_STRING_ARRAY_VALUE, + SourceSpec::skip + ), + java( + """ + import org.example.Foo; + + @Foo({"a"}) + public class A { + } + """, + """ + import org.example.Foo; + + @Foo({"a", "b"}) + public class A { + } + """ + ) + ); + } + + @Test + void implicitWithAttributeNameValue() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute( + "org.example.Foo", + null, + "b", + null, + false, + true)), + java( + FOO_ANNOTATION_WITH_STRING_ARRAY_VALUE, + SourceSpec::skip + ), + java( + """ + import org.example.Foo; + + @Foo(value = {"a"}) + public class A { + } + """, + """ + import org.example.Foo; + + @Foo(value = {"a", "b"}) + public class A { + } + """ + ) + ); + } + + @Test + void explicitWithNullAttributeName() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute( + "org.example.Foo", + null, + "b", + null, + false, + true)), + java( + FOO_ANNOTATION_WITH_STRING_ARRAY_VALUE, + SourceSpec::skip + ), + java( + """ + import org.example.Foo; + + @Foo(value = {"a"}) + public class A { + } + """, + """ + import org.example.Foo; + + @Foo(value = {"a", "b"}) + public class A { + } + """ + ) + ); + } + + @Test + void explicitWithAttributeNameValue() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute( + "org.example.Foo", + "value", + "b", + null, + false, + true)), + java( + FOO_ANNOTATION_WITH_STRING_ARRAY_VALUE, + SourceSpec::skip + ), + java( + """ + import org.example.Foo; + + @Foo(value = {"a"}) + public class A { + } + """, + """ + import org.example.Foo; + + @Foo(value = {"a", "b"}) + public class A { + } + """ + ) + ); + } + } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java b/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java index 05257701bfd..38cb78f8d66 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java @@ -18,6 +18,7 @@ import lombok.EqualsAndHashCode; import lombok.Value; import lombok.With; +import org.jetbrains.annotations.Contract; import org.jspecify.annotations.Nullable; import org.openrewrite.*; import org.openrewrite.internal.ListUtils; @@ -28,11 +29,11 @@ import java.util.Arrays; import java.util.List; -import java.util.Objects; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; +import static java.util.Objects.requireNonNull; import static org.openrewrite.Tree.randomId; @Value @@ -46,7 +47,7 @@ public String getDisplayName() { @Override public String getDescription() { return "Some annotations accept arguments. This recipe sets an existing argument to the specified value, " + - "or adds the argument if it is not already set."; + "or adds the argument if it is not already set."; } @Option(displayName = "Annotation type", @@ -67,6 +68,12 @@ public String getDescription() { @Nullable String attributeValue; + @Option(displayName = "Old Attribute value", + description = "The current value of the attribute, this can be used to filter where the change is applied. Set to `null` for wildcard behavior.", + example = "400") + @Nullable + String oldAttributeValue; + @Option(displayName = "Add only", description = "When set to `true` will not change existing annotation attribute values.") @Nullable @@ -74,9 +81,9 @@ public String getDescription() { @Option(displayName = "Append array", description = "If the attribute is an array, setting this option to `true` will append the value(s). " + - "In conjunction with `addOnly`, it is possible to control duplicates: " + - "`addOnly=true`, always append. " + - "`addOnly=false`, only append if the value is not already present.") + "In conjunction with `addOnly`, it is possible to control duplicates: " + + "`addOnly=true`, always append. " + + "`addOnly=false`, only append if the value is not already present.") @Nullable Boolean appendArray; @@ -93,7 +100,7 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { String newAttributeValue = maybeQuoteStringArgument(attributeName, attributeValue, a); List currentArgs = a.getArguments(); if (currentArgs == null || currentArgs.isEmpty() || currentArgs.get(0) instanceof J.Empty) { - if (newAttributeValue == null) { + if (newAttributeValue == null || oldAttributeValue != null) { return a; } @@ -104,8 +111,8 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { .apply(getCursor(), a.getCoordinates().replaceArguments(), newAttributeValue); } else { String newAttributeValueResult = newAttributeValue; - if (((JavaType.FullyQualified) Objects.requireNonNull(a.getAnnotationType().getType())).getMethods().stream().anyMatch(method -> method.getReturnType().toString().equals("java.lang.String[]"))) { - String attributeValueCleanedUp = attributeValue.replaceAll("\\s+","").replaceAll("[\\s+{}\"]",""); + if (((JavaType.FullyQualified) requireNonNull(a.getAnnotationType().getType())).getMethods().stream().anyMatch(method -> method.getReturnType().toString().equals("java.lang.String[]"))) { + String attributeValueCleanedUp = attributeValue.replaceAll("\\s+", "").replaceAll("[\\s+{}\"]", ""); List attributeList = Arrays.asList(attributeValueCleanedUp.contains(",") ? attributeValueCleanedUp.split(",") : new String[]{attributeValueCleanedUp}); newAttributeValueResult = attributeList.stream() .map(String::valueOf) @@ -124,9 +131,13 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { if (it instanceof J.Assignment) { J.Assignment as = (J.Assignment) it; J.Identifier var = (J.Identifier) as.getVariable(); - if (attributeName == null || !attributeName.equals(var.getSimpleName())) { + if (attributeName == null && !"value".equals(var.getSimpleName())) { + return it; + } + if (attributeName != null && !attributeName.equals(var.getSimpleName())) { return it; } + foundOrSetAttributeWithDesiredValue.set(true); if (newAttributeValue == null) { @@ -134,8 +145,8 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { } if (as.getAssignment() instanceof J.NewArray) { - List jLiteralList = ((J.NewArray) as.getAssignment()).getInitializer(); - String attributeValueCleanedUp = attributeValue.replaceAll("\\s+","").replaceAll("[\\s+{}\"]",""); + List jLiteralList = requireNonNull(((J.NewArray) as.getAssignment()).getInitializer()); + String attributeValueCleanedUp = attributeValue.replaceAll("\\s+", "").replaceAll("[\\s+{}\"]", ""); List attributeList = Arrays.asList(attributeValueCleanedUp.contains(",") ? attributeValueCleanedUp.split(",") : new String[]{attributeValueCleanedUp}); if (as.getMarkers().findFirst(AlreadyAppended.class).filter(ap -> ap.getValues().equals(newAttributeValue)).isPresent()) { @@ -149,36 +160,47 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { if (Boolean.FALSE.equals(addOnly) && attributeValIsAlreadyPresent(jLiteralList, newAttributeListValue)) { continue; } + if (oldAttributeValue != null && !oldAttributeValue.equals(attrListValues)) { + continue; + } changed = true; - jLiteralList.add(new J.Literal(randomId(), Space.EMPTY, Markers.EMPTY, newAttributeListValue, newAttributeListValue, null, JavaType.Primitive.String)); + Expression e = requireNonNull(((J.Annotation) JavaTemplate.builder(newAttributeListValue) + .contextSensitive() + .build() + .apply(getCursor(), finalA.getCoordinates().replaceArguments())) + .getArguments()).get(0); + jLiteralList.add(e); } return changed ? as.withAssignment(((J.NewArray) as.getAssignment()).withInitializer(jLiteralList)) .withMarkers(as.getMarkers().add(new AlreadyAppended(randomId(), newAttributeValue))) : as; } int m = 0; - for (int i = 0; i< Objects.requireNonNull(jLiteralList).size(); i++){ - if (i >= attributeList.size()){ + for (int i = 0; i < requireNonNull(jLiteralList).size(); i++) { + if (i >= attributeList.size()) { jLiteralList.remove(i); i--; continue; } String newAttributeListValue = maybeQuoteStringArgument(attributeName, attributeList.get(i), finalA); - if (jLiteralList.size() == i+1){ - m = i+1; + if (jLiteralList.size() == i + 1) { + m = i + 1; } - if (newAttributeListValue != null && newAttributeListValue.equals(((J.Literal) jLiteralList.get(i)).getValueSource()) || Boolean.TRUE.equals(addOnly)) { + if (newAttributeListValue.equals(((J.Literal) jLiteralList.get(i)).getValueSource()) || Boolean.TRUE.equals(addOnly)) { + continue; + } + if (oldAttributeValue != null && !oldAttributeValue.equals(attributeList.get(i))) { continue; } jLiteralList.set(i, ((J.Literal) jLiteralList.get(i)).withValue(newAttributeListValue).withValueSource(newAttributeListValue).withPrefix(jLiteralList.get(i).getPrefix())); } - if (jLiteralList.size() < attributeList.size() || Boolean.TRUE.equals(addOnly)){ - if (Boolean.TRUE.equals(addOnly)){ + if (jLiteralList.size() < attributeList.size() || Boolean.TRUE.equals(addOnly)) { + if (Boolean.TRUE.equals(addOnly)) { m = 0; } - for (int j = m; j < attributeList.size(); j++){ + for (int j = m; j < attributeList.size(); j++) { String newAttributeListValue = maybeQuoteStringArgument(attributeName, attributeList.get(j), finalA); jLiteralList.add(j, new J.Literal(randomId(), jLiteralList.get(j - 1).getPrefix(), Markers.EMPTY, newAttributeListValue, newAttributeListValue, null, JavaType.Primitive.String)); } @@ -190,6 +212,9 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { if (newAttributeValue.equals(value.getValueSource()) || Boolean.TRUE.equals(addOnly)) { return it; } + if (!valueMatches(value, oldAttributeValue)) { + return it; + } return as.withAssignment(value.withValue(newAttributeValue).withValueSource(newAttributeValue)); } } else if (it instanceof J.Literal) { @@ -203,6 +228,9 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { if (newAttributeValue.equals(value.getValueSource()) || Boolean.TRUE.equals(addOnly)) { return it; } + if (!valueMatches(value, oldAttributeValue)) { + return it; + } return ((J.Literal) it).withValue(newAttributeValue).withValueSource(newAttributeValue); } else { // Make the attribute name explicit, before we add the new value below @@ -217,6 +245,9 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { // The only way anything except an assignment can appear is if there's an implicit assignment to "value" if (attributeName == null || "value".equals(attributeName)) { foundOrSetAttributeWithDesiredValue.set(true); + if (!valueMatches(it, oldAttributeValue)) { + return it; + } if (newAttributeValue == null) { return null; } @@ -236,33 +267,132 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { .apply(getCursor(), finalA.getCoordinates().replaceArguments(), it)) .getArguments().get(0); } + } else if (it instanceof J.NewArray) { + if (it.getMarkers().findFirst(AlreadyAppended.class).filter(ap -> ap.getValues().equals(newAttributeValue)).isPresent()) { + return it; + } + + if (newAttributeValue == null) { + return null; + } + + J.NewArray arrayValue = (J.NewArray) it; + List jLiteralList = requireNonNull(arrayValue.getInitializer()); + String attributeValueCleanedUp = attributeValue.replaceAll("\\s+", "").replaceAll("[\\s+{}\"]", ""); + List attributeList = Arrays.asList(attributeValueCleanedUp.contains(",") ? attributeValueCleanedUp.split(",") : new String[]{attributeValueCleanedUp}); + + if (Boolean.TRUE.equals(appendArray)) { + boolean changed = false; + for (String attrListValues : attributeList) { + String newAttributeListValue = maybeQuoteStringArgument(attributeName, attrListValues, finalA); + if (Boolean.FALSE.equals(addOnly) && attributeValIsAlreadyPresent(jLiteralList, newAttributeListValue)) { + continue; + } + changed = true; + + Expression e = requireNonNull(((J.Annotation) JavaTemplate.builder(newAttributeListValue) + .contextSensitive() + .build() + .apply(getCursor(), finalA.getCoordinates().replaceArguments())) + .getArguments()).get(0); + jLiteralList.add(e); + } + if (oldAttributeValue != null) { // remove old value from array + jLiteralList = ListUtils.map(jLiteralList, val -> valueMatches(val, oldAttributeValue) ? null : val); + } + + return changed ? arrayValue.withInitializer(jLiteralList) + .withMarkers(it.getMarkers().add(new AlreadyAppended(randomId(), newAttributeValue))) : it; + } + int m = 0; + for (int i = 0; i < requireNonNull(jLiteralList).size(); i++) { + if (i >= attributeList.size()) { + jLiteralList.remove(i); + i--; + continue; + } + + String newAttributeListValue = maybeQuoteStringArgument(attributeName, attributeList.get(i), finalA); + if (jLiteralList.size() == i + 1) { + m = i + 1; + } + + if (newAttributeListValue.equals(((J.Literal) jLiteralList.get(i)).getValueSource()) || Boolean.TRUE.equals(addOnly)) { + continue; + } + if (oldAttributeValue != null && !oldAttributeValue.equals(newAttributeListValue)) { + continue; + } + + jLiteralList.set(i, ((J.Literal) jLiteralList.get(i)).withValue(newAttributeListValue).withValueSource(newAttributeListValue).withPrefix(jLiteralList.get(i).getPrefix())); + } + if (jLiteralList.size() < attributeList.size() || Boolean.TRUE.equals(addOnly)) { + if (Boolean.TRUE.equals(addOnly)) { + m = 0; + } + for (int j = m; j < attributeList.size(); j++) { + String newAttributeListValue = maybeQuoteStringArgument(attributeName, attributeList.get(j), finalA); + + Expression e = requireNonNull(((J.Annotation) JavaTemplate.builder(newAttributeListValue) + .contextSensitive() + .build() + .apply(getCursor(), finalA.getCoordinates().replaceArguments())) + .getArguments()).get(0); + jLiteralList.add(j, e); + } + } + + return arrayValue.withInitializer(jLiteralList); } return it; }); + if (newArgs != currentArgs) { a = a.withArguments(newArgs); } - if (foundOrSetAttributeWithDesiredValue.get()) { - a = maybeAutoFormat(original, a, ctx); - return a; + if (!foundOrSetAttributeWithDesiredValue.get() && !attributeValIsAlreadyPresent(newArgs, newAttributeValue)) { + // There was no existing value to update, so add a new value into the argument list + String effectiveName = (attributeName == null) ? "value" : attributeName; + //noinspection ConstantConditions + J.Assignment as = (J.Assignment) ((J.Annotation) JavaTemplate.builder("#{} = #{}") + .contextSensitive() + .build() + .apply(getCursor(), a.getCoordinates().replaceArguments(), effectiveName, newAttributeValue)) + .getArguments().get(0); + a = a.withArguments(ListUtils.concat(as, a.getArguments())); } - // There was no existing value to update, so add a new value into the argument list - String effectiveName = (attributeName == null) ? "value" : attributeName; - //noinspection ConstantConditions - J.Assignment as = (J.Assignment) ((J.Annotation) JavaTemplate.builder("#{} = #{}") - .contextSensitive() - .build() - .apply(getCursor(), a.getCoordinates().replaceArguments(), effectiveName, newAttributeValue)) - .getArguments().get(0); - a = a.withArguments(ListUtils.concat(as, a.getArguments())); - a = maybeAutoFormat(original, a, ctx); } - + a = maybeAutoFormat(original, a, ctx); return a; } }); } + private static boolean valueMatches(@Nullable Expression expression, @Nullable String oldAttributeValue) { + if (expression == null) { + return oldAttributeValue == null; + } + if (oldAttributeValue == null) { // null means wildcard + return true; + } else if (expression instanceof J.Literal) { + return oldAttributeValue.equals(((J.Literal) expression).getValue()); + } else if (expression instanceof J.FieldAccess) { + J.FieldAccess fa = (J.FieldAccess) expression; + String currentValue = ((J.Identifier) fa.getTarget()).getSimpleName() + "." + fa.getSimpleName(); + return oldAttributeValue.equals(currentValue); + } else if (expression instanceof J.Identifier) { // class names, static variables .. + if (oldAttributeValue.endsWith(".class")) { + String className = TypeUtils.toString(requireNonNull(expression.getType())) + ".class"; + return className.endsWith(oldAttributeValue); + } else { + return oldAttributeValue.equals(((J.Identifier) expression).getSimpleName()); + } + } else { + throw new IllegalArgumentException("Unexpected expression type: " + expression.getClass()); + } + } + + @Contract("_, null, _ -> null; _, !null, _ -> !null") private static @Nullable String maybeQuoteStringArgument(@Nullable String attributeName, @Nullable String attributeValue, J.Annotation annotation) { if ((attributeValue != null) && attributeIsString(attributeName, annotation)) { return "\"" + attributeValue + "\""; @@ -284,7 +414,10 @@ private static boolean attributeIsString(@Nullable String attributeName, J.Annot return false; } - private static boolean attributeValIsAlreadyPresent(List expression, @Nullable String attributeValue) { + private static boolean attributeValIsAlreadyPresent(@Nullable List expression, @Nullable String attributeValue) { + if (expression == null) { + return attributeValue == null; + } for (Expression e : expression) { if (e instanceof J.Literal) { J.Literal literal = (J.Literal) e; @@ -292,6 +425,9 @@ private static boolean attributeValIsAlreadyPresent(List expression, return true; } } + if (e instanceof J.NewArray) { + return attributeValIsAlreadyPresent(((J.NewArray) e).getInitializer(), attributeValue); + } } return false; } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/recipes/MissingOptionExample.java b/rewrite-java/src/main/java/org/openrewrite/java/recipes/MissingOptionExample.java index 847f84fdc87..100279d44dc 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/recipes/MissingOptionExample.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/recipes/MissingOptionExample.java @@ -80,7 +80,7 @@ public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ct } } - AddOrUpdateAnnotationAttribute addOrUpdateAnnotationAttribute = new AddOrUpdateAnnotationAttribute(ORG_OPENREWRITE_OPTION, "example", "TODO Provide a usage example for the docs", true, false); + AddOrUpdateAnnotationAttribute addOrUpdateAnnotationAttribute = new AddOrUpdateAnnotationAttribute(ORG_OPENREWRITE_OPTION, "example", "TODO Provide a usage example for the docs", null, true, false); return (J.Annotation) addOrUpdateAnnotationAttribute.getVisitor().visitNonNull(an, ctx, getCursor().getParent()); } }); From c80874b8d7734c7f50e150c408666e1725956b71 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Wed, 15 Jan 2025 22:49:39 +0100 Subject: [PATCH 145/179] TOML model cleanups (#4907) * TOML model cleanups Added a few missing `@Nullable` annotations and added accessors for `Toml.Table#name`. * Add two more overrides to `TomlIsoVisitor` --- .../org/openrewrite/toml/TomlIsoVisitor.java | 10 ++++++++ .../toml/internal/TomlPrinter.java | 4 +-- .../java/org/openrewrite/toml/tree/Toml.java | 25 +++++++++++++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/TomlIsoVisitor.java b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlIsoVisitor.java index fff819fd1af..850c76832a1 100644 --- a/rewrite-toml/src/main/java/org/openrewrite/toml/TomlIsoVisitor.java +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/TomlIsoVisitor.java @@ -29,6 +29,11 @@ public Toml.Document visitDocument(Toml.Document document, P p) { return (Toml.Document) super.visitDocument(document, p); } + @Override + public Toml.Empty visitEmpty(Toml.Empty empty, P p) { + return (Toml.Empty) super.visitEmpty(empty, p); + } + @Override public Toml.Identifier visitIdentifier(Toml.Identifier identifier, P p) { return (Toml.Identifier) super.visitIdentifier(identifier, p); @@ -43,4 +48,9 @@ public Toml.KeyValue visitKeyValue(Toml.KeyValue keyValue, P p) { public Toml.Literal visitLiteral(Toml.Literal literal, P p) { return (Toml.Literal) super.visitLiteral(literal, p); } + + @Override + public Toml.Table visitTable(Toml.Table table, P p) { + return (Toml.Table) super.visitTable(table, p); + } } diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlPrinter.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlPrinter.java index af61c294a17..b0bdeceed5f 100644 --- a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlPrinter.java +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlPrinter.java @@ -103,12 +103,12 @@ public Toml visitTable(Toml.Table table, PrintOutputCapture

p) { p.append("}"); } else if (table.getMarkers().findFirst(ArrayTable.class).isPresent()) { p.append("[["); - visitRightPadded(table.getName(), p); + visitRightPadded(table.getPadding().getName(), p); p.append("]]"); visitRightPadded(table.getPadding().getValues(), "", p); } else { p.append("["); - visitRightPadded(table.getName(), p); + visitRightPadded(table.getPadding().getName(), p); p.append("]"); visitRightPadded(table.getPadding().getValues(), "", p); } diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Toml.java b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Toml.java index 8d6037316fe..f429cd99f56 100644 --- a/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Toml.java +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/tree/Toml.java @@ -128,7 +128,11 @@ class Document implements Toml, SourceFile { String charsetName; boolean charsetBomMarked; + + @Nullable Checksum checksum; + + @Nullable FileAttributes fileAttributes; @Override @@ -137,7 +141,8 @@ public Charset getCharset() { } @Override - public SourceFile withCharset(Charset charset) { + @SuppressWarnings("unchecked") + public Document withCharset(Charset charset) { return withCharsetName(charset.name()); } @@ -309,9 +314,17 @@ class Table implements TomlValue { @With Markers markers; - @With + @Nullable TomlRightPadded name; + public Toml.@Nullable Identifier getName() { + return name != null ? name.getElement() : null; + } + + public Table withName(Toml.@Nullable Identifier name) { + return getPadding().withName(TomlRightPadded.withElement(this.name, name)); + } + List> values; public List getValues() { @@ -353,6 +366,14 @@ public List> getValues() { public Table withValues(List> values) { return t.values == values ? t : new Table(t.id, t.prefix, t.markers, t.name, values); } + + public @Nullable TomlRightPadded getName() { + return t.name; + } + + public Table withName(@Nullable TomlRightPadded name) { + return t.name == name ? t : new Table(t.id, t.prefix, t.markers, name, t.values); + } } } } From 2586748a25b90b3d7f272a8f06bf80ea4628550e Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Wed, 15 Jan 2025 18:17:53 -0800 Subject: [PATCH 146/179] When resolving maven pom properties give system properties precedence. This matches Maven's own behavior. --- .../openrewrite/maven/tree/ResolvedPom.java | 4 ++- .../openrewrite/maven/MavenParserTest.java | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java b/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java index d23f22dbe2c..7f5a0d343e1 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java @@ -281,7 +281,9 @@ public String getPackaging() { if (property == null) { return null; } - String propVal = properties.get(property); + // Maven allows system properties to override project properties + // This facilitates the usage of "-D" arguments on the command line to customize builds + String propVal = System.getProperty(property, properties.get(property)); if (propVal != null) { return propVal; } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java index cef61f90ef3..3b3367c23ff 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java @@ -3358,4 +3358,33 @@ void exclusionsAffectTransitiveDependencies() { ) ); } + + @Test + void systemPropertyTakesPrecedence() { + System.setProperty("hatversion", "2.3.0"); + rewriteRun( + pomXml( + """ + + com.mycompany.app + parent + 1.0-SNAPSHOT + pom + parent + http://www.example.com + + SYSTEM_PROPERTY_SHOULD_OVERRIDE_THIS + + + + org.springframework.hateoas + spring-hateoas + ${hatversion} + + + + """ + ) + ); + } } From 6cd1e2aa00f17fe24ab396ff0fb558f357cd6b47 Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Thu, 16 Jan 2025 06:14:27 +0100 Subject: [PATCH 147/179] Refactoring, extract normalizeNewLines() (#4904) --- .../org/openrewrite/format/LineBreaks.java | 34 +++++++++++++++++++ .../format/NormalizeLineBreaksVisitor.java | 18 ++-------- .../format/NormalizeLineBreaksVisitor.java | 19 ++--------- .../format/NormalizeLineBreaksVisitor.java | 20 ++--------- 4 files changed, 40 insertions(+), 51 deletions(-) create mode 100644 rewrite-core/src/main/java/org/openrewrite/format/LineBreaks.java diff --git a/rewrite-core/src/main/java/org/openrewrite/format/LineBreaks.java b/rewrite-core/src/main/java/org/openrewrite/format/LineBreaks.java new file mode 100644 index 00000000000..da2bdfc05ea --- /dev/null +++ b/rewrite-core/src/main/java/org/openrewrite/format/LineBreaks.java @@ -0,0 +1,34 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.format; + +public class LineBreaks { + public static String normalizeNewLines(String text, boolean useCrlf) { + if (!text.contains("\n")) { + return text; + } + StringBuilder normalized = new StringBuilder(); + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (useCrlf && c == '\n' && (i == 0 || text.charAt(i - 1) != '\r')) { + normalized.append('\r').append('\n'); + } else if (useCrlf || c != '\r') { + normalized.append(c); + } + } + return normalized.toString(); + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/format/NormalizeLineBreaksVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/format/NormalizeLineBreaksVisitor.java index 1e6f9e72aae..a67c26f7ff5 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/format/NormalizeLineBreaksVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/format/NormalizeLineBreaksVisitor.java @@ -24,6 +24,8 @@ import org.openrewrite.java.tree.*; import org.openrewrite.style.GeneralFormatStyle; +import static org.openrewrite.format.LineBreaks.normalizeNewLines; + public class NormalizeLineBreaksVisitor

extends JavaIsoVisitor

{ @Nullable private final Tree stopAfter; @@ -66,22 +68,6 @@ public Space visitSpace(Space space, Space.Location loc, P p) { })); } - private static String normalizeNewLines(String text, boolean useCrlf) { - if (!text.contains("\n")) { - return text; - } - StringBuilder normalized = new StringBuilder(); - for (int i = 0; i < text.length(); i++) { - char c = text.charAt(i); - if (useCrlf && c == '\n' && (i == 0 || text.charAt(i - 1) != '\r')) { - normalized.append('\r').append('\n'); - } else if (useCrlf || c != '\r') { - normalized.append(c); - } - } - return normalized.toString(); - } - @Override public J postVisit(J tree, P p) { if (stopAfter != null && stopAfter.isScope(tree)) { diff --git a/rewrite-xml/src/main/java/org/openrewrite/xml/format/NormalizeLineBreaksVisitor.java b/rewrite-xml/src/main/java/org/openrewrite/xml/format/NormalizeLineBreaksVisitor.java index 90467568ff4..758ae736820 100644 --- a/rewrite-xml/src/main/java/org/openrewrite/xml/format/NormalizeLineBreaksVisitor.java +++ b/rewrite-xml/src/main/java/org/openrewrite/xml/format/NormalizeLineBreaksVisitor.java @@ -21,6 +21,8 @@ import org.openrewrite.xml.XmlIsoVisitor; import org.openrewrite.xml.tree.Xml; +import static org.openrewrite.format.LineBreaks.normalizeNewLines; + public class NormalizeLineBreaksVisitor

extends XmlIsoVisitor

{ @Nullable private final Tree stopAfter; @@ -51,23 +53,6 @@ public NormalizeLineBreaksVisitor(GeneralFormatStyle style, @Nullable Tree stopA return super.visit(tree, p); } - private static String normalizeNewLines(String text, boolean useCrlf) { - if (!text.contains("\n")) { - return text; - } - StringBuilder normalized = new StringBuilder(); - char[] charArray = text.toCharArray(); - for (int i = 0; i < charArray.length; i++) { - char c = charArray[i]; - if (useCrlf && c == '\n' && (i == 0 || text.charAt(i - 1) != '\r')) { - normalized.append('\r').append('\n'); - } else if (useCrlf || c != '\r') { - normalized.append(c); - } - } - return normalized.toString(); - } - @Override public @Nullable Xml postVisit(Xml tree, P p) { if (stopAfter != null && stopAfter.isScope(tree)) { diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/format/NormalizeLineBreaksVisitor.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/format/NormalizeLineBreaksVisitor.java index b50e8e5db17..1077bae9366 100644 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/format/NormalizeLineBreaksVisitor.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/format/NormalizeLineBreaksVisitor.java @@ -21,6 +21,8 @@ import org.openrewrite.yaml.YamlIsoVisitor; import org.openrewrite.yaml.tree.Yaml; +import static org.openrewrite.format.LineBreaks.normalizeNewLines; + public class NormalizeLineBreaksVisitor

extends YamlIsoVisitor

{ private final GeneralFormatStyle generalFormatStyle; @@ -55,22 +57,4 @@ public NormalizeLineBreaksVisitor(GeneralFormatStyle generalFormatStyle, @Nullab } return y; } - - private static String normalizeNewLines(String text, boolean useCrlf) { - if (!text.contains("\n")) { - return text; - } - - StringBuilder normalized = new StringBuilder(); - char[] charArray = text.toCharArray(); - for (int i = 0; i < charArray.length; i++) { - char c = charArray[i]; - if (useCrlf && c == '\n' && (i == 0 || text.charAt(i - 1) != '\r')) { - normalized.append('\r').append('\n'); - } else if (useCrlf || c != '\r') { - normalized.append(c); - } - } - return normalized.toString(); - } } From 462dc74efaacc3d1f548ab6214dd17bd24b8da61 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Thu, 16 Jan 2025 10:16:24 +0100 Subject: [PATCH 148/179] Correct TOML table parsing (#4910) * Correct TOML table parsing Tables in TOML are not nested. I.e. the following should result in an AST with two top-level tables: ```toml [table-1] key1 = "some string" key2 = 123 [table-2] key1 = "another string" key2 = 456 ``` This has now been corrected in the parser. * Adjust Gradle build script for ANTLR generation * Add missing line terminators --- rewrite-toml/build.gradle.kts | 8 +- rewrite-toml/src/main/antlr/TomlParser.g4 | 7 +- .../toml/internal/TomlParserVisitor.java | 4 +- .../toml/internal/grammar/TomlLexer.interp | 5 +- .../toml/internal/grammar/TomlLexer.java | 801 +++++++++--------- .../toml/internal/grammar/TomlParser.interp | 2 +- .../toml/internal/grammar/TomlParser.java | 117 ++- .../org/openrewrite/toml/TomlParserTest.java | 14 +- 8 files changed, 481 insertions(+), 477 deletions(-) diff --git a/rewrite-toml/build.gradle.kts b/rewrite-toml/build.gradle.kts index 13534f609c6..b7e2005ef2e 100644 --- a/rewrite-toml/build.gradle.kts +++ b/rewrite-toml/build.gradle.kts @@ -2,6 +2,10 @@ plugins { id("org.openrewrite.build.language-library") } +val antlrGeneration by configurations.creating { + extendsFrom(configurations.implementation.get()) +} + tasks.register("generateAntlrSources") { mainClass.set("org.antlr.v4.Tool") @@ -11,7 +15,7 @@ tasks.register("generateAntlrSources") { "-visitor" ) + fileTree("src/main/antlr").matching { include("**/*.g4") }.map { it.path } - classpath = sourceSets["main"].runtimeClasspath + classpath = antlrGeneration } dependencies { @@ -19,6 +23,8 @@ dependencies { implementation("org.antlr:antlr4-runtime:4.11.1") implementation("io.micrometer:micrometer-core:1.9.+") + antlrGeneration("org.antlr:antlr4:4.11.1") + compileOnly(project(":rewrite-test")) testImplementation(project(":rewrite-test")) diff --git a/rewrite-toml/src/main/antlr/TomlParser.g4 b/rewrite-toml/src/main/antlr/TomlParser.g4 index 46e51369ef8..c177f35ce54 100644 --- a/rewrite-toml/src/main/antlr/TomlParser.g4 +++ b/rewrite-toml/src/main/antlr/TomlParser.g4 @@ -109,8 +109,7 @@ dateTime ; commentOrNl - : COMMENT NL - | NL + : COMMENT? NL ; array @@ -124,7 +123,7 @@ table ; standardTable - : L_BRACKET key R_BRACKET (commentOrNl* expression)* + : L_BRACKET key R_BRACKET (commentOrNl* keyValue)* ; inlineTable @@ -133,5 +132,5 @@ inlineTable ; arrayTable - : DOUBLE_L_BRACKET key DOUBLE_R_BRACKET (commentOrNl* expression)* + : DOUBLE_L_BRACKET key DOUBLE_R_BRACKET (commentOrNl* keyValue)* ; diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlParserVisitor.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlParserVisitor.java index e72c3f29f44..61c8a4a7551 100644 --- a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlParserVisitor.java +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/TomlParserVisitor.java @@ -384,7 +384,7 @@ public Toml visitStandardTable(TomlParser.StandardTableContext ctx) { Toml.Identifier tableName = visitKey(c.key()); TomlRightPadded nameRightPadded = TomlRightPadded.build(tableName).withAfter(sourceBefore("]")); - List values = c.expression(); + List values = c.keyValue(); List> elements = new ArrayList<>(); for (int i = 0; i < values.size(); i++) { elements.add(TomlRightPadded.build(visit(values.get(i)))); @@ -407,7 +407,7 @@ public Toml visitArrayTable(TomlParser.ArrayTableContext ctx) { Toml.Identifier tableName = visitKey(c.key()); TomlRightPadded nameRightPadded = TomlRightPadded.build(tableName).withAfter(sourceBefore("]]")); - List values = c.expression(); + List values = c.keyValue(); List> elements = new ArrayList<>(); for (int i = 0; i < values.size(); i++) { elements.add(TomlRightPadded.build(visit(values.get(i)))); diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.interp b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.interp index e1b1838c219..45ff08e0e5f 100644 --- a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.interp +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.interp @@ -162,9 +162,6 @@ ARRAY_LOCAL_TIME channel names: DEFAULT_TOKEN_CHANNEL HIDDEN -null -null -COMMENTS_CHANNEL mode names: DEFAULT_MODE @@ -173,4 +170,4 @@ INLINE_TABLE_MODE ARRAY_MODE atn: -[4, 0, 32, 671, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 1, 0, 4, 0, 184, 8, 0, 11, 0, 12, 0, 185, 1, 0, 1, 0, 1, 1, 3, 1, 191, 8, 1, 1, 1, 4, 1, 194, 8, 1, 11, 1, 12, 1, 195, 1, 2, 1, 2, 5, 2, 200, 8, 2, 10, 2, 12, 2, 203, 9, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 235, 8, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 5, 15, 256, 8, 15, 10, 15, 12, 15, 259, 9, 15, 1, 15, 1, 15, 1, 16, 1, 16, 5, 16, 265, 8, 16, 10, 16, 12, 16, 268, 9, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 4, 17, 275, 8, 17, 11, 17, 12, 17, 276, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 3, 21, 301, 8, 21, 1, 21, 1, 21, 1, 22, 1, 22, 3, 22, 307, 8, 22, 1, 22, 1, 22, 3, 22, 311, 8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 324, 8, 24, 10, 24, 12, 24, 327, 9, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 5, 26, 345, 8, 26, 10, 26, 12, 26, 348, 9, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 3, 27, 358, 8, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 5, 28, 366, 8, 28, 10, 28, 12, 28, 369, 9, 28, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 3, 30, 378, 8, 30, 3, 30, 380, 8, 30, 1, 30, 1, 30, 1, 31, 3, 31, 385, 8, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 3, 32, 394, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 3, 33, 404, 8, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 3, 37, 413, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 4, 37, 420, 8, 37, 11, 37, 12, 37, 421, 3, 37, 424, 8, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 435, 8, 38, 10, 38, 12, 38, 438, 9, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 5, 39, 449, 8, 39, 10, 39, 12, 39, 452, 9, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 463, 8, 40, 10, 40, 12, 40, 466, 9, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 4, 48, 494, 8, 48, 11, 48, 12, 48, 495, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 3, 50, 505, 8, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 3, 51, 513, 8, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 4, 257, 266, 325, 346, 0, 89, 4, 1, 6, 2, 8, 3, 10, 4, 12, 5, 14, 6, 16, 7, 18, 8, 20, 9, 22, 10, 24, 0, 26, 0, 28, 0, 30, 0, 32, 0, 34, 11, 36, 12, 38, 13, 40, 14, 42, 15, 44, 0, 46, 16, 48, 0, 50, 0, 52, 17, 54, 0, 56, 18, 58, 0, 60, 0, 62, 0, 64, 19, 66, 20, 68, 21, 70, 0, 72, 0, 74, 0, 76, 0, 78, 22, 80, 23, 82, 24, 84, 25, 86, 0, 88, 0, 90, 0, 92, 0, 94, 0, 96, 0, 98, 0, 100, 0, 102, 0, 104, 0, 106, 0, 108, 0, 110, 0, 112, 26, 114, 27, 116, 28, 118, 29, 120, 30, 122, 0, 124, 0, 126, 31, 128, 0, 130, 0, 132, 0, 134, 0, 136, 32, 138, 0, 140, 0, 142, 0, 144, 0, 146, 0, 148, 0, 150, 0, 152, 0, 154, 0, 156, 0, 158, 0, 160, 0, 162, 0, 164, 0, 166, 0, 168, 0, 170, 0, 172, 0, 174, 0, 176, 0, 178, 0, 180, 0, 4, 0, 1, 2, 3, 16, 2, 0, 9, 9, 32, 32, 2, 0, 10, 10, 13, 13, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 47, 47, 92, 92, 98, 98, 102, 102, 110, 110, 114, 114, 116, 116, 3, 0, 10, 10, 34, 34, 92, 92, 2, 0, 10, 10, 39, 39, 2, 0, 45, 45, 95, 95, 2, 0, 34, 34, 92, 92, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 2, 0, 65, 70, 97, 102, 1, 0, 49, 57, 1, 0, 48, 55, 1, 0, 48, 49, 3, 0, 32, 32, 84, 84, 116, 116, 680, 0, 4, 1, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 10, 1, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 14, 1, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 18, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 34, 1, 0, 0, 0, 0, 36, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 1, 40, 1, 0, 0, 0, 1, 42, 1, 0, 0, 0, 1, 44, 1, 0, 0, 0, 1, 46, 1, 0, 0, 0, 1, 50, 1, 0, 0, 0, 1, 52, 1, 0, 0, 0, 1, 54, 1, 0, 0, 0, 1, 56, 1, 0, 0, 0, 1, 64, 1, 0, 0, 0, 1, 66, 1, 0, 0, 0, 1, 68, 1, 0, 0, 0, 1, 78, 1, 0, 0, 0, 1, 80, 1, 0, 0, 0, 1, 82, 1, 0, 0, 0, 1, 84, 1, 0, 0, 0, 1, 112, 1, 0, 0, 0, 1, 114, 1, 0, 0, 0, 1, 116, 1, 0, 0, 0, 1, 118, 1, 0, 0, 0, 2, 120, 1, 0, 0, 0, 2, 122, 1, 0, 0, 0, 2, 124, 1, 0, 0, 0, 2, 126, 1, 0, 0, 0, 2, 128, 1, 0, 0, 0, 2, 130, 1, 0, 0, 0, 2, 132, 1, 0, 0, 0, 2, 134, 1, 0, 0, 0, 3, 136, 1, 0, 0, 0, 3, 138, 1, 0, 0, 0, 3, 140, 1, 0, 0, 0, 3, 142, 1, 0, 0, 0, 3, 144, 1, 0, 0, 0, 3, 146, 1, 0, 0, 0, 3, 148, 1, 0, 0, 0, 3, 150, 1, 0, 0, 0, 3, 152, 1, 0, 0, 0, 3, 154, 1, 0, 0, 0, 3, 156, 1, 0, 0, 0, 3, 158, 1, 0, 0, 0, 3, 160, 1, 0, 0, 0, 3, 162, 1, 0, 0, 0, 3, 164, 1, 0, 0, 0, 3, 166, 1, 0, 0, 0, 3, 168, 1, 0, 0, 0, 3, 170, 1, 0, 0, 0, 3, 172, 1, 0, 0, 0, 3, 174, 1, 0, 0, 0, 3, 176, 1, 0, 0, 0, 3, 178, 1, 0, 0, 0, 3, 180, 1, 0, 0, 0, 4, 183, 1, 0, 0, 0, 6, 193, 1, 0, 0, 0, 8, 197, 1, 0, 0, 0, 10, 206, 1, 0, 0, 0, 12, 208, 1, 0, 0, 0, 14, 211, 1, 0, 0, 0, 16, 213, 1, 0, 0, 0, 18, 216, 1, 0, 0, 0, 20, 220, 1, 0, 0, 0, 22, 222, 1, 0, 0, 0, 24, 226, 1, 0, 0, 0, 26, 228, 1, 0, 0, 0, 28, 230, 1, 0, 0, 0, 30, 236, 1, 0, 0, 0, 32, 242, 1, 0, 0, 0, 34, 252, 1, 0, 0, 0, 36, 262, 1, 0, 0, 0, 38, 274, 1, 0, 0, 0, 40, 278, 1, 0, 0, 0, 42, 282, 1, 0, 0, 0, 44, 286, 1, 0, 0, 0, 46, 300, 1, 0, 0, 0, 48, 310, 1, 0, 0, 0, 50, 312, 1, 0, 0, 0, 52, 317, 1, 0, 0, 0, 54, 334, 1, 0, 0, 0, 56, 339, 1, 0, 0, 0, 58, 355, 1, 0, 0, 0, 60, 361, 1, 0, 0, 0, 62, 370, 1, 0, 0, 0, 64, 373, 1, 0, 0, 0, 66, 384, 1, 0, 0, 0, 68, 393, 1, 0, 0, 0, 70, 403, 1, 0, 0, 0, 72, 405, 1, 0, 0, 0, 74, 407, 1, 0, 0, 0, 76, 409, 1, 0, 0, 0, 78, 412, 1, 0, 0, 0, 80, 427, 1, 0, 0, 0, 82, 441, 1, 0, 0, 0, 84, 455, 1, 0, 0, 0, 86, 469, 1, 0, 0, 0, 88, 474, 1, 0, 0, 0, 90, 477, 1, 0, 0, 0, 92, 480, 1, 0, 0, 0, 94, 482, 1, 0, 0, 0, 96, 485, 1, 0, 0, 0, 98, 488, 1, 0, 0, 0, 100, 491, 1, 0, 0, 0, 102, 497, 1, 0, 0, 0, 104, 504, 1, 0, 0, 0, 106, 506, 1, 0, 0, 0, 108, 514, 1, 0, 0, 0, 110, 520, 1, 0, 0, 0, 112, 523, 1, 0, 0, 0, 114, 529, 1, 0, 0, 0, 116, 535, 1, 0, 0, 0, 118, 539, 1, 0, 0, 0, 120, 543, 1, 0, 0, 0, 122, 547, 1, 0, 0, 0, 124, 551, 1, 0, 0, 0, 126, 555, 1, 0, 0, 0, 128, 559, 1, 0, 0, 0, 130, 563, 1, 0, 0, 0, 132, 567, 1, 0, 0, 0, 134, 571, 1, 0, 0, 0, 136, 576, 1, 0, 0, 0, 138, 580, 1, 0, 0, 0, 140, 584, 1, 0, 0, 0, 142, 588, 1, 0, 0, 0, 144, 592, 1, 0, 0, 0, 146, 597, 1, 0, 0, 0, 148, 602, 1, 0, 0, 0, 150, 607, 1, 0, 0, 0, 152, 611, 1, 0, 0, 0, 154, 615, 1, 0, 0, 0, 156, 619, 1, 0, 0, 0, 158, 623, 1, 0, 0, 0, 160, 627, 1, 0, 0, 0, 162, 631, 1, 0, 0, 0, 164, 635, 1, 0, 0, 0, 166, 639, 1, 0, 0, 0, 168, 643, 1, 0, 0, 0, 170, 647, 1, 0, 0, 0, 172, 651, 1, 0, 0, 0, 174, 655, 1, 0, 0, 0, 176, 659, 1, 0, 0, 0, 178, 663, 1, 0, 0, 0, 180, 667, 1, 0, 0, 0, 182, 184, 7, 0, 0, 0, 183, 182, 1, 0, 0, 0, 184, 185, 1, 0, 0, 0, 185, 183, 1, 0, 0, 0, 185, 186, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 187, 188, 6, 0, 0, 0, 188, 5, 1, 0, 0, 0, 189, 191, 5, 13, 0, 0, 190, 189, 1, 0, 0, 0, 190, 191, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 192, 194, 5, 10, 0, 0, 193, 190, 1, 0, 0, 0, 194, 195, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 7, 1, 0, 0, 0, 197, 201, 5, 35, 0, 0, 198, 200, 8, 1, 0, 0, 199, 198, 1, 0, 0, 0, 200, 203, 1, 0, 0, 0, 201, 199, 1, 0, 0, 0, 201, 202, 1, 0, 0, 0, 202, 204, 1, 0, 0, 0, 203, 201, 1, 0, 0, 0, 204, 205, 6, 2, 1, 0, 205, 9, 1, 0, 0, 0, 206, 207, 5, 91, 0, 0, 207, 11, 1, 0, 0, 0, 208, 209, 5, 91, 0, 0, 209, 210, 5, 91, 0, 0, 210, 13, 1, 0, 0, 0, 211, 212, 5, 93, 0, 0, 212, 15, 1, 0, 0, 0, 213, 214, 5, 93, 0, 0, 214, 215, 5, 93, 0, 0, 215, 17, 1, 0, 0, 0, 216, 217, 5, 61, 0, 0, 217, 218, 1, 0, 0, 0, 218, 219, 6, 7, 2, 0, 219, 19, 1, 0, 0, 0, 220, 221, 5, 46, 0, 0, 221, 21, 1, 0, 0, 0, 222, 223, 5, 44, 0, 0, 223, 224, 1, 0, 0, 0, 224, 225, 6, 9, 0, 0, 225, 23, 1, 0, 0, 0, 226, 227, 7, 2, 0, 0, 227, 25, 1, 0, 0, 0, 228, 229, 7, 3, 0, 0, 229, 27, 1, 0, 0, 0, 230, 234, 5, 92, 0, 0, 231, 235, 7, 4, 0, 0, 232, 235, 3, 30, 13, 0, 233, 235, 3, 32, 14, 0, 234, 231, 1, 0, 0, 0, 234, 232, 1, 0, 0, 0, 234, 233, 1, 0, 0, 0, 235, 29, 1, 0, 0, 0, 236, 237, 5, 117, 0, 0, 237, 238, 3, 70, 33, 0, 238, 239, 3, 70, 33, 0, 239, 240, 3, 70, 33, 0, 240, 241, 3, 70, 33, 0, 241, 31, 1, 0, 0, 0, 242, 243, 5, 85, 0, 0, 243, 244, 3, 70, 33, 0, 244, 245, 3, 70, 33, 0, 245, 246, 3, 70, 33, 0, 246, 247, 3, 70, 33, 0, 247, 248, 3, 70, 33, 0, 248, 249, 3, 70, 33, 0, 249, 250, 3, 70, 33, 0, 250, 251, 3, 70, 33, 0, 251, 33, 1, 0, 0, 0, 252, 257, 5, 34, 0, 0, 253, 256, 3, 28, 12, 0, 254, 256, 8, 5, 0, 0, 255, 253, 1, 0, 0, 0, 255, 254, 1, 0, 0, 0, 256, 259, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 257, 255, 1, 0, 0, 0, 258, 260, 1, 0, 0, 0, 259, 257, 1, 0, 0, 0, 260, 261, 5, 34, 0, 0, 261, 35, 1, 0, 0, 0, 262, 266, 5, 39, 0, 0, 263, 265, 8, 6, 0, 0, 264, 263, 1, 0, 0, 0, 265, 268, 1, 0, 0, 0, 266, 267, 1, 0, 0, 0, 266, 264, 1, 0, 0, 0, 267, 269, 1, 0, 0, 0, 268, 266, 1, 0, 0, 0, 269, 270, 5, 39, 0, 0, 270, 37, 1, 0, 0, 0, 271, 275, 3, 26, 11, 0, 272, 275, 3, 24, 10, 0, 273, 275, 7, 7, 0, 0, 274, 271, 1, 0, 0, 0, 274, 272, 1, 0, 0, 0, 274, 273, 1, 0, 0, 0, 275, 276, 1, 0, 0, 0, 276, 274, 1, 0, 0, 0, 276, 277, 1, 0, 0, 0, 277, 39, 1, 0, 0, 0, 278, 279, 3, 4, 0, 0, 279, 280, 1, 0, 0, 0, 280, 281, 6, 18, 0, 0, 281, 41, 1, 0, 0, 0, 282, 283, 5, 123, 0, 0, 283, 284, 1, 0, 0, 0, 284, 285, 6, 19, 3, 0, 285, 43, 1, 0, 0, 0, 286, 287, 3, 10, 3, 0, 287, 288, 1, 0, 0, 0, 288, 289, 6, 20, 4, 0, 289, 290, 6, 20, 5, 0, 290, 45, 1, 0, 0, 0, 291, 292, 5, 116, 0, 0, 292, 293, 5, 114, 0, 0, 293, 294, 5, 117, 0, 0, 294, 301, 5, 101, 0, 0, 295, 296, 5, 102, 0, 0, 296, 297, 5, 97, 0, 0, 297, 298, 5, 108, 0, 0, 298, 299, 5, 115, 0, 0, 299, 301, 5, 101, 0, 0, 300, 291, 1, 0, 0, 0, 300, 295, 1, 0, 0, 0, 301, 302, 1, 0, 0, 0, 302, 303, 6, 21, 6, 0, 303, 47, 1, 0, 0, 0, 304, 306, 5, 92, 0, 0, 305, 307, 5, 13, 0, 0, 306, 305, 1, 0, 0, 0, 306, 307, 1, 0, 0, 0, 307, 308, 1, 0, 0, 0, 308, 311, 5, 10, 0, 0, 309, 311, 3, 28, 12, 0, 310, 304, 1, 0, 0, 0, 310, 309, 1, 0, 0, 0, 311, 49, 1, 0, 0, 0, 312, 313, 3, 34, 15, 0, 313, 314, 1, 0, 0, 0, 314, 315, 6, 23, 7, 0, 315, 316, 6, 23, 6, 0, 316, 51, 1, 0, 0, 0, 317, 318, 5, 34, 0, 0, 318, 319, 5, 34, 0, 0, 319, 320, 5, 34, 0, 0, 320, 325, 1, 0, 0, 0, 321, 324, 3, 48, 22, 0, 322, 324, 8, 8, 0, 0, 323, 321, 1, 0, 0, 0, 323, 322, 1, 0, 0, 0, 324, 327, 1, 0, 0, 0, 325, 326, 1, 0, 0, 0, 325, 323, 1, 0, 0, 0, 326, 328, 1, 0, 0, 0, 327, 325, 1, 0, 0, 0, 328, 329, 5, 34, 0, 0, 329, 330, 5, 34, 0, 0, 330, 331, 5, 34, 0, 0, 331, 332, 1, 0, 0, 0, 332, 333, 6, 24, 6, 0, 333, 53, 1, 0, 0, 0, 334, 335, 3, 36, 16, 0, 335, 336, 1, 0, 0, 0, 336, 337, 6, 25, 8, 0, 337, 338, 6, 25, 6, 0, 338, 55, 1, 0, 0, 0, 339, 340, 5, 39, 0, 0, 340, 341, 5, 39, 0, 0, 341, 342, 5, 39, 0, 0, 342, 346, 1, 0, 0, 0, 343, 345, 9, 0, 0, 0, 344, 343, 1, 0, 0, 0, 345, 348, 1, 0, 0, 0, 346, 347, 1, 0, 0, 0, 346, 344, 1, 0, 0, 0, 347, 349, 1, 0, 0, 0, 348, 346, 1, 0, 0, 0, 349, 350, 5, 39, 0, 0, 350, 351, 5, 39, 0, 0, 351, 352, 5, 39, 0, 0, 352, 353, 1, 0, 0, 0, 353, 354, 6, 26, 6, 0, 354, 57, 1, 0, 0, 0, 355, 357, 7, 9, 0, 0, 356, 358, 7, 10, 0, 0, 357, 356, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 359, 1, 0, 0, 0, 359, 360, 3, 60, 28, 0, 360, 59, 1, 0, 0, 0, 361, 367, 3, 24, 10, 0, 362, 366, 3, 24, 10, 0, 363, 364, 5, 95, 0, 0, 364, 366, 3, 24, 10, 0, 365, 362, 1, 0, 0, 0, 365, 363, 1, 0, 0, 0, 366, 369, 1, 0, 0, 0, 367, 365, 1, 0, 0, 0, 367, 368, 1, 0, 0, 0, 368, 61, 1, 0, 0, 0, 369, 367, 1, 0, 0, 0, 370, 371, 5, 46, 0, 0, 371, 372, 3, 60, 28, 0, 372, 63, 1, 0, 0, 0, 373, 379, 3, 78, 37, 0, 374, 380, 3, 58, 27, 0, 375, 377, 3, 62, 29, 0, 376, 378, 3, 58, 27, 0, 377, 376, 1, 0, 0, 0, 377, 378, 1, 0, 0, 0, 378, 380, 1, 0, 0, 0, 379, 374, 1, 0, 0, 0, 379, 375, 1, 0, 0, 0, 380, 381, 1, 0, 0, 0, 381, 382, 6, 30, 6, 0, 382, 65, 1, 0, 0, 0, 383, 385, 7, 10, 0, 0, 384, 383, 1, 0, 0, 0, 384, 385, 1, 0, 0, 0, 385, 386, 1, 0, 0, 0, 386, 387, 5, 105, 0, 0, 387, 388, 5, 110, 0, 0, 388, 389, 5, 102, 0, 0, 389, 390, 1, 0, 0, 0, 390, 391, 6, 31, 6, 0, 391, 67, 1, 0, 0, 0, 392, 394, 7, 10, 0, 0, 393, 392, 1, 0, 0, 0, 393, 394, 1, 0, 0, 0, 394, 395, 1, 0, 0, 0, 395, 396, 5, 110, 0, 0, 396, 397, 5, 97, 0, 0, 397, 398, 5, 110, 0, 0, 398, 399, 1, 0, 0, 0, 399, 400, 6, 32, 6, 0, 400, 69, 1, 0, 0, 0, 401, 404, 7, 11, 0, 0, 402, 404, 3, 24, 10, 0, 403, 401, 1, 0, 0, 0, 403, 402, 1, 0, 0, 0, 404, 71, 1, 0, 0, 0, 405, 406, 7, 12, 0, 0, 406, 73, 1, 0, 0, 0, 407, 408, 7, 13, 0, 0, 408, 75, 1, 0, 0, 0, 409, 410, 7, 14, 0, 0, 410, 77, 1, 0, 0, 0, 411, 413, 7, 10, 0, 0, 412, 411, 1, 0, 0, 0, 412, 413, 1, 0, 0, 0, 413, 423, 1, 0, 0, 0, 414, 424, 3, 24, 10, 0, 415, 419, 3, 72, 34, 0, 416, 420, 3, 24, 10, 0, 417, 418, 5, 95, 0, 0, 418, 420, 3, 24, 10, 0, 419, 416, 1, 0, 0, 0, 419, 417, 1, 0, 0, 0, 420, 421, 1, 0, 0, 0, 421, 419, 1, 0, 0, 0, 421, 422, 1, 0, 0, 0, 422, 424, 1, 0, 0, 0, 423, 414, 1, 0, 0, 0, 423, 415, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 426, 6, 37, 6, 0, 426, 79, 1, 0, 0, 0, 427, 428, 5, 48, 0, 0, 428, 429, 5, 120, 0, 0, 429, 430, 1, 0, 0, 0, 430, 436, 3, 70, 33, 0, 431, 435, 3, 70, 33, 0, 432, 433, 5, 95, 0, 0, 433, 435, 3, 70, 33, 0, 434, 431, 1, 0, 0, 0, 434, 432, 1, 0, 0, 0, 435, 438, 1, 0, 0, 0, 436, 434, 1, 0, 0, 0, 436, 437, 1, 0, 0, 0, 437, 439, 1, 0, 0, 0, 438, 436, 1, 0, 0, 0, 439, 440, 6, 38, 6, 0, 440, 81, 1, 0, 0, 0, 441, 442, 5, 48, 0, 0, 442, 443, 5, 111, 0, 0, 443, 444, 1, 0, 0, 0, 444, 450, 3, 74, 35, 0, 445, 449, 3, 74, 35, 0, 446, 447, 5, 95, 0, 0, 447, 449, 3, 74, 35, 0, 448, 445, 1, 0, 0, 0, 448, 446, 1, 0, 0, 0, 449, 452, 1, 0, 0, 0, 450, 448, 1, 0, 0, 0, 450, 451, 1, 0, 0, 0, 451, 453, 1, 0, 0, 0, 452, 450, 1, 0, 0, 0, 453, 454, 6, 39, 6, 0, 454, 83, 1, 0, 0, 0, 455, 456, 5, 48, 0, 0, 456, 457, 5, 98, 0, 0, 457, 458, 1, 0, 0, 0, 458, 464, 3, 76, 36, 0, 459, 463, 3, 76, 36, 0, 460, 461, 5, 95, 0, 0, 461, 463, 3, 76, 36, 0, 462, 459, 1, 0, 0, 0, 462, 460, 1, 0, 0, 0, 463, 466, 1, 0, 0, 0, 464, 462, 1, 0, 0, 0, 464, 465, 1, 0, 0, 0, 465, 467, 1, 0, 0, 0, 466, 464, 1, 0, 0, 0, 467, 468, 6, 40, 6, 0, 468, 85, 1, 0, 0, 0, 469, 470, 3, 24, 10, 0, 470, 471, 3, 24, 10, 0, 471, 472, 3, 24, 10, 0, 472, 473, 3, 24, 10, 0, 473, 87, 1, 0, 0, 0, 474, 475, 3, 24, 10, 0, 475, 476, 3, 24, 10, 0, 476, 89, 1, 0, 0, 0, 477, 478, 3, 24, 10, 0, 478, 479, 3, 24, 10, 0, 479, 91, 1, 0, 0, 0, 480, 481, 7, 15, 0, 0, 481, 93, 1, 0, 0, 0, 482, 483, 3, 24, 10, 0, 483, 484, 3, 24, 10, 0, 484, 95, 1, 0, 0, 0, 485, 486, 3, 24, 10, 0, 486, 487, 3, 24, 10, 0, 487, 97, 1, 0, 0, 0, 488, 489, 3, 24, 10, 0, 489, 490, 3, 24, 10, 0, 490, 99, 1, 0, 0, 0, 491, 493, 5, 46, 0, 0, 492, 494, 3, 24, 10, 0, 493, 492, 1, 0, 0, 0, 494, 495, 1, 0, 0, 0, 495, 493, 1, 0, 0, 0, 495, 496, 1, 0, 0, 0, 496, 101, 1, 0, 0, 0, 497, 498, 7, 10, 0, 0, 498, 499, 3, 94, 45, 0, 499, 500, 5, 58, 0, 0, 500, 501, 3, 96, 46, 0, 501, 103, 1, 0, 0, 0, 502, 505, 5, 90, 0, 0, 503, 505, 3, 102, 49, 0, 504, 502, 1, 0, 0, 0, 504, 503, 1, 0, 0, 0, 505, 105, 1, 0, 0, 0, 506, 507, 3, 94, 45, 0, 507, 508, 5, 58, 0, 0, 508, 509, 3, 96, 46, 0, 509, 510, 5, 58, 0, 0, 510, 512, 3, 98, 47, 0, 511, 513, 3, 100, 48, 0, 512, 511, 1, 0, 0, 0, 512, 513, 1, 0, 0, 0, 513, 107, 1, 0, 0, 0, 514, 515, 3, 86, 41, 0, 515, 516, 5, 45, 0, 0, 516, 517, 3, 88, 42, 0, 517, 518, 5, 45, 0, 0, 518, 519, 3, 90, 43, 0, 519, 109, 1, 0, 0, 0, 520, 521, 3, 106, 51, 0, 521, 522, 3, 104, 50, 0, 522, 111, 1, 0, 0, 0, 523, 524, 3, 108, 52, 0, 524, 525, 3, 92, 44, 0, 525, 526, 3, 110, 53, 0, 526, 527, 1, 0, 0, 0, 527, 528, 6, 54, 6, 0, 528, 113, 1, 0, 0, 0, 529, 530, 3, 108, 52, 0, 530, 531, 3, 92, 44, 0, 531, 532, 3, 106, 51, 0, 532, 533, 1, 0, 0, 0, 533, 534, 6, 55, 6, 0, 534, 115, 1, 0, 0, 0, 535, 536, 3, 108, 52, 0, 536, 537, 1, 0, 0, 0, 537, 538, 6, 56, 6, 0, 538, 117, 1, 0, 0, 0, 539, 540, 3, 106, 51, 0, 540, 541, 1, 0, 0, 0, 541, 542, 6, 57, 6, 0, 542, 119, 1, 0, 0, 0, 543, 544, 3, 4, 0, 0, 544, 545, 1, 0, 0, 0, 545, 546, 6, 58, 0, 0, 546, 121, 1, 0, 0, 0, 547, 548, 3, 20, 8, 0, 548, 549, 1, 0, 0, 0, 549, 550, 6, 59, 9, 0, 550, 123, 1, 0, 0, 0, 551, 552, 3, 22, 9, 0, 552, 553, 1, 0, 0, 0, 553, 554, 6, 60, 10, 0, 554, 125, 1, 0, 0, 0, 555, 556, 5, 125, 0, 0, 556, 557, 1, 0, 0, 0, 557, 558, 6, 61, 6, 0, 558, 127, 1, 0, 0, 0, 559, 560, 3, 34, 15, 0, 560, 561, 1, 0, 0, 0, 561, 562, 6, 62, 7, 0, 562, 129, 1, 0, 0, 0, 563, 564, 3, 36, 16, 0, 564, 565, 1, 0, 0, 0, 565, 566, 6, 63, 8, 0, 566, 131, 1, 0, 0, 0, 567, 568, 3, 38, 17, 0, 568, 569, 1, 0, 0, 0, 569, 570, 6, 64, 11, 0, 570, 133, 1, 0, 0, 0, 571, 572, 3, 18, 7, 0, 572, 573, 1, 0, 0, 0, 573, 574, 6, 65, 12, 0, 574, 575, 6, 65, 2, 0, 575, 135, 1, 0, 0, 0, 576, 577, 3, 4, 0, 0, 577, 578, 1, 0, 0, 0, 578, 579, 6, 66, 0, 0, 579, 137, 1, 0, 0, 0, 580, 581, 3, 6, 1, 0, 581, 582, 1, 0, 0, 0, 582, 583, 6, 67, 13, 0, 583, 139, 1, 0, 0, 0, 584, 585, 3, 8, 2, 0, 585, 586, 1, 0, 0, 0, 586, 587, 6, 68, 14, 0, 587, 141, 1, 0, 0, 0, 588, 589, 3, 22, 9, 0, 589, 590, 1, 0, 0, 0, 590, 591, 6, 69, 10, 0, 591, 143, 1, 0, 0, 0, 592, 593, 3, 42, 19, 0, 593, 594, 1, 0, 0, 0, 594, 595, 6, 70, 15, 0, 595, 596, 6, 70, 16, 0, 596, 145, 1, 0, 0, 0, 597, 598, 3, 10, 3, 0, 598, 599, 1, 0, 0, 0, 599, 600, 6, 71, 4, 0, 600, 601, 6, 71, 17, 0, 601, 147, 1, 0, 0, 0, 602, 603, 3, 14, 5, 0, 603, 604, 1, 0, 0, 0, 604, 605, 6, 72, 18, 0, 605, 606, 6, 72, 6, 0, 606, 149, 1, 0, 0, 0, 607, 608, 3, 46, 21, 0, 608, 609, 1, 0, 0, 0, 609, 610, 6, 73, 19, 0, 610, 151, 1, 0, 0, 0, 611, 612, 3, 34, 15, 0, 612, 613, 1, 0, 0, 0, 613, 614, 6, 74, 7, 0, 614, 153, 1, 0, 0, 0, 615, 616, 3, 52, 24, 0, 616, 617, 1, 0, 0, 0, 617, 618, 6, 75, 20, 0, 618, 155, 1, 0, 0, 0, 619, 620, 3, 36, 16, 0, 620, 621, 1, 0, 0, 0, 621, 622, 6, 76, 8, 0, 622, 157, 1, 0, 0, 0, 623, 624, 3, 56, 26, 0, 624, 625, 1, 0, 0, 0, 625, 626, 6, 77, 21, 0, 626, 159, 1, 0, 0, 0, 627, 628, 3, 64, 30, 0, 628, 629, 1, 0, 0, 0, 629, 630, 6, 78, 22, 0, 630, 161, 1, 0, 0, 0, 631, 632, 3, 66, 31, 0, 632, 633, 1, 0, 0, 0, 633, 634, 6, 79, 23, 0, 634, 163, 1, 0, 0, 0, 635, 636, 3, 68, 32, 0, 636, 637, 1, 0, 0, 0, 637, 638, 6, 80, 24, 0, 638, 165, 1, 0, 0, 0, 639, 640, 3, 78, 37, 0, 640, 641, 1, 0, 0, 0, 641, 642, 6, 81, 25, 0, 642, 167, 1, 0, 0, 0, 643, 644, 3, 80, 38, 0, 644, 645, 1, 0, 0, 0, 645, 646, 6, 82, 26, 0, 646, 169, 1, 0, 0, 0, 647, 648, 3, 82, 39, 0, 648, 649, 1, 0, 0, 0, 649, 650, 6, 83, 27, 0, 650, 171, 1, 0, 0, 0, 651, 652, 3, 84, 40, 0, 652, 653, 1, 0, 0, 0, 653, 654, 6, 84, 28, 0, 654, 173, 1, 0, 0, 0, 655, 656, 3, 112, 54, 0, 656, 657, 1, 0, 0, 0, 657, 658, 6, 85, 29, 0, 658, 175, 1, 0, 0, 0, 659, 660, 3, 114, 55, 0, 660, 661, 1, 0, 0, 0, 661, 662, 6, 86, 30, 0, 662, 177, 1, 0, 0, 0, 663, 664, 3, 116, 56, 0, 664, 665, 1, 0, 0, 0, 665, 666, 6, 87, 31, 0, 666, 179, 1, 0, 0, 0, 667, 668, 3, 118, 57, 0, 668, 669, 1, 0, 0, 0, 669, 670, 6, 88, 32, 0, 670, 181, 1, 0, 0, 0, 41, 0, 1, 2, 3, 185, 190, 195, 201, 234, 255, 257, 266, 274, 276, 300, 306, 310, 323, 325, 346, 357, 365, 367, 377, 379, 384, 393, 403, 412, 419, 421, 423, 434, 436, 448, 450, 462, 464, 495, 504, 512, 33, 6, 0, 0, 0, 2, 0, 5, 1, 0, 2, 2, 0, 7, 4, 0, 2, 3, 0, 4, 0, 0, 7, 11, 0, 7, 12, 0, 7, 9, 0, 7, 10, 0, 7, 13, 0, 7, 8, 0, 7, 2, 0, 7, 3, 0, 7, 15, 0, 5, 2, 0, 5, 3, 0, 7, 6, 0, 7, 16, 0, 7, 17, 0, 7, 18, 0, 7, 19, 0, 7, 20, 0, 7, 21, 0, 7, 22, 0, 7, 23, 0, 7, 24, 0, 7, 25, 0, 7, 26, 0, 7, 27, 0, 7, 28, 0, 7, 29, 0] \ No newline at end of file +[4, 0, 32, 669, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 1, 0, 4, 0, 184, 8, 0, 11, 0, 12, 0, 185, 1, 0, 1, 0, 1, 1, 3, 1, 191, 8, 1, 1, 1, 4, 1, 194, 8, 1, 11, 1, 12, 1, 195, 1, 2, 1, 2, 5, 2, 200, 8, 2, 10, 2, 12, 2, 203, 9, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 3, 12, 233, 8, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 5, 15, 254, 8, 15, 10, 15, 12, 15, 257, 9, 15, 1, 15, 1, 15, 1, 16, 1, 16, 5, 16, 263, 8, 16, 10, 16, 12, 16, 266, 9, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 4, 17, 273, 8, 17, 11, 17, 12, 17, 274, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 3, 21, 299, 8, 21, 1, 21, 1, 21, 1, 22, 1, 22, 3, 22, 305, 8, 22, 1, 22, 1, 22, 3, 22, 309, 8, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 322, 8, 24, 10, 24, 12, 24, 325, 9, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 5, 26, 343, 8, 26, 10, 26, 12, 26, 346, 9, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 3, 27, 356, 8, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 5, 28, 364, 8, 28, 10, 28, 12, 28, 367, 9, 28, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 3, 30, 376, 8, 30, 3, 30, 378, 8, 30, 1, 30, 1, 30, 1, 31, 3, 31, 383, 8, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 3, 32, 392, 8, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 3, 33, 402, 8, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 36, 1, 36, 1, 37, 3, 37, 411, 8, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 4, 37, 418, 8, 37, 11, 37, 12, 37, 419, 3, 37, 422, 8, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 433, 8, 38, 10, 38, 12, 38, 436, 9, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 5, 39, 447, 8, 39, 10, 39, 12, 39, 450, 9, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 461, 8, 40, 10, 40, 12, 40, 464, 9, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 4, 48, 492, 8, 48, 11, 48, 12, 48, 493, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 3, 50, 503, 8, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 3, 51, 511, 8, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 4, 255, 264, 323, 344, 0, 89, 4, 1, 6, 2, 8, 3, 10, 4, 12, 5, 14, 6, 16, 7, 18, 8, 20, 9, 22, 10, 24, 0, 26, 0, 28, 0, 30, 0, 32, 0, 34, 11, 36, 12, 38, 13, 40, 14, 42, 15, 44, 0, 46, 16, 48, 0, 50, 0, 52, 17, 54, 0, 56, 18, 58, 0, 60, 0, 62, 0, 64, 19, 66, 20, 68, 21, 70, 0, 72, 0, 74, 0, 76, 0, 78, 22, 80, 23, 82, 24, 84, 25, 86, 0, 88, 0, 90, 0, 92, 0, 94, 0, 96, 0, 98, 0, 100, 0, 102, 0, 104, 0, 106, 0, 108, 0, 110, 0, 112, 26, 114, 27, 116, 28, 118, 29, 120, 30, 122, 0, 124, 0, 126, 31, 128, 0, 130, 0, 132, 0, 134, 0, 136, 32, 138, 0, 140, 0, 142, 0, 144, 0, 146, 0, 148, 0, 150, 0, 152, 0, 154, 0, 156, 0, 158, 0, 160, 0, 162, 0, 164, 0, 166, 0, 168, 0, 170, 0, 172, 0, 174, 0, 176, 0, 178, 0, 180, 0, 4, 0, 1, 2, 3, 16, 2, 0, 9, 9, 32, 32, 2, 0, 10, 10, 13, 13, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 47, 47, 92, 92, 98, 98, 102, 102, 110, 110, 114, 114, 116, 116, 3, 0, 10, 10, 34, 34, 92, 92, 2, 0, 10, 10, 39, 39, 2, 0, 45, 45, 95, 95, 2, 0, 34, 34, 92, 92, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 2, 0, 65, 70, 97, 102, 1, 0, 49, 57, 1, 0, 48, 55, 1, 0, 48, 49, 3, 0, 32, 32, 84, 84, 116, 116, 678, 0, 4, 1, 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, 10, 1, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 14, 1, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 18, 1, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 34, 1, 0, 0, 0, 0, 36, 1, 0, 0, 0, 0, 38, 1, 0, 0, 0, 1, 40, 1, 0, 0, 0, 1, 42, 1, 0, 0, 0, 1, 44, 1, 0, 0, 0, 1, 46, 1, 0, 0, 0, 1, 50, 1, 0, 0, 0, 1, 52, 1, 0, 0, 0, 1, 54, 1, 0, 0, 0, 1, 56, 1, 0, 0, 0, 1, 64, 1, 0, 0, 0, 1, 66, 1, 0, 0, 0, 1, 68, 1, 0, 0, 0, 1, 78, 1, 0, 0, 0, 1, 80, 1, 0, 0, 0, 1, 82, 1, 0, 0, 0, 1, 84, 1, 0, 0, 0, 1, 112, 1, 0, 0, 0, 1, 114, 1, 0, 0, 0, 1, 116, 1, 0, 0, 0, 1, 118, 1, 0, 0, 0, 2, 120, 1, 0, 0, 0, 2, 122, 1, 0, 0, 0, 2, 124, 1, 0, 0, 0, 2, 126, 1, 0, 0, 0, 2, 128, 1, 0, 0, 0, 2, 130, 1, 0, 0, 0, 2, 132, 1, 0, 0, 0, 2, 134, 1, 0, 0, 0, 3, 136, 1, 0, 0, 0, 3, 138, 1, 0, 0, 0, 3, 140, 1, 0, 0, 0, 3, 142, 1, 0, 0, 0, 3, 144, 1, 0, 0, 0, 3, 146, 1, 0, 0, 0, 3, 148, 1, 0, 0, 0, 3, 150, 1, 0, 0, 0, 3, 152, 1, 0, 0, 0, 3, 154, 1, 0, 0, 0, 3, 156, 1, 0, 0, 0, 3, 158, 1, 0, 0, 0, 3, 160, 1, 0, 0, 0, 3, 162, 1, 0, 0, 0, 3, 164, 1, 0, 0, 0, 3, 166, 1, 0, 0, 0, 3, 168, 1, 0, 0, 0, 3, 170, 1, 0, 0, 0, 3, 172, 1, 0, 0, 0, 3, 174, 1, 0, 0, 0, 3, 176, 1, 0, 0, 0, 3, 178, 1, 0, 0, 0, 3, 180, 1, 0, 0, 0, 4, 183, 1, 0, 0, 0, 6, 193, 1, 0, 0, 0, 8, 197, 1, 0, 0, 0, 10, 204, 1, 0, 0, 0, 12, 206, 1, 0, 0, 0, 14, 209, 1, 0, 0, 0, 16, 211, 1, 0, 0, 0, 18, 214, 1, 0, 0, 0, 20, 218, 1, 0, 0, 0, 22, 220, 1, 0, 0, 0, 24, 224, 1, 0, 0, 0, 26, 226, 1, 0, 0, 0, 28, 228, 1, 0, 0, 0, 30, 234, 1, 0, 0, 0, 32, 240, 1, 0, 0, 0, 34, 250, 1, 0, 0, 0, 36, 260, 1, 0, 0, 0, 38, 272, 1, 0, 0, 0, 40, 276, 1, 0, 0, 0, 42, 280, 1, 0, 0, 0, 44, 284, 1, 0, 0, 0, 46, 298, 1, 0, 0, 0, 48, 308, 1, 0, 0, 0, 50, 310, 1, 0, 0, 0, 52, 315, 1, 0, 0, 0, 54, 332, 1, 0, 0, 0, 56, 337, 1, 0, 0, 0, 58, 353, 1, 0, 0, 0, 60, 359, 1, 0, 0, 0, 62, 368, 1, 0, 0, 0, 64, 371, 1, 0, 0, 0, 66, 382, 1, 0, 0, 0, 68, 391, 1, 0, 0, 0, 70, 401, 1, 0, 0, 0, 72, 403, 1, 0, 0, 0, 74, 405, 1, 0, 0, 0, 76, 407, 1, 0, 0, 0, 78, 410, 1, 0, 0, 0, 80, 425, 1, 0, 0, 0, 82, 439, 1, 0, 0, 0, 84, 453, 1, 0, 0, 0, 86, 467, 1, 0, 0, 0, 88, 472, 1, 0, 0, 0, 90, 475, 1, 0, 0, 0, 92, 478, 1, 0, 0, 0, 94, 480, 1, 0, 0, 0, 96, 483, 1, 0, 0, 0, 98, 486, 1, 0, 0, 0, 100, 489, 1, 0, 0, 0, 102, 495, 1, 0, 0, 0, 104, 502, 1, 0, 0, 0, 106, 504, 1, 0, 0, 0, 108, 512, 1, 0, 0, 0, 110, 518, 1, 0, 0, 0, 112, 521, 1, 0, 0, 0, 114, 527, 1, 0, 0, 0, 116, 533, 1, 0, 0, 0, 118, 537, 1, 0, 0, 0, 120, 541, 1, 0, 0, 0, 122, 545, 1, 0, 0, 0, 124, 549, 1, 0, 0, 0, 126, 553, 1, 0, 0, 0, 128, 557, 1, 0, 0, 0, 130, 561, 1, 0, 0, 0, 132, 565, 1, 0, 0, 0, 134, 569, 1, 0, 0, 0, 136, 574, 1, 0, 0, 0, 138, 578, 1, 0, 0, 0, 140, 582, 1, 0, 0, 0, 142, 586, 1, 0, 0, 0, 144, 590, 1, 0, 0, 0, 146, 595, 1, 0, 0, 0, 148, 600, 1, 0, 0, 0, 150, 605, 1, 0, 0, 0, 152, 609, 1, 0, 0, 0, 154, 613, 1, 0, 0, 0, 156, 617, 1, 0, 0, 0, 158, 621, 1, 0, 0, 0, 160, 625, 1, 0, 0, 0, 162, 629, 1, 0, 0, 0, 164, 633, 1, 0, 0, 0, 166, 637, 1, 0, 0, 0, 168, 641, 1, 0, 0, 0, 170, 645, 1, 0, 0, 0, 172, 649, 1, 0, 0, 0, 174, 653, 1, 0, 0, 0, 176, 657, 1, 0, 0, 0, 178, 661, 1, 0, 0, 0, 180, 665, 1, 0, 0, 0, 182, 184, 7, 0, 0, 0, 183, 182, 1, 0, 0, 0, 184, 185, 1, 0, 0, 0, 185, 183, 1, 0, 0, 0, 185, 186, 1, 0, 0, 0, 186, 187, 1, 0, 0, 0, 187, 188, 6, 0, 0, 0, 188, 5, 1, 0, 0, 0, 189, 191, 5, 13, 0, 0, 190, 189, 1, 0, 0, 0, 190, 191, 1, 0, 0, 0, 191, 192, 1, 0, 0, 0, 192, 194, 5, 10, 0, 0, 193, 190, 1, 0, 0, 0, 194, 195, 1, 0, 0, 0, 195, 193, 1, 0, 0, 0, 195, 196, 1, 0, 0, 0, 196, 7, 1, 0, 0, 0, 197, 201, 5, 35, 0, 0, 198, 200, 8, 1, 0, 0, 199, 198, 1, 0, 0, 0, 200, 203, 1, 0, 0, 0, 201, 199, 1, 0, 0, 0, 201, 202, 1, 0, 0, 0, 202, 9, 1, 0, 0, 0, 203, 201, 1, 0, 0, 0, 204, 205, 5, 91, 0, 0, 205, 11, 1, 0, 0, 0, 206, 207, 5, 91, 0, 0, 207, 208, 5, 91, 0, 0, 208, 13, 1, 0, 0, 0, 209, 210, 5, 93, 0, 0, 210, 15, 1, 0, 0, 0, 211, 212, 5, 93, 0, 0, 212, 213, 5, 93, 0, 0, 213, 17, 1, 0, 0, 0, 214, 215, 5, 61, 0, 0, 215, 216, 1, 0, 0, 0, 216, 217, 6, 7, 1, 0, 217, 19, 1, 0, 0, 0, 218, 219, 5, 46, 0, 0, 219, 21, 1, 0, 0, 0, 220, 221, 5, 44, 0, 0, 221, 222, 1, 0, 0, 0, 222, 223, 6, 9, 0, 0, 223, 23, 1, 0, 0, 0, 224, 225, 7, 2, 0, 0, 225, 25, 1, 0, 0, 0, 226, 227, 7, 3, 0, 0, 227, 27, 1, 0, 0, 0, 228, 232, 5, 92, 0, 0, 229, 233, 7, 4, 0, 0, 230, 233, 3, 30, 13, 0, 231, 233, 3, 32, 14, 0, 232, 229, 1, 0, 0, 0, 232, 230, 1, 0, 0, 0, 232, 231, 1, 0, 0, 0, 233, 29, 1, 0, 0, 0, 234, 235, 5, 117, 0, 0, 235, 236, 3, 70, 33, 0, 236, 237, 3, 70, 33, 0, 237, 238, 3, 70, 33, 0, 238, 239, 3, 70, 33, 0, 239, 31, 1, 0, 0, 0, 240, 241, 5, 85, 0, 0, 241, 242, 3, 70, 33, 0, 242, 243, 3, 70, 33, 0, 243, 244, 3, 70, 33, 0, 244, 245, 3, 70, 33, 0, 245, 246, 3, 70, 33, 0, 246, 247, 3, 70, 33, 0, 247, 248, 3, 70, 33, 0, 248, 249, 3, 70, 33, 0, 249, 33, 1, 0, 0, 0, 250, 255, 5, 34, 0, 0, 251, 254, 3, 28, 12, 0, 252, 254, 8, 5, 0, 0, 253, 251, 1, 0, 0, 0, 253, 252, 1, 0, 0, 0, 254, 257, 1, 0, 0, 0, 255, 256, 1, 0, 0, 0, 255, 253, 1, 0, 0, 0, 256, 258, 1, 0, 0, 0, 257, 255, 1, 0, 0, 0, 258, 259, 5, 34, 0, 0, 259, 35, 1, 0, 0, 0, 260, 264, 5, 39, 0, 0, 261, 263, 8, 6, 0, 0, 262, 261, 1, 0, 0, 0, 263, 266, 1, 0, 0, 0, 264, 265, 1, 0, 0, 0, 264, 262, 1, 0, 0, 0, 265, 267, 1, 0, 0, 0, 266, 264, 1, 0, 0, 0, 267, 268, 5, 39, 0, 0, 268, 37, 1, 0, 0, 0, 269, 273, 3, 26, 11, 0, 270, 273, 3, 24, 10, 0, 271, 273, 7, 7, 0, 0, 272, 269, 1, 0, 0, 0, 272, 270, 1, 0, 0, 0, 272, 271, 1, 0, 0, 0, 273, 274, 1, 0, 0, 0, 274, 272, 1, 0, 0, 0, 274, 275, 1, 0, 0, 0, 275, 39, 1, 0, 0, 0, 276, 277, 3, 4, 0, 0, 277, 278, 1, 0, 0, 0, 278, 279, 6, 18, 0, 0, 279, 41, 1, 0, 0, 0, 280, 281, 5, 123, 0, 0, 281, 282, 1, 0, 0, 0, 282, 283, 6, 19, 2, 0, 283, 43, 1, 0, 0, 0, 284, 285, 3, 10, 3, 0, 285, 286, 1, 0, 0, 0, 286, 287, 6, 20, 3, 0, 287, 288, 6, 20, 4, 0, 288, 45, 1, 0, 0, 0, 289, 290, 5, 116, 0, 0, 290, 291, 5, 114, 0, 0, 291, 292, 5, 117, 0, 0, 292, 299, 5, 101, 0, 0, 293, 294, 5, 102, 0, 0, 294, 295, 5, 97, 0, 0, 295, 296, 5, 108, 0, 0, 296, 297, 5, 115, 0, 0, 297, 299, 5, 101, 0, 0, 298, 289, 1, 0, 0, 0, 298, 293, 1, 0, 0, 0, 299, 300, 1, 0, 0, 0, 300, 301, 6, 21, 5, 0, 301, 47, 1, 0, 0, 0, 302, 304, 5, 92, 0, 0, 303, 305, 5, 13, 0, 0, 304, 303, 1, 0, 0, 0, 304, 305, 1, 0, 0, 0, 305, 306, 1, 0, 0, 0, 306, 309, 5, 10, 0, 0, 307, 309, 3, 28, 12, 0, 308, 302, 1, 0, 0, 0, 308, 307, 1, 0, 0, 0, 309, 49, 1, 0, 0, 0, 310, 311, 3, 34, 15, 0, 311, 312, 1, 0, 0, 0, 312, 313, 6, 23, 6, 0, 313, 314, 6, 23, 5, 0, 314, 51, 1, 0, 0, 0, 315, 316, 5, 34, 0, 0, 316, 317, 5, 34, 0, 0, 317, 318, 5, 34, 0, 0, 318, 323, 1, 0, 0, 0, 319, 322, 3, 48, 22, 0, 320, 322, 8, 8, 0, 0, 321, 319, 1, 0, 0, 0, 321, 320, 1, 0, 0, 0, 322, 325, 1, 0, 0, 0, 323, 324, 1, 0, 0, 0, 323, 321, 1, 0, 0, 0, 324, 326, 1, 0, 0, 0, 325, 323, 1, 0, 0, 0, 326, 327, 5, 34, 0, 0, 327, 328, 5, 34, 0, 0, 328, 329, 5, 34, 0, 0, 329, 330, 1, 0, 0, 0, 330, 331, 6, 24, 5, 0, 331, 53, 1, 0, 0, 0, 332, 333, 3, 36, 16, 0, 333, 334, 1, 0, 0, 0, 334, 335, 6, 25, 7, 0, 335, 336, 6, 25, 5, 0, 336, 55, 1, 0, 0, 0, 337, 338, 5, 39, 0, 0, 338, 339, 5, 39, 0, 0, 339, 340, 5, 39, 0, 0, 340, 344, 1, 0, 0, 0, 341, 343, 9, 0, 0, 0, 342, 341, 1, 0, 0, 0, 343, 346, 1, 0, 0, 0, 344, 345, 1, 0, 0, 0, 344, 342, 1, 0, 0, 0, 345, 347, 1, 0, 0, 0, 346, 344, 1, 0, 0, 0, 347, 348, 5, 39, 0, 0, 348, 349, 5, 39, 0, 0, 349, 350, 5, 39, 0, 0, 350, 351, 1, 0, 0, 0, 351, 352, 6, 26, 5, 0, 352, 57, 1, 0, 0, 0, 353, 355, 7, 9, 0, 0, 354, 356, 7, 10, 0, 0, 355, 354, 1, 0, 0, 0, 355, 356, 1, 0, 0, 0, 356, 357, 1, 0, 0, 0, 357, 358, 3, 60, 28, 0, 358, 59, 1, 0, 0, 0, 359, 365, 3, 24, 10, 0, 360, 364, 3, 24, 10, 0, 361, 362, 5, 95, 0, 0, 362, 364, 3, 24, 10, 0, 363, 360, 1, 0, 0, 0, 363, 361, 1, 0, 0, 0, 364, 367, 1, 0, 0, 0, 365, 363, 1, 0, 0, 0, 365, 366, 1, 0, 0, 0, 366, 61, 1, 0, 0, 0, 367, 365, 1, 0, 0, 0, 368, 369, 5, 46, 0, 0, 369, 370, 3, 60, 28, 0, 370, 63, 1, 0, 0, 0, 371, 377, 3, 78, 37, 0, 372, 378, 3, 58, 27, 0, 373, 375, 3, 62, 29, 0, 374, 376, 3, 58, 27, 0, 375, 374, 1, 0, 0, 0, 375, 376, 1, 0, 0, 0, 376, 378, 1, 0, 0, 0, 377, 372, 1, 0, 0, 0, 377, 373, 1, 0, 0, 0, 378, 379, 1, 0, 0, 0, 379, 380, 6, 30, 5, 0, 380, 65, 1, 0, 0, 0, 381, 383, 7, 10, 0, 0, 382, 381, 1, 0, 0, 0, 382, 383, 1, 0, 0, 0, 383, 384, 1, 0, 0, 0, 384, 385, 5, 105, 0, 0, 385, 386, 5, 110, 0, 0, 386, 387, 5, 102, 0, 0, 387, 388, 1, 0, 0, 0, 388, 389, 6, 31, 5, 0, 389, 67, 1, 0, 0, 0, 390, 392, 7, 10, 0, 0, 391, 390, 1, 0, 0, 0, 391, 392, 1, 0, 0, 0, 392, 393, 1, 0, 0, 0, 393, 394, 5, 110, 0, 0, 394, 395, 5, 97, 0, 0, 395, 396, 5, 110, 0, 0, 396, 397, 1, 0, 0, 0, 397, 398, 6, 32, 5, 0, 398, 69, 1, 0, 0, 0, 399, 402, 7, 11, 0, 0, 400, 402, 3, 24, 10, 0, 401, 399, 1, 0, 0, 0, 401, 400, 1, 0, 0, 0, 402, 71, 1, 0, 0, 0, 403, 404, 7, 12, 0, 0, 404, 73, 1, 0, 0, 0, 405, 406, 7, 13, 0, 0, 406, 75, 1, 0, 0, 0, 407, 408, 7, 14, 0, 0, 408, 77, 1, 0, 0, 0, 409, 411, 7, 10, 0, 0, 410, 409, 1, 0, 0, 0, 410, 411, 1, 0, 0, 0, 411, 421, 1, 0, 0, 0, 412, 422, 3, 24, 10, 0, 413, 417, 3, 72, 34, 0, 414, 418, 3, 24, 10, 0, 415, 416, 5, 95, 0, 0, 416, 418, 3, 24, 10, 0, 417, 414, 1, 0, 0, 0, 417, 415, 1, 0, 0, 0, 418, 419, 1, 0, 0, 0, 419, 417, 1, 0, 0, 0, 419, 420, 1, 0, 0, 0, 420, 422, 1, 0, 0, 0, 421, 412, 1, 0, 0, 0, 421, 413, 1, 0, 0, 0, 422, 423, 1, 0, 0, 0, 423, 424, 6, 37, 5, 0, 424, 79, 1, 0, 0, 0, 425, 426, 5, 48, 0, 0, 426, 427, 5, 120, 0, 0, 427, 428, 1, 0, 0, 0, 428, 434, 3, 70, 33, 0, 429, 433, 3, 70, 33, 0, 430, 431, 5, 95, 0, 0, 431, 433, 3, 70, 33, 0, 432, 429, 1, 0, 0, 0, 432, 430, 1, 0, 0, 0, 433, 436, 1, 0, 0, 0, 434, 432, 1, 0, 0, 0, 434, 435, 1, 0, 0, 0, 435, 437, 1, 0, 0, 0, 436, 434, 1, 0, 0, 0, 437, 438, 6, 38, 5, 0, 438, 81, 1, 0, 0, 0, 439, 440, 5, 48, 0, 0, 440, 441, 5, 111, 0, 0, 441, 442, 1, 0, 0, 0, 442, 448, 3, 74, 35, 0, 443, 447, 3, 74, 35, 0, 444, 445, 5, 95, 0, 0, 445, 447, 3, 74, 35, 0, 446, 443, 1, 0, 0, 0, 446, 444, 1, 0, 0, 0, 447, 450, 1, 0, 0, 0, 448, 446, 1, 0, 0, 0, 448, 449, 1, 0, 0, 0, 449, 451, 1, 0, 0, 0, 450, 448, 1, 0, 0, 0, 451, 452, 6, 39, 5, 0, 452, 83, 1, 0, 0, 0, 453, 454, 5, 48, 0, 0, 454, 455, 5, 98, 0, 0, 455, 456, 1, 0, 0, 0, 456, 462, 3, 76, 36, 0, 457, 461, 3, 76, 36, 0, 458, 459, 5, 95, 0, 0, 459, 461, 3, 76, 36, 0, 460, 457, 1, 0, 0, 0, 460, 458, 1, 0, 0, 0, 461, 464, 1, 0, 0, 0, 462, 460, 1, 0, 0, 0, 462, 463, 1, 0, 0, 0, 463, 465, 1, 0, 0, 0, 464, 462, 1, 0, 0, 0, 465, 466, 6, 40, 5, 0, 466, 85, 1, 0, 0, 0, 467, 468, 3, 24, 10, 0, 468, 469, 3, 24, 10, 0, 469, 470, 3, 24, 10, 0, 470, 471, 3, 24, 10, 0, 471, 87, 1, 0, 0, 0, 472, 473, 3, 24, 10, 0, 473, 474, 3, 24, 10, 0, 474, 89, 1, 0, 0, 0, 475, 476, 3, 24, 10, 0, 476, 477, 3, 24, 10, 0, 477, 91, 1, 0, 0, 0, 478, 479, 7, 15, 0, 0, 479, 93, 1, 0, 0, 0, 480, 481, 3, 24, 10, 0, 481, 482, 3, 24, 10, 0, 482, 95, 1, 0, 0, 0, 483, 484, 3, 24, 10, 0, 484, 485, 3, 24, 10, 0, 485, 97, 1, 0, 0, 0, 486, 487, 3, 24, 10, 0, 487, 488, 3, 24, 10, 0, 488, 99, 1, 0, 0, 0, 489, 491, 5, 46, 0, 0, 490, 492, 3, 24, 10, 0, 491, 490, 1, 0, 0, 0, 492, 493, 1, 0, 0, 0, 493, 491, 1, 0, 0, 0, 493, 494, 1, 0, 0, 0, 494, 101, 1, 0, 0, 0, 495, 496, 7, 10, 0, 0, 496, 497, 3, 94, 45, 0, 497, 498, 5, 58, 0, 0, 498, 499, 3, 96, 46, 0, 499, 103, 1, 0, 0, 0, 500, 503, 5, 90, 0, 0, 501, 503, 3, 102, 49, 0, 502, 500, 1, 0, 0, 0, 502, 501, 1, 0, 0, 0, 503, 105, 1, 0, 0, 0, 504, 505, 3, 94, 45, 0, 505, 506, 5, 58, 0, 0, 506, 507, 3, 96, 46, 0, 507, 508, 5, 58, 0, 0, 508, 510, 3, 98, 47, 0, 509, 511, 3, 100, 48, 0, 510, 509, 1, 0, 0, 0, 510, 511, 1, 0, 0, 0, 511, 107, 1, 0, 0, 0, 512, 513, 3, 86, 41, 0, 513, 514, 5, 45, 0, 0, 514, 515, 3, 88, 42, 0, 515, 516, 5, 45, 0, 0, 516, 517, 3, 90, 43, 0, 517, 109, 1, 0, 0, 0, 518, 519, 3, 106, 51, 0, 519, 520, 3, 104, 50, 0, 520, 111, 1, 0, 0, 0, 521, 522, 3, 108, 52, 0, 522, 523, 3, 92, 44, 0, 523, 524, 3, 110, 53, 0, 524, 525, 1, 0, 0, 0, 525, 526, 6, 54, 5, 0, 526, 113, 1, 0, 0, 0, 527, 528, 3, 108, 52, 0, 528, 529, 3, 92, 44, 0, 529, 530, 3, 106, 51, 0, 530, 531, 1, 0, 0, 0, 531, 532, 6, 55, 5, 0, 532, 115, 1, 0, 0, 0, 533, 534, 3, 108, 52, 0, 534, 535, 1, 0, 0, 0, 535, 536, 6, 56, 5, 0, 536, 117, 1, 0, 0, 0, 537, 538, 3, 106, 51, 0, 538, 539, 1, 0, 0, 0, 539, 540, 6, 57, 5, 0, 540, 119, 1, 0, 0, 0, 541, 542, 3, 4, 0, 0, 542, 543, 1, 0, 0, 0, 543, 544, 6, 58, 0, 0, 544, 121, 1, 0, 0, 0, 545, 546, 3, 20, 8, 0, 546, 547, 1, 0, 0, 0, 547, 548, 6, 59, 8, 0, 548, 123, 1, 0, 0, 0, 549, 550, 3, 22, 9, 0, 550, 551, 1, 0, 0, 0, 551, 552, 6, 60, 9, 0, 552, 125, 1, 0, 0, 0, 553, 554, 5, 125, 0, 0, 554, 555, 1, 0, 0, 0, 555, 556, 6, 61, 5, 0, 556, 127, 1, 0, 0, 0, 557, 558, 3, 34, 15, 0, 558, 559, 1, 0, 0, 0, 559, 560, 6, 62, 6, 0, 560, 129, 1, 0, 0, 0, 561, 562, 3, 36, 16, 0, 562, 563, 1, 0, 0, 0, 563, 564, 6, 63, 7, 0, 564, 131, 1, 0, 0, 0, 565, 566, 3, 38, 17, 0, 566, 567, 1, 0, 0, 0, 567, 568, 6, 64, 10, 0, 568, 133, 1, 0, 0, 0, 569, 570, 3, 18, 7, 0, 570, 571, 1, 0, 0, 0, 571, 572, 6, 65, 11, 0, 572, 573, 6, 65, 1, 0, 573, 135, 1, 0, 0, 0, 574, 575, 3, 4, 0, 0, 575, 576, 1, 0, 0, 0, 576, 577, 6, 66, 0, 0, 577, 137, 1, 0, 0, 0, 578, 579, 3, 6, 1, 0, 579, 580, 1, 0, 0, 0, 580, 581, 6, 67, 12, 0, 581, 139, 1, 0, 0, 0, 582, 583, 3, 8, 2, 0, 583, 584, 1, 0, 0, 0, 584, 585, 6, 68, 13, 0, 585, 141, 1, 0, 0, 0, 586, 587, 3, 22, 9, 0, 587, 588, 1, 0, 0, 0, 588, 589, 6, 69, 9, 0, 589, 143, 1, 0, 0, 0, 590, 591, 3, 42, 19, 0, 591, 592, 1, 0, 0, 0, 592, 593, 6, 70, 14, 0, 593, 594, 6, 70, 15, 0, 594, 145, 1, 0, 0, 0, 595, 596, 3, 10, 3, 0, 596, 597, 1, 0, 0, 0, 597, 598, 6, 71, 3, 0, 598, 599, 6, 71, 16, 0, 599, 147, 1, 0, 0, 0, 600, 601, 3, 14, 5, 0, 601, 602, 1, 0, 0, 0, 602, 603, 6, 72, 17, 0, 603, 604, 6, 72, 5, 0, 604, 149, 1, 0, 0, 0, 605, 606, 3, 46, 21, 0, 606, 607, 1, 0, 0, 0, 607, 608, 6, 73, 18, 0, 608, 151, 1, 0, 0, 0, 609, 610, 3, 34, 15, 0, 610, 611, 1, 0, 0, 0, 611, 612, 6, 74, 6, 0, 612, 153, 1, 0, 0, 0, 613, 614, 3, 52, 24, 0, 614, 615, 1, 0, 0, 0, 615, 616, 6, 75, 19, 0, 616, 155, 1, 0, 0, 0, 617, 618, 3, 36, 16, 0, 618, 619, 1, 0, 0, 0, 619, 620, 6, 76, 7, 0, 620, 157, 1, 0, 0, 0, 621, 622, 3, 56, 26, 0, 622, 623, 1, 0, 0, 0, 623, 624, 6, 77, 20, 0, 624, 159, 1, 0, 0, 0, 625, 626, 3, 64, 30, 0, 626, 627, 1, 0, 0, 0, 627, 628, 6, 78, 21, 0, 628, 161, 1, 0, 0, 0, 629, 630, 3, 66, 31, 0, 630, 631, 1, 0, 0, 0, 631, 632, 6, 79, 22, 0, 632, 163, 1, 0, 0, 0, 633, 634, 3, 68, 32, 0, 634, 635, 1, 0, 0, 0, 635, 636, 6, 80, 23, 0, 636, 165, 1, 0, 0, 0, 637, 638, 3, 78, 37, 0, 638, 639, 1, 0, 0, 0, 639, 640, 6, 81, 24, 0, 640, 167, 1, 0, 0, 0, 641, 642, 3, 80, 38, 0, 642, 643, 1, 0, 0, 0, 643, 644, 6, 82, 25, 0, 644, 169, 1, 0, 0, 0, 645, 646, 3, 82, 39, 0, 646, 647, 1, 0, 0, 0, 647, 648, 6, 83, 26, 0, 648, 171, 1, 0, 0, 0, 649, 650, 3, 84, 40, 0, 650, 651, 1, 0, 0, 0, 651, 652, 6, 84, 27, 0, 652, 173, 1, 0, 0, 0, 653, 654, 3, 112, 54, 0, 654, 655, 1, 0, 0, 0, 655, 656, 6, 85, 28, 0, 656, 175, 1, 0, 0, 0, 657, 658, 3, 114, 55, 0, 658, 659, 1, 0, 0, 0, 659, 660, 6, 86, 29, 0, 660, 177, 1, 0, 0, 0, 661, 662, 3, 116, 56, 0, 662, 663, 1, 0, 0, 0, 663, 664, 6, 87, 30, 0, 664, 179, 1, 0, 0, 0, 665, 666, 3, 118, 57, 0, 666, 667, 1, 0, 0, 0, 667, 668, 6, 88, 31, 0, 668, 181, 1, 0, 0, 0, 41, 0, 1, 2, 3, 185, 190, 195, 201, 232, 253, 255, 264, 272, 274, 298, 304, 308, 321, 323, 344, 355, 363, 365, 375, 377, 382, 391, 401, 410, 417, 419, 421, 432, 434, 446, 448, 460, 462, 493, 502, 510, 32, 6, 0, 0, 5, 1, 0, 2, 2, 0, 7, 4, 0, 2, 3, 0, 4, 0, 0, 7, 11, 0, 7, 12, 0, 7, 9, 0, 7, 10, 0, 7, 13, 0, 7, 8, 0, 7, 2, 0, 7, 3, 0, 7, 15, 0, 5, 2, 0, 5, 3, 0, 7, 6, 0, 7, 16, 0, 7, 17, 0, 7, 18, 0, 7, 19, 0, 7, 20, 0, 7, 21, 0, 7, 22, 0, 7, 23, 0, 7, 24, 0, 7, 25, 0, 7, 26, 0, 7, 27, 0, 7, 28, 0, 7, 29, 0] \ No newline at end of file diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.java index 2a739910ab1..79166aed4f1 100644 --- a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.java +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlLexer.java @@ -37,12 +37,10 @@ public class TomlLexer extends Lexer { FLOAT=19, INF=20, NAN=21, DEC_INT=22, HEX_INT=23, OCT_INT=24, BIN_INT=25, OFFSET_DATE_TIME=26, LOCAL_DATE_TIME=27, LOCAL_DATE=28, LOCAL_TIME=29, INLINE_TABLE_WS=30, R_BRACE=31, ARRAY_WS=32; - public static final int - COMMENTS_CHANNEL=2; public static final int SIMPLE_VALUE_MODE=1, INLINE_TABLE_MODE=2, ARRAY_MODE=3; public static String[] channelNames = { - "DEFAULT_TOKEN_CHANNEL", "HIDDEN", "COMMENTS_CHANNEL" + "DEFAULT_TOKEN_CHANNEL", "HIDDEN" }; public static String[] modeNames = { @@ -150,7 +148,7 @@ public TomlLexer(CharStream input) { public ATN getATN() { return _ATN; } public static final String _serializedATN = - "\u0004\u0000 \u029f\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ + "\u0004\u0000 \u029d\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff"+ "\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001\u0007\u0001\u0002"+ "\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004\u0007\u0004\u0002"+ "\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007\u0007\u0007\u0002"+ @@ -176,404 +174,403 @@ public TomlLexer(CharStream input) { "\u00b8\b\u0000\u000b\u0000\f\u0000\u00b9\u0001\u0000\u0001\u0000\u0001"+ "\u0001\u0003\u0001\u00bf\b\u0001\u0001\u0001\u0004\u0001\u00c2\b\u0001"+ "\u000b\u0001\f\u0001\u00c3\u0001\u0002\u0001\u0002\u0005\u0002\u00c8\b"+ - "\u0002\n\u0002\f\u0002\u00cb\t\u0002\u0001\u0002\u0001\u0002\u0001\u0003"+ - "\u0001\u0003\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005"+ - "\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007"+ - "\u0001\u0007\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\n\u0001"+ - "\n\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f\u0001\f\u0003\f\u00eb"+ - "\b\f\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\u000e\u0001"+ - "\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001"+ - "\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001\u000f\u0005"+ - "\u000f\u0100\b\u000f\n\u000f\f\u000f\u0103\t\u000f\u0001\u000f\u0001\u000f"+ - "\u0001\u0010\u0001\u0010\u0005\u0010\u0109\b\u0010\n\u0010\f\u0010\u010c"+ - "\t\u0010\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0004"+ - "\u0011\u0113\b\u0011\u000b\u0011\f\u0011\u0114\u0001\u0012\u0001\u0012"+ - "\u0001\u0012\u0001\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013"+ - "\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015"+ - "\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015"+ - "\u0001\u0015\u0001\u0015\u0003\u0015\u012d\b\u0015\u0001\u0015\u0001\u0015"+ - "\u0001\u0016\u0001\u0016\u0003\u0016\u0133\b\u0016\u0001\u0016\u0001\u0016"+ - "\u0003\u0016\u0137\b\u0016\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017"+ - "\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018"+ - "\u0001\u0018\u0005\u0018\u0144\b\u0018\n\u0018\f\u0018\u0147\t\u0018\u0001"+ - "\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001"+ - "\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u001a\u0001"+ - "\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0005\u001a\u0159\b\u001a\n"+ - "\u001a\f\u001a\u015c\t\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001"+ - "\u001a\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0003\u001b\u0166"+ - "\b\u001b\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001\u001c\u0001"+ - "\u001c\u0005\u001c\u016e\b\u001c\n\u001c\f\u001c\u0171\t\u001c\u0001\u001d"+ - "\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e"+ - "\u0003\u001e\u017a\b\u001e\u0003\u001e\u017c\b\u001e\u0001\u001e\u0001"+ - "\u001e\u0001\u001f\u0003\u001f\u0181\b\u001f\u0001\u001f\u0001\u001f\u0001"+ - "\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001 \u0003 \u018a\b \u0001"+ - " \u0001 \u0001 \u0001 \u0001 \u0001 \u0001!\u0001!\u0003!\u0194\b!\u0001"+ - "\"\u0001\"\u0001#\u0001#\u0001$\u0001$\u0001%\u0003%\u019d\b%\u0001%\u0001"+ - "%\u0001%\u0001%\u0001%\u0004%\u01a4\b%\u000b%\f%\u01a5\u0003%\u01a8\b"+ - "%\u0001%\u0001%\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0001&\u0005"+ - "&\u01b3\b&\n&\f&\u01b6\t&\u0001&\u0001&\u0001\'\u0001\'\u0001\'\u0001"+ - "\'\u0001\'\u0001\'\u0001\'\u0005\'\u01c1\b\'\n\'\f\'\u01c4\t\'\u0001\'"+ - "\u0001\'\u0001(\u0001(\u0001(\u0001(\u0001(\u0001(\u0001(\u0005(\u01cf"+ - "\b(\n(\f(\u01d2\t(\u0001(\u0001(\u0001)\u0001)\u0001)\u0001)\u0001)\u0001"+ - "*\u0001*\u0001*\u0001+\u0001+\u0001+\u0001,\u0001,\u0001-\u0001-\u0001"+ - "-\u0001.\u0001.\u0001.\u0001/\u0001/\u0001/\u00010\u00010\u00040\u01ee"+ - "\b0\u000b0\f0\u01ef\u00011\u00011\u00011\u00011\u00011\u00012\u00012\u0003"+ - "2\u01f9\b2\u00013\u00013\u00013\u00013\u00013\u00013\u00033\u0201\b3\u0001"+ - "4\u00014\u00014\u00014\u00014\u00014\u00015\u00015\u00015\u00016\u0001"+ - "6\u00016\u00016\u00016\u00016\u00017\u00017\u00017\u00017\u00017\u0001"+ - "7\u00018\u00018\u00018\u00018\u00019\u00019\u00019\u00019\u0001:\u0001"+ - ":\u0001:\u0001:\u0001;\u0001;\u0001;\u0001;\u0001<\u0001<\u0001<\u0001"+ - "<\u0001=\u0001=\u0001=\u0001=\u0001>\u0001>\u0001>\u0001>\u0001?\u0001"+ - "?\u0001?\u0001?\u0001@\u0001@\u0001@\u0001@\u0001A\u0001A\u0001A\u0001"+ - "A\u0001A\u0001B\u0001B\u0001B\u0001B\u0001C\u0001C\u0001C\u0001C\u0001"+ - "D\u0001D\u0001D\u0001D\u0001E\u0001E\u0001E\u0001E\u0001F\u0001F\u0001"+ - "F\u0001F\u0001F\u0001G\u0001G\u0001G\u0001G\u0001G\u0001H\u0001H\u0001"+ - "H\u0001H\u0001H\u0001I\u0001I\u0001I\u0001I\u0001J\u0001J\u0001J\u0001"+ - "J\u0001K\u0001K\u0001K\u0001K\u0001L\u0001L\u0001L\u0001L\u0001M\u0001"+ - "M\u0001M\u0001M\u0001N\u0001N\u0001N\u0001N\u0001O\u0001O\u0001O\u0001"+ - "O\u0001P\u0001P\u0001P\u0001P\u0001Q\u0001Q\u0001Q\u0001Q\u0001R\u0001"+ - "R\u0001R\u0001R\u0001S\u0001S\u0001S\u0001S\u0001T\u0001T\u0001T\u0001"+ - "T\u0001U\u0001U\u0001U\u0001U\u0001V\u0001V\u0001V\u0001V\u0001W\u0001"+ - "W\u0001W\u0001W\u0001X\u0001X\u0001X\u0001X\u0004\u0101\u010a\u0145\u015a"+ - "\u0000Y\u0004\u0001\u0006\u0002\b\u0003\n\u0004\f\u0005\u000e\u0006\u0010"+ - "\u0007\u0012\b\u0014\t\u0016\n\u0018\u0000\u001a\u0000\u001c\u0000\u001e"+ - "\u0000 \u0000\"\u000b$\f&\r(\u000e*\u000f,\u0000.\u00100\u00002\u0000"+ - "4\u00116\u00008\u0012:\u0000<\u0000>\u0000@\u0013B\u0014D\u0015F\u0000"+ - "H\u0000J\u0000L\u0000N\u0016P\u0017R\u0018T\u0019V\u0000X\u0000Z\u0000"+ - "\\\u0000^\u0000`\u0000b\u0000d\u0000f\u0000h\u0000j\u0000l\u0000n\u0000"+ - "p\u001ar\u001bt\u001cv\u001dx\u001ez\u0000|\u0000~\u001f\u0080\u0000\u0082"+ - "\u0000\u0084\u0000\u0086\u0000\u0088 \u008a\u0000\u008c\u0000\u008e\u0000"+ - "\u0090\u0000\u0092\u0000\u0094\u0000\u0096\u0000\u0098\u0000\u009a\u0000"+ - "\u009c\u0000\u009e\u0000\u00a0\u0000\u00a2\u0000\u00a4\u0000\u00a6\u0000"+ - "\u00a8\u0000\u00aa\u0000\u00ac\u0000\u00ae\u0000\u00b0\u0000\u00b2\u0000"+ - "\u00b4\u0000\u0004\u0000\u0001\u0002\u0003\u0010\u0002\u0000\t\t \u0002"+ - "\u0000\n\n\r\r\u0001\u000009\u0002\u0000AZaz\b\u0000\"\"//\\\\bbffnnr"+ - "rtt\u0003\u0000\n\n\"\"\\\\\u0002\u0000\n\n\'\'\u0002\u0000--__\u0002"+ - "\u0000\"\"\\\\\u0002\u0000EEee\u0002\u0000++--\u0002\u0000AFaf\u0001\u0000"+ - "19\u0001\u000007\u0001\u000001\u0003\u0000 TTtt\u02a8\u0000\u0004\u0001"+ - "\u0000\u0000\u0000\u0000\u0006\u0001\u0000\u0000\u0000\u0000\b\u0001\u0000"+ - "\u0000\u0000\u0000\n\u0001\u0000\u0000\u0000\u0000\f\u0001\u0000\u0000"+ - "\u0000\u0000\u000e\u0001\u0000\u0000\u0000\u0000\u0010\u0001\u0000\u0000"+ - "\u0000\u0000\u0012\u0001\u0000\u0000\u0000\u0000\u0014\u0001\u0000\u0000"+ - "\u0000\u0000\u0016\u0001\u0000\u0000\u0000\u0000\"\u0001\u0000\u0000\u0000"+ - "\u0000$\u0001\u0000\u0000\u0000\u0000&\u0001\u0000\u0000\u0000\u0001("+ - "\u0001\u0000\u0000\u0000\u0001*\u0001\u0000\u0000\u0000\u0001,\u0001\u0000"+ - "\u0000\u0000\u0001.\u0001\u0000\u0000\u0000\u00012\u0001\u0000\u0000\u0000"+ - "\u00014\u0001\u0000\u0000\u0000\u00016\u0001\u0000\u0000\u0000\u00018"+ - "\u0001\u0000\u0000\u0000\u0001@\u0001\u0000\u0000\u0000\u0001B\u0001\u0000"+ - "\u0000\u0000\u0001D\u0001\u0000\u0000\u0000\u0001N\u0001\u0000\u0000\u0000"+ - "\u0001P\u0001\u0000\u0000\u0000\u0001R\u0001\u0000\u0000\u0000\u0001T"+ - "\u0001\u0000\u0000\u0000\u0001p\u0001\u0000\u0000\u0000\u0001r\u0001\u0000"+ - "\u0000\u0000\u0001t\u0001\u0000\u0000\u0000\u0001v\u0001\u0000\u0000\u0000"+ - "\u0002x\u0001\u0000\u0000\u0000\u0002z\u0001\u0000\u0000\u0000\u0002|"+ - "\u0001\u0000\u0000\u0000\u0002~\u0001\u0000\u0000\u0000\u0002\u0080\u0001"+ - "\u0000\u0000\u0000\u0002\u0082\u0001\u0000\u0000\u0000\u0002\u0084\u0001"+ - "\u0000\u0000\u0000\u0002\u0086\u0001\u0000\u0000\u0000\u0003\u0088\u0001"+ - "\u0000\u0000\u0000\u0003\u008a\u0001\u0000\u0000\u0000\u0003\u008c\u0001"+ - "\u0000\u0000\u0000\u0003\u008e\u0001\u0000\u0000\u0000\u0003\u0090\u0001"+ - "\u0000\u0000\u0000\u0003\u0092\u0001\u0000\u0000\u0000\u0003\u0094\u0001"+ - "\u0000\u0000\u0000\u0003\u0096\u0001\u0000\u0000\u0000\u0003\u0098\u0001"+ - "\u0000\u0000\u0000\u0003\u009a\u0001\u0000\u0000\u0000\u0003\u009c\u0001"+ - "\u0000\u0000\u0000\u0003\u009e\u0001\u0000\u0000\u0000\u0003\u00a0\u0001"+ - "\u0000\u0000\u0000\u0003\u00a2\u0001\u0000\u0000\u0000\u0003\u00a4\u0001"+ - "\u0000\u0000\u0000\u0003\u00a6\u0001\u0000\u0000\u0000\u0003\u00a8\u0001"+ - "\u0000\u0000\u0000\u0003\u00aa\u0001\u0000\u0000\u0000\u0003\u00ac\u0001"+ - "\u0000\u0000\u0000\u0003\u00ae\u0001\u0000\u0000\u0000\u0003\u00b0\u0001"+ - "\u0000\u0000\u0000\u0003\u00b2\u0001\u0000\u0000\u0000\u0003\u00b4\u0001"+ - "\u0000\u0000\u0000\u0004\u00b7\u0001\u0000\u0000\u0000\u0006\u00c1\u0001"+ - "\u0000\u0000\u0000\b\u00c5\u0001\u0000\u0000\u0000\n\u00ce\u0001\u0000"+ - "\u0000\u0000\f\u00d0\u0001\u0000\u0000\u0000\u000e\u00d3\u0001\u0000\u0000"+ - "\u0000\u0010\u00d5\u0001\u0000\u0000\u0000\u0012\u00d8\u0001\u0000\u0000"+ - "\u0000\u0014\u00dc\u0001\u0000\u0000\u0000\u0016\u00de\u0001\u0000\u0000"+ - "\u0000\u0018\u00e2\u0001\u0000\u0000\u0000\u001a\u00e4\u0001\u0000\u0000"+ - "\u0000\u001c\u00e6\u0001\u0000\u0000\u0000\u001e\u00ec\u0001\u0000\u0000"+ - "\u0000 \u00f2\u0001\u0000\u0000\u0000\"\u00fc\u0001\u0000\u0000\u0000"+ - "$\u0106\u0001\u0000\u0000\u0000&\u0112\u0001\u0000\u0000\u0000(\u0116"+ - "\u0001\u0000\u0000\u0000*\u011a\u0001\u0000\u0000\u0000,\u011e\u0001\u0000"+ - "\u0000\u0000.\u012c\u0001\u0000\u0000\u00000\u0136\u0001\u0000\u0000\u0000"+ - "2\u0138\u0001\u0000\u0000\u00004\u013d\u0001\u0000\u0000\u00006\u014e"+ - "\u0001\u0000\u0000\u00008\u0153\u0001\u0000\u0000\u0000:\u0163\u0001\u0000"+ - "\u0000\u0000<\u0169\u0001\u0000\u0000\u0000>\u0172\u0001\u0000\u0000\u0000"+ - "@\u0175\u0001\u0000\u0000\u0000B\u0180\u0001\u0000\u0000\u0000D\u0189"+ - "\u0001\u0000\u0000\u0000F\u0193\u0001\u0000\u0000\u0000H\u0195\u0001\u0000"+ - "\u0000\u0000J\u0197\u0001\u0000\u0000\u0000L\u0199\u0001\u0000\u0000\u0000"+ - "N\u019c\u0001\u0000\u0000\u0000P\u01ab\u0001\u0000\u0000\u0000R\u01b9"+ - "\u0001\u0000\u0000\u0000T\u01c7\u0001\u0000\u0000\u0000V\u01d5\u0001\u0000"+ - "\u0000\u0000X\u01da\u0001\u0000\u0000\u0000Z\u01dd\u0001\u0000\u0000\u0000"+ - "\\\u01e0\u0001\u0000\u0000\u0000^\u01e2\u0001\u0000\u0000\u0000`\u01e5"+ - "\u0001\u0000\u0000\u0000b\u01e8\u0001\u0000\u0000\u0000d\u01eb\u0001\u0000"+ - "\u0000\u0000f\u01f1\u0001\u0000\u0000\u0000h\u01f8\u0001\u0000\u0000\u0000"+ - "j\u01fa\u0001\u0000\u0000\u0000l\u0202\u0001\u0000\u0000\u0000n\u0208"+ - "\u0001\u0000\u0000\u0000p\u020b\u0001\u0000\u0000\u0000r\u0211\u0001\u0000"+ - "\u0000\u0000t\u0217\u0001\u0000\u0000\u0000v\u021b\u0001\u0000\u0000\u0000"+ - "x\u021f\u0001\u0000\u0000\u0000z\u0223\u0001\u0000\u0000\u0000|\u0227"+ - "\u0001\u0000\u0000\u0000~\u022b\u0001\u0000\u0000\u0000\u0080\u022f\u0001"+ - "\u0000\u0000\u0000\u0082\u0233\u0001\u0000\u0000\u0000\u0084\u0237\u0001"+ - "\u0000\u0000\u0000\u0086\u023b\u0001\u0000\u0000\u0000\u0088\u0240\u0001"+ - "\u0000\u0000\u0000\u008a\u0244\u0001\u0000\u0000\u0000\u008c\u0248\u0001"+ - "\u0000\u0000\u0000\u008e\u024c\u0001\u0000\u0000\u0000\u0090\u0250\u0001"+ - "\u0000\u0000\u0000\u0092\u0255\u0001\u0000\u0000\u0000\u0094\u025a\u0001"+ - "\u0000\u0000\u0000\u0096\u025f\u0001\u0000\u0000\u0000\u0098\u0263\u0001"+ - "\u0000\u0000\u0000\u009a\u0267\u0001\u0000\u0000\u0000\u009c\u026b\u0001"+ - "\u0000\u0000\u0000\u009e\u026f\u0001\u0000\u0000\u0000\u00a0\u0273\u0001"+ - "\u0000\u0000\u0000\u00a2\u0277\u0001\u0000\u0000\u0000\u00a4\u027b\u0001"+ - "\u0000\u0000\u0000\u00a6\u027f\u0001\u0000\u0000\u0000\u00a8\u0283\u0001"+ - "\u0000\u0000\u0000\u00aa\u0287\u0001\u0000\u0000\u0000\u00ac\u028b\u0001"+ - "\u0000\u0000\u0000\u00ae\u028f\u0001\u0000\u0000\u0000\u00b0\u0293\u0001"+ - "\u0000\u0000\u0000\u00b2\u0297\u0001\u0000\u0000\u0000\u00b4\u029b\u0001"+ - "\u0000\u0000\u0000\u00b6\u00b8\u0007\u0000\u0000\u0000\u00b7\u00b6\u0001"+ - "\u0000\u0000\u0000\u00b8\u00b9\u0001\u0000\u0000\u0000\u00b9\u00b7\u0001"+ - "\u0000\u0000\u0000\u00b9\u00ba\u0001\u0000\u0000\u0000\u00ba\u00bb\u0001"+ - "\u0000\u0000\u0000\u00bb\u00bc\u0006\u0000\u0000\u0000\u00bc\u0005\u0001"+ - "\u0000\u0000\u0000\u00bd\u00bf\u0005\r\u0000\u0000\u00be\u00bd\u0001\u0000"+ - "\u0000\u0000\u00be\u00bf\u0001\u0000\u0000\u0000\u00bf\u00c0\u0001\u0000"+ - "\u0000\u0000\u00c0\u00c2\u0005\n\u0000\u0000\u00c1\u00be\u0001\u0000\u0000"+ - "\u0000\u00c2\u00c3\u0001\u0000\u0000\u0000\u00c3\u00c1\u0001\u0000\u0000"+ - "\u0000\u00c3\u00c4\u0001\u0000\u0000\u0000\u00c4\u0007\u0001\u0000\u0000"+ - "\u0000\u00c5\u00c9\u0005#\u0000\u0000\u00c6\u00c8\b\u0001\u0000\u0000"+ - "\u00c7\u00c6\u0001\u0000\u0000\u0000\u00c8\u00cb\u0001\u0000\u0000\u0000"+ - "\u00c9\u00c7\u0001\u0000\u0000\u0000\u00c9\u00ca\u0001\u0000\u0000\u0000"+ - "\u00ca\u00cc\u0001\u0000\u0000\u0000\u00cb\u00c9\u0001\u0000\u0000\u0000"+ - "\u00cc\u00cd\u0006\u0002\u0001\u0000\u00cd\t\u0001\u0000\u0000\u0000\u00ce"+ - "\u00cf\u0005[\u0000\u0000\u00cf\u000b\u0001\u0000\u0000\u0000\u00d0\u00d1"+ - "\u0005[\u0000\u0000\u00d1\u00d2\u0005[\u0000\u0000\u00d2\r\u0001\u0000"+ - "\u0000\u0000\u00d3\u00d4\u0005]\u0000\u0000\u00d4\u000f\u0001\u0000\u0000"+ - "\u0000\u00d5\u00d6\u0005]\u0000\u0000\u00d6\u00d7\u0005]\u0000\u0000\u00d7"+ - "\u0011\u0001\u0000\u0000\u0000\u00d8\u00d9\u0005=\u0000\u0000\u00d9\u00da"+ - "\u0001\u0000\u0000\u0000\u00da\u00db\u0006\u0007\u0002\u0000\u00db\u0013"+ - "\u0001\u0000\u0000\u0000\u00dc\u00dd\u0005.\u0000\u0000\u00dd\u0015\u0001"+ - "\u0000\u0000\u0000\u00de\u00df\u0005,\u0000\u0000\u00df\u00e0\u0001\u0000"+ - "\u0000\u0000\u00e0\u00e1\u0006\t\u0000\u0000\u00e1\u0017\u0001\u0000\u0000"+ - "\u0000\u00e2\u00e3\u0007\u0002\u0000\u0000\u00e3\u0019\u0001\u0000\u0000"+ - "\u0000\u00e4\u00e5\u0007\u0003\u0000\u0000\u00e5\u001b\u0001\u0000\u0000"+ - "\u0000\u00e6\u00ea\u0005\\\u0000\u0000\u00e7\u00eb\u0007\u0004\u0000\u0000"+ - "\u00e8\u00eb\u0003\u001e\r\u0000\u00e9\u00eb\u0003 \u000e\u0000\u00ea"+ - "\u00e7\u0001\u0000\u0000\u0000\u00ea\u00e8\u0001\u0000\u0000\u0000\u00ea"+ - "\u00e9\u0001\u0000\u0000\u0000\u00eb\u001d\u0001\u0000\u0000\u0000\u00ec"+ - "\u00ed\u0005u\u0000\u0000\u00ed\u00ee\u0003F!\u0000\u00ee\u00ef\u0003"+ - "F!\u0000\u00ef\u00f0\u0003F!\u0000\u00f0\u00f1\u0003F!\u0000\u00f1\u001f"+ - "\u0001\u0000\u0000\u0000\u00f2\u00f3\u0005U\u0000\u0000\u00f3\u00f4\u0003"+ - "F!\u0000\u00f4\u00f5\u0003F!\u0000\u00f5\u00f6\u0003F!\u0000\u00f6\u00f7"+ - "\u0003F!\u0000\u00f7\u00f8\u0003F!\u0000\u00f8\u00f9\u0003F!\u0000\u00f9"+ - "\u00fa\u0003F!\u0000\u00fa\u00fb\u0003F!\u0000\u00fb!\u0001\u0000\u0000"+ - "\u0000\u00fc\u0101\u0005\"\u0000\u0000\u00fd\u0100\u0003\u001c\f\u0000"+ - "\u00fe\u0100\b\u0005\u0000\u0000\u00ff\u00fd\u0001\u0000\u0000\u0000\u00ff"+ - "\u00fe\u0001\u0000\u0000\u0000\u0100\u0103\u0001\u0000\u0000\u0000\u0101"+ - "\u0102\u0001\u0000\u0000\u0000\u0101\u00ff\u0001\u0000\u0000\u0000\u0102"+ - "\u0104\u0001\u0000\u0000\u0000\u0103\u0101\u0001\u0000\u0000\u0000\u0104"+ - "\u0105\u0005\"\u0000\u0000\u0105#\u0001\u0000\u0000\u0000\u0106\u010a"+ - "\u0005\'\u0000\u0000\u0107\u0109\b\u0006\u0000\u0000\u0108\u0107\u0001"+ - "\u0000\u0000\u0000\u0109\u010c\u0001\u0000\u0000\u0000\u010a\u010b\u0001"+ - "\u0000\u0000\u0000\u010a\u0108\u0001\u0000\u0000\u0000\u010b\u010d\u0001"+ - "\u0000\u0000\u0000\u010c\u010a\u0001\u0000\u0000\u0000\u010d\u010e\u0005"+ - "\'\u0000\u0000\u010e%\u0001\u0000\u0000\u0000\u010f\u0113\u0003\u001a"+ - "\u000b\u0000\u0110\u0113\u0003\u0018\n\u0000\u0111\u0113\u0007\u0007\u0000"+ - "\u0000\u0112\u010f\u0001\u0000\u0000\u0000\u0112\u0110\u0001\u0000\u0000"+ - "\u0000\u0112\u0111\u0001\u0000\u0000\u0000\u0113\u0114\u0001\u0000\u0000"+ - "\u0000\u0114\u0112\u0001\u0000\u0000\u0000\u0114\u0115\u0001\u0000\u0000"+ - "\u0000\u0115\'\u0001\u0000\u0000\u0000\u0116\u0117\u0003\u0004\u0000\u0000"+ - "\u0117\u0118\u0001\u0000\u0000\u0000\u0118\u0119\u0006\u0012\u0000\u0000"+ - "\u0119)\u0001\u0000\u0000\u0000\u011a\u011b\u0005{\u0000\u0000\u011b\u011c"+ - "\u0001\u0000\u0000\u0000\u011c\u011d\u0006\u0013\u0003\u0000\u011d+\u0001"+ - "\u0000\u0000\u0000\u011e\u011f\u0003\n\u0003\u0000\u011f\u0120\u0001\u0000"+ - "\u0000\u0000\u0120\u0121\u0006\u0014\u0004\u0000\u0121\u0122\u0006\u0014"+ - "\u0005\u0000\u0122-\u0001\u0000\u0000\u0000\u0123\u0124\u0005t\u0000\u0000"+ - "\u0124\u0125\u0005r\u0000\u0000\u0125\u0126\u0005u\u0000\u0000\u0126\u012d"+ - "\u0005e\u0000\u0000\u0127\u0128\u0005f\u0000\u0000\u0128\u0129\u0005a"+ - "\u0000\u0000\u0129\u012a\u0005l\u0000\u0000\u012a\u012b\u0005s\u0000\u0000"+ - "\u012b\u012d\u0005e\u0000\u0000\u012c\u0123\u0001\u0000\u0000\u0000\u012c"+ - "\u0127\u0001\u0000\u0000\u0000\u012d\u012e\u0001\u0000\u0000\u0000\u012e"+ - "\u012f\u0006\u0015\u0006\u0000\u012f/\u0001\u0000\u0000\u0000\u0130\u0132"+ - "\u0005\\\u0000\u0000\u0131\u0133\u0005\r\u0000\u0000\u0132\u0131\u0001"+ - "\u0000\u0000\u0000\u0132\u0133\u0001\u0000\u0000\u0000\u0133\u0134\u0001"+ - "\u0000\u0000\u0000\u0134\u0137\u0005\n\u0000\u0000\u0135\u0137\u0003\u001c"+ - "\f\u0000\u0136\u0130\u0001\u0000\u0000\u0000\u0136\u0135\u0001\u0000\u0000"+ - "\u0000\u01371\u0001\u0000\u0000\u0000\u0138\u0139\u0003\"\u000f\u0000"+ - "\u0139\u013a\u0001\u0000\u0000\u0000\u013a\u013b\u0006\u0017\u0007\u0000"+ - "\u013b\u013c\u0006\u0017\u0006\u0000\u013c3\u0001\u0000\u0000\u0000\u013d"+ - "\u013e\u0005\"\u0000\u0000\u013e\u013f\u0005\"\u0000\u0000\u013f\u0140"+ - "\u0005\"\u0000\u0000\u0140\u0145\u0001\u0000\u0000\u0000\u0141\u0144\u0003"+ - "0\u0016\u0000\u0142\u0144\b\b\u0000\u0000\u0143\u0141\u0001\u0000\u0000"+ - "\u0000\u0143\u0142\u0001\u0000\u0000\u0000\u0144\u0147\u0001\u0000\u0000"+ - "\u0000\u0145\u0146\u0001\u0000\u0000\u0000\u0145\u0143\u0001\u0000\u0000"+ - "\u0000\u0146\u0148\u0001\u0000\u0000\u0000\u0147\u0145\u0001\u0000\u0000"+ - "\u0000\u0148\u0149\u0005\"\u0000\u0000\u0149\u014a\u0005\"\u0000\u0000"+ - "\u014a\u014b\u0005\"\u0000\u0000\u014b\u014c\u0001\u0000\u0000\u0000\u014c"+ - "\u014d\u0006\u0018\u0006\u0000\u014d5\u0001\u0000\u0000\u0000\u014e\u014f"+ - "\u0003$\u0010\u0000\u014f\u0150\u0001\u0000\u0000\u0000\u0150\u0151\u0006"+ - "\u0019\b\u0000\u0151\u0152\u0006\u0019\u0006\u0000\u01527\u0001\u0000"+ - "\u0000\u0000\u0153\u0154\u0005\'\u0000\u0000\u0154\u0155\u0005\'\u0000"+ - "\u0000\u0155\u0156\u0005\'\u0000\u0000\u0156\u015a\u0001\u0000\u0000\u0000"+ - "\u0157\u0159\t\u0000\u0000\u0000\u0158\u0157\u0001\u0000\u0000\u0000\u0159"+ - "\u015c\u0001\u0000\u0000\u0000\u015a\u015b\u0001\u0000\u0000\u0000\u015a"+ - "\u0158\u0001\u0000\u0000\u0000\u015b\u015d\u0001\u0000\u0000\u0000\u015c"+ - "\u015a\u0001\u0000\u0000\u0000\u015d\u015e\u0005\'\u0000\u0000\u015e\u015f"+ - "\u0005\'\u0000\u0000\u015f\u0160\u0005\'\u0000\u0000\u0160\u0161\u0001"+ - "\u0000\u0000\u0000\u0161\u0162\u0006\u001a\u0006\u0000\u01629\u0001\u0000"+ - "\u0000\u0000\u0163\u0165\u0007\t\u0000\u0000\u0164\u0166\u0007\n\u0000"+ - "\u0000\u0165\u0164\u0001\u0000\u0000\u0000\u0165\u0166\u0001\u0000\u0000"+ - "\u0000\u0166\u0167\u0001\u0000\u0000\u0000\u0167\u0168\u0003<\u001c\u0000"+ - "\u0168;\u0001\u0000\u0000\u0000\u0169\u016f\u0003\u0018\n\u0000\u016a"+ - "\u016e\u0003\u0018\n\u0000\u016b\u016c\u0005_\u0000\u0000\u016c\u016e"+ - "\u0003\u0018\n\u0000\u016d\u016a\u0001\u0000\u0000\u0000\u016d\u016b\u0001"+ - "\u0000\u0000\u0000\u016e\u0171\u0001\u0000\u0000\u0000\u016f\u016d\u0001"+ - "\u0000\u0000\u0000\u016f\u0170\u0001\u0000\u0000\u0000\u0170=\u0001\u0000"+ - "\u0000\u0000\u0171\u016f\u0001\u0000\u0000\u0000\u0172\u0173\u0005.\u0000"+ - "\u0000\u0173\u0174\u0003<\u001c\u0000\u0174?\u0001\u0000\u0000\u0000\u0175"+ - "\u017b\u0003N%\u0000\u0176\u017c\u0003:\u001b\u0000\u0177\u0179\u0003"+ - ">\u001d\u0000\u0178\u017a\u0003:\u001b\u0000\u0179\u0178\u0001\u0000\u0000"+ - "\u0000\u0179\u017a\u0001\u0000\u0000\u0000\u017a\u017c\u0001\u0000\u0000"+ - "\u0000\u017b\u0176\u0001\u0000\u0000\u0000\u017b\u0177\u0001\u0000\u0000"+ - "\u0000\u017c\u017d\u0001\u0000\u0000\u0000\u017d\u017e\u0006\u001e\u0006"+ - "\u0000\u017eA\u0001\u0000\u0000\u0000\u017f\u0181\u0007\n\u0000\u0000"+ - "\u0180\u017f\u0001\u0000\u0000\u0000\u0180\u0181\u0001\u0000\u0000\u0000"+ - "\u0181\u0182\u0001\u0000\u0000\u0000\u0182\u0183\u0005i\u0000\u0000\u0183"+ - "\u0184\u0005n\u0000\u0000\u0184\u0185\u0005f\u0000\u0000\u0185\u0186\u0001"+ - "\u0000\u0000\u0000\u0186\u0187\u0006\u001f\u0006\u0000\u0187C\u0001\u0000"+ - "\u0000\u0000\u0188\u018a\u0007\n\u0000\u0000\u0189\u0188\u0001\u0000\u0000"+ - "\u0000\u0189\u018a\u0001\u0000\u0000\u0000\u018a\u018b\u0001\u0000\u0000"+ - "\u0000\u018b\u018c\u0005n\u0000\u0000\u018c\u018d\u0005a\u0000\u0000\u018d"+ - "\u018e\u0005n\u0000\u0000\u018e\u018f\u0001\u0000\u0000\u0000\u018f\u0190"+ - "\u0006 \u0006\u0000\u0190E\u0001\u0000\u0000\u0000\u0191\u0194\u0007\u000b"+ - "\u0000\u0000\u0192\u0194\u0003\u0018\n\u0000\u0193\u0191\u0001\u0000\u0000"+ - "\u0000\u0193\u0192\u0001\u0000\u0000\u0000\u0194G\u0001\u0000\u0000\u0000"+ - "\u0195\u0196\u0007\f\u0000\u0000\u0196I\u0001\u0000\u0000\u0000\u0197"+ - "\u0198\u0007\r\u0000\u0000\u0198K\u0001\u0000\u0000\u0000\u0199\u019a"+ - "\u0007\u000e\u0000\u0000\u019aM\u0001\u0000\u0000\u0000\u019b\u019d\u0007"+ - "\n\u0000\u0000\u019c\u019b\u0001\u0000\u0000\u0000\u019c\u019d\u0001\u0000"+ - "\u0000\u0000\u019d\u01a7\u0001\u0000\u0000\u0000\u019e\u01a8\u0003\u0018"+ - "\n\u0000\u019f\u01a3\u0003H\"\u0000\u01a0\u01a4\u0003\u0018\n\u0000\u01a1"+ - "\u01a2\u0005_\u0000\u0000\u01a2\u01a4\u0003\u0018\n\u0000\u01a3\u01a0"+ - "\u0001\u0000\u0000\u0000\u01a3\u01a1\u0001\u0000\u0000\u0000\u01a4\u01a5"+ - "\u0001\u0000\u0000\u0000\u01a5\u01a3\u0001\u0000\u0000\u0000\u01a5\u01a6"+ - "\u0001\u0000\u0000\u0000\u01a6\u01a8\u0001\u0000\u0000\u0000\u01a7\u019e"+ - "\u0001\u0000\u0000\u0000\u01a7\u019f\u0001\u0000\u0000\u0000\u01a8\u01a9"+ - "\u0001\u0000\u0000\u0000\u01a9\u01aa\u0006%\u0006\u0000\u01aaO\u0001\u0000"+ - "\u0000\u0000\u01ab\u01ac\u00050\u0000\u0000\u01ac\u01ad\u0005x\u0000\u0000"+ - "\u01ad\u01ae\u0001\u0000\u0000\u0000\u01ae\u01b4\u0003F!\u0000\u01af\u01b3"+ - "\u0003F!\u0000\u01b0\u01b1\u0005_\u0000\u0000\u01b1\u01b3\u0003F!\u0000"+ - "\u01b2\u01af\u0001\u0000\u0000\u0000\u01b2\u01b0\u0001\u0000\u0000\u0000"+ - "\u01b3\u01b6\u0001\u0000\u0000\u0000\u01b4\u01b2\u0001\u0000\u0000\u0000"+ - "\u01b4\u01b5\u0001\u0000\u0000\u0000\u01b5\u01b7\u0001\u0000\u0000\u0000"+ - "\u01b6\u01b4\u0001\u0000\u0000\u0000\u01b7\u01b8\u0006&\u0006\u0000\u01b8"+ - "Q\u0001\u0000\u0000\u0000\u01b9\u01ba\u00050\u0000\u0000\u01ba\u01bb\u0005"+ - "o\u0000\u0000\u01bb\u01bc\u0001\u0000\u0000\u0000\u01bc\u01c2\u0003J#"+ - "\u0000\u01bd\u01c1\u0003J#\u0000\u01be\u01bf\u0005_\u0000\u0000\u01bf"+ - "\u01c1\u0003J#\u0000\u01c0\u01bd\u0001\u0000\u0000\u0000\u01c0\u01be\u0001"+ - "\u0000\u0000\u0000\u01c1\u01c4\u0001\u0000\u0000\u0000\u01c2\u01c0\u0001"+ - "\u0000\u0000\u0000\u01c2\u01c3\u0001\u0000\u0000\u0000\u01c3\u01c5\u0001"+ - "\u0000\u0000\u0000\u01c4\u01c2\u0001\u0000\u0000\u0000\u01c5\u01c6\u0006"+ - "\'\u0006\u0000\u01c6S\u0001\u0000\u0000\u0000\u01c7\u01c8\u00050\u0000"+ - "\u0000\u01c8\u01c9\u0005b\u0000\u0000\u01c9\u01ca\u0001\u0000\u0000\u0000"+ - "\u01ca\u01d0\u0003L$\u0000\u01cb\u01cf\u0003L$\u0000\u01cc\u01cd\u0005"+ - "_\u0000\u0000\u01cd\u01cf\u0003L$\u0000\u01ce\u01cb\u0001\u0000\u0000"+ - "\u0000\u01ce\u01cc\u0001\u0000\u0000\u0000\u01cf\u01d2\u0001\u0000\u0000"+ - "\u0000\u01d0\u01ce\u0001\u0000\u0000\u0000\u01d0\u01d1\u0001\u0000\u0000"+ - "\u0000\u01d1\u01d3\u0001\u0000\u0000\u0000\u01d2\u01d0\u0001\u0000\u0000"+ - "\u0000\u01d3\u01d4\u0006(\u0006\u0000\u01d4U\u0001\u0000\u0000\u0000\u01d5"+ - "\u01d6\u0003\u0018\n\u0000\u01d6\u01d7\u0003\u0018\n\u0000\u01d7\u01d8"+ - "\u0003\u0018\n\u0000\u01d8\u01d9\u0003\u0018\n\u0000\u01d9W\u0001\u0000"+ - "\u0000\u0000\u01da\u01db\u0003\u0018\n\u0000\u01db\u01dc\u0003\u0018\n"+ - "\u0000\u01dcY\u0001\u0000\u0000\u0000\u01dd\u01de\u0003\u0018\n\u0000"+ - "\u01de\u01df\u0003\u0018\n\u0000\u01df[\u0001\u0000\u0000\u0000\u01e0"+ - "\u01e1\u0007\u000f\u0000\u0000\u01e1]\u0001\u0000\u0000\u0000\u01e2\u01e3"+ - "\u0003\u0018\n\u0000\u01e3\u01e4\u0003\u0018\n\u0000\u01e4_\u0001\u0000"+ - "\u0000\u0000\u01e5\u01e6\u0003\u0018\n\u0000\u01e6\u01e7\u0003\u0018\n"+ - "\u0000\u01e7a\u0001\u0000\u0000\u0000\u01e8\u01e9\u0003\u0018\n\u0000"+ - "\u01e9\u01ea\u0003\u0018\n\u0000\u01eac\u0001\u0000\u0000\u0000\u01eb"+ - "\u01ed\u0005.\u0000\u0000\u01ec\u01ee\u0003\u0018\n\u0000\u01ed\u01ec"+ - "\u0001\u0000\u0000\u0000\u01ee\u01ef\u0001\u0000\u0000\u0000\u01ef\u01ed"+ - "\u0001\u0000\u0000\u0000\u01ef\u01f0\u0001\u0000\u0000\u0000\u01f0e\u0001"+ - "\u0000\u0000\u0000\u01f1\u01f2\u0007\n\u0000\u0000\u01f2\u01f3\u0003^"+ - "-\u0000\u01f3\u01f4\u0005:\u0000\u0000\u01f4\u01f5\u0003`.\u0000\u01f5"+ - "g\u0001\u0000\u0000\u0000\u01f6\u01f9\u0005Z\u0000\u0000\u01f7\u01f9\u0003"+ - "f1\u0000\u01f8\u01f6\u0001\u0000\u0000\u0000\u01f8\u01f7\u0001\u0000\u0000"+ - "\u0000\u01f9i\u0001\u0000\u0000\u0000\u01fa\u01fb\u0003^-\u0000\u01fb"+ - "\u01fc\u0005:\u0000\u0000\u01fc\u01fd\u0003`.\u0000\u01fd\u01fe\u0005"+ - ":\u0000\u0000\u01fe\u0200\u0003b/\u0000\u01ff\u0201\u0003d0\u0000\u0200"+ - "\u01ff\u0001\u0000\u0000\u0000\u0200\u0201\u0001\u0000\u0000\u0000\u0201"+ - "k\u0001\u0000\u0000\u0000\u0202\u0203\u0003V)\u0000\u0203\u0204\u0005"+ - "-\u0000\u0000\u0204\u0205\u0003X*\u0000\u0205\u0206\u0005-\u0000\u0000"+ - "\u0206\u0207\u0003Z+\u0000\u0207m\u0001\u0000\u0000\u0000\u0208\u0209"+ - "\u0003j3\u0000\u0209\u020a\u0003h2\u0000\u020ao\u0001\u0000\u0000\u0000"+ - "\u020b\u020c\u0003l4\u0000\u020c\u020d\u0003\\,\u0000\u020d\u020e\u0003"+ - "n5\u0000\u020e\u020f\u0001\u0000\u0000\u0000\u020f\u0210\u00066\u0006"+ - "\u0000\u0210q\u0001\u0000\u0000\u0000\u0211\u0212\u0003l4\u0000\u0212"+ - "\u0213\u0003\\,\u0000\u0213\u0214\u0003j3\u0000\u0214\u0215\u0001\u0000"+ - "\u0000\u0000\u0215\u0216\u00067\u0006\u0000\u0216s\u0001\u0000\u0000\u0000"+ - "\u0217\u0218\u0003l4\u0000\u0218\u0219\u0001\u0000\u0000\u0000\u0219\u021a"+ - "\u00068\u0006\u0000\u021au\u0001\u0000\u0000\u0000\u021b\u021c\u0003j"+ - "3\u0000\u021c\u021d\u0001\u0000\u0000\u0000\u021d\u021e\u00069\u0006\u0000"+ - "\u021ew\u0001\u0000\u0000\u0000\u021f\u0220\u0003\u0004\u0000\u0000\u0220"+ - "\u0221\u0001\u0000\u0000\u0000\u0221\u0222\u0006:\u0000\u0000\u0222y\u0001"+ - "\u0000\u0000\u0000\u0223\u0224\u0003\u0014\b\u0000\u0224\u0225\u0001\u0000"+ - "\u0000\u0000\u0225\u0226\u0006;\t\u0000\u0226{\u0001\u0000\u0000\u0000"+ - "\u0227\u0228\u0003\u0016\t\u0000\u0228\u0229\u0001\u0000\u0000\u0000\u0229"+ - "\u022a\u0006<\n\u0000\u022a}\u0001\u0000\u0000\u0000\u022b\u022c\u0005"+ - "}\u0000\u0000\u022c\u022d\u0001\u0000\u0000\u0000\u022d\u022e\u0006=\u0006"+ - "\u0000\u022e\u007f\u0001\u0000\u0000\u0000\u022f\u0230\u0003\"\u000f\u0000"+ - "\u0230\u0231\u0001\u0000\u0000\u0000\u0231\u0232\u0006>\u0007\u0000\u0232"+ - "\u0081\u0001\u0000\u0000\u0000\u0233\u0234\u0003$\u0010\u0000\u0234\u0235"+ - "\u0001\u0000\u0000\u0000\u0235\u0236\u0006?\b\u0000\u0236\u0083\u0001"+ - "\u0000\u0000\u0000\u0237\u0238\u0003&\u0011\u0000\u0238\u0239\u0001\u0000"+ - "\u0000\u0000\u0239\u023a\u0006@\u000b\u0000\u023a\u0085\u0001\u0000\u0000"+ - "\u0000\u023b\u023c\u0003\u0012\u0007\u0000\u023c\u023d\u0001\u0000\u0000"+ - "\u0000\u023d\u023e\u0006A\f\u0000\u023e\u023f\u0006A\u0002\u0000\u023f"+ - "\u0087\u0001\u0000\u0000\u0000\u0240\u0241\u0003\u0004\u0000\u0000\u0241"+ - "\u0242\u0001\u0000\u0000\u0000\u0242\u0243\u0006B\u0000\u0000\u0243\u0089"+ - "\u0001\u0000\u0000\u0000\u0244\u0245\u0003\u0006\u0001\u0000\u0245\u0246"+ - "\u0001\u0000\u0000\u0000\u0246\u0247\u0006C\r\u0000\u0247\u008b\u0001"+ - "\u0000\u0000\u0000\u0248\u0249\u0003\b\u0002\u0000\u0249\u024a\u0001\u0000"+ - "\u0000\u0000\u024a\u024b\u0006D\u000e\u0000\u024b\u008d\u0001\u0000\u0000"+ - "\u0000\u024c\u024d\u0003\u0016\t\u0000\u024d\u024e\u0001\u0000\u0000\u0000"+ - "\u024e\u024f\u0006E\n\u0000\u024f\u008f\u0001\u0000\u0000\u0000\u0250"+ - "\u0251\u0003*\u0013\u0000\u0251\u0252\u0001\u0000\u0000\u0000\u0252\u0253"+ - "\u0006F\u000f\u0000\u0253\u0254\u0006F\u0010\u0000\u0254\u0091\u0001\u0000"+ - "\u0000\u0000\u0255\u0256\u0003\n\u0003\u0000\u0256\u0257\u0001\u0000\u0000"+ - "\u0000\u0257\u0258\u0006G\u0004\u0000\u0258\u0259\u0006G\u0011\u0000\u0259"+ - "\u0093\u0001\u0000\u0000\u0000\u025a\u025b\u0003\u000e\u0005\u0000\u025b"+ - "\u025c\u0001\u0000\u0000\u0000\u025c\u025d\u0006H\u0012\u0000\u025d\u025e"+ - "\u0006H\u0006\u0000\u025e\u0095\u0001\u0000\u0000\u0000\u025f\u0260\u0003"+ - ".\u0015\u0000\u0260\u0261\u0001\u0000\u0000\u0000\u0261\u0262\u0006I\u0013"+ - "\u0000\u0262\u0097\u0001\u0000\u0000\u0000\u0263\u0264\u0003\"\u000f\u0000"+ - "\u0264\u0265\u0001\u0000\u0000\u0000\u0265\u0266\u0006J\u0007\u0000\u0266"+ - "\u0099\u0001\u0000\u0000\u0000\u0267\u0268\u00034\u0018\u0000\u0268\u0269"+ - "\u0001\u0000\u0000\u0000\u0269\u026a\u0006K\u0014\u0000\u026a\u009b\u0001"+ - "\u0000\u0000\u0000\u026b\u026c\u0003$\u0010\u0000\u026c\u026d\u0001\u0000"+ - "\u0000\u0000\u026d\u026e\u0006L\b\u0000\u026e\u009d\u0001\u0000\u0000"+ - "\u0000\u026f\u0270\u00038\u001a\u0000\u0270\u0271\u0001\u0000\u0000\u0000"+ - "\u0271\u0272\u0006M\u0015\u0000\u0272\u009f\u0001\u0000\u0000\u0000\u0273"+ - "\u0274\u0003@\u001e\u0000\u0274\u0275\u0001\u0000\u0000\u0000\u0275\u0276"+ - "\u0006N\u0016\u0000\u0276\u00a1\u0001\u0000\u0000\u0000\u0277\u0278\u0003"+ - "B\u001f\u0000\u0278\u0279\u0001\u0000\u0000\u0000\u0279\u027a\u0006O\u0017"+ - "\u0000\u027a\u00a3\u0001\u0000\u0000\u0000\u027b\u027c\u0003D \u0000\u027c"+ - "\u027d\u0001\u0000\u0000\u0000\u027d\u027e\u0006P\u0018\u0000\u027e\u00a5"+ - "\u0001\u0000\u0000\u0000\u027f\u0280\u0003N%\u0000\u0280\u0281\u0001\u0000"+ - "\u0000\u0000\u0281\u0282\u0006Q\u0019\u0000\u0282\u00a7\u0001\u0000\u0000"+ - "\u0000\u0283\u0284\u0003P&\u0000\u0284\u0285\u0001\u0000\u0000\u0000\u0285"+ - "\u0286\u0006R\u001a\u0000\u0286\u00a9\u0001\u0000\u0000\u0000\u0287\u0288"+ - "\u0003R\'\u0000\u0288\u0289\u0001\u0000\u0000\u0000\u0289\u028a\u0006"+ - "S\u001b\u0000\u028a\u00ab\u0001\u0000\u0000\u0000\u028b\u028c\u0003T("+ - "\u0000\u028c\u028d\u0001\u0000\u0000\u0000\u028d\u028e\u0006T\u001c\u0000"+ - "\u028e\u00ad\u0001\u0000\u0000\u0000\u028f\u0290\u0003p6\u0000\u0290\u0291"+ - "\u0001\u0000\u0000\u0000\u0291\u0292\u0006U\u001d\u0000\u0292\u00af\u0001"+ - "\u0000\u0000\u0000\u0293\u0294\u0003r7\u0000\u0294\u0295\u0001\u0000\u0000"+ - "\u0000\u0295\u0296\u0006V\u001e\u0000\u0296\u00b1\u0001\u0000\u0000\u0000"+ - "\u0297\u0298\u0003t8\u0000\u0298\u0299\u0001\u0000\u0000\u0000\u0299\u029a"+ - "\u0006W\u001f\u0000\u029a\u00b3\u0001\u0000\u0000\u0000\u029b\u029c\u0003"+ - "v9\u0000\u029c\u029d\u0001\u0000\u0000\u0000\u029d\u029e\u0006X \u0000"+ - "\u029e\u00b5\u0001\u0000\u0000\u0000)\u0000\u0001\u0002\u0003\u00b9\u00be"+ - "\u00c3\u00c9\u00ea\u00ff\u0101\u010a\u0112\u0114\u012c\u0132\u0136\u0143"+ - "\u0145\u015a\u0165\u016d\u016f\u0179\u017b\u0180\u0189\u0193\u019c\u01a3"+ - "\u01a5\u01a7\u01b2\u01b4\u01c0\u01c2\u01ce\u01d0\u01ef\u01f8\u0200!\u0006"+ - "\u0000\u0000\u0000\u0002\u0000\u0005\u0001\u0000\u0002\u0002\u0000\u0007"+ - "\u0004\u0000\u0002\u0003\u0000\u0004\u0000\u0000\u0007\u000b\u0000\u0007"+ - "\f\u0000\u0007\t\u0000\u0007\n\u0000\u0007\r\u0000\u0007\b\u0000\u0007"+ - "\u0002\u0000\u0007\u0003\u0000\u0007\u000f\u0000\u0005\u0002\u0000\u0005"+ - "\u0003\u0000\u0007\u0006\u0000\u0007\u0010\u0000\u0007\u0011\u0000\u0007"+ - "\u0012\u0000\u0007\u0013\u0000\u0007\u0014\u0000\u0007\u0015\u0000\u0007"+ - "\u0016\u0000\u0007\u0017\u0000\u0007\u0018\u0000\u0007\u0019\u0000\u0007"+ - "\u001a\u0000\u0007\u001b\u0000\u0007\u001c\u0000\u0007\u001d\u0000"; + "\u0002\n\u0002\f\u0002\u00cb\t\u0002\u0001\u0003\u0001\u0003\u0001\u0004"+ + "\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006"+ + "\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001"+ + "\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\n\u0001\n\u0001\u000b\u0001\u000b"+ + "\u0001\f\u0001\f\u0001\f\u0001\f\u0003\f\u00e9\b\f\u0001\r\u0001\r\u0001"+ + "\r\u0001\r\u0001\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e"+ + "\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e"+ + "\u0001\u000f\u0001\u000f\u0001\u000f\u0005\u000f\u00fe\b\u000f\n\u000f"+ + "\f\u000f\u0101\t\u000f\u0001\u000f\u0001\u000f\u0001\u0010\u0001\u0010"+ + "\u0005\u0010\u0107\b\u0010\n\u0010\f\u0010\u010a\t\u0010\u0001\u0010\u0001"+ + "\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0004\u0011\u0111\b\u0011\u000b"+ + "\u0011\f\u0011\u0112\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+ + "\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0014\u0001\u0014\u0001"+ + "\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0015\u0001"+ + "\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0003"+ + "\u0015\u012b\b\u0015\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0003"+ + "\u0016\u0131\b\u0016\u0001\u0016\u0001\u0016\u0003\u0016\u0135\b\u0016"+ + "\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0018"+ + "\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0005\u0018"+ + "\u0142\b\u0018\n\u0018\f\u0018\u0145\t\u0018\u0001\u0018\u0001\u0018\u0001"+ + "\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001"+ + "\u0019\u0001\u0019\u0001\u0019\u0001\u001a\u0001\u001a\u0001\u001a\u0001"+ + "\u001a\u0001\u001a\u0005\u001a\u0157\b\u001a\n\u001a\f\u001a\u015a\t\u001a"+ + "\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a"+ + "\u0001\u001b\u0001\u001b\u0003\u001b\u0164\b\u001b\u0001\u001b\u0001\u001b"+ + "\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0005\u001c\u016c\b\u001c"+ + "\n\u001c\f\u001c\u016f\t\u001c\u0001\u001d\u0001\u001d\u0001\u001d\u0001"+ + "\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0003\u001e\u0178\b\u001e\u0003"+ + "\u001e\u017a\b\u001e\u0001\u001e\u0001\u001e\u0001\u001f\u0003\u001f\u017f"+ + "\b\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001"+ + "\u001f\u0001 \u0003 \u0188\b \u0001 \u0001 \u0001 \u0001 \u0001 \u0001"+ + " \u0001!\u0001!\u0003!\u0192\b!\u0001\"\u0001\"\u0001#\u0001#\u0001$\u0001"+ + "$\u0001%\u0003%\u019b\b%\u0001%\u0001%\u0001%\u0001%\u0001%\u0004%\u01a2"+ + "\b%\u000b%\f%\u01a3\u0003%\u01a6\b%\u0001%\u0001%\u0001&\u0001&\u0001"+ + "&\u0001&\u0001&\u0001&\u0001&\u0005&\u01b1\b&\n&\f&\u01b4\t&\u0001&\u0001"+ + "&\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0005\'\u01bf"+ + "\b\'\n\'\f\'\u01c2\t\'\u0001\'\u0001\'\u0001(\u0001(\u0001(\u0001(\u0001"+ + "(\u0001(\u0001(\u0005(\u01cd\b(\n(\f(\u01d0\t(\u0001(\u0001(\u0001)\u0001"+ + ")\u0001)\u0001)\u0001)\u0001*\u0001*\u0001*\u0001+\u0001+\u0001+\u0001"+ + ",\u0001,\u0001-\u0001-\u0001-\u0001.\u0001.\u0001.\u0001/\u0001/\u0001"+ + "/\u00010\u00010\u00040\u01ec\b0\u000b0\f0\u01ed\u00011\u00011\u00011\u0001"+ + "1\u00011\u00012\u00012\u00032\u01f7\b2\u00013\u00013\u00013\u00013\u0001"+ + "3\u00013\u00033\u01ff\b3\u00014\u00014\u00014\u00014\u00014\u00014\u0001"+ + "5\u00015\u00015\u00016\u00016\u00016\u00016\u00016\u00016\u00017\u0001"+ + "7\u00017\u00017\u00017\u00017\u00018\u00018\u00018\u00018\u00019\u0001"+ + "9\u00019\u00019\u0001:\u0001:\u0001:\u0001:\u0001;\u0001;\u0001;\u0001"+ + ";\u0001<\u0001<\u0001<\u0001<\u0001=\u0001=\u0001=\u0001=\u0001>\u0001"+ + ">\u0001>\u0001>\u0001?\u0001?\u0001?\u0001?\u0001@\u0001@\u0001@\u0001"+ + "@\u0001A\u0001A\u0001A\u0001A\u0001A\u0001B\u0001B\u0001B\u0001B\u0001"+ + "C\u0001C\u0001C\u0001C\u0001D\u0001D\u0001D\u0001D\u0001E\u0001E\u0001"+ + "E\u0001E\u0001F\u0001F\u0001F\u0001F\u0001F\u0001G\u0001G\u0001G\u0001"+ + "G\u0001G\u0001H\u0001H\u0001H\u0001H\u0001H\u0001I\u0001I\u0001I\u0001"+ + "I\u0001J\u0001J\u0001J\u0001J\u0001K\u0001K\u0001K\u0001K\u0001L\u0001"+ + "L\u0001L\u0001L\u0001M\u0001M\u0001M\u0001M\u0001N\u0001N\u0001N\u0001"+ + "N\u0001O\u0001O\u0001O\u0001O\u0001P\u0001P\u0001P\u0001P\u0001Q\u0001"+ + "Q\u0001Q\u0001Q\u0001R\u0001R\u0001R\u0001R\u0001S\u0001S\u0001S\u0001"+ + "S\u0001T\u0001T\u0001T\u0001T\u0001U\u0001U\u0001U\u0001U\u0001V\u0001"+ + "V\u0001V\u0001V\u0001W\u0001W\u0001W\u0001W\u0001X\u0001X\u0001X\u0001"+ + "X\u0004\u00ff\u0108\u0143\u0158\u0000Y\u0004\u0001\u0006\u0002\b\u0003"+ + "\n\u0004\f\u0005\u000e\u0006\u0010\u0007\u0012\b\u0014\t\u0016\n\u0018"+ + "\u0000\u001a\u0000\u001c\u0000\u001e\u0000 \u0000\"\u000b$\f&\r(\u000e"+ + "*\u000f,\u0000.\u00100\u00002\u00004\u00116\u00008\u0012:\u0000<\u0000"+ + ">\u0000@\u0013B\u0014D\u0015F\u0000H\u0000J\u0000L\u0000N\u0016P\u0017"+ + "R\u0018T\u0019V\u0000X\u0000Z\u0000\\\u0000^\u0000`\u0000b\u0000d\u0000"+ + "f\u0000h\u0000j\u0000l\u0000n\u0000p\u001ar\u001bt\u001cv\u001dx\u001e"+ + "z\u0000|\u0000~\u001f\u0080\u0000\u0082\u0000\u0084\u0000\u0086\u0000"+ + "\u0088 \u008a\u0000\u008c\u0000\u008e\u0000\u0090\u0000\u0092\u0000\u0094"+ + "\u0000\u0096\u0000\u0098\u0000\u009a\u0000\u009c\u0000\u009e\u0000\u00a0"+ + "\u0000\u00a2\u0000\u00a4\u0000\u00a6\u0000\u00a8\u0000\u00aa\u0000\u00ac"+ + "\u0000\u00ae\u0000\u00b0\u0000\u00b2\u0000\u00b4\u0000\u0004\u0000\u0001"+ + "\u0002\u0003\u0010\u0002\u0000\t\t \u0002\u0000\n\n\r\r\u0001\u00000"+ + "9\u0002\u0000AZaz\b\u0000\"\"//\\\\bbffnnrrtt\u0003\u0000\n\n\"\"\\\\"+ + "\u0002\u0000\n\n\'\'\u0002\u0000--__\u0002\u0000\"\"\\\\\u0002\u0000E"+ + "Eee\u0002\u0000++--\u0002\u0000AFaf\u0001\u000019\u0001\u000007\u0001"+ + "\u000001\u0003\u0000 TTtt\u02a6\u0000\u0004\u0001\u0000\u0000\u0000\u0000"+ + "\u0006\u0001\u0000\u0000\u0000\u0000\b\u0001\u0000\u0000\u0000\u0000\n"+ + "\u0001\u0000\u0000\u0000\u0000\f\u0001\u0000\u0000\u0000\u0000\u000e\u0001"+ + "\u0000\u0000\u0000\u0000\u0010\u0001\u0000\u0000\u0000\u0000\u0012\u0001"+ + "\u0000\u0000\u0000\u0000\u0014\u0001\u0000\u0000\u0000\u0000\u0016\u0001"+ + "\u0000\u0000\u0000\u0000\"\u0001\u0000\u0000\u0000\u0000$\u0001\u0000"+ + "\u0000\u0000\u0000&\u0001\u0000\u0000\u0000\u0001(\u0001\u0000\u0000\u0000"+ + "\u0001*\u0001\u0000\u0000\u0000\u0001,\u0001\u0000\u0000\u0000\u0001."+ + "\u0001\u0000\u0000\u0000\u00012\u0001\u0000\u0000\u0000\u00014\u0001\u0000"+ + "\u0000\u0000\u00016\u0001\u0000\u0000\u0000\u00018\u0001\u0000\u0000\u0000"+ + "\u0001@\u0001\u0000\u0000\u0000\u0001B\u0001\u0000\u0000\u0000\u0001D"+ + "\u0001\u0000\u0000\u0000\u0001N\u0001\u0000\u0000\u0000\u0001P\u0001\u0000"+ + "\u0000\u0000\u0001R\u0001\u0000\u0000\u0000\u0001T\u0001\u0000\u0000\u0000"+ + "\u0001p\u0001\u0000\u0000\u0000\u0001r\u0001\u0000\u0000\u0000\u0001t"+ + "\u0001\u0000\u0000\u0000\u0001v\u0001\u0000\u0000\u0000\u0002x\u0001\u0000"+ + "\u0000\u0000\u0002z\u0001\u0000\u0000\u0000\u0002|\u0001\u0000\u0000\u0000"+ + "\u0002~\u0001\u0000\u0000\u0000\u0002\u0080\u0001\u0000\u0000\u0000\u0002"+ + "\u0082\u0001\u0000\u0000\u0000\u0002\u0084\u0001\u0000\u0000\u0000\u0002"+ + "\u0086\u0001\u0000\u0000\u0000\u0003\u0088\u0001\u0000\u0000\u0000\u0003"+ + "\u008a\u0001\u0000\u0000\u0000\u0003\u008c\u0001\u0000\u0000\u0000\u0003"+ + "\u008e\u0001\u0000\u0000\u0000\u0003\u0090\u0001\u0000\u0000\u0000\u0003"+ + "\u0092\u0001\u0000\u0000\u0000\u0003\u0094\u0001\u0000\u0000\u0000\u0003"+ + "\u0096\u0001\u0000\u0000\u0000\u0003\u0098\u0001\u0000\u0000\u0000\u0003"+ + "\u009a\u0001\u0000\u0000\u0000\u0003\u009c\u0001\u0000\u0000\u0000\u0003"+ + "\u009e\u0001\u0000\u0000\u0000\u0003\u00a0\u0001\u0000\u0000\u0000\u0003"+ + "\u00a2\u0001\u0000\u0000\u0000\u0003\u00a4\u0001\u0000\u0000\u0000\u0003"+ + "\u00a6\u0001\u0000\u0000\u0000\u0003\u00a8\u0001\u0000\u0000\u0000\u0003"+ + "\u00aa\u0001\u0000\u0000\u0000\u0003\u00ac\u0001\u0000\u0000\u0000\u0003"+ + "\u00ae\u0001\u0000\u0000\u0000\u0003\u00b0\u0001\u0000\u0000\u0000\u0003"+ + "\u00b2\u0001\u0000\u0000\u0000\u0003\u00b4\u0001\u0000\u0000\u0000\u0004"+ + "\u00b7\u0001\u0000\u0000\u0000\u0006\u00c1\u0001\u0000\u0000\u0000\b\u00c5"+ + "\u0001\u0000\u0000\u0000\n\u00cc\u0001\u0000\u0000\u0000\f\u00ce\u0001"+ + "\u0000\u0000\u0000\u000e\u00d1\u0001\u0000\u0000\u0000\u0010\u00d3\u0001"+ + "\u0000\u0000\u0000\u0012\u00d6\u0001\u0000\u0000\u0000\u0014\u00da\u0001"+ + "\u0000\u0000\u0000\u0016\u00dc\u0001\u0000\u0000\u0000\u0018\u00e0\u0001"+ + "\u0000\u0000\u0000\u001a\u00e2\u0001\u0000\u0000\u0000\u001c\u00e4\u0001"+ + "\u0000\u0000\u0000\u001e\u00ea\u0001\u0000\u0000\u0000 \u00f0\u0001\u0000"+ + "\u0000\u0000\"\u00fa\u0001\u0000\u0000\u0000$\u0104\u0001\u0000\u0000"+ + "\u0000&\u0110\u0001\u0000\u0000\u0000(\u0114\u0001\u0000\u0000\u0000*"+ + "\u0118\u0001\u0000\u0000\u0000,\u011c\u0001\u0000\u0000\u0000.\u012a\u0001"+ + "\u0000\u0000\u00000\u0134\u0001\u0000\u0000\u00002\u0136\u0001\u0000\u0000"+ + "\u00004\u013b\u0001\u0000\u0000\u00006\u014c\u0001\u0000\u0000\u00008"+ + "\u0151\u0001\u0000\u0000\u0000:\u0161\u0001\u0000\u0000\u0000<\u0167\u0001"+ + "\u0000\u0000\u0000>\u0170\u0001\u0000\u0000\u0000@\u0173\u0001\u0000\u0000"+ + "\u0000B\u017e\u0001\u0000\u0000\u0000D\u0187\u0001\u0000\u0000\u0000F"+ + "\u0191\u0001\u0000\u0000\u0000H\u0193\u0001\u0000\u0000\u0000J\u0195\u0001"+ + "\u0000\u0000\u0000L\u0197\u0001\u0000\u0000\u0000N\u019a\u0001\u0000\u0000"+ + "\u0000P\u01a9\u0001\u0000\u0000\u0000R\u01b7\u0001\u0000\u0000\u0000T"+ + "\u01c5\u0001\u0000\u0000\u0000V\u01d3\u0001\u0000\u0000\u0000X\u01d8\u0001"+ + "\u0000\u0000\u0000Z\u01db\u0001\u0000\u0000\u0000\\\u01de\u0001\u0000"+ + "\u0000\u0000^\u01e0\u0001\u0000\u0000\u0000`\u01e3\u0001\u0000\u0000\u0000"+ + "b\u01e6\u0001\u0000\u0000\u0000d\u01e9\u0001\u0000\u0000\u0000f\u01ef"+ + "\u0001\u0000\u0000\u0000h\u01f6\u0001\u0000\u0000\u0000j\u01f8\u0001\u0000"+ + "\u0000\u0000l\u0200\u0001\u0000\u0000\u0000n\u0206\u0001\u0000\u0000\u0000"+ + "p\u0209\u0001\u0000\u0000\u0000r\u020f\u0001\u0000\u0000\u0000t\u0215"+ + "\u0001\u0000\u0000\u0000v\u0219\u0001\u0000\u0000\u0000x\u021d\u0001\u0000"+ + "\u0000\u0000z\u0221\u0001\u0000\u0000\u0000|\u0225\u0001\u0000\u0000\u0000"+ + "~\u0229\u0001\u0000\u0000\u0000\u0080\u022d\u0001\u0000\u0000\u0000\u0082"+ + "\u0231\u0001\u0000\u0000\u0000\u0084\u0235\u0001\u0000\u0000\u0000\u0086"+ + "\u0239\u0001\u0000\u0000\u0000\u0088\u023e\u0001\u0000\u0000\u0000\u008a"+ + "\u0242\u0001\u0000\u0000\u0000\u008c\u0246\u0001\u0000\u0000\u0000\u008e"+ + "\u024a\u0001\u0000\u0000\u0000\u0090\u024e\u0001\u0000\u0000\u0000\u0092"+ + "\u0253\u0001\u0000\u0000\u0000\u0094\u0258\u0001\u0000\u0000\u0000\u0096"+ + "\u025d\u0001\u0000\u0000\u0000\u0098\u0261\u0001\u0000\u0000\u0000\u009a"+ + "\u0265\u0001\u0000\u0000\u0000\u009c\u0269\u0001\u0000\u0000\u0000\u009e"+ + "\u026d\u0001\u0000\u0000\u0000\u00a0\u0271\u0001\u0000\u0000\u0000\u00a2"+ + "\u0275\u0001\u0000\u0000\u0000\u00a4\u0279\u0001\u0000\u0000\u0000\u00a6"+ + "\u027d\u0001\u0000\u0000\u0000\u00a8\u0281\u0001\u0000\u0000\u0000\u00aa"+ + "\u0285\u0001\u0000\u0000\u0000\u00ac\u0289\u0001\u0000\u0000\u0000\u00ae"+ + "\u028d\u0001\u0000\u0000\u0000\u00b0\u0291\u0001\u0000\u0000\u0000\u00b2"+ + "\u0295\u0001\u0000\u0000\u0000\u00b4\u0299\u0001\u0000\u0000\u0000\u00b6"+ + "\u00b8\u0007\u0000\u0000\u0000\u00b7\u00b6\u0001\u0000\u0000\u0000\u00b8"+ + "\u00b9\u0001\u0000\u0000\u0000\u00b9\u00b7\u0001\u0000\u0000\u0000\u00b9"+ + "\u00ba\u0001\u0000\u0000\u0000\u00ba\u00bb\u0001\u0000\u0000\u0000\u00bb"+ + "\u00bc\u0006\u0000\u0000\u0000\u00bc\u0005\u0001\u0000\u0000\u0000\u00bd"+ + "\u00bf\u0005\r\u0000\u0000\u00be\u00bd\u0001\u0000\u0000\u0000\u00be\u00bf"+ + "\u0001\u0000\u0000\u0000\u00bf\u00c0\u0001\u0000\u0000\u0000\u00c0\u00c2"+ + "\u0005\n\u0000\u0000\u00c1\u00be\u0001\u0000\u0000\u0000\u00c2\u00c3\u0001"+ + "\u0000\u0000\u0000\u00c3\u00c1\u0001\u0000\u0000\u0000\u00c3\u00c4\u0001"+ + "\u0000\u0000\u0000\u00c4\u0007\u0001\u0000\u0000\u0000\u00c5\u00c9\u0005"+ + "#\u0000\u0000\u00c6\u00c8\b\u0001\u0000\u0000\u00c7\u00c6\u0001\u0000"+ + "\u0000\u0000\u00c8\u00cb\u0001\u0000\u0000\u0000\u00c9\u00c7\u0001\u0000"+ + "\u0000\u0000\u00c9\u00ca\u0001\u0000\u0000\u0000\u00ca\t\u0001\u0000\u0000"+ + "\u0000\u00cb\u00c9\u0001\u0000\u0000\u0000\u00cc\u00cd\u0005[\u0000\u0000"+ + "\u00cd\u000b\u0001\u0000\u0000\u0000\u00ce\u00cf\u0005[\u0000\u0000\u00cf"+ + "\u00d0\u0005[\u0000\u0000\u00d0\r\u0001\u0000\u0000\u0000\u00d1\u00d2"+ + "\u0005]\u0000\u0000\u00d2\u000f\u0001\u0000\u0000\u0000\u00d3\u00d4\u0005"+ + "]\u0000\u0000\u00d4\u00d5\u0005]\u0000\u0000\u00d5\u0011\u0001\u0000\u0000"+ + "\u0000\u00d6\u00d7\u0005=\u0000\u0000\u00d7\u00d8\u0001\u0000\u0000\u0000"+ + "\u00d8\u00d9\u0006\u0007\u0001\u0000\u00d9\u0013\u0001\u0000\u0000\u0000"+ + "\u00da\u00db\u0005.\u0000\u0000\u00db\u0015\u0001\u0000\u0000\u0000\u00dc"+ + "\u00dd\u0005,\u0000\u0000\u00dd\u00de\u0001\u0000\u0000\u0000\u00de\u00df"+ + "\u0006\t\u0000\u0000\u00df\u0017\u0001\u0000\u0000\u0000\u00e0\u00e1\u0007"+ + "\u0002\u0000\u0000\u00e1\u0019\u0001\u0000\u0000\u0000\u00e2\u00e3\u0007"+ + "\u0003\u0000\u0000\u00e3\u001b\u0001\u0000\u0000\u0000\u00e4\u00e8\u0005"+ + "\\\u0000\u0000\u00e5\u00e9\u0007\u0004\u0000\u0000\u00e6\u00e9\u0003\u001e"+ + "\r\u0000\u00e7\u00e9\u0003 \u000e\u0000\u00e8\u00e5\u0001\u0000\u0000"+ + "\u0000\u00e8\u00e6\u0001\u0000\u0000\u0000\u00e8\u00e7\u0001\u0000\u0000"+ + "\u0000\u00e9\u001d\u0001\u0000\u0000\u0000\u00ea\u00eb\u0005u\u0000\u0000"+ + "\u00eb\u00ec\u0003F!\u0000\u00ec\u00ed\u0003F!\u0000\u00ed\u00ee\u0003"+ + "F!\u0000\u00ee\u00ef\u0003F!\u0000\u00ef\u001f\u0001\u0000\u0000\u0000"+ + "\u00f0\u00f1\u0005U\u0000\u0000\u00f1\u00f2\u0003F!\u0000\u00f2\u00f3"+ + "\u0003F!\u0000\u00f3\u00f4\u0003F!\u0000\u00f4\u00f5\u0003F!\u0000\u00f5"+ + "\u00f6\u0003F!\u0000\u00f6\u00f7\u0003F!\u0000\u00f7\u00f8\u0003F!\u0000"+ + "\u00f8\u00f9\u0003F!\u0000\u00f9!\u0001\u0000\u0000\u0000\u00fa\u00ff"+ + "\u0005\"\u0000\u0000\u00fb\u00fe\u0003\u001c\f\u0000\u00fc\u00fe\b\u0005"+ + "\u0000\u0000\u00fd\u00fb\u0001\u0000\u0000\u0000\u00fd\u00fc\u0001\u0000"+ + "\u0000\u0000\u00fe\u0101\u0001\u0000\u0000\u0000\u00ff\u0100\u0001\u0000"+ + "\u0000\u0000\u00ff\u00fd\u0001\u0000\u0000\u0000\u0100\u0102\u0001\u0000"+ + "\u0000\u0000\u0101\u00ff\u0001\u0000\u0000\u0000\u0102\u0103\u0005\"\u0000"+ + "\u0000\u0103#\u0001\u0000\u0000\u0000\u0104\u0108\u0005\'\u0000\u0000"+ + "\u0105\u0107\b\u0006\u0000\u0000\u0106\u0105\u0001\u0000\u0000\u0000\u0107"+ + "\u010a\u0001\u0000\u0000\u0000\u0108\u0109\u0001\u0000\u0000\u0000\u0108"+ + "\u0106\u0001\u0000\u0000\u0000\u0109\u010b\u0001\u0000\u0000\u0000\u010a"+ + "\u0108\u0001\u0000\u0000\u0000\u010b\u010c\u0005\'\u0000\u0000\u010c%"+ + "\u0001\u0000\u0000\u0000\u010d\u0111\u0003\u001a\u000b\u0000\u010e\u0111"+ + "\u0003\u0018\n\u0000\u010f\u0111\u0007\u0007\u0000\u0000\u0110\u010d\u0001"+ + "\u0000\u0000\u0000\u0110\u010e\u0001\u0000\u0000\u0000\u0110\u010f\u0001"+ + "\u0000\u0000\u0000\u0111\u0112\u0001\u0000\u0000\u0000\u0112\u0110\u0001"+ + "\u0000\u0000\u0000\u0112\u0113\u0001\u0000\u0000\u0000\u0113\'\u0001\u0000"+ + "\u0000\u0000\u0114\u0115\u0003\u0004\u0000\u0000\u0115\u0116\u0001\u0000"+ + "\u0000\u0000\u0116\u0117\u0006\u0012\u0000\u0000\u0117)\u0001\u0000\u0000"+ + "\u0000\u0118\u0119\u0005{\u0000\u0000\u0119\u011a\u0001\u0000\u0000\u0000"+ + "\u011a\u011b\u0006\u0013\u0002\u0000\u011b+\u0001\u0000\u0000\u0000\u011c"+ + "\u011d\u0003\n\u0003\u0000\u011d\u011e\u0001\u0000\u0000\u0000\u011e\u011f"+ + "\u0006\u0014\u0003\u0000\u011f\u0120\u0006\u0014\u0004\u0000\u0120-\u0001"+ + "\u0000\u0000\u0000\u0121\u0122\u0005t\u0000\u0000\u0122\u0123\u0005r\u0000"+ + "\u0000\u0123\u0124\u0005u\u0000\u0000\u0124\u012b\u0005e\u0000\u0000\u0125"+ + "\u0126\u0005f\u0000\u0000\u0126\u0127\u0005a\u0000\u0000\u0127\u0128\u0005"+ + "l\u0000\u0000\u0128\u0129\u0005s\u0000\u0000\u0129\u012b\u0005e\u0000"+ + "\u0000\u012a\u0121\u0001\u0000\u0000\u0000\u012a\u0125\u0001\u0000\u0000"+ + "\u0000\u012b\u012c\u0001\u0000\u0000\u0000\u012c\u012d\u0006\u0015\u0005"+ + "\u0000\u012d/\u0001\u0000\u0000\u0000\u012e\u0130\u0005\\\u0000\u0000"+ + "\u012f\u0131\u0005\r\u0000\u0000\u0130\u012f\u0001\u0000\u0000\u0000\u0130"+ + "\u0131\u0001\u0000\u0000\u0000\u0131\u0132\u0001\u0000\u0000\u0000\u0132"+ + "\u0135\u0005\n\u0000\u0000\u0133\u0135\u0003\u001c\f\u0000\u0134\u012e"+ + "\u0001\u0000\u0000\u0000\u0134\u0133\u0001\u0000\u0000\u0000\u01351\u0001"+ + "\u0000\u0000\u0000\u0136\u0137\u0003\"\u000f\u0000\u0137\u0138\u0001\u0000"+ + "\u0000\u0000\u0138\u0139\u0006\u0017\u0006\u0000\u0139\u013a\u0006\u0017"+ + "\u0005\u0000\u013a3\u0001\u0000\u0000\u0000\u013b\u013c\u0005\"\u0000"+ + "\u0000\u013c\u013d\u0005\"\u0000\u0000\u013d\u013e\u0005\"\u0000\u0000"+ + "\u013e\u0143\u0001\u0000\u0000\u0000\u013f\u0142\u00030\u0016\u0000\u0140"+ + "\u0142\b\b\u0000\u0000\u0141\u013f\u0001\u0000\u0000\u0000\u0141\u0140"+ + "\u0001\u0000\u0000\u0000\u0142\u0145\u0001\u0000\u0000\u0000\u0143\u0144"+ + "\u0001\u0000\u0000\u0000\u0143\u0141\u0001\u0000\u0000\u0000\u0144\u0146"+ + "\u0001\u0000\u0000\u0000\u0145\u0143\u0001\u0000\u0000\u0000\u0146\u0147"+ + "\u0005\"\u0000\u0000\u0147\u0148\u0005\"\u0000\u0000\u0148\u0149\u0005"+ + "\"\u0000\u0000\u0149\u014a\u0001\u0000\u0000\u0000\u014a\u014b\u0006\u0018"+ + "\u0005\u0000\u014b5\u0001\u0000\u0000\u0000\u014c\u014d\u0003$\u0010\u0000"+ + "\u014d\u014e\u0001\u0000\u0000\u0000\u014e\u014f\u0006\u0019\u0007\u0000"+ + "\u014f\u0150\u0006\u0019\u0005\u0000\u01507\u0001\u0000\u0000\u0000\u0151"+ + "\u0152\u0005\'\u0000\u0000\u0152\u0153\u0005\'\u0000\u0000\u0153\u0154"+ + "\u0005\'\u0000\u0000\u0154\u0158\u0001\u0000\u0000\u0000\u0155\u0157\t"+ + "\u0000\u0000\u0000\u0156\u0155\u0001\u0000\u0000\u0000\u0157\u015a\u0001"+ + "\u0000\u0000\u0000\u0158\u0159\u0001\u0000\u0000\u0000\u0158\u0156\u0001"+ + "\u0000\u0000\u0000\u0159\u015b\u0001\u0000\u0000\u0000\u015a\u0158\u0001"+ + "\u0000\u0000\u0000\u015b\u015c\u0005\'\u0000\u0000\u015c\u015d\u0005\'"+ + "\u0000\u0000\u015d\u015e\u0005\'\u0000\u0000\u015e\u015f\u0001\u0000\u0000"+ + "\u0000\u015f\u0160\u0006\u001a\u0005\u0000\u01609\u0001\u0000\u0000\u0000"+ + "\u0161\u0163\u0007\t\u0000\u0000\u0162\u0164\u0007\n\u0000\u0000\u0163"+ + "\u0162\u0001\u0000\u0000\u0000\u0163\u0164\u0001\u0000\u0000\u0000\u0164"+ + "\u0165\u0001\u0000\u0000\u0000\u0165\u0166\u0003<\u001c\u0000\u0166;\u0001"+ + "\u0000\u0000\u0000\u0167\u016d\u0003\u0018\n\u0000\u0168\u016c\u0003\u0018"+ + "\n\u0000\u0169\u016a\u0005_\u0000\u0000\u016a\u016c\u0003\u0018\n\u0000"+ + "\u016b\u0168\u0001\u0000\u0000\u0000\u016b\u0169\u0001\u0000\u0000\u0000"+ + "\u016c\u016f\u0001\u0000\u0000\u0000\u016d\u016b\u0001\u0000\u0000\u0000"+ + "\u016d\u016e\u0001\u0000\u0000\u0000\u016e=\u0001\u0000\u0000\u0000\u016f"+ + "\u016d\u0001\u0000\u0000\u0000\u0170\u0171\u0005.\u0000\u0000\u0171\u0172"+ + "\u0003<\u001c\u0000\u0172?\u0001\u0000\u0000\u0000\u0173\u0179\u0003N"+ + "%\u0000\u0174\u017a\u0003:\u001b\u0000\u0175\u0177\u0003>\u001d\u0000"+ + "\u0176\u0178\u0003:\u001b\u0000\u0177\u0176\u0001\u0000\u0000\u0000\u0177"+ + "\u0178\u0001\u0000\u0000\u0000\u0178\u017a\u0001\u0000\u0000\u0000\u0179"+ + "\u0174\u0001\u0000\u0000\u0000\u0179\u0175\u0001\u0000\u0000\u0000\u017a"+ + "\u017b\u0001\u0000\u0000\u0000\u017b\u017c\u0006\u001e\u0005\u0000\u017c"+ + "A\u0001\u0000\u0000\u0000\u017d\u017f\u0007\n\u0000\u0000\u017e\u017d"+ + "\u0001\u0000\u0000\u0000\u017e\u017f\u0001\u0000\u0000\u0000\u017f\u0180"+ + "\u0001\u0000\u0000\u0000\u0180\u0181\u0005i\u0000\u0000\u0181\u0182\u0005"+ + "n\u0000\u0000\u0182\u0183\u0005f\u0000\u0000\u0183\u0184\u0001\u0000\u0000"+ + "\u0000\u0184\u0185\u0006\u001f\u0005\u0000\u0185C\u0001\u0000\u0000\u0000"+ + "\u0186\u0188\u0007\n\u0000\u0000\u0187\u0186\u0001\u0000\u0000\u0000\u0187"+ + "\u0188\u0001\u0000\u0000\u0000\u0188\u0189\u0001\u0000\u0000\u0000\u0189"+ + "\u018a\u0005n\u0000\u0000\u018a\u018b\u0005a\u0000\u0000\u018b\u018c\u0005"+ + "n\u0000\u0000\u018c\u018d\u0001\u0000\u0000\u0000\u018d\u018e\u0006 \u0005"+ + "\u0000\u018eE\u0001\u0000\u0000\u0000\u018f\u0192\u0007\u000b\u0000\u0000"+ + "\u0190\u0192\u0003\u0018\n\u0000\u0191\u018f\u0001\u0000\u0000\u0000\u0191"+ + "\u0190\u0001\u0000\u0000\u0000\u0192G\u0001\u0000\u0000\u0000\u0193\u0194"+ + "\u0007\f\u0000\u0000\u0194I\u0001\u0000\u0000\u0000\u0195\u0196\u0007"+ + "\r\u0000\u0000\u0196K\u0001\u0000\u0000\u0000\u0197\u0198\u0007\u000e"+ + "\u0000\u0000\u0198M\u0001\u0000\u0000\u0000\u0199\u019b\u0007\n\u0000"+ + "\u0000\u019a\u0199\u0001\u0000\u0000\u0000\u019a\u019b\u0001\u0000\u0000"+ + "\u0000\u019b\u01a5\u0001\u0000\u0000\u0000\u019c\u01a6\u0003\u0018\n\u0000"+ + "\u019d\u01a1\u0003H\"\u0000\u019e\u01a2\u0003\u0018\n\u0000\u019f\u01a0"+ + "\u0005_\u0000\u0000\u01a0\u01a2\u0003\u0018\n\u0000\u01a1\u019e\u0001"+ + "\u0000\u0000\u0000\u01a1\u019f\u0001\u0000\u0000\u0000\u01a2\u01a3\u0001"+ + "\u0000\u0000\u0000\u01a3\u01a1\u0001\u0000\u0000\u0000\u01a3\u01a4\u0001"+ + "\u0000\u0000\u0000\u01a4\u01a6\u0001\u0000\u0000\u0000\u01a5\u019c\u0001"+ + "\u0000\u0000\u0000\u01a5\u019d\u0001\u0000\u0000\u0000\u01a6\u01a7\u0001"+ + "\u0000\u0000\u0000\u01a7\u01a8\u0006%\u0005\u0000\u01a8O\u0001\u0000\u0000"+ + "\u0000\u01a9\u01aa\u00050\u0000\u0000\u01aa\u01ab\u0005x\u0000\u0000\u01ab"+ + "\u01ac\u0001\u0000\u0000\u0000\u01ac\u01b2\u0003F!\u0000\u01ad\u01b1\u0003"+ + "F!\u0000\u01ae\u01af\u0005_\u0000\u0000\u01af\u01b1\u0003F!\u0000\u01b0"+ + "\u01ad\u0001\u0000\u0000\u0000\u01b0\u01ae\u0001\u0000\u0000\u0000\u01b1"+ + "\u01b4\u0001\u0000\u0000\u0000\u01b2\u01b0\u0001\u0000\u0000\u0000\u01b2"+ + "\u01b3\u0001\u0000\u0000\u0000\u01b3\u01b5\u0001\u0000\u0000\u0000\u01b4"+ + "\u01b2\u0001\u0000\u0000\u0000\u01b5\u01b6\u0006&\u0005\u0000\u01b6Q\u0001"+ + "\u0000\u0000\u0000\u01b7\u01b8\u00050\u0000\u0000\u01b8\u01b9\u0005o\u0000"+ + "\u0000\u01b9\u01ba\u0001\u0000\u0000\u0000\u01ba\u01c0\u0003J#\u0000\u01bb"+ + "\u01bf\u0003J#\u0000\u01bc\u01bd\u0005_\u0000\u0000\u01bd\u01bf\u0003"+ + "J#\u0000\u01be\u01bb\u0001\u0000\u0000\u0000\u01be\u01bc\u0001\u0000\u0000"+ + "\u0000\u01bf\u01c2\u0001\u0000\u0000\u0000\u01c0\u01be\u0001\u0000\u0000"+ + "\u0000\u01c0\u01c1\u0001\u0000\u0000\u0000\u01c1\u01c3\u0001\u0000\u0000"+ + "\u0000\u01c2\u01c0\u0001\u0000\u0000\u0000\u01c3\u01c4\u0006\'\u0005\u0000"+ + "\u01c4S\u0001\u0000\u0000\u0000\u01c5\u01c6\u00050\u0000\u0000\u01c6\u01c7"+ + "\u0005b\u0000\u0000\u01c7\u01c8\u0001\u0000\u0000\u0000\u01c8\u01ce\u0003"+ + "L$\u0000\u01c9\u01cd\u0003L$\u0000\u01ca\u01cb\u0005_\u0000\u0000\u01cb"+ + "\u01cd\u0003L$\u0000\u01cc\u01c9\u0001\u0000\u0000\u0000\u01cc\u01ca\u0001"+ + "\u0000\u0000\u0000\u01cd\u01d0\u0001\u0000\u0000\u0000\u01ce\u01cc\u0001"+ + "\u0000\u0000\u0000\u01ce\u01cf\u0001\u0000\u0000\u0000\u01cf\u01d1\u0001"+ + "\u0000\u0000\u0000\u01d0\u01ce\u0001\u0000\u0000\u0000\u01d1\u01d2\u0006"+ + "(\u0005\u0000\u01d2U\u0001\u0000\u0000\u0000\u01d3\u01d4\u0003\u0018\n"+ + "\u0000\u01d4\u01d5\u0003\u0018\n\u0000\u01d5\u01d6\u0003\u0018\n\u0000"+ + "\u01d6\u01d7\u0003\u0018\n\u0000\u01d7W\u0001\u0000\u0000\u0000\u01d8"+ + "\u01d9\u0003\u0018\n\u0000\u01d9\u01da\u0003\u0018\n\u0000\u01daY\u0001"+ + "\u0000\u0000\u0000\u01db\u01dc\u0003\u0018\n\u0000\u01dc\u01dd\u0003\u0018"+ + "\n\u0000\u01dd[\u0001\u0000\u0000\u0000\u01de\u01df\u0007\u000f\u0000"+ + "\u0000\u01df]\u0001\u0000\u0000\u0000\u01e0\u01e1\u0003\u0018\n\u0000"+ + "\u01e1\u01e2\u0003\u0018\n\u0000\u01e2_\u0001\u0000\u0000\u0000\u01e3"+ + "\u01e4\u0003\u0018\n\u0000\u01e4\u01e5\u0003\u0018\n\u0000\u01e5a\u0001"+ + "\u0000\u0000\u0000\u01e6\u01e7\u0003\u0018\n\u0000\u01e7\u01e8\u0003\u0018"+ + "\n\u0000\u01e8c\u0001\u0000\u0000\u0000\u01e9\u01eb\u0005.\u0000\u0000"+ + "\u01ea\u01ec\u0003\u0018\n\u0000\u01eb\u01ea\u0001\u0000\u0000\u0000\u01ec"+ + "\u01ed\u0001\u0000\u0000\u0000\u01ed\u01eb\u0001\u0000\u0000\u0000\u01ed"+ + "\u01ee\u0001\u0000\u0000\u0000\u01eee\u0001\u0000\u0000\u0000\u01ef\u01f0"+ + "\u0007\n\u0000\u0000\u01f0\u01f1\u0003^-\u0000\u01f1\u01f2\u0005:\u0000"+ + "\u0000\u01f2\u01f3\u0003`.\u0000\u01f3g\u0001\u0000\u0000\u0000\u01f4"+ + "\u01f7\u0005Z\u0000\u0000\u01f5\u01f7\u0003f1\u0000\u01f6\u01f4\u0001"+ + "\u0000\u0000\u0000\u01f6\u01f5\u0001\u0000\u0000\u0000\u01f7i\u0001\u0000"+ + "\u0000\u0000\u01f8\u01f9\u0003^-\u0000\u01f9\u01fa\u0005:\u0000\u0000"+ + "\u01fa\u01fb\u0003`.\u0000\u01fb\u01fc\u0005:\u0000\u0000\u01fc\u01fe"+ + "\u0003b/\u0000\u01fd\u01ff\u0003d0\u0000\u01fe\u01fd\u0001\u0000\u0000"+ + "\u0000\u01fe\u01ff\u0001\u0000\u0000\u0000\u01ffk\u0001\u0000\u0000\u0000"+ + "\u0200\u0201\u0003V)\u0000\u0201\u0202\u0005-\u0000\u0000\u0202\u0203"+ + "\u0003X*\u0000\u0203\u0204\u0005-\u0000\u0000\u0204\u0205\u0003Z+\u0000"+ + "\u0205m\u0001\u0000\u0000\u0000\u0206\u0207\u0003j3\u0000\u0207\u0208"+ + "\u0003h2\u0000\u0208o\u0001\u0000\u0000\u0000\u0209\u020a\u0003l4\u0000"+ + "\u020a\u020b\u0003\\,\u0000\u020b\u020c\u0003n5\u0000\u020c\u020d\u0001"+ + "\u0000\u0000\u0000\u020d\u020e\u00066\u0005\u0000\u020eq\u0001\u0000\u0000"+ + "\u0000\u020f\u0210\u0003l4\u0000\u0210\u0211\u0003\\,\u0000\u0211\u0212"+ + "\u0003j3\u0000\u0212\u0213\u0001\u0000\u0000\u0000\u0213\u0214\u00067"+ + "\u0005\u0000\u0214s\u0001\u0000\u0000\u0000\u0215\u0216\u0003l4\u0000"+ + "\u0216\u0217\u0001\u0000\u0000\u0000\u0217\u0218\u00068\u0005\u0000\u0218"+ + "u\u0001\u0000\u0000\u0000\u0219\u021a\u0003j3\u0000\u021a\u021b\u0001"+ + "\u0000\u0000\u0000\u021b\u021c\u00069\u0005\u0000\u021cw\u0001\u0000\u0000"+ + "\u0000\u021d\u021e\u0003\u0004\u0000\u0000\u021e\u021f\u0001\u0000\u0000"+ + "\u0000\u021f\u0220\u0006:\u0000\u0000\u0220y\u0001\u0000\u0000\u0000\u0221"+ + "\u0222\u0003\u0014\b\u0000\u0222\u0223\u0001\u0000\u0000\u0000\u0223\u0224"+ + "\u0006;\b\u0000\u0224{\u0001\u0000\u0000\u0000\u0225\u0226\u0003\u0016"+ + "\t\u0000\u0226\u0227\u0001\u0000\u0000\u0000\u0227\u0228\u0006<\t\u0000"+ + "\u0228}\u0001\u0000\u0000\u0000\u0229\u022a\u0005}\u0000\u0000\u022a\u022b"+ + "\u0001\u0000\u0000\u0000\u022b\u022c\u0006=\u0005\u0000\u022c\u007f\u0001"+ + "\u0000\u0000\u0000\u022d\u022e\u0003\"\u000f\u0000\u022e\u022f\u0001\u0000"+ + "\u0000\u0000\u022f\u0230\u0006>\u0006\u0000\u0230\u0081\u0001\u0000\u0000"+ + "\u0000\u0231\u0232\u0003$\u0010\u0000\u0232\u0233\u0001\u0000\u0000\u0000"+ + "\u0233\u0234\u0006?\u0007\u0000\u0234\u0083\u0001\u0000\u0000\u0000\u0235"+ + "\u0236\u0003&\u0011\u0000\u0236\u0237\u0001\u0000\u0000\u0000\u0237\u0238"+ + "\u0006@\n\u0000\u0238\u0085\u0001\u0000\u0000\u0000\u0239\u023a\u0003"+ + "\u0012\u0007\u0000\u023a\u023b\u0001\u0000\u0000\u0000\u023b\u023c\u0006"+ + "A\u000b\u0000\u023c\u023d\u0006A\u0001\u0000\u023d\u0087\u0001\u0000\u0000"+ + "\u0000\u023e\u023f\u0003\u0004\u0000\u0000\u023f\u0240\u0001\u0000\u0000"+ + "\u0000\u0240\u0241\u0006B\u0000\u0000\u0241\u0089\u0001\u0000\u0000\u0000"+ + "\u0242\u0243\u0003\u0006\u0001\u0000\u0243\u0244\u0001\u0000\u0000\u0000"+ + "\u0244\u0245\u0006C\f\u0000\u0245\u008b\u0001\u0000\u0000\u0000\u0246"+ + "\u0247\u0003\b\u0002\u0000\u0247\u0248\u0001\u0000\u0000\u0000\u0248\u0249"+ + "\u0006D\r\u0000\u0249\u008d\u0001\u0000\u0000\u0000\u024a\u024b\u0003"+ + "\u0016\t\u0000\u024b\u024c\u0001\u0000\u0000\u0000\u024c\u024d\u0006E"+ + "\t\u0000\u024d\u008f\u0001\u0000\u0000\u0000\u024e\u024f\u0003*\u0013"+ + "\u0000\u024f\u0250\u0001\u0000\u0000\u0000\u0250\u0251\u0006F\u000e\u0000"+ + "\u0251\u0252\u0006F\u000f\u0000\u0252\u0091\u0001\u0000\u0000\u0000\u0253"+ + "\u0254\u0003\n\u0003\u0000\u0254\u0255\u0001\u0000\u0000\u0000\u0255\u0256"+ + "\u0006G\u0003\u0000\u0256\u0257\u0006G\u0010\u0000\u0257\u0093\u0001\u0000"+ + "\u0000\u0000\u0258\u0259\u0003\u000e\u0005\u0000\u0259\u025a\u0001\u0000"+ + "\u0000\u0000\u025a\u025b\u0006H\u0011\u0000\u025b\u025c\u0006H\u0005\u0000"+ + "\u025c\u0095\u0001\u0000\u0000\u0000\u025d\u025e\u0003.\u0015\u0000\u025e"+ + "\u025f\u0001\u0000\u0000\u0000\u025f\u0260\u0006I\u0012\u0000\u0260\u0097"+ + "\u0001\u0000\u0000\u0000\u0261\u0262\u0003\"\u000f\u0000\u0262\u0263\u0001"+ + "\u0000\u0000\u0000\u0263\u0264\u0006J\u0006\u0000\u0264\u0099\u0001\u0000"+ + "\u0000\u0000\u0265\u0266\u00034\u0018\u0000\u0266\u0267\u0001\u0000\u0000"+ + "\u0000\u0267\u0268\u0006K\u0013\u0000\u0268\u009b\u0001\u0000\u0000\u0000"+ + "\u0269\u026a\u0003$\u0010\u0000\u026a\u026b\u0001\u0000\u0000\u0000\u026b"+ + "\u026c\u0006L\u0007\u0000\u026c\u009d\u0001\u0000\u0000\u0000\u026d\u026e"+ + "\u00038\u001a\u0000\u026e\u026f\u0001\u0000\u0000\u0000\u026f\u0270\u0006"+ + "M\u0014\u0000\u0270\u009f\u0001\u0000\u0000\u0000\u0271\u0272\u0003@\u001e"+ + "\u0000\u0272\u0273\u0001\u0000\u0000\u0000\u0273\u0274\u0006N\u0015\u0000"+ + "\u0274\u00a1\u0001\u0000\u0000\u0000\u0275\u0276\u0003B\u001f\u0000\u0276"+ + "\u0277\u0001\u0000\u0000\u0000\u0277\u0278\u0006O\u0016\u0000\u0278\u00a3"+ + "\u0001\u0000\u0000\u0000\u0279\u027a\u0003D \u0000\u027a\u027b\u0001\u0000"+ + "\u0000\u0000\u027b\u027c\u0006P\u0017\u0000\u027c\u00a5\u0001\u0000\u0000"+ + "\u0000\u027d\u027e\u0003N%\u0000\u027e\u027f\u0001\u0000\u0000\u0000\u027f"+ + "\u0280\u0006Q\u0018\u0000\u0280\u00a7\u0001\u0000\u0000\u0000\u0281\u0282"+ + "\u0003P&\u0000\u0282\u0283\u0001\u0000\u0000\u0000\u0283\u0284\u0006R"+ + "\u0019\u0000\u0284\u00a9\u0001\u0000\u0000\u0000\u0285\u0286\u0003R\'"+ + "\u0000\u0286\u0287\u0001\u0000\u0000\u0000\u0287\u0288\u0006S\u001a\u0000"+ + "\u0288\u00ab\u0001\u0000\u0000\u0000\u0289\u028a\u0003T(\u0000\u028a\u028b"+ + "\u0001\u0000\u0000\u0000\u028b\u028c\u0006T\u001b\u0000\u028c\u00ad\u0001"+ + "\u0000\u0000\u0000\u028d\u028e\u0003p6\u0000\u028e\u028f\u0001\u0000\u0000"+ + "\u0000\u028f\u0290\u0006U\u001c\u0000\u0290\u00af\u0001\u0000\u0000\u0000"+ + "\u0291\u0292\u0003r7\u0000\u0292\u0293\u0001\u0000\u0000\u0000\u0293\u0294"+ + "\u0006V\u001d\u0000\u0294\u00b1\u0001\u0000\u0000\u0000\u0295\u0296\u0003"+ + "t8\u0000\u0296\u0297\u0001\u0000\u0000\u0000\u0297\u0298\u0006W\u001e"+ + "\u0000\u0298\u00b3\u0001\u0000\u0000\u0000\u0299\u029a\u0003v9\u0000\u029a"+ + "\u029b\u0001\u0000\u0000\u0000\u029b\u029c\u0006X\u001f\u0000\u029c\u00b5"+ + "\u0001\u0000\u0000\u0000)\u0000\u0001\u0002\u0003\u00b9\u00be\u00c3\u00c9"+ + "\u00e8\u00fd\u00ff\u0108\u0110\u0112\u012a\u0130\u0134\u0141\u0143\u0158"+ + "\u0163\u016b\u016d\u0177\u0179\u017e\u0187\u0191\u019a\u01a1\u01a3\u01a5"+ + "\u01b0\u01b2\u01be\u01c0\u01cc\u01ce\u01ed\u01f6\u01fe \u0006\u0000\u0000"+ + "\u0005\u0001\u0000\u0002\u0002\u0000\u0007\u0004\u0000\u0002\u0003\u0000"+ + "\u0004\u0000\u0000\u0007\u000b\u0000\u0007\f\u0000\u0007\t\u0000\u0007"+ + "\n\u0000\u0007\r\u0000\u0007\b\u0000\u0007\u0002\u0000\u0007\u0003\u0000"+ + "\u0007\u000f\u0000\u0005\u0002\u0000\u0005\u0003\u0000\u0007\u0006\u0000"+ + "\u0007\u0010\u0000\u0007\u0011\u0000\u0007\u0012\u0000\u0007\u0013\u0000"+ + "\u0007\u0014\u0000\u0007\u0015\u0000\u0007\u0016\u0000\u0007\u0017\u0000"+ + "\u0007\u0018\u0000\u0007\u0019\u0000\u0007\u001a\u0000\u0007\u001b\u0000"+ + "\u0007\u001c\u0000\u0007\u001d\u0000"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.interp b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.interp index 826b7607270..314ece3ce49 100644 --- a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.interp +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.interp @@ -93,4 +93,4 @@ arrayTable atn: -[4, 1, 32, 235, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 1, 0, 3, 0, 44, 8, 0, 1, 0, 1, 0, 3, 0, 48, 8, 0, 5, 0, 50, 8, 0, 10, 0, 12, 0, 53, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 59, 8, 1, 1, 1, 1, 1, 3, 1, 63, 8, 1, 1, 1, 3, 1, 66, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 76, 8, 4, 1, 5, 1, 5, 3, 5, 80, 8, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 4, 8, 89, 8, 8, 11, 8, 12, 8, 90, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 100, 8, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 3, 15, 115, 8, 15, 1, 16, 1, 16, 5, 16, 119, 8, 16, 10, 16, 12, 16, 122, 9, 16, 1, 16, 1, 16, 1, 16, 5, 16, 127, 8, 16, 10, 16, 12, 16, 130, 9, 16, 1, 16, 1, 16, 1, 16, 5, 16, 135, 8, 16, 10, 16, 12, 16, 138, 9, 16, 1, 16, 1, 16, 3, 16, 142, 8, 16, 5, 16, 144, 8, 16, 10, 16, 12, 16, 147, 9, 16, 1, 16, 5, 16, 150, 8, 16, 10, 16, 12, 16, 153, 9, 16, 1, 16, 1, 16, 3, 16, 157, 8, 16, 1, 17, 1, 17, 3, 17, 161, 8, 17, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 167, 8, 18, 10, 18, 12, 18, 170, 9, 18, 1, 18, 5, 18, 173, 8, 18, 10, 18, 12, 18, 176, 9, 18, 1, 19, 1, 19, 5, 19, 180, 8, 19, 10, 19, 12, 19, 183, 9, 19, 1, 19, 1, 19, 1, 19, 5, 19, 188, 8, 19, 10, 19, 12, 19, 191, 9, 19, 1, 19, 1, 19, 1, 19, 5, 19, 196, 8, 19, 10, 19, 12, 19, 199, 9, 19, 1, 19, 1, 19, 3, 19, 203, 8, 19, 5, 19, 205, 8, 19, 10, 19, 12, 19, 208, 9, 19, 1, 19, 5, 19, 211, 8, 19, 10, 19, 12, 19, 214, 9, 19, 1, 19, 1, 19, 3, 19, 218, 8, 19, 1, 20, 1, 20, 1, 20, 1, 20, 5, 20, 224, 8, 20, 10, 20, 12, 20, 227, 9, 20, 1, 20, 5, 20, 230, 8, 20, 10, 20, 12, 20, 233, 9, 20, 1, 20, 0, 0, 21, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 0, 5, 1, 0, 11, 12, 2, 0, 11, 12, 17, 18, 1, 0, 22, 25, 1, 0, 19, 21, 1, 0, 26, 29, 249, 0, 43, 1, 0, 0, 0, 2, 65, 1, 0, 0, 0, 4, 67, 1, 0, 0, 0, 6, 69, 1, 0, 0, 0, 8, 75, 1, 0, 0, 0, 10, 79, 1, 0, 0, 0, 12, 81, 1, 0, 0, 0, 14, 83, 1, 0, 0, 0, 16, 85, 1, 0, 0, 0, 18, 99, 1, 0, 0, 0, 20, 101, 1, 0, 0, 0, 22, 103, 1, 0, 0, 0, 24, 105, 1, 0, 0, 0, 26, 107, 1, 0, 0, 0, 28, 109, 1, 0, 0, 0, 30, 114, 1, 0, 0, 0, 32, 156, 1, 0, 0, 0, 34, 160, 1, 0, 0, 0, 36, 162, 1, 0, 0, 0, 38, 217, 1, 0, 0, 0, 40, 219, 1, 0, 0, 0, 42, 44, 3, 2, 1, 0, 43, 42, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 51, 1, 0, 0, 0, 45, 47, 5, 2, 0, 0, 46, 48, 3, 2, 1, 0, 47, 46, 1, 0, 0, 0, 47, 48, 1, 0, 0, 0, 48, 50, 1, 0, 0, 0, 49, 45, 1, 0, 0, 0, 50, 53, 1, 0, 0, 0, 51, 49, 1, 0, 0, 0, 51, 52, 1, 0, 0, 0, 52, 54, 1, 0, 0, 0, 53, 51, 1, 0, 0, 0, 54, 55, 5, 0, 0, 1, 55, 1, 1, 0, 0, 0, 56, 58, 3, 6, 3, 0, 57, 59, 3, 4, 2, 0, 58, 57, 1, 0, 0, 0, 58, 59, 1, 0, 0, 0, 59, 66, 1, 0, 0, 0, 60, 62, 3, 34, 17, 0, 61, 63, 3, 4, 2, 0, 62, 61, 1, 0, 0, 0, 62, 63, 1, 0, 0, 0, 63, 66, 1, 0, 0, 0, 64, 66, 3, 4, 2, 0, 65, 56, 1, 0, 0, 0, 65, 60, 1, 0, 0, 0, 65, 64, 1, 0, 0, 0, 66, 3, 1, 0, 0, 0, 67, 68, 5, 3, 0, 0, 68, 5, 1, 0, 0, 0, 69, 70, 3, 8, 4, 0, 70, 71, 5, 8, 0, 0, 71, 72, 3, 18, 9, 0, 72, 7, 1, 0, 0, 0, 73, 76, 3, 10, 5, 0, 74, 76, 3, 16, 8, 0, 75, 73, 1, 0, 0, 0, 75, 74, 1, 0, 0, 0, 76, 9, 1, 0, 0, 0, 77, 80, 3, 14, 7, 0, 78, 80, 3, 12, 6, 0, 79, 77, 1, 0, 0, 0, 79, 78, 1, 0, 0, 0, 80, 11, 1, 0, 0, 0, 81, 82, 5, 13, 0, 0, 82, 13, 1, 0, 0, 0, 83, 84, 7, 0, 0, 0, 84, 15, 1, 0, 0, 0, 85, 88, 3, 10, 5, 0, 86, 87, 5, 9, 0, 0, 87, 89, 3, 10, 5, 0, 88, 86, 1, 0, 0, 0, 89, 90, 1, 0, 0, 0, 90, 88, 1, 0, 0, 0, 90, 91, 1, 0, 0, 0, 91, 17, 1, 0, 0, 0, 92, 100, 3, 20, 10, 0, 93, 100, 3, 22, 11, 0, 94, 100, 3, 24, 12, 0, 95, 100, 3, 26, 13, 0, 96, 100, 3, 28, 14, 0, 97, 100, 3, 32, 16, 0, 98, 100, 3, 38, 19, 0, 99, 92, 1, 0, 0, 0, 99, 93, 1, 0, 0, 0, 99, 94, 1, 0, 0, 0, 99, 95, 1, 0, 0, 0, 99, 96, 1, 0, 0, 0, 99, 97, 1, 0, 0, 0, 99, 98, 1, 0, 0, 0, 100, 19, 1, 0, 0, 0, 101, 102, 7, 1, 0, 0, 102, 21, 1, 0, 0, 0, 103, 104, 7, 2, 0, 0, 104, 23, 1, 0, 0, 0, 105, 106, 7, 3, 0, 0, 106, 25, 1, 0, 0, 0, 107, 108, 5, 16, 0, 0, 108, 27, 1, 0, 0, 0, 109, 110, 7, 4, 0, 0, 110, 29, 1, 0, 0, 0, 111, 112, 5, 3, 0, 0, 112, 115, 5, 2, 0, 0, 113, 115, 5, 2, 0, 0, 114, 111, 1, 0, 0, 0, 114, 113, 1, 0, 0, 0, 115, 31, 1, 0, 0, 0, 116, 120, 5, 4, 0, 0, 117, 119, 3, 30, 15, 0, 118, 117, 1, 0, 0, 0, 119, 122, 1, 0, 0, 0, 120, 118, 1, 0, 0, 0, 120, 121, 1, 0, 0, 0, 121, 123, 1, 0, 0, 0, 122, 120, 1, 0, 0, 0, 123, 157, 5, 6, 0, 0, 124, 128, 5, 4, 0, 0, 125, 127, 3, 30, 15, 0, 126, 125, 1, 0, 0, 0, 127, 130, 1, 0, 0, 0, 128, 126, 1, 0, 0, 0, 128, 129, 1, 0, 0, 0, 129, 131, 1, 0, 0, 0, 130, 128, 1, 0, 0, 0, 131, 145, 3, 18, 9, 0, 132, 136, 5, 10, 0, 0, 133, 135, 3, 30, 15, 0, 134, 133, 1, 0, 0, 0, 135, 138, 1, 0, 0, 0, 136, 134, 1, 0, 0, 0, 136, 137, 1, 0, 0, 0, 137, 139, 1, 0, 0, 0, 138, 136, 1, 0, 0, 0, 139, 141, 3, 18, 9, 0, 140, 142, 5, 10, 0, 0, 141, 140, 1, 0, 0, 0, 141, 142, 1, 0, 0, 0, 142, 144, 1, 0, 0, 0, 143, 132, 1, 0, 0, 0, 144, 147, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 145, 146, 1, 0, 0, 0, 146, 151, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 148, 150, 3, 30, 15, 0, 149, 148, 1, 0, 0, 0, 150, 153, 1, 0, 0, 0, 151, 149, 1, 0, 0, 0, 151, 152, 1, 0, 0, 0, 152, 154, 1, 0, 0, 0, 153, 151, 1, 0, 0, 0, 154, 155, 5, 6, 0, 0, 155, 157, 1, 0, 0, 0, 156, 116, 1, 0, 0, 0, 156, 124, 1, 0, 0, 0, 157, 33, 1, 0, 0, 0, 158, 161, 3, 36, 18, 0, 159, 161, 3, 40, 20, 0, 160, 158, 1, 0, 0, 0, 160, 159, 1, 0, 0, 0, 161, 35, 1, 0, 0, 0, 162, 163, 5, 4, 0, 0, 163, 164, 3, 8, 4, 0, 164, 174, 5, 6, 0, 0, 165, 167, 3, 30, 15, 0, 166, 165, 1, 0, 0, 0, 167, 170, 1, 0, 0, 0, 168, 166, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 171, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 173, 3, 2, 1, 0, 172, 168, 1, 0, 0, 0, 173, 176, 1, 0, 0, 0, 174, 172, 1, 0, 0, 0, 174, 175, 1, 0, 0, 0, 175, 37, 1, 0, 0, 0, 176, 174, 1, 0, 0, 0, 177, 181, 5, 15, 0, 0, 178, 180, 3, 30, 15, 0, 179, 178, 1, 0, 0, 0, 180, 183, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 181, 182, 1, 0, 0, 0, 182, 184, 1, 0, 0, 0, 183, 181, 1, 0, 0, 0, 184, 218, 5, 31, 0, 0, 185, 189, 5, 15, 0, 0, 186, 188, 3, 30, 15, 0, 187, 186, 1, 0, 0, 0, 188, 191, 1, 0, 0, 0, 189, 187, 1, 0, 0, 0, 189, 190, 1, 0, 0, 0, 190, 192, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 206, 3, 6, 3, 0, 193, 197, 5, 10, 0, 0, 194, 196, 3, 30, 15, 0, 195, 194, 1, 0, 0, 0, 196, 199, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 197, 198, 1, 0, 0, 0, 198, 200, 1, 0, 0, 0, 199, 197, 1, 0, 0, 0, 200, 202, 3, 6, 3, 0, 201, 203, 5, 10, 0, 0, 202, 201, 1, 0, 0, 0, 202, 203, 1, 0, 0, 0, 203, 205, 1, 0, 0, 0, 204, 193, 1, 0, 0, 0, 205, 208, 1, 0, 0, 0, 206, 204, 1, 0, 0, 0, 206, 207, 1, 0, 0, 0, 207, 212, 1, 0, 0, 0, 208, 206, 1, 0, 0, 0, 209, 211, 3, 30, 15, 0, 210, 209, 1, 0, 0, 0, 211, 214, 1, 0, 0, 0, 212, 210, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 215, 1, 0, 0, 0, 214, 212, 1, 0, 0, 0, 215, 216, 5, 31, 0, 0, 216, 218, 1, 0, 0, 0, 217, 177, 1, 0, 0, 0, 217, 185, 1, 0, 0, 0, 218, 39, 1, 0, 0, 0, 219, 220, 5, 5, 0, 0, 220, 221, 3, 8, 4, 0, 221, 231, 5, 7, 0, 0, 222, 224, 3, 30, 15, 0, 223, 222, 1, 0, 0, 0, 224, 227, 1, 0, 0, 0, 225, 223, 1, 0, 0, 0, 225, 226, 1, 0, 0, 0, 226, 228, 1, 0, 0, 0, 227, 225, 1, 0, 0, 0, 228, 230, 3, 2, 1, 0, 229, 225, 1, 0, 0, 0, 230, 233, 1, 0, 0, 0, 231, 229, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 41, 1, 0, 0, 0, 233, 231, 1, 0, 0, 0, 30, 43, 47, 51, 58, 62, 65, 75, 79, 90, 99, 114, 120, 128, 136, 141, 145, 151, 156, 160, 168, 174, 181, 189, 197, 202, 206, 212, 217, 225, 231] \ No newline at end of file +[4, 1, 32, 235, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 1, 0, 3, 0, 44, 8, 0, 1, 0, 1, 0, 3, 0, 48, 8, 0, 5, 0, 50, 8, 0, 10, 0, 12, 0, 53, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 59, 8, 1, 1, 1, 1, 1, 3, 1, 63, 8, 1, 1, 1, 3, 1, 66, 8, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 3, 4, 76, 8, 4, 1, 5, 1, 5, 3, 5, 80, 8, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 4, 8, 89, 8, 8, 11, 8, 12, 8, 90, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 100, 8, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 3, 15, 113, 8, 15, 1, 15, 1, 15, 1, 16, 1, 16, 5, 16, 119, 8, 16, 10, 16, 12, 16, 122, 9, 16, 1, 16, 1, 16, 1, 16, 5, 16, 127, 8, 16, 10, 16, 12, 16, 130, 9, 16, 1, 16, 1, 16, 1, 16, 5, 16, 135, 8, 16, 10, 16, 12, 16, 138, 9, 16, 1, 16, 1, 16, 3, 16, 142, 8, 16, 5, 16, 144, 8, 16, 10, 16, 12, 16, 147, 9, 16, 1, 16, 5, 16, 150, 8, 16, 10, 16, 12, 16, 153, 9, 16, 1, 16, 1, 16, 3, 16, 157, 8, 16, 1, 17, 1, 17, 3, 17, 161, 8, 17, 1, 18, 1, 18, 1, 18, 1, 18, 5, 18, 167, 8, 18, 10, 18, 12, 18, 170, 9, 18, 1, 18, 5, 18, 173, 8, 18, 10, 18, 12, 18, 176, 9, 18, 1, 19, 1, 19, 5, 19, 180, 8, 19, 10, 19, 12, 19, 183, 9, 19, 1, 19, 1, 19, 1, 19, 5, 19, 188, 8, 19, 10, 19, 12, 19, 191, 9, 19, 1, 19, 1, 19, 1, 19, 5, 19, 196, 8, 19, 10, 19, 12, 19, 199, 9, 19, 1, 19, 1, 19, 3, 19, 203, 8, 19, 5, 19, 205, 8, 19, 10, 19, 12, 19, 208, 9, 19, 1, 19, 5, 19, 211, 8, 19, 10, 19, 12, 19, 214, 9, 19, 1, 19, 1, 19, 3, 19, 218, 8, 19, 1, 20, 1, 20, 1, 20, 1, 20, 5, 20, 224, 8, 20, 10, 20, 12, 20, 227, 9, 20, 1, 20, 5, 20, 230, 8, 20, 10, 20, 12, 20, 233, 9, 20, 1, 20, 0, 0, 21, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 0, 5, 1, 0, 11, 12, 2, 0, 11, 12, 17, 18, 1, 0, 22, 25, 1, 0, 19, 21, 1, 0, 26, 29, 249, 0, 43, 1, 0, 0, 0, 2, 65, 1, 0, 0, 0, 4, 67, 1, 0, 0, 0, 6, 69, 1, 0, 0, 0, 8, 75, 1, 0, 0, 0, 10, 79, 1, 0, 0, 0, 12, 81, 1, 0, 0, 0, 14, 83, 1, 0, 0, 0, 16, 85, 1, 0, 0, 0, 18, 99, 1, 0, 0, 0, 20, 101, 1, 0, 0, 0, 22, 103, 1, 0, 0, 0, 24, 105, 1, 0, 0, 0, 26, 107, 1, 0, 0, 0, 28, 109, 1, 0, 0, 0, 30, 112, 1, 0, 0, 0, 32, 156, 1, 0, 0, 0, 34, 160, 1, 0, 0, 0, 36, 162, 1, 0, 0, 0, 38, 217, 1, 0, 0, 0, 40, 219, 1, 0, 0, 0, 42, 44, 3, 2, 1, 0, 43, 42, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 51, 1, 0, 0, 0, 45, 47, 5, 2, 0, 0, 46, 48, 3, 2, 1, 0, 47, 46, 1, 0, 0, 0, 47, 48, 1, 0, 0, 0, 48, 50, 1, 0, 0, 0, 49, 45, 1, 0, 0, 0, 50, 53, 1, 0, 0, 0, 51, 49, 1, 0, 0, 0, 51, 52, 1, 0, 0, 0, 52, 54, 1, 0, 0, 0, 53, 51, 1, 0, 0, 0, 54, 55, 5, 0, 0, 1, 55, 1, 1, 0, 0, 0, 56, 58, 3, 6, 3, 0, 57, 59, 3, 4, 2, 0, 58, 57, 1, 0, 0, 0, 58, 59, 1, 0, 0, 0, 59, 66, 1, 0, 0, 0, 60, 62, 3, 34, 17, 0, 61, 63, 3, 4, 2, 0, 62, 61, 1, 0, 0, 0, 62, 63, 1, 0, 0, 0, 63, 66, 1, 0, 0, 0, 64, 66, 3, 4, 2, 0, 65, 56, 1, 0, 0, 0, 65, 60, 1, 0, 0, 0, 65, 64, 1, 0, 0, 0, 66, 3, 1, 0, 0, 0, 67, 68, 5, 3, 0, 0, 68, 5, 1, 0, 0, 0, 69, 70, 3, 8, 4, 0, 70, 71, 5, 8, 0, 0, 71, 72, 3, 18, 9, 0, 72, 7, 1, 0, 0, 0, 73, 76, 3, 10, 5, 0, 74, 76, 3, 16, 8, 0, 75, 73, 1, 0, 0, 0, 75, 74, 1, 0, 0, 0, 76, 9, 1, 0, 0, 0, 77, 80, 3, 14, 7, 0, 78, 80, 3, 12, 6, 0, 79, 77, 1, 0, 0, 0, 79, 78, 1, 0, 0, 0, 80, 11, 1, 0, 0, 0, 81, 82, 5, 13, 0, 0, 82, 13, 1, 0, 0, 0, 83, 84, 7, 0, 0, 0, 84, 15, 1, 0, 0, 0, 85, 88, 3, 10, 5, 0, 86, 87, 5, 9, 0, 0, 87, 89, 3, 10, 5, 0, 88, 86, 1, 0, 0, 0, 89, 90, 1, 0, 0, 0, 90, 88, 1, 0, 0, 0, 90, 91, 1, 0, 0, 0, 91, 17, 1, 0, 0, 0, 92, 100, 3, 20, 10, 0, 93, 100, 3, 22, 11, 0, 94, 100, 3, 24, 12, 0, 95, 100, 3, 26, 13, 0, 96, 100, 3, 28, 14, 0, 97, 100, 3, 32, 16, 0, 98, 100, 3, 38, 19, 0, 99, 92, 1, 0, 0, 0, 99, 93, 1, 0, 0, 0, 99, 94, 1, 0, 0, 0, 99, 95, 1, 0, 0, 0, 99, 96, 1, 0, 0, 0, 99, 97, 1, 0, 0, 0, 99, 98, 1, 0, 0, 0, 100, 19, 1, 0, 0, 0, 101, 102, 7, 1, 0, 0, 102, 21, 1, 0, 0, 0, 103, 104, 7, 2, 0, 0, 104, 23, 1, 0, 0, 0, 105, 106, 7, 3, 0, 0, 106, 25, 1, 0, 0, 0, 107, 108, 5, 16, 0, 0, 108, 27, 1, 0, 0, 0, 109, 110, 7, 4, 0, 0, 110, 29, 1, 0, 0, 0, 111, 113, 5, 3, 0, 0, 112, 111, 1, 0, 0, 0, 112, 113, 1, 0, 0, 0, 113, 114, 1, 0, 0, 0, 114, 115, 5, 2, 0, 0, 115, 31, 1, 0, 0, 0, 116, 120, 5, 4, 0, 0, 117, 119, 3, 30, 15, 0, 118, 117, 1, 0, 0, 0, 119, 122, 1, 0, 0, 0, 120, 118, 1, 0, 0, 0, 120, 121, 1, 0, 0, 0, 121, 123, 1, 0, 0, 0, 122, 120, 1, 0, 0, 0, 123, 157, 5, 6, 0, 0, 124, 128, 5, 4, 0, 0, 125, 127, 3, 30, 15, 0, 126, 125, 1, 0, 0, 0, 127, 130, 1, 0, 0, 0, 128, 126, 1, 0, 0, 0, 128, 129, 1, 0, 0, 0, 129, 131, 1, 0, 0, 0, 130, 128, 1, 0, 0, 0, 131, 145, 3, 18, 9, 0, 132, 136, 5, 10, 0, 0, 133, 135, 3, 30, 15, 0, 134, 133, 1, 0, 0, 0, 135, 138, 1, 0, 0, 0, 136, 134, 1, 0, 0, 0, 136, 137, 1, 0, 0, 0, 137, 139, 1, 0, 0, 0, 138, 136, 1, 0, 0, 0, 139, 141, 3, 18, 9, 0, 140, 142, 5, 10, 0, 0, 141, 140, 1, 0, 0, 0, 141, 142, 1, 0, 0, 0, 142, 144, 1, 0, 0, 0, 143, 132, 1, 0, 0, 0, 144, 147, 1, 0, 0, 0, 145, 143, 1, 0, 0, 0, 145, 146, 1, 0, 0, 0, 146, 151, 1, 0, 0, 0, 147, 145, 1, 0, 0, 0, 148, 150, 3, 30, 15, 0, 149, 148, 1, 0, 0, 0, 150, 153, 1, 0, 0, 0, 151, 149, 1, 0, 0, 0, 151, 152, 1, 0, 0, 0, 152, 154, 1, 0, 0, 0, 153, 151, 1, 0, 0, 0, 154, 155, 5, 6, 0, 0, 155, 157, 1, 0, 0, 0, 156, 116, 1, 0, 0, 0, 156, 124, 1, 0, 0, 0, 157, 33, 1, 0, 0, 0, 158, 161, 3, 36, 18, 0, 159, 161, 3, 40, 20, 0, 160, 158, 1, 0, 0, 0, 160, 159, 1, 0, 0, 0, 161, 35, 1, 0, 0, 0, 162, 163, 5, 4, 0, 0, 163, 164, 3, 8, 4, 0, 164, 174, 5, 6, 0, 0, 165, 167, 3, 30, 15, 0, 166, 165, 1, 0, 0, 0, 167, 170, 1, 0, 0, 0, 168, 166, 1, 0, 0, 0, 168, 169, 1, 0, 0, 0, 169, 171, 1, 0, 0, 0, 170, 168, 1, 0, 0, 0, 171, 173, 3, 6, 3, 0, 172, 168, 1, 0, 0, 0, 173, 176, 1, 0, 0, 0, 174, 172, 1, 0, 0, 0, 174, 175, 1, 0, 0, 0, 175, 37, 1, 0, 0, 0, 176, 174, 1, 0, 0, 0, 177, 181, 5, 15, 0, 0, 178, 180, 3, 30, 15, 0, 179, 178, 1, 0, 0, 0, 180, 183, 1, 0, 0, 0, 181, 179, 1, 0, 0, 0, 181, 182, 1, 0, 0, 0, 182, 184, 1, 0, 0, 0, 183, 181, 1, 0, 0, 0, 184, 218, 5, 31, 0, 0, 185, 189, 5, 15, 0, 0, 186, 188, 3, 30, 15, 0, 187, 186, 1, 0, 0, 0, 188, 191, 1, 0, 0, 0, 189, 187, 1, 0, 0, 0, 189, 190, 1, 0, 0, 0, 190, 192, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 206, 3, 6, 3, 0, 193, 197, 5, 10, 0, 0, 194, 196, 3, 30, 15, 0, 195, 194, 1, 0, 0, 0, 196, 199, 1, 0, 0, 0, 197, 195, 1, 0, 0, 0, 197, 198, 1, 0, 0, 0, 198, 200, 1, 0, 0, 0, 199, 197, 1, 0, 0, 0, 200, 202, 3, 6, 3, 0, 201, 203, 5, 10, 0, 0, 202, 201, 1, 0, 0, 0, 202, 203, 1, 0, 0, 0, 203, 205, 1, 0, 0, 0, 204, 193, 1, 0, 0, 0, 205, 208, 1, 0, 0, 0, 206, 204, 1, 0, 0, 0, 206, 207, 1, 0, 0, 0, 207, 212, 1, 0, 0, 0, 208, 206, 1, 0, 0, 0, 209, 211, 3, 30, 15, 0, 210, 209, 1, 0, 0, 0, 211, 214, 1, 0, 0, 0, 212, 210, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 215, 1, 0, 0, 0, 214, 212, 1, 0, 0, 0, 215, 216, 5, 31, 0, 0, 216, 218, 1, 0, 0, 0, 217, 177, 1, 0, 0, 0, 217, 185, 1, 0, 0, 0, 218, 39, 1, 0, 0, 0, 219, 220, 5, 5, 0, 0, 220, 221, 3, 8, 4, 0, 221, 231, 5, 7, 0, 0, 222, 224, 3, 30, 15, 0, 223, 222, 1, 0, 0, 0, 224, 227, 1, 0, 0, 0, 225, 223, 1, 0, 0, 0, 225, 226, 1, 0, 0, 0, 226, 228, 1, 0, 0, 0, 227, 225, 1, 0, 0, 0, 228, 230, 3, 6, 3, 0, 229, 225, 1, 0, 0, 0, 230, 233, 1, 0, 0, 0, 231, 229, 1, 0, 0, 0, 231, 232, 1, 0, 0, 0, 232, 41, 1, 0, 0, 0, 233, 231, 1, 0, 0, 0, 30, 43, 47, 51, 58, 62, 65, 75, 79, 90, 99, 112, 120, 128, 136, 141, 145, 151, 156, 160, 168, 174, 181, 189, 197, 202, 206, 212, 217, 225, 231] \ No newline at end of file diff --git a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.java b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.java index 36f1d699925..13f6a167f1b 100644 --- a/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.java +++ b/rewrite-toml/src/main/java/org/openrewrite/toml/internal/grammar/TomlParser.java @@ -249,6 +249,7 @@ public T accept(ParseTreeVisitor visitor) { public final ExpressionContext expression() throws RecognitionException { ExpressionContext _localctx = new ExpressionContext(_ctx, getState()); enterRule(_localctx, 2, RULE_expression); + int _la; try { setState(65); _errHandler.sync(this); @@ -262,14 +263,14 @@ public final ExpressionContext expression() throws RecognitionException { keyValue(); setState(58); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,3,_ctx) ) { - case 1: + _la = _input.LA(1); + if (_la==COMMENT) { { setState(57); comment(); } - break; } + } break; case L_BRACKET: @@ -280,14 +281,14 @@ public final ExpressionContext expression() throws RecognitionException { table(); setState(62); _errHandler.sync(this); - switch ( getInterpreter().adaptivePredict(_input,4,_ctx) ) { - case 1: + _la = _input.LA(1); + if (_la==COMMENT) { { setState(61); comment(); } - break; } + } break; case COMMENT: @@ -1086,8 +1087,8 @@ public final DateTimeContext dateTime() throws RecognitionException { @SuppressWarnings("CheckReturnValue") public static class CommentOrNlContext extends ParserRuleContext { - public TerminalNode COMMENT() { return getToken(TomlParser.COMMENT, 0); } public TerminalNode NL() { return getToken(TomlParser.NL, 0); } + public TerminalNode COMMENT() { return getToken(TomlParser.COMMENT, 0); } public CommentOrNlContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @@ -1110,28 +1111,22 @@ public T accept(ParseTreeVisitor visitor) { public final CommentOrNlContext commentOrNl() throws RecognitionException { CommentOrNlContext _localctx = new CommentOrNlContext(_ctx, getState()); enterRule(_localctx, 30, RULE_commentOrNl); + int _la; try { - setState(114); + enterOuterAlt(_localctx, 1); + { + setState(112); _errHandler.sync(this); - switch (_input.LA(1)) { - case COMMENT: - enterOuterAlt(_localctx, 1); + _la = _input.LA(1); + if (_la==COMMENT) { { setState(111); match(COMMENT); - setState(112); - match(NL); } - break; - case NL: - enterOuterAlt(_localctx, 2); - { - setState(113); - match(NL); - } - break; - default: - throw new NoViableAltException(this); + } + + setState(114); + match(NL); } } catch (RecognitionException re) { @@ -1377,11 +1372,11 @@ public KeyContext key() { return getRuleContext(KeyContext.class,0); } public TerminalNode R_BRACKET() { return getToken(TomlParser.R_BRACKET, 0); } - public List expression() { - return getRuleContexts(ExpressionContext.class); + public List keyValue() { + return getRuleContexts(KeyValueContext.class); } - public ExpressionContext expression(int i) { - return getRuleContext(ExpressionContext.class,i); + public KeyValueContext keyValue(int i) { + return getRuleContext(KeyValueContext.class,i); } public List commentOrNl() { return getRuleContexts(CommentOrNlContext.class); @@ -1411,6 +1406,7 @@ public T accept(ParseTreeVisitor visitor) { public final StandardTableContext standardTable() throws RecognitionException { StandardTableContext _localctx = new StandardTableContext(_ctx, getState()); enterRule(_localctx, 36, RULE_standardTable); + int _la; try { int _alt; enterOuterAlt(_localctx, 1); @@ -1430,22 +1426,20 @@ public final StandardTableContext standardTable() throws RecognitionException { { setState(168); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,19,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { - if ( _alt==1 ) { - { - { - setState(165); - commentOrNl(); - } - } + _la = _input.LA(1); + while (_la==NL || _la==COMMENT) { + { + { + setState(165); + commentOrNl(); + } } setState(170); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,19,_ctx); + _la = _input.LA(1); } setState(171); - expression(); + keyValue(); } } } @@ -1635,11 +1629,11 @@ public KeyContext key() { return getRuleContext(KeyContext.class,0); } public TerminalNode DOUBLE_R_BRACKET() { return getToken(TomlParser.DOUBLE_R_BRACKET, 0); } - public List expression() { - return getRuleContexts(ExpressionContext.class); + public List keyValue() { + return getRuleContexts(KeyValueContext.class); } - public ExpressionContext expression(int i) { - return getRuleContext(ExpressionContext.class,i); + public KeyValueContext keyValue(int i) { + return getRuleContext(KeyValueContext.class,i); } public List commentOrNl() { return getRuleContexts(CommentOrNlContext.class); @@ -1669,6 +1663,7 @@ public T accept(ParseTreeVisitor visitor) { public final ArrayTableContext arrayTable() throws RecognitionException { ArrayTableContext _localctx = new ArrayTableContext(_ctx, getState()); enterRule(_localctx, 40, RULE_arrayTable); + int _la; try { int _alt; enterOuterAlt(_localctx, 1); @@ -1688,22 +1683,20 @@ public final ArrayTableContext arrayTable() throws RecognitionException { { setState(225); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,28,_ctx); - while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { - if ( _alt==1 ) { - { - { - setState(222); - commentOrNl(); - } - } + _la = _input.LA(1); + while (_la==NL || _la==COMMENT) { + { + { + setState(222); + commentOrNl(); + } } setState(227); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,28,_ctx); + _la = _input.LA(1); } setState(228); - expression(); + keyValue(); } } } @@ -1741,8 +1734,8 @@ public final ArrayTableContext arrayTable() throws RecognitionException { "\u0006\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001\b\u0004\bY\b\b\u000b"+ "\b\f\bZ\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0003"+ "\td\b\t\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001"+ - "\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001\u000f"+ - "\u0003\u000fs\b\u000f\u0001\u0010\u0001\u0010\u0005\u0010w\b\u0010\n\u0010"+ + "\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000f\u0003\u000fq\b\u000f\u0001"+ + "\u000f\u0001\u000f\u0001\u0010\u0001\u0010\u0005\u0010w\b\u0010\n\u0010"+ "\f\u0010z\t\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0005\u0010\u007f"+ "\b\u0010\n\u0010\f\u0010\u0082\t\u0010\u0001\u0010\u0001\u0010\u0001\u0010"+ "\u0005\u0010\u0087\b\u0010\n\u0010\f\u0010\u008a\t\u0010\u0001\u0010\u0001"+ @@ -1771,7 +1764,7 @@ public final ArrayTableContext arrayTable() throws RecognitionException { "U\u0001\u0000\u0000\u0000\u0012c\u0001\u0000\u0000\u0000\u0014e\u0001"+ "\u0000\u0000\u0000\u0016g\u0001\u0000\u0000\u0000\u0018i\u0001\u0000\u0000"+ "\u0000\u001ak\u0001\u0000\u0000\u0000\u001cm\u0001\u0000\u0000\u0000\u001e"+ - "r\u0001\u0000\u0000\u0000 \u009c\u0001\u0000\u0000\u0000\"\u00a0\u0001"+ + "p\u0001\u0000\u0000\u0000 \u009c\u0001\u0000\u0000\u0000\"\u00a0\u0001"+ "\u0000\u0000\u0000$\u00a2\u0001\u0000\u0000\u0000&\u00d9\u0001\u0000\u0000"+ "\u0000(\u00db\u0001\u0000\u0000\u0000*,\u0003\u0002\u0001\u0000+*\u0001"+ "\u0000\u0000\u0000+,\u0001\u0000\u0000\u0000,3\u0001\u0000\u0000\u0000"+ @@ -1804,9 +1797,9 @@ public final ArrayTableContext arrayTable() throws RecognitionException { "f\u0015\u0001\u0000\u0000\u0000gh\u0007\u0002\u0000\u0000h\u0017\u0001"+ "\u0000\u0000\u0000ij\u0007\u0003\u0000\u0000j\u0019\u0001\u0000\u0000"+ "\u0000kl\u0005\u0010\u0000\u0000l\u001b\u0001\u0000\u0000\u0000mn\u0007"+ - "\u0004\u0000\u0000n\u001d\u0001\u0000\u0000\u0000op\u0005\u0003\u0000"+ - "\u0000ps\u0005\u0002\u0000\u0000qs\u0005\u0002\u0000\u0000ro\u0001\u0000"+ - "\u0000\u0000rq\u0001\u0000\u0000\u0000s\u001f\u0001\u0000\u0000\u0000"+ + "\u0004\u0000\u0000n\u001d\u0001\u0000\u0000\u0000oq\u0005\u0003\u0000"+ + "\u0000po\u0001\u0000\u0000\u0000pq\u0001\u0000\u0000\u0000qr\u0001\u0000"+ + "\u0000\u0000rs\u0005\u0002\u0000\u0000s\u001f\u0001\u0000\u0000\u0000"+ "tx\u0005\u0004\u0000\u0000uw\u0003\u001e\u000f\u0000vu\u0001\u0000\u0000"+ "\u0000wz\u0001\u0000\u0000\u0000xv\u0001\u0000\u0000\u0000xy\u0001\u0000"+ "\u0000\u0000y{\u0001\u0000\u0000\u0000zx\u0001\u0000\u0000\u0000{\u009d"+ @@ -1836,7 +1829,7 @@ public final ArrayTableContext arrayTable() throws RecognitionException { "\u0000\u00a5\u00a7\u0003\u001e\u000f\u0000\u00a6\u00a5\u0001\u0000\u0000"+ "\u0000\u00a7\u00aa\u0001\u0000\u0000\u0000\u00a8\u00a6\u0001\u0000\u0000"+ "\u0000\u00a8\u00a9\u0001\u0000\u0000\u0000\u00a9\u00ab\u0001\u0000\u0000"+ - "\u0000\u00aa\u00a8\u0001\u0000\u0000\u0000\u00ab\u00ad\u0003\u0002\u0001"+ + "\u0000\u00aa\u00a8\u0001\u0000\u0000\u0000\u00ab\u00ad\u0003\u0006\u0003"+ "\u0000\u00ac\u00a8\u0001\u0000\u0000\u0000\u00ad\u00b0\u0001\u0000\u0000"+ "\u0000\u00ae\u00ac\u0001\u0000\u0000\u0000\u00ae\u00af\u0001\u0000\u0000"+ "\u0000\u00af%\u0001\u0000\u0000\u0000\u00b0\u00ae\u0001\u0000\u0000\u0000"+ @@ -1869,10 +1862,10 @@ public final ArrayTableContext arrayTable() throws RecognitionException { "\u000f\u0000\u00df\u00de\u0001\u0000\u0000\u0000\u00e0\u00e3\u0001\u0000"+ "\u0000\u0000\u00e1\u00df\u0001\u0000\u0000\u0000\u00e1\u00e2\u0001\u0000"+ "\u0000\u0000\u00e2\u00e4\u0001\u0000\u0000\u0000\u00e3\u00e1\u0001\u0000"+ - "\u0000\u0000\u00e4\u00e6\u0003\u0002\u0001\u0000\u00e5\u00e1\u0001\u0000"+ + "\u0000\u0000\u00e4\u00e6\u0003\u0006\u0003\u0000\u00e5\u00e1\u0001\u0000"+ "\u0000\u0000\u00e6\u00e9\u0001\u0000\u0000\u0000\u00e7\u00e5\u0001\u0000"+ "\u0000\u0000\u00e7\u00e8\u0001\u0000\u0000\u0000\u00e8)\u0001\u0000\u0000"+ - "\u0000\u00e9\u00e7\u0001\u0000\u0000\u0000\u001e+/3:>AKOZcrx\u0080\u0088"+ + "\u0000\u00e9\u00e7\u0001\u0000\u0000\u0000\u001e+/3:>AKOZcpx\u0080\u0088"+ "\u008d\u0091\u0097\u009c\u00a0\u00a8\u00ae\u00b5\u00bd\u00c5\u00ca\u00ce"+ "\u00d4\u00d9\u00e1\u00e7"; public static final ATN _ATN = diff --git a/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java b/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java index 2693151c649..d466abf86e2 100644 --- a/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java +++ b/rewrite-toml/src/test/java/org/openrewrite/toml/TomlParserTest.java @@ -17,7 +17,13 @@ import org.junit.jupiter.api.Test; import org.openrewrite.test.RewriteTest; +import org.openrewrite.toml.tree.Toml; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; import static org.openrewrite.toml.Assertions.toml; class TomlParserTest implements RewriteTest { @@ -198,7 +204,13 @@ void table() { [dog."tater.man"] type.name = "pug" - """ + """, + spec -> spec.afterRecipe(doc -> { + assertThat(doc.getValues()).hasSize(3); + assertThat(doc.getValues()).allSatisfy( + v -> assertThat(v).isInstanceOf(Toml.Table.class) + ); + }) ) ); } From 36efb73d894b14440f7955d9aaf67a615ce41cd6 Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Thu, 16 Jan 2025 01:44:22 -0800 Subject: [PATCH 149/179] Add a test validation that execution context is not mutated during recipe execution (#4879) * Add a test validation that execution context is not mutated during the recipe run. * Allow messages from MavenExecutionContextView --- .../CursorValidatingExecutionContextView.java | 22 ++++++++++++ .../org/openrewrite/ExecutionContextTest.java | 4 ++- .../org/openrewrite/test/RewriteTest.java | 6 ++-- .../org/openrewrite/test/TypeValidation.java | 10 +++++- .../test/internal/RewriteTestTest.java | 36 +++++++++++++++++++ 5 files changed, 73 insertions(+), 5 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/CursorValidatingExecutionContextView.java b/rewrite-core/src/main/java/org/openrewrite/CursorValidatingExecutionContextView.java index 35fd3616483..cb8be5ce807 100644 --- a/rewrite-core/src/main/java/org/openrewrite/CursorValidatingExecutionContextView.java +++ b/rewrite-core/src/main/java/org/openrewrite/CursorValidatingExecutionContextView.java @@ -15,8 +15,11 @@ */ package org.openrewrite; +import org.jspecify.annotations.Nullable; + public class CursorValidatingExecutionContextView extends DelegatingExecutionContext { private static final String VALIDATE_CURSOR_ACYCLIC = "org.openrewrite.CursorValidatingExecutionContextView.ValidateCursorAcyclic"; + private static final String VALIDATE_CTX_MUTATION = "org.openrewrite.CursorValidatingExecutionContextView.ValidateExecutionContextImmutability"; public CursorValidatingExecutionContextView(ExecutionContext delegate) { super(delegate); @@ -38,4 +41,23 @@ public CursorValidatingExecutionContextView setValidateCursorAcyclic(boolean val putMessage(VALIDATE_CURSOR_ACYCLIC, validateCursorAcyclic); return this; } + + public CursorValidatingExecutionContextView setValidateImmutableExecutionContext(boolean allowExecutionContextMutation) { + putMessage(VALIDATE_CTX_MUTATION, allowExecutionContextMutation); + return this; + } + + @Override + public void putMessage(String key, @Nullable Object value) { + boolean mutationAllowed = !getMessage(VALIDATE_CTX_MUTATION, false) || key.equals(VALIDATE_CURSOR_ACYCLIC) || key.equals(VALIDATE_CTX_MUTATION) + || key.equals(ExecutionContext.CURRENT_CYCLE) || key.equals(ExecutionContext.CURRENT_RECIPE) || key.equals(ExecutionContext.DATA_TABLES) + || key.startsWith("org.openrewrite.maven"); // MavenExecutionContextView stores metrics + assert mutationAllowed + : "Recipe mutated execution context key \"" + key + "\". " + + "Recipes should not mutate the contents of the ExecutionContext as it allows mutable state to leak between " + + "recipes, opening the door for difficult to debug recipe composition errors. " + + "If you need to store state within the execution of a single recipe use Cursor messaging. " + + "If you want to pass state between recipes, use a ScanningRecipe instead."; + super.putMessage(key, value); + } } diff --git a/rewrite-core/src/test/java/org/openrewrite/ExecutionContextTest.java b/rewrite-core/src/test/java/org/openrewrite/ExecutionContextTest.java index ab9ad0ef731..fa7aaa25d7c 100644 --- a/rewrite-core/src/test/java/org/openrewrite/ExecutionContextTest.java +++ b/rewrite-core/src/test/java/org/openrewrite/ExecutionContextTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Test; import org.openrewrite.test.RewriteTest; +import org.openrewrite.test.TypeValidation; import org.openrewrite.text.PlainText; import org.openrewrite.text.PlainTextVisitor; @@ -41,7 +42,8 @@ public PlainText visitText(PlainText text, ExecutionContext ctx) { cycles.incrementAndGet(); return text; } - }).withCausesAnotherCycle(true)), + }).withCausesAnotherCycle(true)) + .typeValidationOptions(TypeValidation.all().immutableExecutionContext(false)), text("hello world") ); assertThat(cycles.get()).isEqualTo(2); diff --git a/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java b/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java index 11c218c6495..073da655b1e 100644 --- a/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java +++ b/rewrite-test/src/main/java/org/openrewrite/test/RewriteTest.java @@ -367,9 +367,9 @@ default void rewriteRun(Consumer spec, SourceSpec... sourceSpecs) lss = new LargeSourceSetCheckingExpectedCycles(expectedCyclesThatMakeChanges, runnableSourceFiles); } - CursorValidatingExecutionContextView.view(recipeCtx) - .setValidateCursorAcyclic(TypeValidation.before(testMethodSpec, testClassSpec) - .cursorAcyclic()); + recipeCtx = CursorValidatingExecutionContextView.view(recipeCtx) + .setValidateCursorAcyclic(TypeValidation.before(testMethodSpec, testClassSpec).cursorAcyclic()) + .setValidateImmutableExecutionContext(TypeValidation.before(testMethodSpec, testClassSpec).immutableExecutionContext()); RecipeRun recipeRun = recipe.run( lss, recipeCtx, diff --git a/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java b/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java index 9d78cd0a33a..e395db403da 100644 --- a/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java +++ b/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java @@ -103,6 +103,14 @@ public class TypeValidation { @Builder.Default private boolean erroneous = true; + /** + * Adding messages to execution context is a side effect which makes the recipe run itself stateful. + * Potentially allows recipes to interfere with each other in surprising and hard to debug ways. + * Problematic for all the same reasons mutable global variables or singletons are. + */ + @Builder.Default + private boolean immutableExecutionContext = true; + /** * Enable all invariant validation checks. */ @@ -114,7 +122,7 @@ public static TypeValidation all() { * Skip all invariant validation checks. */ public static TypeValidation none() { - return new TypeValidation(false, false, false, false, false, false, false, false, o -> false, false); + return new TypeValidation(false, false, false, false, false, false, false, false, o -> false, false, false); } static TypeValidation before(RecipeSpec testMethodSpec, RecipeSpec testClassSpec) { diff --git a/rewrite-test/src/test/java/org/openrewrite/test/internal/RewriteTestTest.java b/rewrite-test/src/test/java/org/openrewrite/test/internal/RewriteTestTest.java index 343fe976074..aacab205113 100644 --- a/rewrite-test/src/test/java/org/openrewrite/test/internal/RewriteTestTest.java +++ b/rewrite-test/src/test/java/org/openrewrite/test/internal/RewriteTestTest.java @@ -112,6 +112,42 @@ void rejectRecipeValidationFailure() { """, "org.openrewrite.RefersToNonExistentRecipe") )); } + + @Test + void rejectExecutionContextMutation() { + assertThrows(AssertionError.class, () -> + rewriteRun( + spec -> spec.recipe(new MutateExecutionContext()), + text("irrelevant") + )); + } +} + +@Value +@EqualsAndHashCode(callSuper = false) +@NullMarked +class MutateExecutionContext extends Recipe { + + @Override + public String getDisplayName() { + return "Mutate execution context"; + } + + @Override + public String getDescription() { + return "Mutates the execution context to trigger a validation failure."; + } + + @Override + public TreeVisitor getVisitor() { + return new TreeVisitor<>() { + @Override + public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) { + ctx.putMessage("mutated", true); + return tree; + } + }; + } } @Value From 68f86ee0af22206b5578e458a651835cefd3d3e3 Mon Sep 17 00:00:00 2001 From: JesseEstum Date: Thu, 16 Jan 2025 03:59:23 -0600 Subject: [PATCH 150/179] Optionally update maven plugin version in ChangePluginGroupIdAndArtifactId (#4905) * Remove deprecated newArtifact Option * Add newVersion Option to ChangePluginGroupIdAndArtifactId * Apply formatter --------- Co-authored-by: jestum_uhg Co-authored-by: Tim te Beek --- .../ChangePluginGroupIdAndArtifactId.java | 22 +- .../ChangePluginGroupIdAndArtifactIdTest.java | 214 +++++++++++++++++- 2 files changed, 212 insertions(+), 24 deletions(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangePluginGroupIdAndArtifactId.java b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangePluginGroupIdAndArtifactId.java index ba633f1dd9e..3ca0e66448e 100755 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/ChangePluginGroupIdAndArtifactId.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/ChangePluginGroupIdAndArtifactId.java @@ -58,17 +58,12 @@ public class ChangePluginGroupIdAndArtifactId extends Recipe { @Nullable String newArtifactId; - /** - * Mistakenly introduced, we restored newArtifactId but let's not break recipes abruptly. - */ - @Option(displayName = "New artifact ID", - description = "The new artifact ID to use. Defaults to the existing artifact ID. This property is deprecated, use newArtifactId instead.", - example = "my-new-maven-plugin", - required = false) + @Option(displayName = "New version", + description = "An exact version number or node-style semver selector used to select the version number.", + example = "29.X", + required = false) @Nullable - @Deprecated - @SuppressWarnings("DeprecatedIsStillUsed") - String newArtifact; + String newVersion; @Override public String getDisplayName() { @@ -82,7 +77,7 @@ public String getInstanceNameSuffix() { @Override public String getDescription() { - return "Change the groupId and/or the artifactId of a specified Maven plugin."; + return "Change the groupId and/or the artifactId of a specified Maven plugin. Optionally update the plugin version."; } @Override @@ -98,8 +93,9 @@ public Xml visitTag(Xml.Tag tag, ExecutionContext ctx) { } if (newArtifactId != null) { t = changeChildTagValue(t, "artifactId", newArtifactId, ctx); - } else if (newArtifact != null) { - t = changeChildTagValue(t, "artifactId", newArtifact, ctx); + } + if (newVersion != null) { + t = changeChildTagValue(t, "version", newVersion, ctx); } if (t != tag) { maybeUpdateModel(); diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/ChangePluginGroupIdAndArtifactIdTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/ChangePluginGroupIdAndArtifactIdTest.java index 55147edecf3..1de416271d6 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/ChangePluginGroupIdAndArtifactIdTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/ChangePluginGroupIdAndArtifactIdTest.java @@ -103,14 +103,14 @@ void changePluginGroupIdAndArtifactId() { @DocumentExample @Test - void changePluginGroupIdAndArtifactIdDeprecatedNewArtifact() { + void changePluginGroupIdAndArtifactIdWithVersion() { rewriteRun( spec -> spec.recipe(new ChangePluginGroupIdAndArtifactId( "io.quarkus", "quarkus-bootstrap-maven-plugin", null, - null, - "quarkus-extension-maven-plugin" + "quarkus-extension-maven-plugin", + "4.0.0" )), pomXml( """ @@ -128,6 +128,55 @@ void changePluginGroupIdAndArtifactIdDeprecatedNewArtifact() { + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + + + io.quarkus + quarkus-extension-maven-plugin + 4.0.0 + + + + + """ + ) + ); + } + + @Test + void changePluginGroupIdAndArtifactIdNoChange() { + rewriteRun( + spec -> spec.recipe(new ChangePluginGroupIdAndArtifactId( + "io.quarkus", + "quarkus-bootstrap-maven-plugin", + null, + "quarkus-extension-maven-plugin", + null + )), + pomXml( + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + + + io.quarkus + quarkus-extension-maven-plugin + 3.0.0.Beta1 + + + profile @@ -135,7 +184,7 @@ void changePluginGroupIdAndArtifactIdDeprecatedNewArtifact() { io.quarkus - quarkus-bootstrap-maven-plugin + quarkus-extension-maven-plugin 3.0.0.Beta1 @@ -143,7 +192,22 @@ void changePluginGroupIdAndArtifactIdDeprecatedNewArtifact() { - """, + """ + ) + ); + } + + @Test + void changePluginGroupIdAndArtifactIdNoChangeWithVersion() { + rewriteRun( + spec -> spec.recipe(new ChangePluginGroupIdAndArtifactId( + "io.quarkus", + "quarkus-bootstrap-maven-plugin", + null, + "quarkus-extension-maven-plugin", + "4.0.0" + )), + pomXml( """ 4.0.0 @@ -180,7 +244,7 @@ void changePluginGroupIdAndArtifactIdDeprecatedNewArtifact() { } @Test - void changePluginGroupIdAndArtifactIdNoChange() { + void changeManagedPluginGroupIdAndArtifactId() { rewriteRun( spec -> spec.recipe(new ChangePluginGroupIdAndArtifactId( "io.quarkus", @@ -197,6 +261,63 @@ void changePluginGroupIdAndArtifactIdNoChange() { my-app 1 + + + + io.quarkus + quarkus-bootstrap-maven-plugin + 3.0.0.Beta1 + + + + + + io.quarkus + quarkus-bootstrap-maven-plugin + 3.0.0.Beta1 + + + + + + profile + + + + + io.quarkus + quarkus-bootstrap-maven-plugin + 3.0.0.Beta1 + + + + + + io.quarkus + quarkus-bootstrap-maven-plugin + + + + + + + """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + + + + io.quarkus + quarkus-extension-maven-plugin + 3.0.0.Beta1 + + + io.quarkus @@ -209,11 +330,19 @@ void changePluginGroupIdAndArtifactIdNoChange() { profile + + + + io.quarkus + quarkus-extension-maven-plugin + 3.0.0.Beta1 + + + io.quarkus quarkus-extension-maven-plugin - 3.0.0.Beta1 @@ -226,14 +355,14 @@ void changePluginGroupIdAndArtifactIdNoChange() { } @Test - void changeManagedPluginGroupIdAndArtifactId() { + void changeManagedPluginGroupIdAndArtifactIdWithVersion() { rewriteRun( spec -> spec.recipe(new ChangePluginGroupIdAndArtifactId( "io.quarkus", "quarkus-bootstrap-maven-plugin", null, "quarkus-extension-maven-plugin", - null + "4.0.0" )), pomXml( """ @@ -284,6 +413,69 @@ void changeManagedPluginGroupIdAndArtifactId() { """, + """ + + 4.0.0 + com.mycompany.app + my-app + 1 + + + + + io.quarkus + quarkus-extension-maven-plugin + 4.0.0 + + + + + + io.quarkus + quarkus-extension-maven-plugin + 4.0.0 + + + + + + profile + + + + + io.quarkus + quarkus-extension-maven-plugin + 4.0.0 + + + + + + io.quarkus + quarkus-extension-maven-plugin + + + + + + + """ + ) + ); + } + + @Test + void changeManagedPluginGroupIdAndArtifactIdNoChange() { + rewriteRun( + spec -> spec.recipe(new ChangePluginGroupIdAndArtifactId( + "io.quarkus", + "quarkus-bootstrap-maven-plugin", + null, + "quarkus-extension-maven-plugin", + null + )), + pomXml( """ 4.0.0 @@ -337,14 +529,14 @@ void changeManagedPluginGroupIdAndArtifactId() { } @Test - void changeManagedPluginGroupIdAndArtifactIdNoChange() { + void changeManagedPluginGroupIdAndArtifactIdNoChangeWithVersion() { rewriteRun( spec -> spec.recipe(new ChangePluginGroupIdAndArtifactId( "io.quarkus", "quarkus-bootstrap-maven-plugin", null, "quarkus-extension-maven-plugin", - null + "4.0.0" )), pomXml( """ From 1fd511c3b31787ba6517b8b2db137d73fa05e6bb Mon Sep 17 00:00:00 2001 From: SiBorea <108953913+SiBorea@users.noreply.github.com> Date: Thu, 16 Jan 2025 18:20:35 +0800 Subject: [PATCH 151/179] Fix AddOrUpdateAnnotationAttribute unable to handle FieldAccess (#4898) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix AddOrUpdateAnnotationAttribute unable to handle FieldAccess (cherry picked from commit 7d7451acfb6d939694f8d1cffc967affc5077710) * Fix AddOrUpdateAnnotationAttribute unable to handle FieldAccess (cherry picked from commit 7d7451acfb6d939694f8d1cffc967affc5077710) * Fix omitting addOnly and code style * Use getCursor() for JavaTemplate --------- Co-authored-by: Merlin Bögershausen --- .../AddOrUpdateAnnotationAttributeTest.java | 41 +++++++++++++++++++ .../java/AddOrUpdateAnnotationAttribute.java | 29 +++++++++---- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java index fc520e7f8ab..fa9c34deb28 100755 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/AddOrUpdateAnnotationAttributeTest.java @@ -907,6 +907,47 @@ public class A { ); } + @Test + void updateFieldAccessAttribute() { + rewriteRun( + spec -> spec.recipe(new AddOrUpdateAnnotationAttribute("org.example.Foo", "value", "hello", null, false, null)), + java( + """ + package org.example; + + public class Const { + public static final String HI = "hi"; + } + """), + java( + """ + package org.example; + public @interface Foo { + String value() default ""; + } + """ + ), + java( + """ + import org.example.Foo; + import org.example.Const; + + @Foo(value = Const.HI) + public class A { + } + """, + """ + import org.example.Foo; + import org.example.Const; + + @Foo(value = "hello") + public class A { + } + """ + ) + ); + } + @Test void addAttributeToNestedAnnotationArray() { rewriteRun( diff --git a/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java b/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java index 38cb78f8d66..2f7a8858857 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/AddOrUpdateAnnotationAttribute.java @@ -23,7 +23,10 @@ import org.openrewrite.*; import org.openrewrite.internal.ListUtils; import org.openrewrite.java.search.UsesType; -import org.openrewrite.java.tree.*; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.TypeUtils; import org.openrewrite.marker.Marker; import org.openrewrite.marker.Markers; @@ -208,14 +211,24 @@ public J.Annotation visitAnnotation(J.Annotation a, ExecutionContext ctx) { return as.withAssignment(((J.NewArray) as.getAssignment()).withInitializer(jLiteralList)); } else { - J.Literal value = (J.Literal) as.getAssignment(); - if (newAttributeValue.equals(value.getValueSource()) || Boolean.TRUE.equals(addOnly)) { - return it; - } - if (!valueMatches(value, oldAttributeValue)) { - return it; + Expression exp = as.getAssignment(); + if (exp instanceof J.Literal) { + J.Literal value = (J.Literal) exp; + if (newAttributeValue.equals(value.getValueSource()) || Boolean.TRUE.equals(addOnly)) { + return it; + } + if (!valueMatches(value, oldAttributeValue)) { + return it; + } + return as.withAssignment(value.withValue(newAttributeValue).withValueSource(newAttributeValue)); + } else if (exp instanceof J.FieldAccess) { + if (Boolean.TRUE.equals(addOnly)) { + return it; + } + int index = finalA.getArguments().indexOf(as); + as = (J.Assignment) ((J.Annotation) JavaTemplate.apply("#{} = #{}", getCursor(), as.getCoordinates().replace(), var.getSimpleName(), newAttributeValue)).getArguments().get(index); + return as; } - return as.withAssignment(value.withValue(newAttributeValue).withValueSource(newAttributeValue)); } } else if (it instanceof J.Literal) { // The only way anything except an assignment can appear is if there's an implicit assignment to "value" From 3d9653d441e90f46be502765b449aff251dcb5e6 Mon Sep 17 00:00:00 2001 From: t-huebner-id <161744488+t-huebner-id@users.noreply.github.com> Date: Thu, 16 Jan 2025 21:15:07 +0100 Subject: [PATCH 152/179] =?UTF-8?q?Fixed=20missing=20version=20on=20multip?= =?UTF-8?q?le=20dependency=20management=20sections=20in=20m=E2=80=A6=20(#4?= =?UTF-8?q?888)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed missing version on multiple dependency management sections in multi-module projects and fixed ignored classifiers when choosing snapshot timestamp * Formatted code, add unit test * Added issue annotation to test * Formatted * Minor polish * Further polish * Generalize comment on continue * Test for snapshot downloading issue * Minor polish --------- Co-authored-by: Tobias Hübner Co-authored-by: Tim te Beek --- .../maven/internal/MavenPomDownloader.java | 76 ++++-- .../openrewrite/maven/tree/MavenMetadata.java | 2 + .../openrewrite/maven/tree/ResolvedPom.java | 4 +- .../internal/MavenPomDownloaderTest.java | 246 +++++++++++++----- .../maven/tree/ResolvedPomTest.java | 140 +++++++++- 5 files changed, 378 insertions(+), 90 deletions(-) diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java b/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java index 26e59770b35..175cdb7a9a0 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/internal/MavenPomDownloader.java @@ -219,7 +219,7 @@ private List getAncestryWithinProject(Pom projectPom, Map projec .normalize(); Pom parentPom = projectPoms.get(parentPath); return parentPom != null && parentPom.getGav().getGroupId().equals(parent.getGav().getGroupId()) && - parentPom.getGav().getArtifactId().equals(parent.getGav().getArtifactId()) ? parentPom : null; + parentPom.getGav().getArtifactId().equals(parent.getGav().getArtifactId()) ? parentPom : null; } public MavenMetadata downloadMetadata(GroupArtifact groupArtifact, @Nullable ResolvedPom containingPom, List repositories) throws MavenDownloadingException { @@ -259,9 +259,9 @@ public MavenMetadata downloadMetadata(GroupArtifactVersion gav, @Nullable Resolv try { String scheme = URI.create(repo.getUri()).getScheme(); String baseUri = repo.getUri() + (repo.getUri().endsWith("/") ? "" : "/") + - requireNonNull(gav.getGroupId()).replace('.', '/') + '/' + - gav.getArtifactId() + '/' + - (gav.getVersion() == null ? "" : gav.getVersion() + '/'); + requireNonNull(gav.getGroupId()).replace('.', '/') + '/' + + gav.getArtifactId() + '/' + + (gav.getVersion() == null ? "" : gav.getVersion() + '/'); if ("file".equals(scheme)) { // A maven repository can be expressed as a URI with a file scheme @@ -356,8 +356,8 @@ public MavenMetadata downloadMetadata(GroupArtifactVersion gav, @Nullable Resolv String scheme = URI.create(repo.getUri()).getScheme(); String uri = repo.getUri() + (repo.getUri().endsWith("/") ? "" : "/") + - requireNonNull(gav.getGroupId()).replace('.', '/') + '/' + - gav.getArtifactId() + '/'; + requireNonNull(gav.getGroupId()).replace('.', '/') + '/' + + gav.getArtifactId() + '/'; try { MavenMetadata.Versioning versioning; @@ -496,7 +496,7 @@ public Pom download(GroupArtifactVersion gav, // The requested gav might itself have an unresolved placeholder in the version, so also check raw values for (Pom projectPom : projectPoms.values()) { if (!projectPom.getGroupId().equals(gav.getGroupId()) || - !projectPom.getArtifactId().equals(gav.getArtifactId())) { + !projectPom.getArtifactId().equals(gav.getArtifactId())) { continue; } @@ -512,7 +512,7 @@ public Pom download(GroupArtifactVersion gav, } if (containingPom != null && containingPom.getRequested().getSourcePath() != null && - !StringUtils.isBlank(relativePath) && !relativePath.contains(":")) { + !StringUtils.isBlank(relativePath) && !relativePath.contains(":")) { Path folderContainingPom = containingPom.getRequested().getSourcePath().getParent(); if (folderContainingPom != null) { Pom maybeLocalPom = projectPoms.get(folderContainingPom.resolve(Paths.get(relativePath, "pom.xml")) @@ -521,9 +521,9 @@ public Pom download(GroupArtifactVersion gav, // So double check that the GAV coordinates match so that we don't get a relative path from a remote // pom like ".." or "../.." which coincidentally _happens_ to have led to an unrelated pom on the local filesystem if (maybeLocalPom != null && - gav.getGroupId().equals(maybeLocalPom.getGroupId()) && - gav.getArtifactId().equals(maybeLocalPom.getArtifactId()) && - gav.getVersion().equals(maybeLocalPom.getVersion())) { + gav.getGroupId().equals(maybeLocalPom.getGroupId()) && + gav.getArtifactId().equals(maybeLocalPom.getArtifactId()) && + gav.getVersion().equals(maybeLocalPom.getVersion())) { return maybeLocalPom; } } @@ -552,10 +552,10 @@ public Pom download(GroupArtifactVersion gav, if (result == null) { URI uri = URI.create(repo.getUri() + (repo.getUri().endsWith("/") ? "" : "/") + - requireNonNull(gav.getGroupId()).replace('.', '/') + '/' + - gav.getArtifactId() + '/' + - gav.getVersion() + '/' + - gav.getArtifactId() + '-' + versionMaybeDatedSnapshot + ".pom"); + requireNonNull(gav.getGroupId()).replace('.', '/') + '/' + + gav.getArtifactId() + '/' + + gav.getVersion() + '/' + + gav.getArtifactId() + '-' + versionMaybeDatedSnapshot + ".pom"); uris.add(uri.toString()); if ("file".equals(uri.getScheme())) { Path inputPath = Paths.get(gav.getGroupId(), gav.getArtifactId(), gav.getVersion()); @@ -688,9 +688,9 @@ private GroupArtifactVersion handleSnapshotTimestampVersion(GroupArtifactVersion if (gav.getVersion() != null && gav.getVersion().endsWith("-SNAPSHOT")) { for (ResolvedGroupArtifactVersion pinnedSnapshotVersion : new MavenExecutionContextView(ctx).getPinnedSnapshotVersions()) { if (pinnedSnapshotVersion.getDatedSnapshotVersion() != null && - pinnedSnapshotVersion.getGroupId().equals(gav.getGroupId()) && - pinnedSnapshotVersion.getArtifactId().equals(gav.getArtifactId()) && - pinnedSnapshotVersion.getVersion().equals(gav.getVersion())) { + pinnedSnapshotVersion.getGroupId().equals(gav.getGroupId()) && + pinnedSnapshotVersion.getArtifactId().equals(gav.getArtifactId()) && + pinnedSnapshotVersion.getVersion().equals(gav.getVersion())) { return pinnedSnapshotVersion.getDatedSnapshotVersion(); } } @@ -702,6 +702,23 @@ private GroupArtifactVersion handleSnapshotTimestampVersion(GroupArtifactVersion //This can happen if the artifact only exists in the local maven cache. In this case, just return the original return gav.getVersion(); } + + // Find the newest with a matching classifier - the latest snapshot may not have artifacts for all classifiers. + List snapshotVersions = mavenMetadata.getVersioning().getSnapshotVersions(); + if (snapshotVersions != null) { + // Try to get requested classifier (this is unfortunately not present in 'gav' structure) + String classifier = getClassifierFromContainingPom(gav, containingPom); + MavenMetadata.SnapshotVersion snapshotVersion = snapshotVersions.stream() + .sorted(Comparator.comparing(MavenMetadata.SnapshotVersion::getUpdated).reversed()) + .filter(s -> Objects.equals(s.getClassifier(), classifier)) + .findFirst() + .orElse(null); + if (snapshotVersion != null) { + return snapshotVersion.getValue(); + } + } + + // Replace SNAPSHOT suffix with timestamp and build number MavenMetadata.Snapshot snapshot = mavenMetadata.getVersioning().getSnapshot(); if (snapshot != null && snapshot.getTimestamp() != null) { return gav.getVersion().replaceFirst("SNAPSHOT$", snapshot.getTimestamp() + "-" + snapshot.getBuildNumber()); @@ -1054,4 +1071,27 @@ private static boolean hasPomFile(Path dir, Path versionPath, GroupArtifactVersi String artifactPomFile = gav.getArtifactId() + "-" + versionPath.getFileName() + ".pom"; return Files.exists(dir.resolve(versionPath.resolve(artifactPomFile))); } + + /** + * Retrieves the classifier of a dependency from a provided resolved POM, if it exists. + * + * @param gav The group, artifact, and version information of the dependency to locate. + * @param containingPom The resolved POM that potentially contains the dependency information. + * If null, the method will return null. + * @return The classifier of the dependency within the provided POM, or null if no matching + * dependency or classifier is found. + */ + private static @Nullable String getClassifierFromContainingPom(GroupArtifactVersion gav, @Nullable ResolvedPom containingPom) { + if (containingPom != null) { + for (Dependency dep : containingPom.getRequestedDependencies()) { + if (Objects.equals(dep.getGroupId(), gav.getGroupId())) { + if (Objects.equals(dep.getArtifactId(), gav.getArtifactId())) { + return dep.getClassifier(); + } + } + } + } + return null; + } + } diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/tree/MavenMetadata.java b/rewrite-maven/src/main/java/org/openrewrite/maven/tree/MavenMetadata.java index 2ece965a7f5..8d94d2dd036 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/tree/MavenMetadata.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/tree/MavenMetadata.java @@ -101,5 +101,7 @@ public static class SnapshotVersion { String extension; String value; String updated; + @Nullable + String classifier; } } diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java b/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java index 7f5a0d343e1..7b9b00721d3 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java @@ -320,11 +320,13 @@ public String getPackaging() { public @Nullable String getManagedVersion(@Nullable String groupId, String artifactId, @Nullable String type, @Nullable String classifier) { for (ResolvedManagedDependency dm : dependencyManagement) { + if (dm.getVersion() == null) { + continue; // Unclear why this happens; just ignore those entries, because a valid version is requested + } if (dm.matches(groupId, artifactId, type, classifier)) { return getValue(dm.getVersion()); } } - return null; } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java index 4c19fc87f33..b641f835b64 100755 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/internal/MavenPomDownloaderTest.java @@ -33,11 +33,11 @@ import org.openrewrite.*; import org.openrewrite.ipc.http.HttpSender; import org.openrewrite.ipc.http.HttpUrlConnectionSender; -import org.openrewrite.maven.http.OkHttpSender; import org.openrewrite.maven.MavenDownloadingException; import org.openrewrite.maven.MavenExecutionContextView; import org.openrewrite.maven.MavenParser; import org.openrewrite.maven.MavenSettings; +import org.openrewrite.maven.http.OkHttpSender; import org.openrewrite.maven.tree.*; import javax.net.ssl.SSLSocketFactory; @@ -314,7 +314,7 @@ void useHttpWhenHttpsFails() throws IOException { @Test @Disabled - void dontFetchSnapshotsFromReleaseRepos() { + void dontFetchSnapshotsFromReleaseRepos() throws Exception { try (MockWebServer snapshotRepo = new MockWebServer(); MockWebServer releaseRepo = new MockWebServer()) { snapshotRepo.setDispatcher(new Dispatcher() { @@ -322,39 +322,39 @@ void dontFetchSnapshotsFromReleaseRepos() { public MockResponse dispatch(RecordedRequest request) { MockResponse response = new MockResponse().setResponseCode(200); if (request.getPath() != null && request.getPath().contains("maven-metadata")) { + //language=xml response.setBody( - //language=xml """ - - org.springframework.cloud - spring-cloud-dataflow-build - 2.10.0-SNAPSHOT - - - 20220201.001946 - 85 - - 20220201001950 - - - pom - 2.10.0-20220201.001946-85 - 20220201001946 - - - - + + org.springframework.cloud + spring-cloud-dataflow-build + 2.10.0-SNAPSHOT + + + 20220201.001946 + 85 + + 20220201001950 + + + pom + 2.10.0-20220201.001946-85 + 20220201001946 + + + + """ ); } else if (request.getPath() != null && request.getPath().endsWith(".pom")) { + //language=xml response.setBody( - //language=xml """ - - org.springframework.cloud - spring-cloud-dataflow-build - 2.10.0-SNAPSHOT - + + org.springframework.cloud + spring-cloud-dataflow-build + 2.10.0-SNAPSHOT + """ ); } @@ -380,45 +380,173 @@ public MockResponse dispatch(RecordedRequest request) { MavenParser.builder().build().parse(ctx, //language=xml """ - - 4.0.0 + + 4.0.0 - org.openrewrite.test - foo - 0.1.0-SNAPSHOT + org.openrewrite.test + foo + 0.1.0-SNAPSHOT - - - snapshot - - true - - http://%s:%d - - - release - - false - - http://%s:%d - - + + + snapshot + + true + + http://%s:%d + + + release + + false + + http://%s:%d + + - - - org.springframework.cloud - spring-cloud-dataflow-build - 2.10.0-SNAPSHOT - - - + + + org.springframework.cloud + spring-cloud-dataflow-build + 2.10.0-SNAPSHOT + + + """.formatted(snapshotRepo.getHostName(), snapshotRepo.getPort(), releaseRepo.getHostName(), releaseRepo.getPort()) ); assertThat(snapshotRepo.getRequestCount()).isGreaterThan(1); assertThat(metadataPaths.get()).isEqualTo(0); - } catch (IOException e) { - throw new RuntimeException(e); + } + } + + @Issue("https://github.com/openrewrite/rewrite-maven-plugin/issues/862") + @Test + void fetchSnapshotWithCorrectClassifier() throws Exception { + try (MockWebServer snapshotServer = new MockWebServer()) { + snapshotServer.setDispatcher(new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest request) { + MockResponse response = new MockResponse().setResponseCode(200); + if (request.getPath() != null && request.getPath().contains("maven-metadata")) { + //language=xml + response.setBody( + """ + + com.some + an-artifact + 10.5.0-SNAPSHOT + + + 20250113.114247 + 36 + + 20250113114247 + + + javadoc + jar + 10.5.0-20250113.114247-36 + 20250113114247 + + + tests + jar + 10.5.0-20250113.114244-35 + 20250113114244 + + + sources + jar + 10.5.0-20250113.114242-34 + 20250113114242 + + + jar + 10.5.0-20250113.114227-33 + 20250113114227 + + + pom + 10.5.0-20250113.114227-33 + 20250113114227 + + + + + """ + ); + } else if (request.getPath() != null && request.getPath().endsWith(".pom")) { + //language=xml + response.setBody( + """ + + com.some + an-artifact + 10.5.0-SNAPSHOT + + """ + ); + } + return response; + } + }); + + snapshotServer.start(); + + //language=xml + MavenParser.builder().build().parse(ctx, + """ + + 4.0.0 + org.openrewrite.test + foo + 0.1.0-SNAPSHOT + + + snapshot + + true + + http://%s:%d + + + + + com.some + an-artifact + 10.5.0-SNAPSHOT + + + + """.formatted(snapshotServer.getHostName(), snapshotServer.getPort()) + ); + + MavenRepository snapshotRepo = MavenRepository.builder() + .id("id") + .uri("http://%s:%d/maven/".formatted(snapshotServer.getHostName(), snapshotServer.getPort())) + .build(); + + var gav = new GroupArtifactVersion("com.some", "an-artifact", "10.5.0-SNAPSHOT"); + var mavenPomDownloader = new MavenPomDownloader(emptyMap(), ctx); + + var pomPath = Paths.get("pom.xml"); + var pom = Pom.builder() + .sourcePath(pomPath) + .repository(snapshotRepo) + .properties(singletonMap("REPO_URL", snapshotRepo.getUri())) + .gav(new ResolvedGroupArtifactVersion( + "${REPO_URL}", gav.getGroupId(), gav.getArtifactId(), gav.getVersion(), null)) + .build(); + var resolvedPom = ResolvedPom.builder() + .requested(pom) + .properties(singletonMap("REPO_URL", snapshotRepo.getUri())) + .repositories(singletonList(snapshotRepo)) + .build(); + + // Ensure that classifier 'javadoc', 'tests' and 'sources' are not used + var downloadedPom = mavenPomDownloader.download(gav, null, resolvedPom, List.of(snapshotRepo)); + assertThat(downloadedPom).returns("10.5.0-20250113.114227-33", Pom::getDatedSnapshotVersion); } } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/tree/ResolvedPomTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/tree/ResolvedPomTest.java index b1c0e12f1bd..ea52800af59 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/tree/ResolvedPomTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/tree/ResolvedPomTest.java @@ -367,19 +367,135 @@ public void downloadError(GroupArtifactVersion gav, List attemptedUris, assertThat(downloadErrorArgs).hasSize(1); } - private static void createJarFile(Path localRepository1) throws IOException { - Path localJar = localRepository1.resolve("com/some/some-artifact/1/some-artifact-1.jar"); - assertThat(localJar.getParent().toFile().mkdirs()).isTrue(); - Files.writeString(localJar, "some content not to be empty"); - } + } - private static MavenRepository createMavenRepository(Path localRepository, String name) { - return MavenRepository.builder() - .id(name) - .uri(localRepository.toUri().toString()) - .snapshots(false) - .knownToExist(true) - .build(); + @Nested + class DependencyManagement { + + @Issue("https://github.com/openrewrite/rewrite-maven-plugin/issues/862") + @Test + void resolveVersionFromParentDependencyManagement(@TempDir Path localRepository) throws IOException { + MavenRepository mavenLocal = createMavenRepository(localRepository, "local"); + createJarFile(localRepository); + createJarFile(localRepository, "org.openrewrite.test", "lib", "1.0"); + + List> downloadErrorArgs = new ArrayList<>(); + MavenExecutionContextView ctx = MavenExecutionContextView.view(new InMemoryExecutionContext(Throwable::printStackTrace)); + ctx.setRepositories(List.of(mavenLocal)); + ctx.setResolutionListener(new ResolutionEventListener() { + @Override + public void downloadError(GroupArtifactVersion gav, List attemptedUris, @Nullable Pom containing) { + List list = new ArrayList<>(); + list.add(gav); + list.add(attemptedUris); + list.add(containing); + downloadErrorArgs.add(list); + } + }); + + String father = """ + + 4.0.0 + org.example + father + 1.0.0-SNAPSHOT + pom + + childA + childB + + + + + com.some + some-artifact + 1 + + + + + """; + String childA = """ + + 4.0.0 + + org.example + father + 1.0.0-SNAPSHOT + + childA + + + + org.openrewrite.test + lib + 1.0 + pom + import + + + + + + com.some + some-artifact + + + + """; + String childB = """ + + 4.0.0 + + org.example + father + 1.0.0-SNAPSHOT + + childB + + + + com.some + some-artifact + compile + + + + + """; + + rewriteRun( + spec -> spec.executionContext(ctx), + pomXml(father, spec -> spec.path("pom.xml")), + pomXml(childA, spec -> spec.path("childA/pom.xml")), + pomXml(childB, spec -> spec.path("childB/pom.xml").afterRecipe(doc -> { + ResolvedPom pom = doc.getMarkers().findFirst(MavenResolutionResult.class).get().getPom(); + String version = pom.getManagedVersion("com.some", "some-artifact", null, null); + // Assert that version is not null! + assertThat(version).isEqualTo("1"); + }) + ) + ); } } + + private static void createJarFile(Path localRepository1) throws IOException { + createJarFile(localRepository1, "com/some", "some-artifact", "1"); + } + + private static void createJarFile(Path localRepository, String groupId, String artifactId, String version) throws IOException { + Path localJar = localRepository.resolve("%s/%s/%s/%s-%s.jar".formatted( + groupId.replace('.', '/'), artifactId, version, artifactId, version)); + assertThat(localJar.getParent().toFile().mkdirs()).isTrue(); + Files.writeString(localJar, "some content not to be empty"); + } + + private static MavenRepository createMavenRepository(Path localRepository, String name) { + return MavenRepository.builder() + .id(name) + .uri(localRepository.toUri().toString()) + .snapshots(false) + .knownToExist(true) + .build(); + } } From a6afce055efd0274e86ea26b2eecb9d7cc4d56fe Mon Sep 17 00:00:00 2001 From: Sam Snyder Date: Thu, 16 Jan 2025 12:33:58 -0800 Subject: [PATCH 153/179] Tweak AddDependency to be a bit more permissive when adding a dependency without onlyIfUsing constraint. --- .../org/openrewrite/gradle/AddDependency.java | 24 ++++++++++++------- .../openrewrite/gradle/AddDependencyTest.java | 3 --- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependency.java b/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependency.java index 990a0606d65..59084bd7cec 100644 --- a/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependency.java +++ b/rewrite-gradle/src/main/java/org/openrewrite/gradle/AddDependency.java @@ -34,6 +34,7 @@ import java.util.*; +import static java.util.Collections.*; import static java.util.Objects.requireNonNull; @Value @@ -171,14 +172,14 @@ private boolean usesType(SourceFile sourceFile, ExecutionContext ctx) { return tree; } SourceFile sourceFile = (SourceFile) tree; - sourceFile.getMarkers().findFirst(JavaProject.class).ifPresent(javaProject -> - sourceFile.getMarkers().findFirst(JavaSourceSet.class).ifPresent(sourceSet -> { - if (usesType(sourceFile, ctx)) { - acc.usingType = true; - } - Set configurations = acc.configurationsByProject.computeIfAbsent(javaProject, ignored -> new HashSet<>()); - configurations.add("main".equals(sourceSet.getName()) ? "implementation" : sourceSet.getName() + "Implementation"); - })); + sourceFile.getMarkers().findFirst(JavaProject.class).ifPresent(javaProject -> { + if (usesType(sourceFile, ctx)) { + acc.usingType = true; + } + Set configurations = acc.configurationsByProject.computeIfAbsent(javaProject, ignored -> new HashSet<>()); + sourceFile.getMarkers().findFirst(JavaSourceSet.class).ifPresent(sourceSet -> + configurations.add("main".equals(sourceSet.getName()) ? "implementation" : sourceSet.getName() + "Implementation")); + }); return tree; } }; @@ -216,7 +217,12 @@ public TreeVisitor getVisitor(Scanned acc) { GradleProject gp = maybeGp.get(); - Set resolvedConfigurations = StringUtils.isBlank(configuration) ? acc.configurationsByProject.get(jp) : new HashSet<>(Collections.singletonList(configuration)); + Set resolvedConfigurations = StringUtils.isBlank(configuration) ? + acc.configurationsByProject.getOrDefault(jp, new HashSet<>()) : + new HashSet<>(singletonList(configuration)); + if (resolvedConfigurations.isEmpty()) { + resolvedConfigurations.add("implementation"); + } Set tmpConfigurations = new HashSet<>(resolvedConfigurations); for (String tmpConfiguration : tmpConfigurations) { GradleDependencyConfiguration gdc = gp.getConfiguration(tmpConfiguration); diff --git a/rewrite-gradle/src/test/java/org/openrewrite/gradle/AddDependencyTest.java b/rewrite-gradle/src/test/java/org/openrewrite/gradle/AddDependencyTest.java index 6330f931018..cb1da2ffe4a 100644 --- a/rewrite-gradle/src/test/java/org/openrewrite/gradle/AddDependencyTest.java +++ b/rewrite-gradle/src/test/java/org/openrewrite/gradle/AddDependencyTest.java @@ -1317,9 +1317,6 @@ void addUnconditionally() { rewriteRun( spec -> spec.recipe(addDependency("org.apache.logging.log4j:log4j-core:2.22.1")), mavenProject("project", - srcMainJava( - java(usingGuavaIntMath) - ), buildGradle(""" plugins { id "java-library" From c1b258eef30f430104c733575da99b99e8d1eaba Mon Sep 17 00:00:00 2001 From: Ralph Sanders <59902221+rlsanders4@users.noreply.github.com> Date: Fri, 17 Jan 2025 02:24:31 -0600 Subject: [PATCH 154/179] Fix issue parsing string with Java8ReloadableParser (#4914) * Fix parser * restore build files * Restore build file * Put arguments on new line for readability * Add test case (even though not reproducible) --------- Co-authored-by: Tim te Beek Co-authored-by: Knut Wannheden --- .../java/ReloadableJava8Parser.java | 7 ++- .../org/openrewrite/java/tree/ParserTest.java | 43 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 rewrite-java-tck/src/main/java/org/openrewrite/java/tree/ParserTest.java diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java index bad6fc19a4d..73fbc46c6ba 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java @@ -113,7 +113,7 @@ class ReloadableJava8Parser implements JavaParser { LOMBOK: if (System.getenv().getOrDefault("REWRITE_LOMBOK", System.getProperty("rewrite.lombok")) != null && - classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) { + classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) { Processor lombokProcessor = null; try { // https://projectlombok.org/contributing/lombok-execution-path @@ -255,7 +255,10 @@ LinkedHashMap parseInputsToCompilerAst(Iterable } try { //noinspection unchecked - com.sun.tools.javac.util.List jcCompilationUnits = compiler.parseFiles((List) (List) inputFileObjects); + com.sun.tools.javac.util.List jcCompilationUnits = com.sun.tools.javac.util.List.from( + inputFileObjects.stream() + .map(input -> compiler.parse(input)) + .toArray(JCTree.JCCompilationUnit[]::new)); for (int i = 0; i < inputFileObjects.size(); i++) { cus.put(inputFileObjects.get(i).getInput(), jcCompilationUnits.get(i)); } diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/ParserTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/ParserTest.java new file mode 100644 index 00000000000..065ef0c22f9 --- /dev/null +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/ParserTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.tree; + +import org.junit.jupiter.api.Test; +import org.openrewrite.Issue; +import org.openrewrite.SourceFile; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RewriteTest; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; + +class ParserTest implements RewriteTest { + + @Test + @Issue("https://github.com/openrewrite/rewrite/pull/4914") + void parseString() throws IOException { + // path needs to be resolvable from `rewrite-java-8` etc. + Path targetFile = Paths.get("../rewrite-java-tck/src/main/java/org/openrewrite/java/tree/ParserTest.java"); + @SuppressWarnings("SimplifyStreamApiCallChains") List ignore = JavaParser.fromJavaVersion() + .build() + .parse(new String(Files.readAllBytes(targetFile))) + .collect(Collectors.toList()); + } +} From b7746cf85bfa915bb68061a756f11273cfeae98d Mon Sep 17 00:00:00 2001 From: Valentin Delaye Date: Fri, 17 Jan 2025 09:24:55 +0100 Subject: [PATCH 155/179] Groovy parser fail with single line comment (#4887) * Groovy parser fail with Jenkinsfile and single line comment * Minimize example * Update rewrite-groovy/src/test/java/org/openrewrite/groovy/JenkinsFileTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Fix `StringUtils#indexOfNextNonWhitespace()` A `//` sequence inside a multi-line comment caused trouble. --------- Co-authored-by: Tim te Beek Co-authored-by: Tim te Beek Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Knut Wannheden --- .../org/openrewrite/internal/StringUtils.java | 12 +++++++----- .../org/openrewrite/groovy/JenkinsFileTest.java | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java b/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java index 4f0f76ae578..e06c1d58281 100644 --- a/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java @@ -692,7 +692,13 @@ public static int indexOfNextNonWhitespace(int cursor, String source) { continue; } else if (length > cursor + 1) { char next = source.charAt(cursor + 1); - if (current == '/' && next == '/') { + if (inMultiLineComment) { + if (current == '*' && next == '/') { + inMultiLineComment = false; + cursor++; + continue; + } + } else if (current == '/' && next == '/') { inSingleLineComment = true; cursor++; continue; @@ -700,10 +706,6 @@ public static int indexOfNextNonWhitespace(int cursor, String source) { inMultiLineComment = true; cursor++; continue; - } else if (current == '*' && next == '/') { - inMultiLineComment = false; - cursor++; - continue; } } if (!inMultiLineComment && !Character.isWhitespace(current)) { diff --git a/rewrite-groovy/src/test/java/org/openrewrite/groovy/JenkinsFileTest.java b/rewrite-groovy/src/test/java/org/openrewrite/groovy/JenkinsFileTest.java index f677fb9f019..75ff46b9ffe 100644 --- a/rewrite-groovy/src/test/java/org/openrewrite/groovy/JenkinsFileTest.java +++ b/rewrite-groovy/src/test/java/org/openrewrite/groovy/JenkinsFileTest.java @@ -16,6 +16,7 @@ package org.openrewrite.groovy; import org.junit.jupiter.api.Test; +import org.openrewrite.Issue; import org.openrewrite.test.RewriteTest; import static org.openrewrite.groovy.Assertions.groovy; @@ -119,4 +120,19 @@ void jenkinsfile() { ) ); } + + @Issue("https://github.com/openrewrite/rewrite/pull/4887") + @Test + void jenkinsfileWithComment() { + // the Jenkinsfile adapted from https://github.com/jenkinsci/ssh-plugin/blob/158.ve2a_e90fb_7319/Jenkinsfile + rewriteRun( + groovy( + """ + /* https://github.com */ + foo() + """, + spec -> spec.path("Jenkinsfile") + ) + ); + } } From b2a641dd69a7e846692834760c73e1e279ff61b4 Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Fri, 17 Jan 2025 11:07:26 +0100 Subject: [PATCH 156/179] YAML Parser not to take @variables@ in the middle of scalar (#4917) --- .../java/org/openrewrite/yaml/YamlParser.java | 2 +- .../org/openrewrite/yaml/YamlParserTest.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/rewrite-yaml/src/main/java/org/openrewrite/yaml/YamlParser.java b/rewrite-yaml/src/main/java/org/openrewrite/yaml/YamlParser.java index ca7685f37ba..deac37d20cd 100644 --- a/rewrite-yaml/src/main/java/org/openrewrite/yaml/YamlParser.java +++ b/rewrite-yaml/src/main/java/org/openrewrite/yaml/YamlParser.java @@ -52,7 +52,7 @@ import static org.openrewrite.Tree.randomId; public class YamlParser implements org.openrewrite.Parser { - private static final Pattern VARIABLE_PATTERN = Pattern.compile(":\\s*(@[^\n\r@]+@)"); + private static final Pattern VARIABLE_PATTERN = Pattern.compile(":\\s+(@[^\n\r@]+@)"); @Override public Stream parse(@Language("yml") String... sources) { diff --git a/rewrite-yaml/src/test/java/org/openrewrite/yaml/YamlParserTest.java b/rewrite-yaml/src/test/java/org/openrewrite/yaml/YamlParserTest.java index e3033a4b827..7b8653cd68a 100644 --- a/rewrite-yaml/src/test/java/org/openrewrite/yaml/YamlParserTest.java +++ b/rewrite-yaml/src/test/java/org/openrewrite/yaml/YamlParserTest.java @@ -216,4 +216,20 @@ void troublesomeYaml() { ) ); } + + @Test + void atSymbols() { + rewriteRun( + yaml( + // BTW, the @ sign is forbidden as the first character of a scalar value by the YAML spec: + // https://github.com/yaml/yaml-spec/blob/1b1a1be43bd6e0cfec45caf0e40af3b5d2bb7f8a/spec/1.2.2/spec.md#L1877 + """ + root: + specifier: npm:@testing-library/vue@5.0.4 + date: @build.timestamp@ + version: @project.version@ + """ + ) + ); + } } From fa191cb152d4aad33f3b1a7c9d97f5a1fbf95655 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Fri, 17 Jan 2025 13:27:05 +0100 Subject: [PATCH 157/179] Add missing `@Contract` to `ListUtils#map()` method --- .../src/main/java/org/openrewrite/internal/ListUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/ListUtils.java b/rewrite-core/src/main/java/org/openrewrite/internal/ListUtils.java index a18cc8bf585..5de88dc8c50 100644 --- a/rewrite-core/src/main/java/org/openrewrite/internal/ListUtils.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/ListUtils.java @@ -261,6 +261,7 @@ public static List insert(@Nullable List ls, @Nullable T t, int index) /** * For backwards compatibility; prefer {@link #map(List, Function)}. */ + @Contract("null, _ -> null; !null, _ -> !null") public static @Nullable List map(@Nullable List ls, UnaryOperator<@Nullable T> map) { return map(ls, (Function) map); } From 9ddbb83f038cd989d4679aa12fe1951b5e0836c2 Mon Sep 17 00:00:00 2001 From: Niels de Bruin Date: Fri, 17 Jan 2025 14:08:21 +0100 Subject: [PATCH 158/179] Support JEP-441: Pattern Matching for switch for Java 21+ (#4661) * Add full blown support for Switch pattern matching * Add print idempotency for Record pattern matching --------- Co-authored-by: Laurens Westerlaken Co-authored-by: Tim te Beek --- .../groovy/GroovyParserVisitor.java | 13 +- .../ReloadableJava11ParserVisitor.java | 2 + .../ReloadableJava17ParserVisitor.java | 2 + .../ReloadableJava21ParserVisitor.java | 28 +++- .../java/ReloadableJava8ParserVisitor.java | 32 ++-- .../java/tree/RecordPatternMatchingTest.java | 74 +++++++++ .../java/tree/SwitchPatternMatchingTest.java | 155 ++++++++++++++++++ .../java/org/openrewrite/java/Assertions.java | 19 ++- .../org/openrewrite/java/JavaPrinter.java | 12 +- .../org/openrewrite/java/JavaVisitor.java | 5 +- .../java/search/SemanticallyEqual.java | 8 +- .../java/org/openrewrite/java/tree/J.java | 77 +++++++-- .../org/openrewrite/java/tree/JContainer.java | 1 + .../openrewrite/java/tree/JRightPadded.java | 1 + .../java/org/openrewrite/java/tree/Space.java | 5 +- .../org/openrewrite/test/TypeValidation.java | 8 +- 16 files changed, 394 insertions(+), 48 deletions(-) create mode 100644 rewrite-java-tck/src/main/java/org/openrewrite/java/tree/RecordPatternMatchingTest.java create mode 100644 rewrite-java-tck/src/main/java/org/openrewrite/java/tree/SwitchPatternMatchingTest.java diff --git a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java index d38c154ef76..e36026b986a 100644 --- a/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java +++ b/rewrite-groovy/src/main/java/org/openrewrite/groovy/GroovyParserVisitor.java @@ -650,7 +650,7 @@ public List visitAndGetAnnotations(AnnotatedNode node) { for (AnnotationNode annotationNode : node.getAnnotations()) { // The groovy compiler can add or remove annotations for AST transformations. // Because @groovy.transform.Immutable is discarded in favour of other transform annotations, the removed annotation must be parsed by hand. - if (sourceStartsWith("@" + Immutable.class.getSimpleName()) || sourceStartsWith("@" + Immutable.class.getCanonicalName()) ) { + if (sourceStartsWith("@" + Immutable.class.getSimpleName()) || sourceStartsWith("@" + Immutable.class.getCanonicalName())) { visitAnnotation(new AnnotationNode(new ClassNode(Immutable.class))); paramAnnotations.add(pollQueue()); } @@ -1135,10 +1135,12 @@ public void visitCaseStatement(CaseStatement statement) { J.Case.Type.Statement, null, JContainer.build(singletonList(JRightPadded.build(visit(statement.getExpression())))), + null, + null, statement.getCode() instanceof EmptyStatement ? JContainer.build(sourceBefore(":"), convertStatements(emptyList()), Markers.EMPTY) : - JContainer.build(sourceBefore(":"), convertStatements(((BlockStatement) statement.getCode()).getStatements()), Markers.EMPTY) - , null) + JContainer.build(sourceBefore(":"), convertStatements(((BlockStatement) statement.getCode()).getStatements()), Markers.EMPTY), + null) ); } @@ -1149,6 +1151,8 @@ private J.Case visitDefaultCaseStatement(BlockStatement statement) { J.Case.Type.Statement, null, JContainer.build(singletonList(JRightPadded.build(new J.Identifier(randomId(), EMPTY, Markers.EMPTY, emptyList(), skip("default"), null, null)))), + null, + null, JContainer.build(sourceBefore(":"), convertStatements(statement.getStatements()), Markers.EMPTY), null ); @@ -1609,7 +1613,7 @@ public void visitGStringExpression(GStringExpression gstring) { } } - queue.add(new G.GString(randomId(), fmt, Markers.EMPTY, delimiter, strings,typeMapping.type(gstring.getType()))); + queue.add(new G.GString(randomId(), fmt, Markers.EMPTY, delimiter, strings, typeMapping.type(gstring.getType()))); skip(delimiter); // Closing delim for GString } @@ -2778,6 +2782,7 @@ private static ClassNode staticType(Parameter parameter) { } private static final Map modifierNameToType; + static { modifierNameToType = new LinkedHashMap<>(); modifierNameToType.put("def", J.Modifier.Type.LanguageExtension); diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index 8c434c84edd..22648604cd2 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -346,6 +346,8 @@ public J visitCase(CaseTree node, Space fmt) { ), Markers.EMPTY ), + null, + null, JContainer.build(sourceBefore(":"), convertStatements(node.getStatements()), Markers.EMPTY), null ); diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 7fbd874ed01..4cfa6f14764 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -355,6 +355,8 @@ public J visitCase(CaseTree node, Space fmt) { convertAll(node.getExpressions(), commaDelim, t -> EMPTY), Markers.EMPTY ), + null, + null, JContainer.build( sourceBefore(type == J.Case.Type.Rule ? "->" : ":"), convertStatements(node.getStatements()), diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index 4a6973da177..0614a13714f 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -348,13 +348,15 @@ public J visitCase(CaseTree node, Space fmt) { Markers.EMPTY, type, null, + null, JContainer.build( - node.getExpressions().isEmpty() ? EMPTY : sourceBefore("case"), - node.getExpressions().isEmpty() ? + node.getLabels().isEmpty() ? EMPTY : sourceBefore("case"), + node.getLabels().isEmpty() || node.getLabels().getFirst() instanceof DefaultCaseLabelTree ? List.of(JRightPadded.build(new J.Identifier(randomId(), Space.EMPTY, Markers.EMPTY, emptyList(), skip("default"), null, null))) : - convertAll(node.getExpressions(), commaDelim, t -> EMPTY), + convertAll(node.getLabels(), commaDelim, ignored -> node.getGuard() != null ? sourceBefore("when", '-') : EMPTY), Markers.EMPTY ), + convert(node.getGuard()), JContainer.build( sourceBefore(type == J.Case.Type.Rule ? "->" : ":"), convertStatements(node.getStatements()), @@ -779,12 +781,26 @@ public J visitInstanceOf(InstanceOfTree node, Space fmt) { return new J.InstanceOf(randomId(), fmt, Markers.EMPTY, convert(node.getExpression(), t -> sourceBefore("instanceof")), convert(node.getType()), - node.getPattern() instanceof JCBindingPattern b ? - new J.Identifier(randomId(), sourceBefore(b.getVariable().getName().toString()), Markers.EMPTY, emptyList(), b.getVariable().getName().toString(), - type, typeMapping.variableType(b.var.sym)) : null, + getNodePattern(node.getPattern(), type), type); } + private @Nullable J getNodePattern(@Nullable PatternTree pattern, JavaType type) { + if (pattern instanceof JCBindingPattern b) { + return new J.Identifier(randomId(), sourceBefore(b.getVariable().getName().toString()), Markers.EMPTY, emptyList(), b.getVariable().getName().toString(), + type, typeMapping.variableType(b.var.sym)); + } else { + if (pattern == null) { + return null; + } + int saveCursor = cursor; + int endCursor = max(endPos(pattern), cursor); + cursor = endCursor; + return new J.Unknown(randomId(), whitespace(), Markers.EMPTY, new J.Unknown.Source(randomId(), whitespace(), Markers.EMPTY, source.substring(saveCursor, endCursor))); + + } + } + @Override public J visitIntersectionType(IntersectionTypeTree node, Space fmt) { JContainer bounds = node.getBounds().isEmpty() ? null : diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index 0d6cf8309fc..5d35ffcc46a 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -343,6 +343,8 @@ public J visitCase(CaseTree node, Space fmt) { ), Markers.EMPTY ), + null, + null, JContainer.build(sourceBefore(":"), convertStatements(node.getStatements()), Markers.EMPTY), null ); @@ -1787,17 +1789,17 @@ private List> convertAll(List tr private Space statementDelim(@Nullable Tree t) { if (t instanceof JCAssert || - t instanceof JCAssign || - t instanceof JCAssignOp || - t instanceof JCBreak || - t instanceof JCContinue || - t instanceof JCDoWhileLoop || - t instanceof JCImport || - t instanceof JCMethodInvocation || - t instanceof JCNewClass || - t instanceof JCReturn || - t instanceof JCThrow || - t instanceof JCUnary) { + t instanceof JCAssign || + t instanceof JCAssignOp || + t instanceof JCBreak || + t instanceof JCContinue || + t instanceof JCDoWhileLoop || + t instanceof JCImport || + t instanceof JCMethodInvocation || + t instanceof JCNewClass || + t instanceof JCReturn || + t instanceof JCThrow || + t instanceof JCUnary) { return sourceBefore(";"); } @@ -1808,7 +1810,7 @@ private Space statementDelim(@Nullable Tree t) { if (t instanceof JCExpressionStatement) { ExpressionTree expTree = ((ExpressionStatementTree) t).getExpression(); if (expTree instanceof ErroneousTree) { - return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable),((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); + return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable), ((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList()); } else { return sourceBefore(";"); } @@ -1972,7 +1974,7 @@ private int positionOfNext(String untilDelim, @Nullable Character stop) { char c2 = source.charAt(delimIndex + 1); switch (c1) { case '/': - switch(c2) { + switch (c2) { case '/': inSingleLineComment = true; delimIndex++; @@ -1984,7 +1986,7 @@ private int positionOfNext(String untilDelim, @Nullable Character stop) { } break; case '*': - if(c2 == '/') { + if (c2 == '/') { inMultiLineComment = false; delimIndex++; continue; @@ -2051,7 +2053,7 @@ private List listFlags(long flags) { try { // FIXME instanceof probably not right here... return field.get(null) instanceof Long && - field.getName().matches("[A-Z_]+"); + field.getName().matches("[A-Z_]+"); } catch (IllegalAccessException e) { throw new RuntimeException(e); } diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/RecordPatternMatchingTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/RecordPatternMatchingTest.java new file mode 100644 index 00000000000..6af88fe84f1 --- /dev/null +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/RecordPatternMatchingTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.tree; + +import org.junit.jupiter.api.Test; +import org.openrewrite.java.MinimumJava21; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; +import org.openrewrite.test.TypeValidation; + +import static org.openrewrite.java.Assertions.java; + +@MinimumJava21 +class RecordPatternMatchingTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.typeValidationOptions(TypeValidation.all().unknown(false)); + } + + @Test + void shouldParseJava21PatternMatchForRecords() { + rewriteRun( + java( + //language=java + """ + record Point(int x, int y) {} + class Test { + void printSum(Object obj) { + if (obj instanceof Point(int x, int y)) { + System.out.println(x+y); + } + } + } + """ + )); + } + + @Test + void shouldParseJava21NestedPatternMatchForRecords() { + rewriteRun( + java( + //language=java + """ + record Point(int x, int y) {} + enum Color { RED, GREEN, BLUE } + record ColoredPoint(Point p, Color c) {} + record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {} + class Test { + void printColorOfUpperLeftPoint(Rectangle r) { + if (r instanceof Rectangle(ColoredPoint(Point p, Color c), + ColoredPoint lr)) { + System.out.println(c); + } + } + } + """ + )); + } + +} diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/SwitchPatternMatchingTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/SwitchPatternMatchingTest.java new file mode 100644 index 00000000000..30d89070966 --- /dev/null +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/SwitchPatternMatchingTest.java @@ -0,0 +1,155 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.tree; + +import org.junit.jupiter.api.Test; +import org.openrewrite.java.MinimumJava21; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +@MinimumJava21 +class SwitchPatternMatchingTest implements RewriteTest { + + @Test + void shouldParseJava21PatternSwitch() { + rewriteRun( + java( + //language=java + """ + class Test { + String formatterPatternSwitch(Object obj) { + return switch (obj) { + case Integer i -> String.format("int %d", i); + case Long l -> String.format("long %d", l); + case Double d -> String.format("double %f", d); + case String s -> String.format("String %s", s); + default -> obj.toString(); + }; + } + } + """ + )); + } + + @Test + void shouldSupportParsingNullSwitch() { + rewriteRun( + java( + //language=java + """ + class Test { + void fooBarWithNull(String s) { + switch (s) { + case null -> System.out.println("Oops"); + case "Foo", "Bar" -> System.out.println("Great"); + default -> System.out.println("Ok"); + } + } + } + """ + )); + } + + @Test + void shouldParseJava21EnumSupportInSwitch() { + rewriteRun( + java( + //language=java + """ + enum Coin { HEADS, TAILS } + + class Test { + void switchEnum(Coin c) { + switch (c) { + case HEADS -> System.out.println("Heads"); + case Coin.TAILS -> System.out.println("Tails"); + } + } + } + """ + ) + ); + } + + @Test + void shouldParseJava21ImprovedEnumSupportInSwitch() { + rewriteRun( + java( + //language=java + """ + sealed interface I permits Foo, Bar {} + public enum Foo implements I { A, B } + final class Bar implements I {} + + class Test { + void switchEnumExtendedType(I c) { + switch (c) { + case Foo.A -> System.out.println("It's Foo A"); + case Foo.B -> System.out.println("It's Foo B"); + case Bar b -> System.out.println("It's Bar"); + } + } + } + """ + )); + } + + @Test + void shouldParseJava21SwitchWithRelaxedTypeRestrictions() { + rewriteRun( + java( + //language=java + """ + record Point(int i, int j) {} + enum Color { RED, GREEN, BLUE; } + + class Test { + void typeTester(Object obj) { + switch (obj) { + case null -> System.out.println("null"); + case String s -> System.out.println("String"); + case Color c -> System.out.println("Color: " + c.toString()); + case Point p -> System.out.println("Record class: " + p.toString()); + case int[] ia -> System.out.println("Array of ints of length" + ia.length); + default -> System.out.println("Something else"); + } + } + } + """ + )); + } + + @Test + void shouldParseJava21SwitchWithSpecialCases() { + rewriteRun( + java( + //language=java + """ + class Test { + void integerTester(Integer i) { + switch (i) { + case -1, 1 -> System.out.println("special"); + case Integer j when (j - 1) > -1 -> System.out.println("pos"); + case Integer j -> System.out.println("others"); + } + } + } + """ + )); + } + +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java b/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java index 1524c72188e..4d2196083ca 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/Assertions.java @@ -74,13 +74,28 @@ public J.Erroneous visitErroneous(J.Erroneous erroneous, List list) .collect(joining("\n\n"))); } } + if (typeValidation.unknown()) { + List allUnknown = new JavaIsoVisitor>() { + @Override + public J.Unknown visitUnknown(J.Unknown unknown, List list) { + J.Unknown err = super.visitUnknown(unknown, list); + list.add(err); + return err; + } + }.reduce(source, new ArrayList<>()); + if (!allUnknown.isEmpty()) { + throw new IllegalStateException("LST contains erroneous nodes\n" + allUnknown.stream() + .map(unknown -> unknown.getSource().getText()) + .collect(joining("\n\n"))); + } + } } return source; } private static void assertValidTypes(TypeValidation typeValidation, J sf) { if (typeValidation.identifiers() || typeValidation.methodInvocations() || typeValidation.methodDeclarations() || typeValidation.classDeclarations() || - typeValidation.constructorInvocations()) { + typeValidation.constructorInvocations()) { List missingTypeResults = FindMissingTypes.findMissingTypes(sf); missingTypeResults = missingTypeResults.stream() .filter(missingType -> { @@ -108,7 +123,7 @@ private static void assertValidTypes(TypeValidation typeValidation, J sf) { .collect(joining("\n\n")); throw new IllegalStateException( "LST contains missing or invalid type information\n" + missingTypes + - "\nhttps://docs.openrewrite.org/reference/faq#im-seeing-lst-contains-missing-or-invalid-type-information-in-my-recipe-unit-tests-how-to-resolve"); + "\nhttps://docs.openrewrite.org/reference/faq#im-seeing-lst-contains-missing-or-invalid-type-information-in-my-recipe-unit-tests-how-to-resolve"); } } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java index 9743bb1abcd..38e6fc9715b 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java @@ -442,8 +442,8 @@ protected void printStatementTerminator(Statement s, PrintOutputCapture

p) { getCursor() .dropParentUntil( c -> c instanceof Switch || - c instanceof SwitchExpression || - c == Cursor.ROOT_VALUE + c instanceof SwitchExpression || + c == Cursor.ROOT_VALUE ) .getValue(); if (aSwitch instanceof SwitchExpression) { @@ -484,11 +484,15 @@ public J visitBreak(Break breakStatement, PrintOutputCapture

p) { @Override public J visitCase(Case case_, PrintOutputCapture

p) { beforeSyntax(case_, Space.Location.CASE_PREFIX, p); - Expression elem = case_.getExpressions().get(0); + J elem = case_.getCaseLabels().get(0); if (!(elem instanceof Identifier) || !((Identifier) elem).getSimpleName().equals("default")) { p.append("case"); } - visitContainer("", case_.getPadding().getExpressions(), JContainer.Location.CASE_EXPRESSION, ",", "", p); + visitContainer("", case_.getPadding().getCaseLabels(), JContainer.Location.CASE_LABEL, ",", "", p); + if (case_.getGuard() != null) { + p.append("when"); + visit(case_.getGuard(), p); + } visitSpace(case_.getPadding().getStatements().getBefore(), Space.Location.CASE, p); p.append(case_.getType() == Case.Type.Statement ? ":" : "->"); visitStatements(case_.getPadding().getStatements().getPadding() diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java index be5ca459848..8f8e05bb1bd 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaVisitor.java @@ -423,7 +423,8 @@ public J visitCase(J.Case case_, P p) { } else { c = (J.Case) temp; } - c = c.getPadding().withExpressions(visitContainer(c.getPadding().getExpressions(), JContainer.Location.CASE_EXPRESSION, p)); + c = c.getPadding().withCaseLabels(visitContainer(c.getPadding().getCaseLabels(), JContainer.Location.CASE_LABEL, p)); + c = c.withGuard(visitAndCast(c.getGuard(), p)); c = c.getPadding().withBody(visitRightPadded(c.getPadding().getBody(), JRightPadded.Location.CASE_BODY, p)); c = c.getPadding().withStatements(visitContainer(c.getPadding().getStatements(), JContainer.Location.CASE, p)); return c; @@ -1406,7 +1407,7 @@ public J visitYield(J.Yield yield, P p) { } public @Nullable JContainer visitContainer(@Nullable JContainer container, - JContainer.Location loc, P p) { + JContainer.Location loc, P p) { if (container == null) { //noinspection ConstantConditions return null; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/search/SemanticallyEqual.java b/rewrite-java/src/main/java/org/openrewrite/java/search/SemanticallyEqual.java index 6260ae2ec1a..3618a95f763 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/search/SemanticallyEqual.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/search/SemanticallyEqual.java @@ -366,7 +366,13 @@ public J.Case visitCase(J.Case _case, J j) { J.Case compareTo = (J.Case) j; this.visitList(_case.getStatements(), compareTo.getStatements()); visit(_case.getBody(), compareTo.getBody()); - this.visitList(_case.getExpressions(), compareTo.getExpressions()); + this.visitList(_case.getCaseLabels(), compareTo.getCaseLabels()); + if (_case.getGuard() != null && compareTo.getGuard() != null) { + visit(_case.getGuard(), compareTo.getGuard()); + } else if (nullMissMatch(_case.getGuard(), compareTo.getGuard())) { + isEqual.set(false); + return _case; + } } return _case; } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java index 3c6f581bb8a..592e839a3e3 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/J.java @@ -1027,14 +1027,36 @@ public Case withPattern(@Nullable Expression pattern) { return withExpressions(ListUtils.mapFirst(getExpressions(), first -> pattern)); } - JContainer expressions; - + /** + * @deprecated As of Java 21 this is referred to as case labels and can be broader than just Expressions. + * Use {@link #getCaseLabels} and {@link #withCaseLabels(List)} instead. + */ + @Deprecated public List getExpressions() { - return expressions.getElements(); + return caseLabels.getElements().stream().filter(Expression.class::isInstance).map(Expression.class::cast).collect(toList()); } + /** + * @deprecated As of Java 21 this is referred to as case labels and can be broader than just Expressions. + * Use {@link #getCaseLabels} and {@link #withCaseLabels(List)} instead. + */ public Case withExpressions(List expressions) { - return getPadding().withExpressions(requireNonNull(JContainer.withElementsNullable(this.expressions, expressions))); + if (caseLabels.getElements().stream().allMatch(Expression.class::isInstance)) { + //noinspection unchecked + return getPadding().withCaseLabels(requireNonNull(JContainer.withElementsNullable(this.caseLabels, (List) (List) expressions))); + } else { + throw new IllegalStateException("caseLabels contains an entry that is not an Expression, use withCaseLabels instead."); + } + } + + JContainer caseLabels; + + public List getCaseLabels() { + return caseLabels.getElements(); + } + + public Case withCaseLabels(List caseLabels) { + return getPadding().withCaseLabels(requireNonNull(JContainer.withElementsNullable(this.caseLabels, caseLabels))); } /** @@ -1067,17 +1089,27 @@ public Case withBody(J body) { return getPadding().withBody(JRightPadded.withElement(this.body, body)); } + @Nullable + @Getter + @With + Expression guard; + @JsonCreator - public Case(UUID id, Space prefix, Markers markers, Type type, @Deprecated @Nullable Expression pattern, JContainer expressions, JContainer statements, @Nullable JRightPadded body) { + public Case(UUID id, Space prefix, Markers markers, Type type, @Deprecated @Nullable Expression pattern, @Nullable JContainer expressions, @Nullable JContainer caseLabels, @Nullable Expression guard, JContainer statements, @Nullable JRightPadded body) { this.id = id; this.prefix = prefix; this.markers = markers; this.type = type; if (pattern != null) { - this.expressions = requireNonNull(JContainer.withElementsNullable(null, singletonList(pattern))); + this.caseLabels = requireNonNull(JContainer.withElementsNullable(null, singletonList(pattern))); + } else if (expressions != null) { + this.caseLabels = JContainer.build(expressions.getBefore(), expressions.getElements().stream().map(J.class::cast).map(JRightPadded::build).collect(toList()), expressions.getMarkers()); + } else if (caseLabels != null) { + this.caseLabels = caseLabels; } else { - this.expressions = expressions; + this.caseLabels = JContainer.empty(); } + this.guard = guard; this.statements = statements; this.body = body; } @@ -1127,7 +1159,7 @@ public static class Padding { } public Case withBody(@Nullable JRightPadded body) { - return t.body == body ? t : new Case(t.id, t.prefix, t.markers, t.type, null, t.expressions, t.statements, body); + return t.body == body ? t : new Case(t.id, t.prefix, t.markers, t.type, null, null, t.caseLabels, t.guard, t.statements, body); } public JContainer getStatements() { @@ -1135,15 +1167,38 @@ public JContainer getStatements() { } public Case withStatements(JContainer statements) { - return t.statements == statements ? t : new Case(t.id, t.prefix, t.markers, t.type, null, t.expressions, statements, t.body); + return t.statements == statements ? t : new Case(t.id, t.prefix, t.markers, t.type, null, null, t.caseLabels, t.guard, statements, t.body); } + /** + * @deprecated As of Java 21 this is referred to as case labels and can be broader than just Expressions. + * Use {@link #getCaseLabels} and {@link #withCaseLabels(JContainer)} instead. + */ + @Deprecated public JContainer getExpressions() { - return t.expressions; + return JContainer.build(t.caseLabels.getBefore(), t.caseLabels.getElements().stream().filter(Expression.class::isInstance).map(Expression.class::cast).map(JRightPadded::build).collect(toList()), t.caseLabels.getMarkers()); } + /** + * @deprecated As of Java 21 this is referred to as case labels and can be broader than just Expressions. + * Use {@link #getCaseLabels} and {@link #withCaseLabels(JContainer)} instead. + */ + @Deprecated public Case withExpressions(JContainer expressions) { - return t.expressions == expressions ? t : new Case(t.id, t.prefix, t.markers, t.type, null, expressions, t.statements, t.body); + if (t.getExpressions() == expressions) { + return t; + } else if (t.caseLabels.getElements().stream().allMatch(Expression.class::isInstance)) { + return new Case(t.id, t.prefix, t.markers, t.type, null, expressions, null, t.guard, t.statements, t.body); + } + throw new IllegalStateException("caseLabels contains an entry that is not an Expression, use withCaseLabels instead."); + } + + public JContainer getCaseLabels() { + return t.caseLabels; + } + + public Case withCaseLabels(JContainer caseLabels) { + return t.caseLabels == caseLabels ? t : new Case(t.id, t.prefix, t.markers, t.type, null, null, caseLabels, t.guard, t.statements, t.body); } } } diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JContainer.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JContainer.java index a299f98da67..c03505a05d2 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JContainer.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JContainer.java @@ -102,6 +102,7 @@ public enum Location { ANNOTATION_ARGUMENTS(Space.Location.ANNOTATION_ARGUMENTS, JRightPadded.Location.ANNOTATION_ARGUMENT), CASE(Space.Location.CASE, JRightPadded.Location.CASE), CASE_EXPRESSION(Space.Location.CASE_EXPRESSION, JRightPadded.Location.CASE_EXPRESSION), + CASE_LABEL(Space.Location.CASE_LABEL, JRightPadded.Location.CASE_LABEL), IMPLEMENTS(Space.Location.IMPLEMENTS, JRightPadded.Location.IMPLEMENTS), PERMITS(Space.Location.PERMITS, JRightPadded.Location.PERMITS), LANGUAGE_EXTENSION(Space.Location.LANGUAGE_EXTENSION, JRightPadded.Location.LANGUAGE_EXTENSION), diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JRightPadded.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JRightPadded.java index 78c65a04a14..b90a9abc19d 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JRightPadded.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JRightPadded.java @@ -47,6 +47,7 @@ public enum Location { BLOCK_STATEMENT(Space.Location.BLOCK_STATEMENT_SUFFIX), CASE(Space.Location.CASE_SUFFIX), CASE_EXPRESSION(Space.Location.CASE_EXPRESSION), + CASE_LABEL(Space.Location.CASE_LABEL), CASE_BODY(Space.Location.CASE_BODY), CATCH_ALTERNATIVE(Space.Location.CATCH_ALTERNATIVE_SUFFIX), DIMENSION(Space.Location.DIMENSION_SUFFIX), diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java index a334eafa601..a18deff4ce0 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/Space.java @@ -295,8 +295,8 @@ public String toString() { String whitespaces = printedWs.toString(); return "Space(" + - "comments=<" + (comments.size() == 1 ? "1 comment" : comments.size() + " comments") + ">, " + - "whitespace=" + (whitespaces.isEmpty() ? "" : "'" + whitespaces + "'") + ")"; + "comments=<" + (comments.size() == 1 ? "1 comment" : comments.size() + " comments") + ">, " + + "whitespace=" + (whitespaces.isEmpty() ? "" : "'" + whitespaces + "'") + ")"; } public enum Location { @@ -325,6 +325,7 @@ public enum Location { CASE, CASE_BODY, CASE_EXPRESSION, + CASE_LABEL, CASE_PREFIX, CASE_SUFFIX, CATCH_ALTERNATIVE_SUFFIX, diff --git a/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java b/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java index e395db403da..81bbc478a61 100644 --- a/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java +++ b/rewrite-test/src/main/java/org/openrewrite/test/TypeValidation.java @@ -103,6 +103,12 @@ public class TypeValidation { @Builder.Default private boolean erroneous = true; + /** + * Controls whether the LST is validated not to contain any `J.Unknown` elements. + */ + @Builder.Default + private boolean unknown = true; + /** * Adding messages to execution context is a side effect which makes the recipe run itself stateful. * Potentially allows recipes to interfere with each other in surprising and hard to debug ways. @@ -122,7 +128,7 @@ public static TypeValidation all() { * Skip all invariant validation checks. */ public static TypeValidation none() { - return new TypeValidation(false, false, false, false, false, false, false, false, o -> false, false, false); + return new TypeValidation(false, false, false, false, false, false, false, false, o -> false, false, false, false); } static TypeValidation before(RecipeSpec testMethodSpec, RecipeSpec testClassSpec) { From 1d9685808c9fbad430c9e85c5df69c2b9d12fc89 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Fri, 17 Jan 2025 14:33:25 +0100 Subject: [PATCH 159/179] Pull up recipes from rewrite-migrate-java (#4918) * Pull up recipes from rewrite-migrate-java * Also pull up `UpdateMavenProjectPropertyJavaVersion` * Apply formatter --- .../ChangeMethodInvocationReturnType.java | 116 ++++ .../java/ReplaceStringLiteralValue.java | 76 +++ .../ChangeMethodInvocationReturnTypeTest.java | 124 ++++ .../java/ReplaceStringLiteralValueTest.java | 64 ++ ...UpdateMavenProjectPropertyJavaVersion.java | 142 +++++ ...venCompilerPluginReleaseConfiguration.java | 116 ++++ ...teMavenProjectPropertyJavaVersionTest.java | 316 ++++++++++ ...ompilerPluginReleaseConfigurationTest.java | 561 ++++++++++++++++++ 8 files changed, 1515 insertions(+) create mode 100644 rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodInvocationReturnType.java create mode 100644 rewrite-java/src/main/java/org/openrewrite/java/ReplaceStringLiteralValue.java create mode 100644 rewrite-java/src/test/java/org/openrewrite/java/ChangeMethodInvocationReturnTypeTest.java create mode 100644 rewrite-java/src/test/java/org/openrewrite/java/ReplaceStringLiteralValueTest.java create mode 100644 rewrite-maven/src/main/java/org/openrewrite/maven/UpdateMavenProjectPropertyJavaVersion.java create mode 100644 rewrite-maven/src/main/java/org/openrewrite/maven/UseMavenCompilerPluginReleaseConfiguration.java create mode 100644 rewrite-maven/src/test/java/org/openrewrite/maven/UpdateMavenProjectPropertyJavaVersionTest.java create mode 100644 rewrite-maven/src/test/java/org/openrewrite/maven/UseMavenCompilerPluginReleaseConfigurationTest.java diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodInvocationReturnType.java b/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodInvocationReturnType.java new file mode 100644 index 00000000000..6cf60bfc3e8 --- /dev/null +++ b/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodInvocationReturnType.java @@ -0,0 +1,116 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.TypeUtils; +import org.openrewrite.marker.Markers; + +import static java.util.Collections.emptyList; + +@Value +@EqualsAndHashCode(callSuper = false) +public class ChangeMethodInvocationReturnType extends Recipe { + + @Option(displayName = "Method pattern", + description = "A method pattern that is used to find matching method declarations/invocations.", + example = "org.mockito.Matchers anyVararg()") + String methodPattern; + + @Option(displayName = "New method invocation return type", + description = "The fully qualified new return type of method invocation.", + example = "long") + String newReturnType; + + @Override + public String getDisplayName() { + return "Change method invocation return type"; + } + + @Override + public String getDescription() { + return "Changes the return type of a method invocation."; + } + + @Override + public TreeVisitor getVisitor() { + return new JavaIsoVisitor() { + private final MethodMatcher methodMatcher = new MethodMatcher(methodPattern, false); + + private boolean methodUpdated; + + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); + JavaType.Method type = m.getMethodType(); + if (methodMatcher.matches(method) && type != null && !newReturnType.equals(type.getReturnType().toString())) { + type = type.withReturnType(JavaType.buildType(newReturnType)); + m = m.withMethodType(type); + if (m.getName().getType() != null) { + m = m.withName(m.getName().withType(type)); + } + methodUpdated = true; + } + return m; + } + + @Override + public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) { + methodUpdated = false; + JavaType.FullyQualified originalType = multiVariable.getTypeAsFullyQualified(); + J.VariableDeclarations mv = super.visitVariableDeclarations(multiVariable, ctx); + + if (methodUpdated) { + JavaType newType = JavaType.buildType(newReturnType); + JavaType.FullyQualified newFieldType = TypeUtils.asFullyQualified(newType); + + maybeAddImport(newFieldType); + maybeRemoveImport(originalType); + + mv = mv.withTypeExpression(mv.getTypeExpression() == null ? + null : + new J.Identifier(mv.getTypeExpression().getId(), + mv.getTypeExpression().getPrefix(), + Markers.EMPTY, + emptyList(), + newReturnType.substring(newReturnType.lastIndexOf('.') + 1), + newType, + null + ) + ); + + mv = mv.withVariables(ListUtils.map(mv.getVariables(), var -> { + JavaType.FullyQualified varType = TypeUtils.asFullyQualified(var.getType()); + if (varType != null && !varType.equals(newType)) { + return var.withType(newType).withName(var.getName().withType(newType)); + } + return var; + })); + } + + return mv; + } + }; + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ReplaceStringLiteralValue.java b/rewrite-java/src/main/java/org/openrewrite/java/ReplaceStringLiteralValue.java new file mode 100644 index 00000000000..64bea17ed38 --- /dev/null +++ b/rewrite-java/src/main/java/org/openrewrite/java/ReplaceStringLiteralValue.java @@ -0,0 +1,76 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; + +@Value +@EqualsAndHashCode(callSuper = false) +public class ReplaceStringLiteralValue extends Recipe { + + @Option(displayName = "Old literal `String` value", + description = "The `String` value to replace.", + example = "apple") + String oldLiteralValue; + + @Option(displayName = "New literal `String` value", + description = "The `String` value to replace with.", + example = "orange") + String newLiteralValue; + + @JsonCreator + public ReplaceStringLiteralValue(@JsonProperty("oldStringValue") String oldStringValue, @JsonProperty("newStringValue") String newStringValue) { + this.oldLiteralValue = oldStringValue; + this.newLiteralValue = newStringValue; + } + + @Override + public String getDisplayName() { + return "Replace `String` literal"; + } + + @Override + public String getDescription() { + return "Replace the value of a complete `String` literal."; + } + + @Override + public TreeVisitor getVisitor() { + return new JavaIsoVisitor() { + @Override + public J.Literal visitLiteral(J.Literal literal, ExecutionContext ctx) { + J.Literal lit = super.visitLiteral(literal, ctx); + if (lit.getType() == JavaType.Primitive.String && + oldLiteralValue.equals(lit.getValue())) { + return lit + .withValue(newLiteralValue) + .withValueSource('"' + newLiteralValue + '"'); + } + return lit; + } + }; + } + +} diff --git a/rewrite-java/src/test/java/org/openrewrite/java/ChangeMethodInvocationReturnTypeTest.java b/rewrite-java/src/test/java/org/openrewrite/java/ChangeMethodInvocationReturnTypeTest.java new file mode 100644 index 00000000000..339e1777c28 --- /dev/null +++ b/rewrite-java/src/test/java/org/openrewrite/java/ChangeMethodInvocationReturnTypeTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class ChangeMethodInvocationReturnTypeTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new ChangeMethodInvocationReturnType("java.lang.Integer parseInt(String)", "long")); + } + + @Test + @DocumentExample + void replaceVariableAssignment() { + rewriteRun( + //language=java + java( + """ + class Foo { + void bar() { + int one = Integer.parseInt("1"); + } + } + """, + """ + class Foo { + void bar() { + long one = Integer.parseInt("1"); + } + } + """ + ) + ); + } + + @Test + void shouldOnlyChangeTargetMethodAssignments() { + rewriteRun( + //language=java + java( + """ + class Foo { + void bar() { + int zero = Integer.valueOf("0"); + int one = Integer.parseInt("1"); + int two = Integer.valueOf("2"); + } + } + """, + """ + class Foo { + void bar() { + int zero = Integer.valueOf("0"); + long one = Integer.parseInt("1"); + int two = Integer.valueOf("2"); + } + } + """ + ) + ); + } + + @Test + void replaceVariableAssignmentFullyQualified() { + rewriteRun( + spec -> spec.recipe(new ChangeMethodInvocationReturnType("bar.Bar bar()", "java.math.BigInteger")) + .parser(JavaParser.fromJavaVersion() + //language=java + .dependsOn( + """ + package bar; + public class Bar { + public static Integer bar() { + return null; + } + } + """ + ) + ), + //language=java + java( + """ + import bar.Bar; + class Foo { + void foo() { + Integer one = Bar.bar(); + } + } + """, + """ + import bar.Bar; + + import java.math.BigInteger; + + class Foo { + void foo() { + BigInteger one = Bar.bar(); + } + } + """ + ) + ); + } +} diff --git a/rewrite-java/src/test/java/org/openrewrite/java/ReplaceStringLiteralValueTest.java b/rewrite-java/src/test/java/org/openrewrite/java/ReplaceStringLiteralValueTest.java new file mode 100644 index 00000000000..e40fd0f9f93 --- /dev/null +++ b/rewrite-java/src/test/java/org/openrewrite/java/ReplaceStringLiteralValueTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class ReplaceStringLiteralValueTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new ReplaceStringLiteralValue("apple", "orange")); + } + + @DocumentExample + @Test + void replaceAppleWithOrange() { + rewriteRun( + java( + """ + class Test { + String s = "apple"; + } + """, + """ + class Test { + String s = "orange"; + } + """ + ) + ); + } + @Test + void doNotReplacePineapply() { + rewriteRun( + java( + """ + class Test { + // We only match the full String literal value + String s = "pineapple"; + } + """ + ) + ); + } + +} diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/UpdateMavenProjectPropertyJavaVersion.java b/rewrite-maven/src/main/java/org/openrewrite/maven/UpdateMavenProjectPropertyJavaVersion.java new file mode 100644 index 00000000000..405ffbb4645 --- /dev/null +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/UpdateMavenProjectPropertyJavaVersion.java @@ -0,0 +1,142 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.maven; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.xml.XPathMatcher; +import org.openrewrite.xml.tree.Xml; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Value +@EqualsAndHashCode(callSuper = false) +public class UpdateMavenProjectPropertyJavaVersion extends Recipe { + + private static final List JAVA_VERSION_PROPERTIES = Arrays.asList( + "java.version", + "jdk.version", + "javaVersion", + "jdkVersion", + "maven.compiler.source", + "maven.compiler.target", + "maven.compiler.release", + "release.version"); + + private static final List JAVA_VERSION_XPATH_MATCHERS = + JAVA_VERSION_PROPERTIES.stream() + .map(property -> "/project/properties/" + property) + .map(XPathMatcher::new).collect(Collectors.toList()); + + private static final XPathMatcher PLUGINS_MATCHER = new XPathMatcher("/project/build//plugins"); + + @Option(displayName = "Java version", + description = "The Java version to upgrade to.", + example = "11") + Integer version; + + @Override + public String getDisplayName() { + return "Update Maven Java project properties"; + } + + @Override + public String getDescription() { + //language=markdown + return "The Java version is determined by several project properties, including:\n\n" + + " * `java.version`\n" + + " * `jdk.version`\n" + + " * `javaVersion`\n" + + " * `jdkVersion`\n" + + " * `maven.compiler.source`\n" + + " * `maven.compiler.target`\n" + + " * `maven.compiler.release`\n" + + " * `release.version`\n\n" + + "If none of these properties are in use and the maven compiler plugin is not otherwise configured, adds the `maven.compiler.release` property."; + } + + @Override + public TreeVisitor getVisitor() { + return new MavenIsoVisitor() { + boolean compilerPluginConfiguredExplicitly; + + @Override + public Xml.Document visitDocument(Xml.Document document, ExecutionContext ctx) { + // Update properties already defined in the current pom + Xml.Document d = super.visitDocument(document, ctx); + + // Return early if the parent appears to be within the current repository, as properties defined there will be updated + if (getResolutionResult().parentPomIsProjectPom()) { + return d; + } + + // Otherwise override remote parent's properties locally + Map currentProperties = getResolutionResult().getPom().getProperties(); + boolean foundProperty = false; + for (String property : JAVA_VERSION_PROPERTIES) { + String propertyValue = currentProperties.get(property); + if (propertyValue != null) { + foundProperty = true; + try { + if (Float.parseFloat(propertyValue) < version) { + d = (Xml.Document) new AddProperty(property, String.valueOf(version), null, false) + .getVisitor() + .visitNonNull(d, ctx); + maybeUpdateModel(); + } + } catch (NumberFormatException ex) { + // either an expression or something else, don't touch + } + } + } + + // When none of the relevant properties are explicitly configured Maven defaults to Java 8 + // The release option was added in 9 + // If no properties have yet been updated then set release explicitly + if (!foundProperty && version >= 9 && !compilerPluginConfiguredExplicitly) { + d = (Xml.Document) new AddProperty("maven.compiler.release", String.valueOf(version), null, false) + .getVisitor() + .visitNonNull(d, ctx); + maybeUpdateModel(); + } + + return d; + } + + @Override + public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { + Xml.Tag t = super.visitTag(tag, ctx); + if (isPluginTag("org.apache.maven.plugins", "maven-compiler-plugin")) { + t.getChild("configuration").ifPresent(compilerPluginConfig -> { + if (compilerPluginConfig.getChildValue("source").isPresent() || + compilerPluginConfig.getChildValue("target").isPresent() || + compilerPluginConfig.getChildValue("release").isPresent()) { + compilerPluginConfiguredExplicitly = true; + } + }); + } + return t; + } + }; + } +} diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/UseMavenCompilerPluginReleaseConfiguration.java b/rewrite-maven/src/main/java/org/openrewrite/maven/UseMavenCompilerPluginReleaseConfiguration.java new file mode 100644 index 00000000000..c126accf448 --- /dev/null +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/UseMavenCompilerPluginReleaseConfiguration.java @@ -0,0 +1,116 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.maven; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.maven.tree.MavenResolutionResult; +import org.openrewrite.xml.XPathMatcher; +import org.openrewrite.xml.tree.Xml; + +import java.util.Optional; + +import static org.openrewrite.xml.AddOrUpdateChild.addOrUpdateChild; +import static org.openrewrite.xml.FilterTagChildrenVisitor.filterTagChildren; + +@Value +@EqualsAndHashCode(callSuper = false) +public class UseMavenCompilerPluginReleaseConfiguration extends Recipe { + private static final XPathMatcher PLUGINS_MATCHER = new XPathMatcher("/project/build//plugins"); + + @Option( + displayName = "Release version", + description = "The new value for the release configuration. This recipe prefers ${java.version} if defined.", + example = "11" + ) + Integer releaseVersion; + + @Override + public String getDisplayName() { + return "Use Maven compiler plugin release configuration"; + } + + @Override + public String getDescription() { + return "Replaces any explicit `source` or `target` configuration (if present) on the `maven-compiler-plugin` with " + + "`release`, and updates the `release` value if needed. Will not downgrade the Java version if the current version is higher."; + } + + @Override + public TreeVisitor getVisitor() { + return new MavenIsoVisitor() { + @Override + public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) { + Xml.Tag t = super.visitTag(tag, ctx); + if (!PLUGINS_MATCHER.matches(getCursor())) { + return t; + } + Optional maybeCompilerPlugin = t.getChildren().stream() + .filter(plugin -> + "plugin".equals(plugin.getName()) && + "org.apache.maven.plugins".equals(plugin.getChildValue("groupId").orElse("org.apache.maven.plugins")) && + "maven-compiler-plugin".equals(plugin.getChildValue("artifactId").orElse(null))) + .findAny(); + Optional maybeCompilerPluginConfig = maybeCompilerPlugin + .flatMap(it -> it.getChild("configuration")); + if (!maybeCompilerPluginConfig.isPresent()) { + return t; + } + Xml.Tag compilerPluginConfig = maybeCompilerPluginConfig.get(); + Optional source = compilerPluginConfig.getChildValue("source"); + Optional target = compilerPluginConfig.getChildValue("target"); + Optional release = compilerPluginConfig.getChildValue("release"); + if (!source.isPresent() && + !target.isPresent() && + !release.isPresent() || + currentNewerThanProposed(release)) { + return t; + } + Xml.Tag updated = filterTagChildren(t, compilerPluginConfig, + child -> !("source".equals(child.getName()) || "target".equals(child.getName()))); + String releaseVersionValue = hasJavaVersionProperty(getCursor().firstEnclosingOrThrow(Xml.Document.class)) ? + "${java.version}" : releaseVersion.toString(); + updated = addOrUpdateChild(updated, compilerPluginConfig, + Xml.Tag.build("" + releaseVersionValue + ""), getCursor().getParentOrThrow()); + return updated; + } + + }; + } + + private boolean currentNewerThanProposed(@SuppressWarnings("OptionalUsedAsFieldOrParameterType") Optional maybeRelease) { + if (!maybeRelease.isPresent()) { + return false; + } + try { + float currentVersion = Float.parseFloat(maybeRelease.get()); + float proposedVersion = Float.parseFloat(releaseVersion.toString()); + return proposedVersion < currentVersion; + } catch (NumberFormatException e) { + return false; + } + } + + private boolean hasJavaVersionProperty(Xml.Document xml) { + return xml.getMarkers().findFirst(MavenResolutionResult.class) + .map(r -> r.getPom().getProperties().get("java.version") != null) + .orElse(false); + } +} diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/UpdateMavenProjectPropertyJavaVersionTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/UpdateMavenProjectPropertyJavaVersionTest.java new file mode 100644 index 00000000000..6fc6a2fca0b --- /dev/null +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/UpdateMavenProjectPropertyJavaVersionTest.java @@ -0,0 +1,316 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.maven; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.Issue; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.mavenProject; +import static org.openrewrite.maven.Assertions.pomXml; + +@Deprecated(forRemoval = true) +class UpdateMavenProjectPropertyJavaVersionTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new UpdateMavenProjectPropertyJavaVersion(17)); + } + + @DocumentExample + @Test + void basic() { + rewriteRun( + //language=xml + pomXml( + """ + + com.example + foo + 1.0.0 + 4.0 + + 11 + 11 + 11 + 11 + 11 + 11 + 11 + 11 + + + """, + """ + + com.example + foo + 1.0.0 + 4.0 + + 17 + 17 + 17 + 17 + 17 + 17 + 17 + 17 + + + """ + ) + ); + } + + @Test + void basicWithVariables() { + rewriteRun( + //language=xml + pomXml( + """ + + com.example + foo + 1.0.0 + 4.0 + + ${release.version} + 11 + ${release.version} + ${jdk.version} + ${maven.compiler.release} + ${maven.compiler.release} + 11 + 11 + + + """, + """ + + com.example + foo + 1.0.0 + 4.0 + + ${release.version} + 17 + ${release.version} + ${jdk.version} + ${maven.compiler.release} + ${maven.compiler.release} + 17 + 17 + + + """) + ); + } + + @Test + void updateLocalParent() { + rewriteRun( + //language=xml + pomXml( + """ + + com.example + example-parent + 1.0.0 + 4.0 + + 11 + 11 + 11 + 11 + 11 + 11 + 11 + 11 + + + """, + """ + + com.example + example-parent + 1.0.0 + 4.0 + + 17 + 17 + 17 + 17 + 17 + 17 + 17 + 17 + + + """), + mavenProject("example-child", + //language=xml + pomXml( + """ + + + com.example + example-parent + 1.0.0 + + com.example + example-child + 1.0.0 + 4.0 + + """ + ) + ) + ); + } + + @Test + void doNothingForExplicitPluginConfiguration() { + // Use UseMavenCompilerPluginReleaseConfiguration for this case + rewriteRun( + //language=xml + pomXml( + """ + + com.example + example-child + 1.0.0 + 4.0 + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 11 + 11 + 11 + + + + + + """ + ) + ); + } + + @Test + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/514") + void addReleaseIfNoOtherChangeIsMade() { + rewriteRun( + //language=xml + pomXml( + """ + + com.example + example-child + 1.0.0 + 4.0 + + """, + """ + + com.example + example-child + 1.0.0 + 4.0 + + 17 + + + """ + ) + ); + } + + @Test + void springBoot3ParentToJava17() { + // Spring Boot Starter Parent already enforces Java 17 + rewriteRun( + pomXml( + //language=xml + """ + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.3 + + + + com.mycompany.app + my-app + 1 + + """ + ) + ); + } + + @Test + void springBoot3ParentToJava21() { + rewriteRun( + spec -> spec.recipe(new UpdateMavenProjectPropertyJavaVersion(21)), + pomXml( + //language=xml + """ + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.3 + + + + com.mycompany.app + my-app + 1 + + """, + //language=xml + """ + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.3 + + + + com.mycompany.app + my-app + 1 + + 21 + + + """ + ) + ); + } +} diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/UseMavenCompilerPluginReleaseConfigurationTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/UseMavenCompilerPluginReleaseConfigurationTest.java new file mode 100644 index 00000000000..ce23a97daa5 --- /dev/null +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/UseMavenCompilerPluginReleaseConfigurationTest.java @@ -0,0 +1,561 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.maven; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.Issue; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.mavenProject; +import static org.openrewrite.maven.Assertions.pomXml; + +class UseMavenCompilerPluginReleaseConfigurationTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new UseMavenCompilerPluginReleaseConfiguration(11)); + } + + @DocumentExample + @Test + void replacesSourceAndTargetConfig() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 1.8 + 1.8 + + + + + + + """, + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 11 + + + + + + + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/514") + @Test + void replaceSourceAndTargetConfigIfDefault() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + true + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + """, + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + true + 11 + + + + + + + """ + ) + ); + } + + @Test + void reusesJavaVersionVariableIfAvailable() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + 11 + + + + + + maven-compiler-plugin + 3.8.0 + + ${java.version} + ${java.version} + + + + + + + """, + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + 11 + + + + + + maven-compiler-plugin + 3.8.0 + + ${java.version} + + + + + + + """ + ) + ); + } + + @Test + void upgradesExistingReleaseConfig() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 10 + + + + + + + """, + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 11 + + + + + + + """ + ) + ); + } + + @Test + void prefersJavaVersionIfAvailable() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + 11 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 10 + + + + + + + """, + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + 11 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + ${java.version} + + + + + + + """ + ) + ); + } + + @Test + void notMisledByUnrelatedProperty() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + 11 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 10 + ${foobar} + + + + + + + """, + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + 11 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 11 + ${foobar} + + + + + + + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/169") + @Test + void noVersionDowngrade() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + org.sample + sample + 1.0.0 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + 17 + + + + + + + """) + ); + } + + @Test + void reusesJavaVersionVariableIfDefinedInParentPom() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + org.sample + parent + 1.0.0 + + + 11 + + + pom + + """), + mavenProject( + "sample", + //language=xml + pomXml(""" + + + 4.0.0 + + + org.sample + parent + 1.0.0 + + + sample + 1.0.0 + + + + + maven-compiler-plugin + 3.8.0 + + ${java.version} + ${java.version} + + + + + + """, + """ + + + 4.0.0 + + + org.sample + parent + 1.0.0 + + + sample + 1.0.0 + + + + + maven-compiler-plugin + 3.8.0 + + ${java.version} + + + + + + """ + ) + ) + ); + } + + @Test + void pluginManagement() { + rewriteRun( + //language=xml + pomXml( + """ + + + 4.0.0 + org.sample + parent + 1.0.0 + + + + + maven-compiler-plugin + 3.8.0 + + 8 + + + + + + + """, + """ + + + 4.0.0 + org.sample + parent + 1.0.0 + + + + + maven-compiler-plugin + 3.8.0 + + 11 + + + + + + + """ + ) + ); + } +} From afa160e7e7dd6a066a4b84d04764bdc7bcef1a0a Mon Sep 17 00:00:00 2001 From: Greg Oledzki Date: Fri, 17 Jan 2025 17:10:55 +0100 Subject: [PATCH 160/179] Autodetect formatting style of JSON code (#4916) * feat: recipe for adding a key value pair to a json * Slight polish * Slight polish * Strive for better formatting after insertion * Improve some existing cases already * Update test as suggested * Refactoring, extract normalizeNewLines() * Autoformat visitor for JSON * Removing @NotNull annotations * Basic tests for Autodetect * Basic tests for NormalizeLineBreaksVisitor * No public classifier Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Copy&paste typo Co-authored-by: Knut Wannheden * Copy&paste typo Co-authored-by: Knut Wannheden * Rename FindLineFormatJsonVisitor * Adding package-info.java files * Parsing the value parameter to JSON * Fixed description * Removing unneeded unQuote method --------- Co-authored-by: dpozinen Co-authored-by: Tim te Beek Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Knut Wannheden --- .../org/openrewrite/json/AddKeyValue.java | 135 ++++++++++ .../org/openrewrite/json/JsonVisitor.java | 30 +++ .../json/format/AutoFormatVisitor.java | 93 +++++++ .../org/openrewrite/json/format/Indents.java | 57 +++++ .../format/NormalizeLineBreaksVisitor.java | 60 +++++ .../json/format/TabsAndIndentsVisitor.java | 89 +++++++ .../openrewrite/json/format/package-info.java | 21 ++ .../openrewrite/json/style/Autodetect.java | 237 ++++++++++++++++++ .../org/openrewrite/json/style/JsonStyle.java | 21 ++ .../json/style/TabsAndIndentsStyle.java | 55 ++++ .../openrewrite/json/style/package-info.java | 21 ++ .../json/tree/JsonRightPadded.java | 22 +- .../org/openrewrite/json/AddKeyValueTest.java | 170 +++++++++++++ .../NormalizeLineBreaksVisitorTest.java | 92 +++++++ .../json/style/AutodetectTest.java | 102 ++++++++ 15 files changed, 1199 insertions(+), 6 deletions(-) create mode 100644 rewrite-json/src/main/java/org/openrewrite/json/AddKeyValue.java create mode 100644 rewrite-json/src/main/java/org/openrewrite/json/format/AutoFormatVisitor.java create mode 100644 rewrite-json/src/main/java/org/openrewrite/json/format/Indents.java create mode 100644 rewrite-json/src/main/java/org/openrewrite/json/format/NormalizeLineBreaksVisitor.java create mode 100755 rewrite-json/src/main/java/org/openrewrite/json/format/TabsAndIndentsVisitor.java create mode 100644 rewrite-json/src/main/java/org/openrewrite/json/format/package-info.java create mode 100644 rewrite-json/src/main/java/org/openrewrite/json/style/Autodetect.java create mode 100644 rewrite-json/src/main/java/org/openrewrite/json/style/JsonStyle.java create mode 100644 rewrite-json/src/main/java/org/openrewrite/json/style/TabsAndIndentsStyle.java create mode 100644 rewrite-json/src/main/java/org/openrewrite/json/style/package-info.java create mode 100644 rewrite-json/src/test/java/org/openrewrite/json/AddKeyValueTest.java create mode 100644 rewrite-json/src/test/java/org/openrewrite/json/format/NormalizeLineBreaksVisitorTest.java create mode 100644 rewrite-json/src/test/java/org/openrewrite/json/style/AutodetectTest.java diff --git a/rewrite-json/src/main/java/org/openrewrite/json/AddKeyValue.java b/rewrite-json/src/main/java/org/openrewrite/json/AddKeyValue.java new file mode 100644 index 00000000000..4fc66417797 --- /dev/null +++ b/rewrite-json/src/main/java/org/openrewrite/json/AddKeyValue.java @@ -0,0 +1,135 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.json; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.intellij.lang.annotations.Language; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.json.tree.*; +import org.openrewrite.marker.Markers; + +import java.util.Collections; +import java.util.List; + +import static java.util.Collections.emptyList; +import static org.openrewrite.Tree.randomId; + +@Value +@EqualsAndHashCode(callSuper = false) +public class AddKeyValue extends Recipe { + + @Option(displayName = "Key path", + description = "A JsonPath expression to locate the *parent* JSON entry.", + example = "'$.subjects.*' or '$.' or '$.x[1].y.*' etc.") + String keyPath; + + @Option(displayName = "Key", + description = "The key to create.", + example = "myKey") + String key; + + @Option(displayName = "Value", + description = "The value to add to the document at the specified key. Can be of any type representing JSON value." + + " String values should be quoted to be inserted as Strings.", + example = "`\"myValue\"` or `{\"a\": 1}` or `[ 123 ]`") + @Language("Json") + String value; + + @Option(displayName = "Prepend", + required = false, + description = "If set to `true` the value will be added to the beginning of the object") + boolean prepend; + + @Override + public String getDisplayName() { + return "Add value to JSON Object"; + } + + @Override + public String getDescription() { + return "Adds a `value` at the specified `keyPath` with the specified `key`, if the key doesn't already exist."; + } + + + @Override + public TreeVisitor getVisitor() { + return new JsonIsoVisitor() { + private final JsonPathMatcher pathMatcher = new JsonPathMatcher(keyPath); + + @Override + public Json.JsonObject visitObject(Json.JsonObject obj, ExecutionContext ctx) { + obj = super.visitObject(obj, ctx); + + if (pathMatcher.matches(getCursor()) && objectDoesNotContainKey(obj, key)) { + List originalMembers = obj.getMembers(); + boolean jsonIsEmpty = originalMembers.isEmpty() || originalMembers.get(0) instanceof Json.Empty; + Space space = jsonIsEmpty || prepend ? originalMembers.get(0).getPrefix() : Space.build("\n", emptyList()); + + Json newMember = new Json.Member(randomId(), space, Markers.EMPTY, rightPaddedKey(), parsedValue()); + + if (jsonIsEmpty) { + return autoFormat(obj.withMembers(Collections.singletonList(newMember)), ctx, getCursor().getParent()); + } + + List newMembers = prepend ? + ListUtils.concat(newMember, originalMembers) : + ListUtils.concat(originalMembers, newMember); + return autoFormat(obj.withMembers(newMembers), ctx, getCursor().getParent()); + } + return obj; + } + + private JsonValue parsedValue() { + Json.Document parsedDoc = (Json.Document) JsonParser.builder().build() + .parse(value.trim()).findFirst().get(); + JsonValue value = parsedDoc.getValue(); + return value.withPrefix(value.getPrefix().withWhitespace(" ")); + } + + private JsonRightPadded rightPaddedKey() { + return new JsonRightPadded<>( + new Json.Literal(randomId(), Space.EMPTY, Markers.EMPTY, "\"" + key + "\"", key), + Space.EMPTY, Markers.EMPTY + ); + } + + private boolean objectDoesNotContainKey(Json.JsonObject obj, String key) { + for (Json member : obj.getMembers()) { + if (member instanceof Json.Member) { + if (keyMatches(((Json.Member) member).getKey(), key)) { + return false; + } + } + } + return true; + } + + private boolean keyMatches(JsonKey jsonKey, String key) { + if (jsonKey instanceof Json.Literal) { + return key.equals(((Json.Literal) jsonKey).getValue()); + } else if (jsonKey instanceof Json.Identifier) { + return key.equals(((Json.Identifier) jsonKey).getName()); + } + return false; + } + }; + } +} diff --git a/rewrite-json/src/main/java/org/openrewrite/json/JsonVisitor.java b/rewrite-json/src/main/java/org/openrewrite/json/JsonVisitor.java index ad1980f5b8b..2389969407e 100755 --- a/rewrite-json/src/main/java/org/openrewrite/json/JsonVisitor.java +++ b/rewrite-json/src/main/java/org/openrewrite/json/JsonVisitor.java @@ -20,6 +20,7 @@ import org.openrewrite.SourceFile; import org.openrewrite.TreeVisitor; import org.openrewrite.internal.ListUtils; +import org.openrewrite.json.format.AutoFormatVisitor; import org.openrewrite.json.tree.Json; import org.openrewrite.json.tree.JsonRightPadded; import org.openrewrite.json.tree.JsonValue; @@ -37,6 +38,35 @@ public String getLanguage() { return "json"; } + public Y2 maybeAutoFormat(Y2 before, Y2 after, P p) { + return maybeAutoFormat(before, after, p, getCursor()); + } + + public Y2 maybeAutoFormat(Y2 before, Y2 after, P p, Cursor cursor) { + return maybeAutoFormat(before, after, null, p, cursor); + } + + @SuppressWarnings({"unchecked", "ConstantConditions"}) + public Y2 maybeAutoFormat(Y2 before, Y2 after, @Nullable Json stopAfter, P p, Cursor cursor) { + if (before != after) { + return (Y2) new AutoFormatVisitor<>(stopAfter).visit(after, p, cursor); + } + return after; + } + + public Y2 autoFormat(Y2 y, P p) { + return autoFormat(y, p, getCursor()); + } + + public Y2 autoFormat(Y2 y, P p, Cursor cursor) { + return autoFormat(y, null, p, cursor); + } + + @SuppressWarnings({"ConstantConditions", "unchecked"}) + public Y2 autoFormat(Y2 y, @Nullable Json stopAfter, P p, Cursor cursor) { + return (Y2) new AutoFormatVisitor<>(stopAfter).visit(y, p, cursor); + } + public Json visitArray(Json.Array array, P p) { Json.Array a = array; a = a.withPrefix(visitSpace(a.getPrefix(), p)); diff --git a/rewrite-json/src/main/java/org/openrewrite/json/format/AutoFormatVisitor.java b/rewrite-json/src/main/java/org/openrewrite/json/format/AutoFormatVisitor.java new file mode 100644 index 00000000000..f161c95c20e --- /dev/null +++ b/rewrite-json/src/main/java/org/openrewrite/json/format/AutoFormatVisitor.java @@ -0,0 +1,93 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.json.format; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.Cursor; +import org.openrewrite.Tree; +import org.openrewrite.json.JsonIsoVisitor; +import org.openrewrite.json.style.Autodetect; +import org.openrewrite.json.style.TabsAndIndentsStyle; +import org.openrewrite.json.tree.Json; +import org.openrewrite.style.GeneralFormatStyle; +import org.openrewrite.style.NamedStyles; + +import java.util.Optional; + +import static java.util.Collections.singletonList; + +public class AutoFormatVisitor

extends JsonIsoVisitor

{ + @Nullable + private final Tree stopAfter; + + public AutoFormatVisitor(@Nullable Tree stopAfter) { + this.stopAfter = stopAfter; + } + + @Override + public Json preVisit(Json tree, P p) { + stopAfterPreVisit(); + Json.Document doc = getCursor().firstEnclosingOrThrow(Json.Document.class); + Cursor cursor = getCursor().getParentOrThrow(); + Autodetect autodetectedStyle = Autodetect.detector().sample(doc).build(); + Json js = tree; + + TabsAndIndentsStyle taiStyle = Optional.ofNullable(doc.getStyle(TabsAndIndentsStyle.class)) + .orElseGet(() -> NamedStyles.merge(TabsAndIndentsStyle.class, singletonList(autodetectedStyle))); + assert(taiStyle != null); + js = new TabsAndIndentsVisitor<>(taiStyle, stopAfter).visitNonNull(js, p, cursor.fork()); + + GeneralFormatStyle gfStyle = Optional.ofNullable(doc.getStyle(GeneralFormatStyle.class)) + .orElseGet(() -> NamedStyles.merge(GeneralFormatStyle.class, singletonList(autodetectedStyle))); + assert(gfStyle != null); + js = new NormalizeLineBreaksVisitor<>(gfStyle, stopAfter).visitNonNull(js, p, cursor.fork()); + + return js; + } + + @Override + public Json.Document visitDocument(Json.Document js, P p) { + Autodetect autodetectedStyle = Autodetect.detector().sample(js).build(); + + TabsAndIndentsStyle taiStyle = Optional.ofNullable(js.getStyle(TabsAndIndentsStyle.class)) + .orElseGet(() -> NamedStyles.merge(TabsAndIndentsStyle.class, singletonList(autodetectedStyle))); + assert(taiStyle != null); + js = (Json.Document) new TabsAndIndentsVisitor<>(taiStyle, stopAfter).visitNonNull(js, p); + + GeneralFormatStyle gfStyle = Optional.ofNullable(js.getStyle(GeneralFormatStyle.class)) + .orElseGet(() -> NamedStyles.merge(GeneralFormatStyle.class, singletonList(autodetectedStyle))); + assert(gfStyle != null); + js = (Json.Document) new NormalizeLineBreaksVisitor<>(gfStyle, stopAfter).visitNonNull(js, p); + + return js; + } + + @Override + public @Nullable Json postVisit(Json tree, P p) { + if (stopAfter != null && stopAfter.isScope(tree)) { + getCursor().putMessageOnFirstEnclosing(Json.Document.class, "stop", true); + } + return super.postVisit(tree, p); + } + + @Override + public @Nullable Json visit(@Nullable Tree tree, P p) { + if (getCursor().getNearestMessage("stop") != null) { + return (Json) tree; + } + return super.visit(tree, p); + } +} diff --git a/rewrite-json/src/main/java/org/openrewrite/json/format/Indents.java b/rewrite-json/src/main/java/org/openrewrite/json/format/Indents.java new file mode 100644 index 00000000000..d636ea9e07d --- /dev/null +++ b/rewrite-json/src/main/java/org/openrewrite/json/format/Indents.java @@ -0,0 +1,57 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.json.format; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.json.JsonIsoVisitor; +import org.openrewrite.json.style.Autodetect; +import org.openrewrite.json.style.TabsAndIndentsStyle; +import org.openrewrite.json.tree.Json; +import org.openrewrite.style.NamedStyles; + +import static java.util.Collections.singletonList; + +public class Indents extends Recipe { + @Override + public String getDisplayName() { + return "JSON indent"; + } + + @Override + public String getDescription() { + return "Format tabs and indents in JSON."; + } + + @Override + public TreeVisitor getVisitor() { + return new TabsAndIndentsFromCompilationUnitStyle(); + } + + private static class TabsAndIndentsFromCompilationUnitStyle extends JsonIsoVisitor { + @Override + public Json. Document visitDocument(Json.Document docs, ExecutionContext ctx) { + TabsAndIndentsStyle style = docs.getStyle(TabsAndIndentsStyle.class); + if (style == null) { + style = NamedStyles.merge(TabsAndIndentsStyle.class, singletonList(Autodetect.detector().sample(docs).build())); + assert(style != null); + } + doAfterVisit(new TabsAndIndentsVisitor<>(style, null)); + return docs; + } + } +} diff --git a/rewrite-json/src/main/java/org/openrewrite/json/format/NormalizeLineBreaksVisitor.java b/rewrite-json/src/main/java/org/openrewrite/json/format/NormalizeLineBreaksVisitor.java new file mode 100644 index 00000000000..34f19d6829f --- /dev/null +++ b/rewrite-json/src/main/java/org/openrewrite/json/format/NormalizeLineBreaksVisitor.java @@ -0,0 +1,60 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.json.format; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.Tree; +import org.openrewrite.style.GeneralFormatStyle; +import org.openrewrite.json.JsonIsoVisitor; +import org.openrewrite.json.tree.Json; + +import static org.openrewrite.format.LineBreaks.normalizeNewLines; + +public class NormalizeLineBreaksVisitor

extends JsonIsoVisitor

{ + private final GeneralFormatStyle generalFormatStyle; + + @Nullable + private final Tree stopAfter; + + public NormalizeLineBreaksVisitor(GeneralFormatStyle generalFormatStyle, @Nullable Tree stopAfter) { + this.generalFormatStyle = generalFormatStyle; + this.stopAfter = stopAfter; + } + + @Override + public @Nullable Json postVisit(Json tree, P p) { + if (stopAfter != null && stopAfter.isScope(tree)) { + getCursor().putMessageOnFirstEnclosing(Json.Document.class, "stop", true); + } + return super.postVisit(tree, p); + } + + @Override + public @Nullable Json visit(@Nullable Tree tree, P p) { + if (getCursor().getNearestMessage("stop") != null) { + return (Json) tree; + } + + Json y = super.visit(tree, p); + if (y != null) { + String modifiedWs = normalizeNewLines(y.getPrefix().getWhitespace(), generalFormatStyle.isUseCRLFNewLines()); + if (!y.getPrefix().getWhitespace().equals(modifiedWs)) { + y = y.withPrefix(y.getPrefix().withWhitespace(modifiedWs)); + } + } + return y; + } +} diff --git a/rewrite-json/src/main/java/org/openrewrite/json/format/TabsAndIndentsVisitor.java b/rewrite-json/src/main/java/org/openrewrite/json/format/TabsAndIndentsVisitor.java new file mode 100755 index 00000000000..bd17823efaa --- /dev/null +++ b/rewrite-json/src/main/java/org/openrewrite/json/format/TabsAndIndentsVisitor.java @@ -0,0 +1,89 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.json.format; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.Cursor; +import org.openrewrite.Tree; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.json.JsonIsoVisitor; +import org.openrewrite.json.style.TabsAndIndentsStyle; +import org.openrewrite.json.tree.Json; + +import java.util.Iterator; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TabsAndIndentsVisitor

extends JsonIsoVisitor

{ + + private final TabsAndIndentsStyle style; + + @Nullable + private final Tree stopAfter; + + public TabsAndIndentsVisitor(TabsAndIndentsStyle style, @Nullable Tree stopAfter) { + this.style = style; + this.stopAfter = stopAfter; + } + + @Override + public Json preVisit(Json tree, P p) { + Json json = super.preVisit(tree, p); + if (json != null) { + final String ws = json.getPrefix().getWhitespace(); + if (ws.contains("\n")) { + int indentMultiple = (int) getCursor().getPathAsStream().filter(Json.JsonObject.class::isInstance).count(); + String shiftedPrefix = createIndent(ws, indentMultiple); + if (!shiftedPrefix.equals(ws)) { + return json.withPrefix(json.getPrefix().withWhitespace(shiftedPrefix)); + } + } + } + return json; + } + + @Override + public @Nullable Json postVisit(Json tree, P p) { + if (stopAfter != null && stopAfter.isScope(tree)) { + getCursor().putMessageOnFirstEnclosing(Json.Document.class, "stop", true); + } + return super.postVisit(tree, p); + } + + @Override + public @Nullable Json visit(@Nullable Tree tree, P p) { + if (getCursor().getNearestMessage("stop") != null) { + return (Json) tree; + } + return super.visit(tree, p); + } + + private String createIndent(String ws, int indentMultiple) { + StringBuilder shiftedPrefixBuilder = new StringBuilder(ws.substring(0, ws.lastIndexOf('\n') + 1)); + for (int i = 0; i < indentMultiple; i++) { + if (style.getUseTabCharacter()) { + shiftedPrefixBuilder.append("\t"); + } else { + for (int j = 0; j < style.getIndentSize(); j++) { + shiftedPrefixBuilder.append(" "); + } + } + } + + return shiftedPrefixBuilder.toString(); + } +} diff --git a/rewrite-json/src/main/java/org/openrewrite/json/format/package-info.java b/rewrite-json/src/main/java/org/openrewrite/json/format/package-info.java new file mode 100644 index 00000000000..cfab9d193b9 --- /dev/null +++ b/rewrite-json/src/main/java/org/openrewrite/json/format/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2020 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +@NonNullFields +package org.openrewrite.json.format; + +import org.jspecify.annotations.NullMarked; +import org.openrewrite.internal.lang.NonNullFields; diff --git a/rewrite-json/src/main/java/org/openrewrite/json/style/Autodetect.java b/rewrite-json/src/main/java/org/openrewrite/json/style/Autodetect.java new file mode 100644 index 00000000000..c07657d42e6 --- /dev/null +++ b/rewrite-json/src/main/java/org/openrewrite/json/style/Autodetect.java @@ -0,0 +1,237 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.json.style; + +import com.fasterxml.jackson.annotation.JsonCreator; +import org.jspecify.annotations.Nullable; +import org.openrewrite.SourceFile; +import org.openrewrite.Tree; +import org.openrewrite.json.JsonVisitor; +import org.openrewrite.style.GeneralFormatStyle; +import org.openrewrite.style.NamedStyles; +import org.openrewrite.style.Style; +import org.openrewrite.json.tree.Json; + +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +import static java.util.Collections.emptySet; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.counting; + +public class Autodetect extends NamedStyles { + @JsonCreator + public Autodetect(UUID id, Collection