From 8cb80366467d2bf318205866601fd454a10146ec Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Wed, 27 Apr 2022 17:18:10 -0400 Subject: [PATCH] Fix all source file line endings (#1726) --- .gitattributes | 54 + CONTRIBUTORS.md | 56 +- build-src/build.gradle.kts | 118 +- .../kotlin/org.openrewrite.base.gradle.kts | 60 +- ...rg.openrewrite.dependency-check.gradle.kts | 48 +- .../org.openrewrite.java-base.gradle.kts | 132 +- .../org.openrewrite.java-library.gradle.kts | 58 +- .../kotlin/org.openrewrite.license.gradle.kts | 42 +- .../org.openrewrite.maven-publish.gradle.kts | 64 +- .../org.openrewrite.root-project.gradle.kts | 44 +- .../kotlin/org.openrewrite.shadow.gradle.kts | 30 +- gradlew.bat | 178 +- lombok.config | 12 +- rewrite-bom/build.gradle.kts | 40 +- .../main/java/org/openrewrite/Incubating.java | 58 +- .../src/main/java/org/openrewrite/Parser.java | 372 ++-- .../org/openrewrite/config/RecipeExample.java | 64 +- .../internal/NameCaseConvention.java | 432 ++-- .../internal/PropertyPlaceholderHelper.java | 310 +-- .../org/openrewrite/internal/StreamUtils.java | 70 +- .../org/openrewrite/internal/StringUtils.java | 1116 +++++----- .../org/openrewrite/semver/CaretRange.java | 200 +- .../org/openrewrite/semver/ExactVersion.java | 102 +- .../org/openrewrite/semver/HyphenRange.java | 106 +- .../org/openrewrite/semver/LatestPatch.java | 96 +- .../org/openrewrite/semver/LatestRelease.java | 272 +-- .../java/org/openrewrite/semver/Semver.java | 154 +- .../org/openrewrite/semver/TildeRange.java | 158 +- .../openrewrite/semver/VersionComparator.java | 120 +- .../java/org/openrewrite/semver/XRange.java | 204 +- .../java/org/openrewrite/style/Style.java | 86 +- .../org/openrewrite/style/package-info.java | 38 +- .../java/org/openrewrite/text/ChangeText.java | 134 +- .../java/org/openrewrite/text/PlainText.java | 154 +- .../java/org/openrewrite/text/TextStyle.java | 60 +- .../internal/NameCaseConventionTest.kt | 270 +-- .../openrewrite/internal/StringUtilsTest.kt | 552 ++--- .../org/openrewrite/semver/CaretRangeTest.kt | 208 +- .../org/openrewrite/semver/HyphenRangeTest.kt | 142 +- .../org/openrewrite/semver/LatestPatchTest.kt | 78 +- .../openrewrite/semver/LatestReleaseTest.kt | 234 +- .../org/openrewrite/semver/SemverTest.kt | 70 +- .../org/openrewrite/semver/TildeRangeTest.kt | 164 +- .../org/openrewrite/semver/XRangeTest.kt | 186 +- rewrite-gradle/src/main/resources/gradlew.bat | 210 +- .../java/org/openrewrite/hcl/HclStyle.java | 42 +- .../hcl/style/TabsAndIndentsStyle.java | 80 +- .../java/Java11ParserInputFileObject.java | 240 +-- .../org/openrewrite/java/Java8Parser.java | 298 +-- .../java/Java8ParserInputFileObject.java | 242 +-- .../java/ReloadableJava8Parser.java | 840 ++++---- .../kotlin/org/openrewrite/java/Java8Test.kt | 40 +- .../java/Java8TreeCompatibilityTest.kt | 40 +- .../openrewrite/java/Java8TreeDebugTest.kt | 432 ++-- .../java/Java8VisitorCompatibilityTest.kt | 40 +- .../java/ChangeMethodAccessLevel.java | 178 +- .../java/ChangeMethodAccessLevelVisitor.java | 258 +-- .../openrewrite/java/ImplementInterface.java | 128 +- .../java/org/openrewrite/java/JavaParser.java | 522 ++--- .../java/org/openrewrite/java/JavaStyle.java | 42 +- .../java/RemoveAnnotationVisitor.java | 274 +-- .../org/openrewrite/java/UseStaticImport.java | 180 +- .../java/cleanup/CatchClauseOnlyRethrows.java | 230 +- .../cleanup/ExplicitLambdaArgumentTypes.java | 292 +-- .../openrewrite/java/cleanup/FinalClass.java | 102 +- .../java/cleanup/FinalClassVisitor.java | 142 +- .../java/cleanup/MethodParamPad.java | 226 +- .../java/cleanup/OperatorWrap.java | 838 ++++---- .../cleanup/PadEmptyForLoopComponents.java | 214 +- .../java/cleanup/TypecastParenPad.java | 150 +- .../openrewrite/java/marker/package-info.java | 38 +- .../openrewrite/java/style/Checkstyle.java | 298 +-- .../java/style/CheckstyleConfigLoader.java | 1290 +++++------ .../style/EmptyForInitializerPadStyle.java | 74 +- .../java/style/EmptyForIteratorPadStyle.java | 74 +- .../HideUtilityClassConstructorStyle.java | 70 +- .../java/style/ImportLayoutStyle.java | 1894 ++++++++--------- .../java/style/MethodParamPadStyle.java | 120 +- .../java/style/TabsAndIndentsStyle.java | 80 +- .../META-INF/rewrite/google-java-format.yml | 54 +- .../java/style/CheckstyleConfigLoaderTest.kt | 682 +++--- .../org/openrewrite/json/ChangeKeyTest.kt | 202 +- rewrite-maven/build.gradle.kts | 200 +- .../maven/ParentModelResolver.java | 382 ++-- .../ChangeDependencyGroupIdAndArtifactId.java | 206 +- .../maven/ChangeDependencyScope.java | 186 +- ...ManagedDependencyGroupIdAndArtifactId.java | 208 +- .../maven/ChangePropertyValue.java | 194 +- .../maven/MavenTagInsertionComparator.java | 224 +- .../maven/UpgradeParentVersion.java | 194 +- .../internal/MavenDownloadingException.java | 68 +- .../maven/internal/MavenParsingException.java | 68 +- .../utilities/PrintMavenAsCycloneDxBom.java | 448 ++-- .../org/openrewrite/maven/AddPluginTest.kt | 510 ++--- ...hangeDependencyGroupIdAndArtifactIdTest.kt | 586 ++--- .../maven/ChangeDependencyScopeTest.kt | 340 +-- ...nagedDependencyGroupIdAndArtifactIdTest.kt | 132 +- .../maven/ChangePropertyValueTest.kt | 342 +-- .../openrewrite/maven/RemoveDependencyTest.kt | 460 ++-- .../openrewrite/maven/RemoveExclusionTest.kt | 214 +- .../maven/RemoveManagedDependencyTest.kt | 398 ++-- .../org/openrewrite/maven/RemovePluginTest.kt | 612 +++--- .../maven/UpgradeParentVersionTest.kt | 342 +-- .../utilities/PrintMavenAsCycloneDxBomTest.kt | 190 +- rewrite-maven/src/test/resources/logback.xml | 60 +- rewrite-properties/build.gradle.kts | 28 +- .../properties/ChangePropertyKey.java | 182 +- .../properties/ChangePropertyValue.java | 198 +- .../properties/PropertiesParser.java | 486 ++--- .../properties/tree/Properties.java | 298 +-- .../properties/ChangePropertyKeyTest.kt | 286 +-- rewrite-test/build.gradle.kts | 98 +- .../main/java/org/openrewrite/DebugOnly.java | 66 +- .../src/main/java/org/openrewrite/Issue.java | 60 +- .../openrewrite/java/JavaParserResolver.java | 148 +- .../openrewrite/groovy/GroovyRecipeTest.kt | 156 +- .../org/openrewrite/hcl/HclRecipeTest.kt | 160 +- .../java/ChangeMethodAccessLevelTest.kt | 720 +++---- .../java/ImplementInterfaceTest.kt | 152 +- .../java/JavaTreeCompatibilityKit.kt | 354 +-- .../openrewrite/java/MethodParamPadTest.kt | 606 +++--- .../openrewrite/java/NoStaticImportTest.kt | 88 +- .../org/openrewrite/java/OrderImportsTest.kt | 1142 +++++----- .../java/PadEmptyForLoopComponentsTest.kt | 348 +-- .../org/openrewrite/java/TypeValidator.kt | 200 +- .../openrewrite/java/UseStaticImportTest.kt | 382 ++-- .../cleanup/CatchClauseOnlyRethrowsTest.kt | 392 ++-- .../java/cleanup/FinalClassTest.kt | 230 +- .../java/internal/TypesInUseTest.kt | 122 +- .../org/openrewrite/java/tree/PackageTest.kt | 62 +- .../org/openrewrite/json/JsonRecipeTest.kt | 160 +- .../org/openrewrite/maven/MavenRecipeTest.kt | 204 +- .../properties/PropertiesRecipeTest.kt | 160 +- .../openrewrite/protobuf/ProtoRecipeTest.kt | 160 +- .../org/openrewrite/xml/XmlRecipeTest.kt | 160 +- .../org/openrewrite/yaml/YamlRecipeTest.kt | 160 +- .../text/KotlinDataClassChangeText.kt | 78 +- .../test/resources/META-INF/rewrite/other.yml | 50 +- .../resources/META-INF/rewrite/rewrite.yml | 108 +- .../org/openrewrite/xml/XPathMatcher.java | 192 +- .../openrewrite/xml/marker/package-info.java | 38 +- .../org/openrewrite/xml/style/XmlStyle.java | 42 +- rewrite-yaml/build.gradle.kts | 58 +- .../openrewrite/yaml/ChangePropertyKey.java | 482 ++--- .../openrewrite/yaml/CoalesceProperties.java | 78 +- .../yaml/FormatPreservingReader.java | 182 +- .../java/org/openrewrite/yaml/YamlParser.java | 984 ++++----- .../yaml/internal/YamlPrinter.java | 310 +-- .../java/org/openrewrite/yaml/tree/Yaml.java | 934 ++++---- .../org/openrewrite/yaml/ChangeKeyTest.kt | 284 +-- .../openrewrite/yaml/ChangePropertyKeyTest.kt | 540 ++--- .../org/openrewrite/yaml/ChangeValueTest.kt | 292 +-- .../yaml/CoalescePropertiesTest.kt | 456 ++-- .../org/openrewrite/yaml/DeleteKeyTest.kt | 412 ++-- .../yaml/FormatPreservingReaderTest.kt | 120 +- settings.gradle.kts | 132 +- 156 files changed, 19330 insertions(+), 19276 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..d21dc057c39 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,54 @@ +* text eol=lf + +# +# The above will handle all files NOT found below +# https://help.github.com/articles/dealing-with-line-endings/ +# https://github.com/Danimoth/gitattributes + +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + +# These files are text and should be normalized (Convert crlf => lf) +*.bash text eol=lf +*.css text diff=css +*.htm text diff=html +*.html text diff=html +*.java text diff=java +*.sh text eol=lf + + +# These files are binary and should be left untouched +# (binary is a macro for -text -diff) +*.a binary +*.lib binary +*.icns binary +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.mov binary +*.mp4 binary +*.mp3 binary +*.flv binary +*.fla binary +*.swf binary +*.gz binary +*.zip binary +*.jar binary +*.tar binary +*.tar.gz binary +*.7z binary +*.ttf binary +*.pyc binary +*.gpg binary +*.bin binary +*.exe binary +*.dll binary +*.so binary +*.dylib binary +*.class binary +*.jar binary +*.war binary +*.ear binary +*.rar binary diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 4382caa96e1..85b031cb803 100755 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,28 +1,28 @@ -# Building & Developing OpenRewrite - -We use [Gradle](https://gradle.org/) to build this project. -The gradle wrapper checked into this project defines the gradle version to use. -When building from the command line invoke the wrapper with `./gradlew build` on unix-style terminals and `gradlew build` on windows-style terminals. - -NOTE: windows-style users should ensure that they configure `core.autocrlf = false` as Rewrite requires unix-style line endings. This can be done at clone time by using `git clone -c core.autocrlf=false https://github.com/openrewrite/rewrite.git`. - -### CLI Environment Configuration: - -* [JDK](https://adoptopenjdk.net/) version: 11 - * JDK language & bytecode level: 1.8 -* [Gradle](https://gradle.org/) version: Defined in wrapper -* [Kotlin](https://kotlinlang.org/) version: 1.5 - * Kotlin language level: 1.5 - * Kotlin JVM bytecode level: 1.8 - -### IDE Configuration - -We use [IntelliJ IDEA](https://www.jetbrains.com/idea/) to develop this project. -Other IDEs or versions of this IDE can be made to work. -These are one set of versions we know works: - -* IDEA version: 2021.1.3 - -You must set the `-parameters` compiler flag to run Rewrite tests. -If your system does not have UTF-8 as its default character encoding (e.g., Windows) you must also add `-encoding utf8`. -Add these to the "additional command line parameters" field in IntelliJ -> Preferences -> Build, Execution, Deployment -> Compiler -> Java Compiler. +# Building & Developing OpenRewrite + +We use [Gradle](https://gradle.org/) to build this project. +The gradle wrapper checked into this project defines the gradle version to use. +When building from the command line invoke the wrapper with `./gradlew build` on unix-style terminals and `gradlew build` on windows-style terminals. + +NOTE: windows-style users should ensure that they configure `core.autocrlf = false` as Rewrite requires unix-style line endings. This can be done at clone time by using `git clone -c core.autocrlf=false https://github.com/openrewrite/rewrite.git`. + +### CLI Environment Configuration: + +* [JDK](https://adoptopenjdk.net/) version: 11 + * JDK language & bytecode level: 1.8 +* [Gradle](https://gradle.org/) version: Defined in wrapper +* [Kotlin](https://kotlinlang.org/) version: 1.5 + * Kotlin language level: 1.5 + * Kotlin JVM bytecode level: 1.8 + +### IDE Configuration + +We use [IntelliJ IDEA](https://www.jetbrains.com/idea/) to develop this project. +Other IDEs or versions of this IDE can be made to work. +These are one set of versions we know works: + +* IDEA version: 2021.1.3 + +You must set the `-parameters` compiler flag to run Rewrite tests. +If your system does not have UTF-8 as its default character encoding (e.g., Windows) you must also add `-encoding utf8`. +Add these to the "additional command line parameters" field in IntelliJ -> Preferences -> Build, Execution, Deployment -> Compiler -> Java Compiler. diff --git a/build-src/build.gradle.kts b/build-src/build.gradle.kts index 24300bebead..817f4f6289d 100644 --- a/build-src/build.gradle.kts +++ b/build-src/build.gradle.kts @@ -1,59 +1,59 @@ -plugins { - `kotlin-dsl` -} - -repositories { - gradlePluginPortal() -} - -dependencies { - implementation("org.gradle:test-retry-gradle-plugin:1.2.1") - implementation("com.gradle.enterprise:test-distribution-gradle-plugin:2.3") - implementation("com.gradle:gradle-enterprise-gradle-plugin:3.10") - implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21") - implementation("org.owasp:dependency-check-gradle:7.0.4.1") - implementation("gradle.plugin.com.hierynomus.gradle.plugins:license-gradle-plugin:0.16.1") - implementation("com.github.jk1:gradle-license-report:2.0") - implementation("com.netflix.nebula:gradle-contacts-plugin:6.0.0") - implementation("com.netflix.nebula:gradle-info-plugin:11.3.3") - implementation("com.netflix.nebula:nebula-release-plugin:16.0.0") - implementation("com.netflix.nebula:nebula-publishing-plugin:18.4.0") - implementation("com.netflix.nebula:nebula-project-plugin:9.6.3") - implementation("io.github.gradle-nexus:publish-plugin:1.0.0") - implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.2") - implementation("org.openrewrite:plugin:latest.release") -} - -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(11)) - } -} - -kotlin { - jvmToolchain { - this as JavaToolchainSpec - languageVersion.set(JavaLanguageVersion.of("11")) - } -} - -tasks.withType().configureEach { - kotlinOptions { - jvmTarget = "11" - } -} - -tasks.named("test").configure { - maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1 - useJUnitPlatform() - jvmArgs = listOf( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+ShowHiddenFrames" - ) - testLogging { - showExceptions = true - exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL - showCauses = true - showStackTraces = true - } -} +plugins { + `kotlin-dsl` +} + +repositories { + gradlePluginPortal() +} + +dependencies { + implementation("org.gradle:test-retry-gradle-plugin:1.2.1") + implementation("com.gradle.enterprise:test-distribution-gradle-plugin:2.3") + implementation("com.gradle:gradle-enterprise-gradle-plugin:3.10") + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21") + implementation("org.owasp:dependency-check-gradle:7.0.4.1") + implementation("gradle.plugin.com.hierynomus.gradle.plugins:license-gradle-plugin:0.16.1") + implementation("com.github.jk1:gradle-license-report:2.0") + implementation("com.netflix.nebula:gradle-contacts-plugin:6.0.0") + implementation("com.netflix.nebula:gradle-info-plugin:11.3.3") + implementation("com.netflix.nebula:nebula-release-plugin:16.0.0") + implementation("com.netflix.nebula:nebula-publishing-plugin:18.4.0") + implementation("com.netflix.nebula:nebula-project-plugin:9.6.3") + implementation("io.github.gradle-nexus:publish-plugin:1.0.0") + implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.2") + implementation("org.openrewrite:plugin:latest.release") +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } +} + +kotlin { + jvmToolchain { + this as JavaToolchainSpec + languageVersion.set(JavaLanguageVersion.of("11")) + } +} + +tasks.withType().configureEach { + kotlinOptions { + jvmTarget = "11" + } +} + +tasks.named("test").configure { + maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1 + useJUnitPlatform() + jvmArgs = listOf( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+ShowHiddenFrames" + ) + testLogging { + showExceptions = true + exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL + showCauses = true + showStackTraces = true + } +} diff --git a/build-src/src/main/kotlin/org.openrewrite.base.gradle.kts b/build-src/src/main/kotlin/org.openrewrite.base.gradle.kts index c65c000ebf2..0ed67678645 100644 --- a/build-src/src/main/kotlin/org.openrewrite.base.gradle.kts +++ b/build-src/src/main/kotlin/org.openrewrite.base.gradle.kts @@ -1,30 +1,30 @@ -import nebula.plugin.contacts.Contact -import nebula.plugin.contacts.ContactsExtension - -plugins { - base - id("org.openrewrite.license") - id("org.openrewrite.dependency-check") - id("nebula.contacts") - id("nebula.info") -} - -group = "org.openrewrite" -description = "Eliminate tech-debt. Automatically." - -repositories { - if (!project.hasProperty("releasing")) { - mavenLocal() - maven { - url = uri("https://oss.sonatype.org/content/repositories/snapshots/") - } - } - mavenCentral() -} - -configure { - val j = Contact("team@moderne.io") - j.moniker("Moderne") - - people["team@moderne.io"] = j -} +import nebula.plugin.contacts.Contact +import nebula.plugin.contacts.ContactsExtension + +plugins { + base + id("org.openrewrite.license") + id("org.openrewrite.dependency-check") + id("nebula.contacts") + id("nebula.info") +} + +group = "org.openrewrite" +description = "Eliminate tech-debt. Automatically." + +repositories { + if (!project.hasProperty("releasing")) { + mavenLocal() + maven { + url = uri("https://oss.sonatype.org/content/repositories/snapshots/") + } + } + mavenCentral() +} + +configure { + val j = Contact("team@moderne.io") + j.moniker("Moderne") + + people["team@moderne.io"] = j +} diff --git a/build-src/src/main/kotlin/org.openrewrite.dependency-check.gradle.kts b/build-src/src/main/kotlin/org.openrewrite.dependency-check.gradle.kts index 90aa0ce9bd5..dc24cf88292 100644 --- a/build-src/src/main/kotlin/org.openrewrite.dependency-check.gradle.kts +++ b/build-src/src/main/kotlin/org.openrewrite.dependency-check.gradle.kts @@ -1,24 +1,24 @@ -plugins { - id("org.owasp.dependencycheck") -} - -configure { - analyzers.assemblyEnabled = false - failBuildOnCVSS = 9.0F - scanProjects = listOf("rewrite-core", - "rewrite-gradle", - "rewrite-groovy", - "rewrite-hcl", - "rewrite-java", - "rewrite-java-8", - "rewrite-java-11", - "rewrite-json", - "rewrite-maven", - "rewrite-properties", - "rewrite-protobuf", - "rewrite-xml", - "rewrite-yaml", - "rewrite-test", - "rewrite-bom", - "rewrite-benchmarks") -} +plugins { + id("org.owasp.dependencycheck") +} + +configure { + analyzers.assemblyEnabled = false + failBuildOnCVSS = 9.0F + scanProjects = listOf("rewrite-core", + "rewrite-gradle", + "rewrite-groovy", + "rewrite-hcl", + "rewrite-java", + "rewrite-java-8", + "rewrite-java-11", + "rewrite-json", + "rewrite-maven", + "rewrite-properties", + "rewrite-protobuf", + "rewrite-xml", + "rewrite-yaml", + "rewrite-test", + "rewrite-bom", + "rewrite-benchmarks") +} diff --git a/build-src/src/main/kotlin/org.openrewrite.java-base.gradle.kts b/build-src/src/main/kotlin/org.openrewrite.java-base.gradle.kts index a9712559476..2ce9e6fd05c 100644 --- a/build-src/src/main/kotlin/org.openrewrite.java-base.gradle.kts +++ b/build-src/src/main/kotlin/org.openrewrite.java-base.gradle.kts @@ -1,66 +1,66 @@ -import org.gradle.api.tasks.compile.JavaCompile -import org.gradle.api.tasks.testing.Test -import org.gradle.jvm.toolchain.JavaLanguageVersion -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - `java-base` - kotlin("jvm") - id("org.openrewrite.base") - id("org.gradle.test-retry") -} - -java { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - toolchain { - languageVersion.set(JavaLanguageVersion.of(11)) - } -} - -configurations.all { - exclude("com.google.errorprone", "*") - resolutionStrategy.cacheDynamicVersionsFor(0, "seconds") -} - -if(name != "rewrite-test") { - listOf("compileClasspath", "runtimeClasspath") - .map(configurations::named) - .forEach { it -> - it.configure { - exclude("org.jetbrains.kotlin") - } - } -} - -tasks.withType().configureEach { - kotlinOptions { - jvmTarget = "1.8" - } -} - -tasks.withType().configureEach { - options.encoding = "UTF-8" - options.compilerArgs.add("-parameters") - options.isFork = true - options.release.set(8) - sourceCompatibility = "1.8" - targetCompatibility = "1.8" -} - -tasks.named("test").configure { - maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1 - useJUnitPlatform { - excludeTags("debug") - } - jvmArgs = listOf( - "-XX:+UnlockDiagnosticVMOptions", - "-XX:+ShowHiddenFrames" - ) - testLogging { - showExceptions = true - exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL - showCauses = true - showStackTraces = true - } -} +import org.gradle.api.tasks.compile.JavaCompile +import org.gradle.api.tasks.testing.Test +import org.gradle.jvm.toolchain.JavaLanguageVersion +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + `java-base` + kotlin("jvm") + id("org.openrewrite.base") + id("org.gradle.test-retry") +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + toolchain { + languageVersion.set(JavaLanguageVersion.of(11)) + } +} + +configurations.all { + exclude("com.google.errorprone", "*") + resolutionStrategy.cacheDynamicVersionsFor(0, "seconds") +} + +if(name != "rewrite-test") { + listOf("compileClasspath", "runtimeClasspath") + .map(configurations::named) + .forEach { it -> + it.configure { + exclude("org.jetbrains.kotlin") + } + } +} + +tasks.withType().configureEach { + kotlinOptions { + jvmTarget = "1.8" + } +} + +tasks.withType().configureEach { + options.encoding = "UTF-8" + options.compilerArgs.add("-parameters") + options.isFork = true + options.release.set(8) + sourceCompatibility = "1.8" + targetCompatibility = "1.8" +} + +tasks.named("test").configure { + maxParallelForks = (Runtime.getRuntime().availableProcessors() / 2).takeIf { it > 0 } ?: 1 + useJUnitPlatform { + excludeTags("debug") + } + jvmArgs = listOf( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+ShowHiddenFrames" + ) + testLogging { + showExceptions = true + exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL + showCauses = true + showStackTraces = true + } +} diff --git a/build-src/src/main/kotlin/org.openrewrite.java-library.gradle.kts b/build-src/src/main/kotlin/org.openrewrite.java-library.gradle.kts index a52c8672384..485884a0716 100644 --- a/build-src/src/main/kotlin/org.openrewrite.java-library.gradle.kts +++ b/build-src/src/main/kotlin/org.openrewrite.java-library.gradle.kts @@ -1,29 +1,29 @@ -plugins { - `java-library` - id("org.openrewrite.java-base") - id("nebula.javadoc-jar") - id("nebula.source-jar") -} - -dependencies { - implementation("org.jetbrains:annotations:latest.release") - compileOnly("com.google.code.findbugs:jsr305:latest.release") - - compileOnly("org.projectlombok:lombok:latest.release") - annotationProcessor("org.projectlombok:lombok:latest.release") - - testImplementation(platform("org.junit:junit-bom:latest.release")) - testImplementation("org.junit.jupiter:junit-jupiter-api") - testImplementation("org.junit.jupiter:junit-jupiter-params") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") - - testImplementation(platform("org.jetbrains.kotlin:kotlin-bom")) - testImplementation("org.jetbrains.kotlin:kotlin-reflect") - testImplementation("org.jetbrains.kotlin:kotlin-stdlib") - testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - testImplementation("org.jetbrains.kotlin:kotlin-stdlib-common") - - testImplementation("org.assertj:assertj-core:latest.release") - - testRuntimeOnly("ch.qos.logback:logback-classic:1.2.10") -} +plugins { + `java-library` + id("org.openrewrite.java-base") + id("nebula.javadoc-jar") + id("nebula.source-jar") +} + +dependencies { + implementation("org.jetbrains:annotations:latest.release") + compileOnly("com.google.code.findbugs:jsr305:latest.release") + + compileOnly("org.projectlombok:lombok:latest.release") + annotationProcessor("org.projectlombok:lombok:latest.release") + + testImplementation(platform("org.junit:junit-bom:latest.release")) + testImplementation("org.junit.jupiter:junit-jupiter-api") + testImplementation("org.junit.jupiter:junit-jupiter-params") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") + + testImplementation(platform("org.jetbrains.kotlin:kotlin-bom")) + testImplementation("org.jetbrains.kotlin:kotlin-reflect") + testImplementation("org.jetbrains.kotlin:kotlin-stdlib") + testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + testImplementation("org.jetbrains.kotlin:kotlin-stdlib-common") + + testImplementation("org.assertj:assertj-core:latest.release") + + testRuntimeOnly("ch.qos.logback:logback-classic:1.2.10") +} diff --git a/build-src/src/main/kotlin/org.openrewrite.license.gradle.kts b/build-src/src/main/kotlin/org.openrewrite.license.gradle.kts index 387d335a43f..74ae286f8d8 100644 --- a/build-src/src/main/kotlin/org.openrewrite.license.gradle.kts +++ b/build-src/src/main/kotlin/org.openrewrite.license.gradle.kts @@ -1,21 +1,21 @@ -import com.github.jk1.license.LicenseReportExtension -import nl.javadude.gradle.plugins.license.LicenseExtension -import java.util.Calendar - -plugins { - id("com.github.hierynomus.license") - id("com.github.jk1.dependency-license-report") -} - -configure { - renderers = arrayOf(com.github.jk1.license.render.CsvReportRenderer()) -} - -configure { - ext.set("year", Calendar.getInstance().get(Calendar.YEAR)) - skipExistingHeaders = true - excludePatterns.addAll(listOf("**/*.tokens", "**/*.config", "**/*.interp", "**/*.txt")) - header = project.rootProject.file("gradle/licenseHeader.txt") - mapping(mapOf("kt" to "SLASHSTAR_STYLE", "java" to "SLASHSTAR_STYLE")) - strictCheck = true -} +import com.github.jk1.license.LicenseReportExtension +import nl.javadude.gradle.plugins.license.LicenseExtension +import java.util.Calendar + +plugins { + id("com.github.hierynomus.license") + id("com.github.jk1.dependency-license-report") +} + +configure { + renderers = arrayOf(com.github.jk1.license.render.CsvReportRenderer()) +} + +configure { + ext.set("year", Calendar.getInstance().get(Calendar.YEAR)) + skipExistingHeaders = true + excludePatterns.addAll(listOf("**/*.tokens", "**/*.config", "**/*.interp", "**/*.txt")) + header = project.rootProject.file("gradle/licenseHeader.txt") + mapping(mapOf("kt" to "SLASHSTAR_STYLE", "java" to "SLASHSTAR_STYLE")) + strictCheck = true +} diff --git a/build-src/src/main/kotlin/org.openrewrite.maven-publish.gradle.kts b/build-src/src/main/kotlin/org.openrewrite.maven-publish.gradle.kts index c1eabaeeb91..1eec751632f 100644 --- a/build-src/src/main/kotlin/org.openrewrite.maven-publish.gradle.kts +++ b/build-src/src/main/kotlin/org.openrewrite.maven-publish.gradle.kts @@ -1,32 +1,32 @@ -import org.gradle.api.tasks.javadoc.Javadoc - -plugins { - `java-base` - signing - id("org.openrewrite.base") - id("nebula.maven-publish") - id("nebula.maven-resolved-dependencies") - id("nebula.maven-apache-license") -} - -plugins.withId("com.github.johnrengelman.shadow") { - apply(plugin = "nebula.maven-shadow-publish") -} - -tasks.withType().configureEach { - options.encoding = "UTF-8" -} - -tasks.withType().configureEach { - enabled = false -} - -signing { - setRequired({ - !project.version.toString().endsWith("SNAPSHOT") || project.hasProperty("forceSigning") - }) - val signingKey: String? by project - val signingPassword: String? by project - useInMemoryPgpKeys(signingKey, signingPassword) - sign(publishing.publications["nebula"]) -} +import org.gradle.api.tasks.javadoc.Javadoc + +plugins { + `java-base` + signing + id("org.openrewrite.base") + id("nebula.maven-publish") + id("nebula.maven-resolved-dependencies") + id("nebula.maven-apache-license") +} + +plugins.withId("com.github.johnrengelman.shadow") { + apply(plugin = "nebula.maven-shadow-publish") +} + +tasks.withType().configureEach { + options.encoding = "UTF-8" +} + +tasks.withType().configureEach { + enabled = false +} + +signing { + setRequired({ + !project.version.toString().endsWith("SNAPSHOT") || project.hasProperty("forceSigning") + }) + val signingKey: String? by project + val signingPassword: String? by project + useInMemoryPgpKeys(signingKey, signingPassword) + sign(publishing.publications["nebula"]) +} diff --git a/build-src/src/main/kotlin/org.openrewrite.root-project.gradle.kts b/build-src/src/main/kotlin/org.openrewrite.root-project.gradle.kts index 1bc558a5830..ce3e69ff9e1 100644 --- a/build-src/src/main/kotlin/org.openrewrite.root-project.gradle.kts +++ b/build-src/src/main/kotlin/org.openrewrite.root-project.gradle.kts @@ -1,22 +1,22 @@ -plugins { - id("org.openrewrite.base") - id("org.openrewrite.rewrite") - id("nebula.release") - id("io.github.gradle-nexus.publish-plugin") -} - -nexusPublishing { - repositories { - sonatype() - } -} - -configure { - defaultVersionStrategy = nebula.plugin.release.NetflixOssStrategies.SNAPSHOT(project) -} - -configure { - activeRecipes = listOf("org.openrewrite.java.format.AutoFormat") -} - -defaultTasks("build") +plugins { + id("org.openrewrite.base") + id("org.openrewrite.rewrite") + id("nebula.release") + id("io.github.gradle-nexus.publish-plugin") +} + +nexusPublishing { + repositories { + sonatype() + } +} + +configure { + defaultVersionStrategy = nebula.plugin.release.NetflixOssStrategies.SNAPSHOT(project) +} + +configure { + activeRecipes = listOf("org.openrewrite.java.format.AutoFormat") +} + +defaultTasks("build") diff --git a/build-src/src/main/kotlin/org.openrewrite.shadow.gradle.kts b/build-src/src/main/kotlin/org.openrewrite.shadow.gradle.kts index 2566db928eb..0e5e211484f 100644 --- a/build-src/src/main/kotlin/org.openrewrite.shadow.gradle.kts +++ b/build-src/src/main/kotlin/org.openrewrite.shadow.gradle.kts @@ -1,15 +1,15 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - -plugins { - id("org.openrewrite.java-library") - id("com.github.johnrengelman.shadow") -} - -tasks.named("jar") { - enabled = false -} - -tasks.withType() { - configurations = listOf(project.configurations.compileClasspath.get()) - archiveClassifier.set(null as String?) -} +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + id("org.openrewrite.java-library") + id("com.github.johnrengelman.shadow") +} + +tasks.named("jar") { + enabled = false +} + +tasks.withType() { + configurations = listOf(project.configurations.compileClasspath.get()) + archiveClassifier.set(null as String?) +} diff --git a/gradlew.bat b/gradlew.bat index ac1b06f9382..107acd32c4e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,89 +1,89 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lombok.config b/lombok.config index 80b7c559937..fe3b18ad591 100755 --- a/lombok.config +++ b/lombok.config @@ -1,6 +1,6 @@ -# https://projectlombok.org/features/configuration -config.stopBubbling = true -lombok.copyableAnnotations += org.intellij.lang.annotations.Language -lombok.addNullAnnotations = CUSTOM:org.openrewrite.internal.lang.NonNull:org.openrewrite.internal.lang.Nullable -lombok.copyableAnnotations += org.openrewrite.internal.lang.Nullable -lombok.copyableAnnotations += org.openrewrite.internal.lang.NonNull +# https://projectlombok.org/features/configuration +config.stopBubbling = true +lombok.copyableAnnotations += org.intellij.lang.annotations.Language +lombok.addNullAnnotations = CUSTOM:org.openrewrite.internal.lang.NonNull:org.openrewrite.internal.lang.Nullable +lombok.copyableAnnotations += org.openrewrite.internal.lang.Nullable +lombok.copyableAnnotations += org.openrewrite.internal.lang.NonNull diff --git a/rewrite-bom/build.gradle.kts b/rewrite-bom/build.gradle.kts index 2d2641a3f13..002cd35fb89 100644 --- a/rewrite-bom/build.gradle.kts +++ b/rewrite-bom/build.gradle.kts @@ -1,20 +1,20 @@ -plugins { - `java-platform` - id("org.openrewrite.maven-publish") -} - -dependencies { - constraints { - rootProject.subprojects.filter { it != project && !it.name.contains("benchmark") }.sortedBy { it.name }.forEach { - api(it) - } - } -} - -publishing { - publications { - named("nebula", MavenPublication::class.java) { - from(components["javaPlatform"]) - } - } -} +plugins { + `java-platform` + id("org.openrewrite.maven-publish") +} + +dependencies { + constraints { + rootProject.subprojects.filter { it != project && !it.name.contains("benchmark") }.sortedBy { it.name }.forEach { + api(it) + } + } +} + +publishing { + publications { + named("nebula", MavenPublication::class.java) { + from(components["javaPlatform"]) + } + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/Incubating.java b/rewrite-core/src/main/java/org/openrewrite/Incubating.java index 99d9523359e..ca63edd7727 100644 --- a/rewrite-core/src/main/java/org/openrewrite/Incubating.java +++ b/rewrite-core/src/main/java/org/openrewrite/Incubating.java @@ -1,29 +1,29 @@ -/* - * 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; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Target; - -/** - * This is a feature that is experimental and may yield a breaking change in a minor release. - */ -@Documented -@Target({ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD}) -public @interface Incubating { - String since(); -} +/* + * 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; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * This is a feature that is experimental and may yield a breaking change in a minor release. + */ +@Documented +@Target({ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD}) +public @interface Incubating { + String since(); +} diff --git a/rewrite-core/src/main/java/org/openrewrite/Parser.java b/rewrite-core/src/main/java/org/openrewrite/Parser.java index 7c789a5c19c..f510405f4e6 100644 --- a/rewrite-core/src/main/java/org/openrewrite/Parser.java +++ b/rewrite-core/src/main/java/org/openrewrite/Parser.java @@ -1,186 +1,186 @@ -/* - * 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; - -import org.openrewrite.internal.EncodingDetectingInputStream; -import org.openrewrite.internal.StringUtils; -import org.openrewrite.internal.lang.Nullable; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.function.Supplier; -import java.util.stream.StreamSupport; - -import static java.util.stream.Collectors.toList; - -public interface Parser { - default List parse(Iterable sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { - return parseInputs(StreamSupport - .stream(sourceFiles.spliterator(), false) - .map(sourceFile -> new Input(sourceFile, () -> { - try { - return Files.newInputStream(sourceFile); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }) - ) - .collect(toList()), - relativeTo, - ctx - ); - } - - default List parse(String... sources) { - return parse(new InMemoryExecutionContext(), sources); - } - - default List parse(ExecutionContext ctx, String... sources) { - return parseInputs( - Arrays.stream(sources).map(source -> - new Input( - sourcePathFromSourceText(Paths.get(Long.toString(System.nanoTime())), source), - () -> new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)), - true - ) - ).collect(toList()), - null, - ctx - ); - } - - /** - * @param sources A collection of inputs. At the conclusion of parsing all sources' {@link Input#source} - * are closed. - * @param relativeTo A common relative path for all {@link Input#path}. - * @param ctx The execution context - * @return A list of {@link SourceFile}. - */ - List parseInputs(Iterable sources, @Nullable Path relativeTo, ExecutionContext ctx); - - boolean accept(Path path); - - default boolean accept(Input input) { - return input.isSynthetic() || accept(input.getPath()); - } - - default List acceptedInputs(Iterable input) { - return StreamSupport.stream(input.spliterator(), false) - .filter(this::accept) - .collect(toList()); - } - - default Parser reset() { - return this; - } - - /** - * A source input. {@link Input#path} may be a synthetic path and not - * represent a resolvable path on disk, as is the case when parsing sources - * from BigQuery (we have a relative path from the original Github repository - * and the sources, but don't have these sources on disk). - *

- * Nevertheless, this class is a generalization that applies well enough to - * paths that are resolvable on disk, where the file has been pre-read into - * memory. - */ - class Input { - private final boolean synthetic; - private final Path path; - private final Supplier source; - - public Input(Path path, Supplier source) { - this(path, source, false); - } - - public Input(Path path, Supplier source, boolean synthetic) { - this.path = path; - this.source = source; - this.synthetic = synthetic; - } - - public static Input fromString(String source) { - return fromString(source, StandardCharsets.UTF_8); - } - - public static Input fromString(String source, Charset charset) { - return new Input( - Paths.get(Long.toString(System.nanoTime())), - () -> new ByteArrayInputStream(source.getBytes(charset)), - true - ); - } - - public static Input fromResource(String resource) { - return new Input( - Paths.get(Long.toString(System.nanoTime())), - () -> Input.class.getResourceAsStream(resource), - true - ); - } - - public static List fromResource(String resource, String delimiter) { - return Arrays.stream(StringUtils.readFully(Input.class.getResourceAsStream(resource)).split(delimiter)) - .map(source -> new Parser.Input( - Paths.get(Long.toString(System.nanoTime())), - () -> new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)), - true - )) - .collect(toList()); - } - - public Path getPath() { - return path; - } - - public Path getRelativePath(@Nullable Path relativeTo) { - return relativeTo == null ? path : relativeTo.relativize(path); - } - - public EncodingDetectingInputStream getSource() { - return new EncodingDetectingInputStream(source.get()); - } - - public boolean isSynthetic() { - return synthetic; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Input input = (Input) o; - return Objects.equals(path, input.path); - } - - @Override - public int hashCode() { - return Objects.hash(path); - } - } - - Path sourcePathFromSourceText(Path prefix, String sourceCode); -} +/* + * 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; + +import org.openrewrite.internal.EncodingDetectingInputStream; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.internal.lang.Nullable; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; +import java.util.stream.StreamSupport; + +import static java.util.stream.Collectors.toList; + +public interface Parser { + default List parse(Iterable sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + return parseInputs(StreamSupport + .stream(sourceFiles.spliterator(), false) + .map(sourceFile -> new Input(sourceFile, () -> { + try { + return Files.newInputStream(sourceFile); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }) + ) + .collect(toList()), + relativeTo, + ctx + ); + } + + default List parse(String... sources) { + return parse(new InMemoryExecutionContext(), sources); + } + + default List parse(ExecutionContext ctx, String... sources) { + return parseInputs( + Arrays.stream(sources).map(source -> + new Input( + sourcePathFromSourceText(Paths.get(Long.toString(System.nanoTime())), source), + () -> new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)), + true + ) + ).collect(toList()), + null, + ctx + ); + } + + /** + * @param sources A collection of inputs. At the conclusion of parsing all sources' {@link Input#source} + * are closed. + * @param relativeTo A common relative path for all {@link Input#path}. + * @param ctx The execution context + * @return A list of {@link SourceFile}. + */ + List parseInputs(Iterable sources, @Nullable Path relativeTo, ExecutionContext ctx); + + boolean accept(Path path); + + default boolean accept(Input input) { + return input.isSynthetic() || accept(input.getPath()); + } + + default List acceptedInputs(Iterable input) { + return StreamSupport.stream(input.spliterator(), false) + .filter(this::accept) + .collect(toList()); + } + + default Parser reset() { + return this; + } + + /** + * A source input. {@link Input#path} may be a synthetic path and not + * represent a resolvable path on disk, as is the case when parsing sources + * from BigQuery (we have a relative path from the original Github repository + * and the sources, but don't have these sources on disk). + *

+ * Nevertheless, this class is a generalization that applies well enough to + * paths that are resolvable on disk, where the file has been pre-read into + * memory. + */ + class Input { + private final boolean synthetic; + private final Path path; + private final Supplier source; + + public Input(Path path, Supplier source) { + this(path, source, false); + } + + public Input(Path path, Supplier source, boolean synthetic) { + this.path = path; + this.source = source; + this.synthetic = synthetic; + } + + public static Input fromString(String source) { + return fromString(source, StandardCharsets.UTF_8); + } + + public static Input fromString(String source, Charset charset) { + return new Input( + Paths.get(Long.toString(System.nanoTime())), + () -> new ByteArrayInputStream(source.getBytes(charset)), + true + ); + } + + public static Input fromResource(String resource) { + return new Input( + Paths.get(Long.toString(System.nanoTime())), + () -> Input.class.getResourceAsStream(resource), + true + ); + } + + public static List fromResource(String resource, String delimiter) { + return Arrays.stream(StringUtils.readFully(Input.class.getResourceAsStream(resource)).split(delimiter)) + .map(source -> new Parser.Input( + Paths.get(Long.toString(System.nanoTime())), + () -> new ByteArrayInputStream(source.getBytes(StandardCharsets.UTF_8)), + true + )) + .collect(toList()); + } + + public Path getPath() { + return path; + } + + public Path getRelativePath(@Nullable Path relativeTo) { + return relativeTo == null ? path : relativeTo.relativize(path); + } + + public EncodingDetectingInputStream getSource() { + return new EncodingDetectingInputStream(source.get()); + } + + public boolean isSynthetic() { + return synthetic; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Input input = (Input) o; + return Objects.equals(path, input.path); + } + + @Override + public int hashCode() { + return Objects.hash(path); + } + } + + Path sourcePathFromSourceText(Path prefix, String sourceCode); +} diff --git a/rewrite-core/src/main/java/org/openrewrite/config/RecipeExample.java b/rewrite-core/src/main/java/org/openrewrite/config/RecipeExample.java index 8cce207d84a..a36434f3dec 100755 --- a/rewrite-core/src/main/java/org/openrewrite/config/RecipeExample.java +++ b/rewrite-core/src/main/java/org/openrewrite/config/RecipeExample.java @@ -1,32 +1,32 @@ -/* - * 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.config; - -import lombok.Value; -import org.openrewrite.internal.lang.Nullable; - -@Value -public class RecipeExample { - @Nullable - String name; - - @Nullable - String description; - - String recipe; - String before; - String after; -} +/* + * 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.config; + +import lombok.Value; +import org.openrewrite.internal.lang.Nullable; + +@Value +public class RecipeExample { + @Nullable + String name; + + @Nullable + String description; + + String recipe; + String before; + String after; +} 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 895a2722c53..5d54813a8d2 100755 --- a/rewrite-core/src/main/java/org/openrewrite/internal/NameCaseConvention.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/NameCaseConvention.java @@ -1,216 +1,216 @@ -/* - * 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.internal; - -import org.openrewrite.Incubating; - -import java.util.regex.Pattern; - -/** - * Utilities for standard name case conventions. - */ -@Incubating(since = "7.17.0") -public enum NameCaseConvention { - /** - * Lowercase and hyphen-separated, e.g., "lower-hyphen". - * This is also known as "kebab-case". - */ - LOWER_HYPHEN, - - /** - * Lowercase and underscore-separated, e.g., "lower_underscore". - * This is also known as "snake_case". - */ - LOWER_UNDERSCORE, - - /** - * Camel case with the first letter lowercase, e.g., "lowerCamel". - * This is the standard Java variable naming convention. - */ - LOWER_CAMEL, - - /** - * Camel case with the first letter uppercase, e.g., "UpperCamel". - * This is the standard Java and C++ class naming convention. - */ - UPPER_CAMEL, - - /** - * Underscore separated with all letters uppercase, e.g., "UPPER_UNDERSCORE". - * This is the standard Java and C++ constant variable naming convention. - * This is also known as "SCREAMING_SNAKE_CASE". - */ - UPPER_UNDERSCORE; - - private static final Pattern CAMEL_CASE_SPLIT = Pattern.compile("[\\s_-]"); - - /** - * Formats the input to the style of this {@link NameCaseConvention}. - * - * @param str The input string to format. - * @return The string formatted to the style of this convention. - */ - public String format(String str) { - return format(this, str); - } - - public static String format(NameCaseConvention convention, String str) { - switch (convention) { - case LOWER_HYPHEN: - return lowerHyphen(str); - case LOWER_UNDERSCORE: - return lowerUnderscore(str); - case LOWER_CAMEL: - return toCamelCase(str, true); - case UPPER_CAMEL: - return toCamelCase(str, false); - case UPPER_UNDERSCORE: - return upperUnderscore(str); - default: - return str; - } - } - - /** - * Whether the input matches the formatting style of this {@link NameCaseConvention}. - * - * @param str The input string to check. - * @return Whether the input matches the formatting style of this convention. - */ - public boolean matches(String str) { - return matches(this, str); - } - - public static boolean matches(NameCaseConvention convention, String str) { - return str.matches(format(convention, str)); - } - - /** - * Check equality between two inputs using "relaxed binding" rules. - * The inputs will be converted to {@link NameCaseConvention#LOWER_CAMEL} before being checked using {@link String#equals}. - * - * @param str0 The first input to compare. - * @param str1 The second input to compare. - * @return Whether the inputs are equal. - * @see Micronaut Property Value Binding Normalization - * @see Spring Boot Relaxed Binding - */ - public static boolean equalsRelaxedBinding(String str0, String str1) { - return LOWER_CAMEL.format(str0).equals(LOWER_CAMEL.format(str1)); - } - - private static String lowerHyphen(String str) { - return nameCaseJoiner(str.replace('_', '-').replace(' ', '-'), true, '-'); - } - - private static String lowerUnderscore(String str) { - return nameCaseJoiner(str.replace('-', '_').replace(' ', '_'), true, '_') - .toLowerCase(); - } - - /** - * Returns input formatted using the Java "camelCase" (or "CamelCase") naming convention. - * - * @param str The input string to check. - * @param lowerCaseFirstLetter Whether the first letter should be lowerCase or UpperCase. - * @return The string formatted as {@link NameCaseConvention#LOWER_CAMEL}. - */ - private static String toCamelCase(String str, boolean lowerCaseFirstLetter) { - StringBuilder sb = new StringBuilder(str.length()); - for (String s : CAMEL_CASE_SPLIT.split(str)) { - String capitalize = StringUtils.capitalize(s); - sb.append(capitalize); - } - String result = sb.toString(); - if (lowerCaseFirstLetter) { - return StringUtils.uncapitalize(result); - } - return result; - } - - private static String upperUnderscore(String str) { - return nameCaseJoiner(str.replace('-', '_').replace(' ', '_'), false, '_') - .toUpperCase(); - } - - private static String nameCaseJoiner(String str, boolean lowerCaseFirstLetter, char separatorChar) { - StringBuilder builder = new StringBuilder(); - if (lowerCaseFirstLetter) { - char[] chars = str.toCharArray(); - boolean first = true; - char last = '0'; - char secondLast = separatorChar; - for (int i = 0; i < chars.length; i++) { - char c = chars[i]; - if (Character.isLowerCase(c) || !Character.isLetter(c)) { - first = false; - if (c != separatorChar) { - if (last == separatorChar) { - builder.append(separatorChar); - } - builder.append(c); - } - } else { - char lowerCaseChar = Character.toLowerCase(c); - if (first) { - first = false; - builder.append(lowerCaseChar); - } else if (Character.isUpperCase(last) || last == '.') { - builder.append(lowerCaseChar); - } else if (Character.isDigit(last) && (Character.isUpperCase(secondLast) || secondLast == separatorChar)) { - builder.append(lowerCaseChar); - } else { - builder.append(separatorChar).append(lowerCaseChar); - } - } - if (i > 1) { - secondLast = last; - } - last = c; - } - } else { - boolean first = true; - char last = '0'; - for (char c : str.toCharArray()) { - if (first) { - builder.append(c); - first = false; - } else { - if (Character.isUpperCase(c) && !Character.isUpperCase(last)) { - if (c != separatorChar) { - builder.append(separatorChar); - } - builder.append(c); - } else { - if (c == '.') { - first = true; - } - if (c != separatorChar) { - if (last == separatorChar) { - builder.append(separatorChar); - } - builder.append(c); - } - } - } - last = c; - } - } - - return builder.toString(); - } - -} +/* + * 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.internal; + +import org.openrewrite.Incubating; + +import java.util.regex.Pattern; + +/** + * Utilities for standard name case conventions. + */ +@Incubating(since = "7.17.0") +public enum NameCaseConvention { + /** + * Lowercase and hyphen-separated, e.g., "lower-hyphen". + * This is also known as "kebab-case". + */ + LOWER_HYPHEN, + + /** + * Lowercase and underscore-separated, e.g., "lower_underscore". + * This is also known as "snake_case". + */ + LOWER_UNDERSCORE, + + /** + * Camel case with the first letter lowercase, e.g., "lowerCamel". + * This is the standard Java variable naming convention. + */ + LOWER_CAMEL, + + /** + * Camel case with the first letter uppercase, e.g., "UpperCamel". + * This is the standard Java and C++ class naming convention. + */ + UPPER_CAMEL, + + /** + * Underscore separated with all letters uppercase, e.g., "UPPER_UNDERSCORE". + * This is the standard Java and C++ constant variable naming convention. + * This is also known as "SCREAMING_SNAKE_CASE". + */ + UPPER_UNDERSCORE; + + private static final Pattern CAMEL_CASE_SPLIT = Pattern.compile("[\\s_-]"); + + /** + * Formats the input to the style of this {@link NameCaseConvention}. + * + * @param str The input string to format. + * @return The string formatted to the style of this convention. + */ + public String format(String str) { + return format(this, str); + } + + public static String format(NameCaseConvention convention, String str) { + switch (convention) { + case LOWER_HYPHEN: + return lowerHyphen(str); + case LOWER_UNDERSCORE: + return lowerUnderscore(str); + case LOWER_CAMEL: + return toCamelCase(str, true); + case UPPER_CAMEL: + return toCamelCase(str, false); + case UPPER_UNDERSCORE: + return upperUnderscore(str); + default: + return str; + } + } + + /** + * Whether the input matches the formatting style of this {@link NameCaseConvention}. + * + * @param str The input string to check. + * @return Whether the input matches the formatting style of this convention. + */ + public boolean matches(String str) { + return matches(this, str); + } + + public static boolean matches(NameCaseConvention convention, String str) { + return str.matches(format(convention, str)); + } + + /** + * Check equality between two inputs using "relaxed binding" rules. + * The inputs will be converted to {@link NameCaseConvention#LOWER_CAMEL} before being checked using {@link String#equals}. + * + * @param str0 The first input to compare. + * @param str1 The second input to compare. + * @return Whether the inputs are equal. + * @see Micronaut Property Value Binding Normalization + * @see Spring Boot Relaxed Binding + */ + public static boolean equalsRelaxedBinding(String str0, String str1) { + return LOWER_CAMEL.format(str0).equals(LOWER_CAMEL.format(str1)); + } + + private static String lowerHyphen(String str) { + return nameCaseJoiner(str.replace('_', '-').replace(' ', '-'), true, '-'); + } + + private static String lowerUnderscore(String str) { + return nameCaseJoiner(str.replace('-', '_').replace(' ', '_'), true, '_') + .toLowerCase(); + } + + /** + * Returns input formatted using the Java "camelCase" (or "CamelCase") naming convention. + * + * @param str The input string to check. + * @param lowerCaseFirstLetter Whether the first letter should be lowerCase or UpperCase. + * @return The string formatted as {@link NameCaseConvention#LOWER_CAMEL}. + */ + private static String toCamelCase(String str, boolean lowerCaseFirstLetter) { + StringBuilder sb = new StringBuilder(str.length()); + for (String s : CAMEL_CASE_SPLIT.split(str)) { + String capitalize = StringUtils.capitalize(s); + sb.append(capitalize); + } + String result = sb.toString(); + if (lowerCaseFirstLetter) { + return StringUtils.uncapitalize(result); + } + return result; + } + + private static String upperUnderscore(String str) { + return nameCaseJoiner(str.replace('-', '_').replace(' ', '_'), false, '_') + .toUpperCase(); + } + + private static String nameCaseJoiner(String str, boolean lowerCaseFirstLetter, char separatorChar) { + StringBuilder builder = new StringBuilder(); + if (lowerCaseFirstLetter) { + char[] chars = str.toCharArray(); + boolean first = true; + char last = '0'; + char secondLast = separatorChar; + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + if (Character.isLowerCase(c) || !Character.isLetter(c)) { + first = false; + if (c != separatorChar) { + if (last == separatorChar) { + builder.append(separatorChar); + } + builder.append(c); + } + } else { + char lowerCaseChar = Character.toLowerCase(c); + if (first) { + first = false; + builder.append(lowerCaseChar); + } else if (Character.isUpperCase(last) || last == '.') { + builder.append(lowerCaseChar); + } else if (Character.isDigit(last) && (Character.isUpperCase(secondLast) || secondLast == separatorChar)) { + builder.append(lowerCaseChar); + } else { + builder.append(separatorChar).append(lowerCaseChar); + } + } + if (i > 1) { + secondLast = last; + } + last = c; + } + } else { + boolean first = true; + char last = '0'; + for (char c : str.toCharArray()) { + if (first) { + builder.append(c); + first = false; + } else { + if (Character.isUpperCase(c) && !Character.isUpperCase(last)) { + if (c != separatorChar) { + builder.append(separatorChar); + } + builder.append(c); + } else { + if (c == '.') { + first = true; + } + if (c != separatorChar) { + if (last == separatorChar) { + builder.append(separatorChar); + } + builder.append(c); + } + } + } + last = c; + } + } + + return builder.toString(); + } + +} diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/PropertyPlaceholderHelper.java b/rewrite-core/src/main/java/org/openrewrite/internal/PropertyPlaceholderHelper.java index 9c439a36ad6..0c7a82081ec 100644 --- a/rewrite-core/src/main/java/org/openrewrite/internal/PropertyPlaceholderHelper.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/PropertyPlaceholderHelper.java @@ -1,155 +1,155 @@ -/* - * 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.internal; - -import org.openrewrite.internal.lang.Nullable; - -import java.util.*; -import java.util.function.Function; - -/** - * Simplified from Spring's PropertyPlaceholderHelper. - * - * @author Juergen Hoeller - * @author Rob Harrop - */ -public class PropertyPlaceholderHelper { - private static final Map wellKnownSimplePrefixes = new HashMap<>(4); - - static { - wellKnownSimplePrefixes.put("}", "{"); - wellKnownSimplePrefixes.put("]", "["); - wellKnownSimplePrefixes.put(")", "("); - } - - private final String placeholderPrefix; - private final String placeholderSuffix; - - private final String simplePrefix; - - @Nullable - private final String valueSeparator; - - public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix, - @Nullable String valueSeparator) { - this.placeholderPrefix = placeholderPrefix; - this.placeholderSuffix = placeholderSuffix; - String simplePrefixForSuffix = wellKnownSimplePrefixes.get(this.placeholderSuffix); - if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) { - this.simplePrefix = simplePrefixForSuffix; - } else { - this.simplePrefix = this.placeholderPrefix; - } - this.valueSeparator = valueSeparator; - } - - public String replacePlaceholders(String value, final Properties properties) { - return replacePlaceholders(value, properties::getProperty); - } - - public String replacePlaceholders(String value, Function placeholderResolver) { - return parseStringValue(value, placeholderResolver, null); - } - - protected String parseStringValue(String value, Function placeholderResolver, - @Nullable Set visitedPlaceholders) { - int startIndex = value.indexOf(placeholderPrefix); - if (startIndex == -1) { - return value; - } - - StringBuilder result = new StringBuilder(value); - while (startIndex != -1) { - int endIndex = findPlaceholderEndIndex(result, startIndex); - if (endIndex != -1) { - String placeholder = result.substring(startIndex + placeholderPrefix.length(), endIndex); - String originalPlaceholder = placeholder; - if (visitedPlaceholders == null) { - visitedPlaceholders = new HashSet<>(4); - } - if (!visitedPlaceholders.add(originalPlaceholder)) { - throw new IllegalArgumentException( - "Circular placeholder reference '" + originalPlaceholder + "' in property definitions"); - } - // Recursive invocation, parsing placeholders contained in the placeholder key. - placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); - // Now obtain the value for the fully resolved key... - String propVal = placeholderResolver.apply(placeholder); - if (propVal == null && valueSeparator != null) { - int separatorIndex = placeholder.indexOf(valueSeparator); - if (separatorIndex != -1) { - String actualPlaceholder = placeholder.substring(0, separatorIndex); - String defaultValue = placeholder.substring(separatorIndex + valueSeparator.length()); - propVal = placeholderResolver.apply(actualPlaceholder); - if (propVal == null) { - propVal = defaultValue; - } - } - } - if (propVal != null) { - // Recursive invocation, parsing placeholders contained in the - // previously resolved placeholder value. - propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); - result.replace(startIndex, endIndex + placeholderSuffix.length(), propVal); - - if (propVal.length() < endIndex - startIndex + 1) { - endIndex = startIndex + propVal.length(); - } - } - - // Proceed with unprocessed value. - startIndex = result.indexOf(placeholderPrefix, endIndex + placeholderSuffix.length()); - visitedPlaceholders.remove(originalPlaceholder); - } else { - startIndex = -1; - } - } - return result.toString(); - } - - private int findPlaceholderEndIndex(CharSequence buf, int startIndex) { - int index = startIndex + placeholderPrefix.length(); - int withinNestedPlaceholder = 0; - while (index < buf.length()) { - if (substringMatch(buf, index, placeholderSuffix)) { - if (withinNestedPlaceholder > 0) { - withinNestedPlaceholder--; - index = index + placeholderSuffix.length(); - } else { - return index; - } - } else if (substringMatch(buf, index, simplePrefix)) { - withinNestedPlaceholder++; - index = index + simplePrefix.length(); - } else { - index++; - } - } - return -1; - } - - private static boolean substringMatch(CharSequence str, int index, CharSequence substring) { - if (index + substring.length() > str.length()) { - return false; - } - for (int i = 0; i < substring.length(); i++) { - if (str.charAt(index + i) != substring.charAt(i)) { - return false; - } - } - return true; - } -} +/* + * 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.internal; + +import org.openrewrite.internal.lang.Nullable; + +import java.util.*; +import java.util.function.Function; + +/** + * Simplified from Spring's PropertyPlaceholderHelper. + * + * @author Juergen Hoeller + * @author Rob Harrop + */ +public class PropertyPlaceholderHelper { + private static final Map wellKnownSimplePrefixes = new HashMap<>(4); + + static { + wellKnownSimplePrefixes.put("}", "{"); + wellKnownSimplePrefixes.put("]", "["); + wellKnownSimplePrefixes.put(")", "("); + } + + private final String placeholderPrefix; + private final String placeholderSuffix; + + private final String simplePrefix; + + @Nullable + private final String valueSeparator; + + public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix, + @Nullable String valueSeparator) { + this.placeholderPrefix = placeholderPrefix; + this.placeholderSuffix = placeholderSuffix; + String simplePrefixForSuffix = wellKnownSimplePrefixes.get(this.placeholderSuffix); + if (simplePrefixForSuffix != null && this.placeholderPrefix.endsWith(simplePrefixForSuffix)) { + this.simplePrefix = simplePrefixForSuffix; + } else { + this.simplePrefix = this.placeholderPrefix; + } + this.valueSeparator = valueSeparator; + } + + public String replacePlaceholders(String value, final Properties properties) { + return replacePlaceholders(value, properties::getProperty); + } + + public String replacePlaceholders(String value, Function placeholderResolver) { + return parseStringValue(value, placeholderResolver, null); + } + + protected String parseStringValue(String value, Function placeholderResolver, + @Nullable Set visitedPlaceholders) { + int startIndex = value.indexOf(placeholderPrefix); + if (startIndex == -1) { + return value; + } + + StringBuilder result = new StringBuilder(value); + while (startIndex != -1) { + int endIndex = findPlaceholderEndIndex(result, startIndex); + if (endIndex != -1) { + String placeholder = result.substring(startIndex + placeholderPrefix.length(), endIndex); + String originalPlaceholder = placeholder; + if (visitedPlaceholders == null) { + visitedPlaceholders = new HashSet<>(4); + } + if (!visitedPlaceholders.add(originalPlaceholder)) { + throw new IllegalArgumentException( + "Circular placeholder reference '" + originalPlaceholder + "' in property definitions"); + } + // Recursive invocation, parsing placeholders contained in the placeholder key. + placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); + // Now obtain the value for the fully resolved key... + String propVal = placeholderResolver.apply(placeholder); + if (propVal == null && valueSeparator != null) { + int separatorIndex = placeholder.indexOf(valueSeparator); + if (separatorIndex != -1) { + String actualPlaceholder = placeholder.substring(0, separatorIndex); + String defaultValue = placeholder.substring(separatorIndex + valueSeparator.length()); + propVal = placeholderResolver.apply(actualPlaceholder); + if (propVal == null) { + propVal = defaultValue; + } + } + } + if (propVal != null) { + // Recursive invocation, parsing placeholders contained in the + // previously resolved placeholder value. + propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); + result.replace(startIndex, endIndex + placeholderSuffix.length(), propVal); + + if (propVal.length() < endIndex - startIndex + 1) { + endIndex = startIndex + propVal.length(); + } + } + + // Proceed with unprocessed value. + startIndex = result.indexOf(placeholderPrefix, endIndex + placeholderSuffix.length()); + visitedPlaceholders.remove(originalPlaceholder); + } else { + startIndex = -1; + } + } + return result.toString(); + } + + private int findPlaceholderEndIndex(CharSequence buf, int startIndex) { + int index = startIndex + placeholderPrefix.length(); + int withinNestedPlaceholder = 0; + while (index < buf.length()) { + if (substringMatch(buf, index, placeholderSuffix)) { + if (withinNestedPlaceholder > 0) { + withinNestedPlaceholder--; + index = index + placeholderSuffix.length(); + } else { + return index; + } + } else if (substringMatch(buf, index, simplePrefix)) { + withinNestedPlaceholder++; + index = index + simplePrefix.length(); + } else { + index++; + } + } + return -1; + } + + private static boolean substringMatch(CharSequence str, int index, CharSequence substring) { + if (index + substring.length() > str.length()) { + return false; + } + for (int i = 0; i < substring.length(); i++) { + if (str.charAt(index + i) != substring.charAt(i)) { + return false; + } + } + return true; + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/StreamUtils.java b/rewrite-core/src/main/java/org/openrewrite/internal/StreamUtils.java index 75c0bb0170f..0919e629f58 100755 --- a/rewrite-core/src/main/java/org/openrewrite/internal/StreamUtils.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/StreamUtils.java @@ -1,35 +1,35 @@ -/* - * 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.internal; - -import java.util.HashSet; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Predicate; - -public class StreamUtils { - // Returns a predicate suitable for use with stream().filter() that will result in a set filtered to - // contain only items that are distinct as evaluated by keyFunc - public static Predicate distinctBy(Function keyFunc) { - Set seen = new HashSet<>(); - return t -> { - Object it = keyFunc.apply(t); - boolean alreadySeen = seen.contains(it); - seen.add(it); - return !alreadySeen; - }; - } -} +/* + * 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.internal; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; + +public class StreamUtils { + // Returns a predicate suitable for use with stream().filter() that will result in a set filtered to + // contain only items that are distinct as evaluated by keyFunc + public static Predicate distinctBy(Function keyFunc) { + Set seen = new HashSet<>(); + return t -> { + Object it = keyFunc.apply(t); + boolean alreadySeen = seen.contains(it); + seen.add(it); + return !alreadySeen; + }; + } +} 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 8ae66f50aaa..2dec063084a 100644 --- a/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java +++ b/rewrite-core/src/main/java/org/openrewrite/internal/StringUtils.java @@ -1,558 +1,558 @@ -/* - * 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.internal; - -import org.openrewrite.internal.lang.NonNull; -import org.openrewrite.internal.lang.Nullable; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.*; -import java.util.Arrays; -import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Predicate; -import java.util.stream.Stream; - -import static java.util.Arrays.copyOfRange; -import static java.util.function.Function.identity; -import static java.util.stream.Collectors.counting; -import static java.util.stream.Collectors.groupingBy; - -public class StringUtils { - private final static FileSystem FS = FileSystems.getDefault(); - - private StringUtils() { - } - - public static String trimIndentPreserveCRLF(String text) { - return trimIndent(text.replace('\r', '⏎')) - .replace('⏎', '\r'); - } - - /** - * Detects a common minimal indent of all the input lines and removes the indent from each line. - * - * This is modeled after Kotlin's trimIndent and is useful for pruning the indent from multi-line text blocks. - * - * Note: Blank lines do not affect the detected indent level. - * - * @param text A string that have a common indention - * @return A mutated version of the string that removed the common indention. - */ - public static String trimIndent(String text) { - - if (text.isEmpty()) { - return text; - } - - int indentLevel = minCommonIndentLevel(text); - - // The logic for trimming the start of the string is consistent with the functionality of Kotlin's trimIndent. - char startChar = text.charAt(0); - int start = 0; - if (startChar == '\n' || startChar == '\r') { - //If the string starts with a line break, always trim it. - int i = 1; - for (; i < text.length(); i++) { - char c = text.charAt(i); - if (!Character.isWhitespace(c)) { - //If there is any non-whitespace on the first line, do not trim the line. - start = 1; - break; - } else if (c == '\n' || c == '\r') { - if (i - 1 <= indentLevel) { - //If the first line is only whitespace and the line size is less than indent size, trim it. - start = i; - } else { - //If the line size is equal or greater than indent, do not trim the line. - start = 1; - } - break; - } - } - } - - //If the last line of the string is only whitespace, trim it. - int end = text.length() - 1; - while (end > start) { - char endChar = text.charAt(end); - if (!Character.isWhitespace(endChar)) { - end = text.length(); - break; - } else if (endChar == '\n' || endChar == '\r') { - break; - } - end--; - } - if (end == start) { - end++; - } - char[] charArray = text.substring(start, end).toCharArray(); - - StringBuilder trimmed = new StringBuilder(); - for (int i = 0; i < charArray.length; i++) { - boolean nonWhitespaceEncountered = false; - int j = i; - for (; j < charArray.length; j++) { - char c = charArray[j]; - if (j - i >= indentLevel || (nonWhitespaceEncountered |= !Character.isWhitespace(c))) { - trimmed.append(c); - } - if (c == '\r' || c == '\n') { - if (!nonWhitespaceEncountered && j - 1 < indentLevel) { - trimmed.append(c); - } - break; - } - } - i = j; - } - - return trimmed.toString(); - } - - - /** - * This method will count the number of white space characters that precede any content for each line contained - * in string. It will not compute a white space count for a line, if the entire line is blank (only made up of white - * space characters). - *

- * It will compute the minimum common number of white spaces across all lines and return that minimum. - * - * @param text A string with zero or more line breaks. - * @return The minimum count of white space characters preceding each line of content. - */ - private static int minCommonIndentLevel(String text) { - int minIndent = Integer.MAX_VALUE; - int whiteSpaceCount = 0; - boolean contentEncountered = false; - for (char c : text.toCharArray()) { - if (c == '\n' || c == '\r') { - if (contentEncountered) { - minIndent = Math.min(whiteSpaceCount, minIndent); - if (minIndent == 0) { - break; - } - } - whiteSpaceCount = 0; - contentEncountered = false; - } else if (!contentEncountered && Character.isWhitespace(c)) { - whiteSpaceCount++; - } else { - contentEncountered = true; - } - } - if (contentEncountered) { - minIndent = Math.min(whiteSpaceCount, minIndent); - } - return minIndent; - } - - static int indentLevel(String text) { - Stream lines = Arrays.stream(text.replaceAll("\\s+$", "").split("\\r?\\n")).filter(s -> !isBlank(s)); - - AtomicBoolean dropWhile = new AtomicBoolean(false); - AtomicBoolean takeWhile = new AtomicBoolean(true); - SortedMap indentFrequencies = lines - .filter(l -> { - dropWhile.set(dropWhile.get() || !l.isEmpty()); - return dropWhile.get(); - }) - .map(l -> { - takeWhile.set(true); - return (int) l.chars() - .filter(c -> { - takeWhile.set(takeWhile.get() && Character.isWhitespace(c)); - return takeWhile.get(); - }) - .count(); - }) - .collect(groupingBy(identity(), TreeMap::new, counting())); - return mostCommonIndent(indentFrequencies); - } - - public static int mostCommonIndent(SortedMap indentFrequencies) { - // the frequency with which each indent level is an integral divisor of longer indent levels - SortedMap indentFrequencyAsDivisors = new TreeMap<>(); - for (Map.Entry indentFrequency : indentFrequencies.entrySet()) { - int indent = indentFrequency.getKey(); - int freq; - switch (indent) { - case 0: - freq = indentFrequency.getValue().intValue(); - break; - case 1: - // gcd(1, N) == 1, so we can avoid the test for this case - freq = (int) indentFrequencies.tailMap(indent).values().stream().mapToLong(l -> l).sum(); - break; - default: - freq = (int) indentFrequencies.tailMap(indent).entrySet().stream() - .filter(inF -> gcd(inF.getKey(), indent) != 0) - .mapToLong(Map.Entry::getValue) - .sum(); - } - - indentFrequencyAsDivisors.put(indent, freq); - } - - if (indentFrequencies.getOrDefault(0, 0L) > 1) { - return 0; - } - - return indentFrequencyAsDivisors.entrySet().stream() - .max((e1, e2) -> { - int valCompare = e1.getValue().compareTo(e2.getValue()); - return valCompare != 0 ? - valCompare : - // take the smallest indent otherwise, unless it would be zero - e1.getKey() == 0 ? -1 : e2.getKey().compareTo(e1.getKey()); - }) - .map(Map.Entry::getKey) - .orElse(0); - } - - static int gcd(int n1, int n2) { - return n2 == 0 ? n1 : gcd(n2, n1 % n2); - } - - /** - * Check if the String is null or has only whitespaces. - *

- * Modified from apache commons lang StringUtils. - * - * @param string String to check - * @return {@code true} if the String is null or has only whitespaces - */ - public static boolean isBlank(@Nullable String string) { - if (string == null || string.isEmpty()) { - return true; - } - for (int i = 0; i < string.length(); i++) { - if (!Character.isWhitespace(string.charAt(i))) { - return false; - } - } - return true; - } - - /** - * Check if the String is empty string or null. - * - * @param string String to check - * @return {@code true} if the String is null or empty string - */ - public static boolean isNullOrEmpty(@Nullable String string) { - return string == null || string.isEmpty(); - } - - /** - * If the input stream is coming from a stream with an unknown encoding, use - * {@link EncodingDetectingInputStream#readFully()} instead. - * - * @param inputStream An input stream. - * @return A UTF-8 encoded string. - */ - public static String readFully(InputStream inputStream) { - try (InputStream is = inputStream) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] buffer = new byte[4096]; - int n; - while ((n = is.read(buffer)) != -1) { - bos.write(buffer, 0, n); - } - - byte[] bytes = bos.toByteArray(); - return new String(bytes, 0, bytes.length, StandardCharsets.UTF_8); - } catch (IOException e) { - throw new UnsupportedOperationException(e); - } - } - - public static String capitalize(String value) { - if (value.isEmpty()) { - return value; - } - return Character.toUpperCase(value.charAt(0)) + - value.substring(1); - } - - public static String uncapitalize(String value) { - if (value.isEmpty()) { - return value; - } - return Character.toLowerCase(value.charAt(0)) + value.substring(1); - } - - public static boolean containsOnlyWhitespaceAndComments(String text) { - int i = 0; - char[] chars = text.toCharArray(); - boolean inSingleLineComment = false; - boolean inMultilineComment = false; - while (i < chars.length) { - char c = chars[i]; - if (inSingleLineComment && c == '\n') { - inSingleLineComment = false; - continue; - } - if (i < chars.length - 1) { - String s = String.valueOf(c) + chars[i + 1]; - switch (s) { - case "//": { - inSingleLineComment = true; - i += 2; - continue; - } - case "/*": { - inMultilineComment = true; - i += 2; - continue; - } - case "*/": { - inMultilineComment = false; - i += 2; - continue; - } - } - } - if (!inSingleLineComment && !inMultilineComment && !Character.isWhitespace(c)) { - return false; - } - i++; - } - return true; - } - - public static int indexOfNonWhitespace(String text) { - return indexOf(text, it -> !(it == ' ' || it == '\t' || it == '\n' || it == '\r')); - } - - /** - * @param text Text to scan - * @param test The predicate to match - * @return The index of the first character for which the predicate returns true, - * or -1 if no character in the string matches the predicate. - */ - public static int indexOf(String text, Predicate test) { - for (int i = 0; i < text.length(); i++) { - if (test.test(text.charAt(i))) { - return i; - } - } - return -1; - } - - /** - * Return the number of times a substring occurs within a target string. - * - * @param text A target string - * @param substring The substring to search for - * @return the number of times the substring is found in the target. 0 if no occurances are found. - */ - public static int countOccurrences(@NonNull String text, @NonNull String substring) { - - if (text.isEmpty() || substring.isEmpty()) { - return 0; - } - - int count = 0; - for (int index = text.indexOf(substring); index >= 0; index = text.indexOf(substring, index + substring.length())) { - count++; - } - return count; - } - - /** - * This method will search and replace the first occurrence of a matching substring. There is a a replaceFirst method - * on the String class but that version leverages regular expressions and is a magnitude slower than this simple - * replacement. - * - * @param text The source string to search - * @param match The substring that is being searched for - * @param replacement The replacement. - * @return The original string with the first occurrence replaced or the original text if a match is not found. - */ - public static String replaceFirst(@NonNull String text, @NonNull String match, @NonNull String replacement) { - int start = text.indexOf(match); - if (match.isEmpty() || text.isEmpty() || start == -1) { - return text; - } else { - StringBuilder newValue = new StringBuilder(text.length()); - newValue.append(text, 0, start); - newValue.append(replacement); - int end = start + match.length(); - if (end < text.length()) { - newValue.append(text, end, text.length()); - } - return newValue.toString(); - } - } - - public static String repeat(String s, int count) { - if (count == 1) { - return s; - } - - byte[] value = s.getBytes(); - int len = value.length; - if (len == 0 || count == 0) { - return ""; - } - if (len == 1) { - final byte[] single = new byte[count]; - Arrays.fill(single, value[0]); - return new String(single); - } - int limit = len * count; - byte[] multiple = new byte[limit]; - System.arraycopy(value, 0, multiple, 0, len); - int copied = len; - for (; copied < limit - copied; copied <<= 1) { - System.arraycopy(multiple, 0, multiple, copied, copied); - } - System.arraycopy(multiple, 0, multiple, copied, limit - copied); - return new String(multiple); - } - - public static boolean matchesGlob(@Nullable String value, @Nullable String globPattern) { - if ("*".equals(globPattern)) { - return true; - } - if (null == globPattern) { - return false; - } - if (null == value) { - value = ""; - } - PathMatcher pm = FS.getPathMatcher("glob:" + globPattern); - Path path = Paths.get(""); - if (value.contains("/")) { - String[] parts = value.split("/"); - if (parts.length > 1) { - for (int i = 0, len = parts.length; i < len; i++) { - path = Paths.get("", copyOfRange(parts, i, parts.length)); - if (!isBlank(parts[i])) { - break; - } - } - } else { - path = Paths.get(parts[0]); - } - } else { - path = Paths.get(value); - } - return pm.matches(path); - } - - public static String indent(String text) { - StringBuilder indent = new StringBuilder(); - for (char c : text.toCharArray()) { - if (c == '\n' || c == '\r') { - return indent.toString(); - } else if (Character.isWhitespace(c)) { - indent.append(c); - } else { - return indent.toString(); - } - } - return indent.toString(); - } - - /** - * Locate the greatest common margin of a multi-line string - * - * @param multiline A string of one or more lines. - * @return The greatest common margin consisting only of whitespace characters. - */ - public static String greatestCommonMargin(String multiline) { - String gcm = null; - StringBuilder margin = new StringBuilder(); - boolean skipRestOfLine = false; - char[] charArray = multiline.toCharArray(); - for (int i = 0; i < charArray.length; i++) { - char c = charArray[i]; - if (c == '\n') { - if (i < charArray.length - 1 && charArray[i + 1] == '\n') { - i++; - continue; - } else if (i > 0) { - if (margin.length() == 0) { - return ""; - } else { - gcm = commonMargin(gcm, margin); - margin = new StringBuilder(); - } - } - skipRestOfLine = false; - } else if (Character.isWhitespace(c) && !skipRestOfLine) { - margin.append(c); - } else { - skipRestOfLine = true; - } - } - return gcm == null ? "" : gcm; - } - - public static String commonMargin(@Nullable CharSequence s1, CharSequence s2) { - if (s1 == null) { - String s = s2.toString(); - return s.substring(s.lastIndexOf('\n') + 1); - } - for (int i = 0; i < s1.length() && i < s2.length(); i++) { - if (s1.charAt(i) != s2.charAt(i) || !Character.isWhitespace(s1.charAt(i))) { - return s1.toString().substring(0, i); - } - } - return s2.length() < s1.length() ? s2.toString() : s1.toString(); - } - - public static boolean isNumeric(String str) { - if (str == null) { - return false; - } - int sz = str.length(); - for (int i = 0; i < sz; i++) { - if (!Character.isDigit(str.charAt(i))) { - return false; - } - } - return true; - } - - /** - * See https://eclipse.org/aspectj/doc/next/progguide/semantics-pointcuts.html#type-patterns - *

- * An embedded * in an identifier matches any sequence of characters, but - * does not match the package (or inner-type) separator ".". - *

- * The ".." wildcard matches any sequence of characters that start and end with a ".", so it can be used to pick out all - * types in any subpackage, or all inner types. e.g. within(com.xerox..*) picks out all join points where - * the code is in any declaration of a type whose name begins with "com.xerox.". - */ - public static String aspectjNameToPattern(String name) { - return name - .replace("$", "\\$") - .replace("[", "\\[") - .replace("]", "\\]") - .replaceAll("([^.]*)\\.([^.]*)", "$1\\.$2") - .replace("*", "[^.]*") - .replace("..", "\\.(.+\\.)?"); - } -} +/* + * 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.internal; + +import org.openrewrite.internal.lang.NonNull; +import org.openrewrite.internal.lang.Nullable; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.util.Arrays; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import static java.util.Arrays.copyOfRange; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.counting; +import static java.util.stream.Collectors.groupingBy; + +public class StringUtils { + private final static FileSystem FS = FileSystems.getDefault(); + + private StringUtils() { + } + + public static String trimIndentPreserveCRLF(String text) { + return trimIndent(text.replace('\r', '⏎')) + .replace('⏎', '\r'); + } + + /** + * Detects a common minimal indent of all the input lines and removes the indent from each line. + * + * This is modeled after Kotlin's trimIndent and is useful for pruning the indent from multi-line text blocks. + * + * Note: Blank lines do not affect the detected indent level. + * + * @param text A string that have a common indention + * @return A mutated version of the string that removed the common indention. + */ + public static String trimIndent(String text) { + + if (text.isEmpty()) { + return text; + } + + int indentLevel = minCommonIndentLevel(text); + + // The logic for trimming the start of the string is consistent with the functionality of Kotlin's trimIndent. + char startChar = text.charAt(0); + int start = 0; + if (startChar == '\n' || startChar == '\r') { + //If the string starts with a line break, always trim it. + int i = 1; + for (; i < text.length(); i++) { + char c = text.charAt(i); + if (!Character.isWhitespace(c)) { + //If there is any non-whitespace on the first line, do not trim the line. + start = 1; + break; + } else if (c == '\n' || c == '\r') { + if (i - 1 <= indentLevel) { + //If the first line is only whitespace and the line size is less than indent size, trim it. + start = i; + } else { + //If the line size is equal or greater than indent, do not trim the line. + start = 1; + } + break; + } + } + } + + //If the last line of the string is only whitespace, trim it. + int end = text.length() - 1; + while (end > start) { + char endChar = text.charAt(end); + if (!Character.isWhitespace(endChar)) { + end = text.length(); + break; + } else if (endChar == '\n' || endChar == '\r') { + break; + } + end--; + } + if (end == start) { + end++; + } + char[] charArray = text.substring(start, end).toCharArray(); + + StringBuilder trimmed = new StringBuilder(); + for (int i = 0; i < charArray.length; i++) { + boolean nonWhitespaceEncountered = false; + int j = i; + for (; j < charArray.length; j++) { + char c = charArray[j]; + if (j - i >= indentLevel || (nonWhitespaceEncountered |= !Character.isWhitespace(c))) { + trimmed.append(c); + } + if (c == '\r' || c == '\n') { + if (!nonWhitespaceEncountered && j - 1 < indentLevel) { + trimmed.append(c); + } + break; + } + } + i = j; + } + + return trimmed.toString(); + } + + + /** + * This method will count the number of white space characters that precede any content for each line contained + * in string. It will not compute a white space count for a line, if the entire line is blank (only made up of white + * space characters). + *

+ * It will compute the minimum common number of white spaces across all lines and return that minimum. + * + * @param text A string with zero or more line breaks. + * @return The minimum count of white space characters preceding each line of content. + */ + private static int minCommonIndentLevel(String text) { + int minIndent = Integer.MAX_VALUE; + int whiteSpaceCount = 0; + boolean contentEncountered = false; + for (char c : text.toCharArray()) { + if (c == '\n' || c == '\r') { + if (contentEncountered) { + minIndent = Math.min(whiteSpaceCount, minIndent); + if (minIndent == 0) { + break; + } + } + whiteSpaceCount = 0; + contentEncountered = false; + } else if (!contentEncountered && Character.isWhitespace(c)) { + whiteSpaceCount++; + } else { + contentEncountered = true; + } + } + if (contentEncountered) { + minIndent = Math.min(whiteSpaceCount, minIndent); + } + return minIndent; + } + + static int indentLevel(String text) { + Stream lines = Arrays.stream(text.replaceAll("\\s+$", "").split("\\r?\\n")).filter(s -> !isBlank(s)); + + AtomicBoolean dropWhile = new AtomicBoolean(false); + AtomicBoolean takeWhile = new AtomicBoolean(true); + SortedMap indentFrequencies = lines + .filter(l -> { + dropWhile.set(dropWhile.get() || !l.isEmpty()); + return dropWhile.get(); + }) + .map(l -> { + takeWhile.set(true); + return (int) l.chars() + .filter(c -> { + takeWhile.set(takeWhile.get() && Character.isWhitespace(c)); + return takeWhile.get(); + }) + .count(); + }) + .collect(groupingBy(identity(), TreeMap::new, counting())); + return mostCommonIndent(indentFrequencies); + } + + public static int mostCommonIndent(SortedMap indentFrequencies) { + // the frequency with which each indent level is an integral divisor of longer indent levels + SortedMap indentFrequencyAsDivisors = new TreeMap<>(); + for (Map.Entry indentFrequency : indentFrequencies.entrySet()) { + int indent = indentFrequency.getKey(); + int freq; + switch (indent) { + case 0: + freq = indentFrequency.getValue().intValue(); + break; + case 1: + // gcd(1, N) == 1, so we can avoid the test for this case + freq = (int) indentFrequencies.tailMap(indent).values().stream().mapToLong(l -> l).sum(); + break; + default: + freq = (int) indentFrequencies.tailMap(indent).entrySet().stream() + .filter(inF -> gcd(inF.getKey(), indent) != 0) + .mapToLong(Map.Entry::getValue) + .sum(); + } + + indentFrequencyAsDivisors.put(indent, freq); + } + + if (indentFrequencies.getOrDefault(0, 0L) > 1) { + return 0; + } + + return indentFrequencyAsDivisors.entrySet().stream() + .max((e1, e2) -> { + int valCompare = e1.getValue().compareTo(e2.getValue()); + return valCompare != 0 ? + valCompare : + // take the smallest indent otherwise, unless it would be zero + e1.getKey() == 0 ? -1 : e2.getKey().compareTo(e1.getKey()); + }) + .map(Map.Entry::getKey) + .orElse(0); + } + + static int gcd(int n1, int n2) { + return n2 == 0 ? n1 : gcd(n2, n1 % n2); + } + + /** + * Check if the String is null or has only whitespaces. + *

+ * Modified from apache commons lang StringUtils. + * + * @param string String to check + * @return {@code true} if the String is null or has only whitespaces + */ + public static boolean isBlank(@Nullable String string) { + if (string == null || string.isEmpty()) { + return true; + } + for (int i = 0; i < string.length(); i++) { + if (!Character.isWhitespace(string.charAt(i))) { + return false; + } + } + return true; + } + + /** + * Check if the String is empty string or null. + * + * @param string String to check + * @return {@code true} if the String is null or empty string + */ + public static boolean isNullOrEmpty(@Nullable String string) { + return string == null || string.isEmpty(); + } + + /** + * If the input stream is coming from a stream with an unknown encoding, use + * {@link EncodingDetectingInputStream#readFully()} instead. + * + * @param inputStream An input stream. + * @return A UTF-8 encoded string. + */ + public static String readFully(InputStream inputStream) { + try (InputStream is = inputStream) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int n; + while ((n = is.read(buffer)) != -1) { + bos.write(buffer, 0, n); + } + + byte[] bytes = bos.toByteArray(); + return new String(bytes, 0, bytes.length, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new UnsupportedOperationException(e); + } + } + + public static String capitalize(String value) { + if (value.isEmpty()) { + return value; + } + return Character.toUpperCase(value.charAt(0)) + + value.substring(1); + } + + public static String uncapitalize(String value) { + if (value.isEmpty()) { + return value; + } + return Character.toLowerCase(value.charAt(0)) + value.substring(1); + } + + public static boolean containsOnlyWhitespaceAndComments(String text) { + int i = 0; + char[] chars = text.toCharArray(); + boolean inSingleLineComment = false; + boolean inMultilineComment = false; + while (i < chars.length) { + char c = chars[i]; + if (inSingleLineComment && c == '\n') { + inSingleLineComment = false; + continue; + } + if (i < chars.length - 1) { + String s = String.valueOf(c) + chars[i + 1]; + switch (s) { + case "//": { + inSingleLineComment = true; + i += 2; + continue; + } + case "/*": { + inMultilineComment = true; + i += 2; + continue; + } + case "*/": { + inMultilineComment = false; + i += 2; + continue; + } + } + } + if (!inSingleLineComment && !inMultilineComment && !Character.isWhitespace(c)) { + return false; + } + i++; + } + return true; + } + + public static int indexOfNonWhitespace(String text) { + return indexOf(text, it -> !(it == ' ' || it == '\t' || it == '\n' || it == '\r')); + } + + /** + * @param text Text to scan + * @param test The predicate to match + * @return The index of the first character for which the predicate returns true, + * or -1 if no character in the string matches the predicate. + */ + public static int indexOf(String text, Predicate test) { + for (int i = 0; i < text.length(); i++) { + if (test.test(text.charAt(i))) { + return i; + } + } + return -1; + } + + /** + * Return the number of times a substring occurs within a target string. + * + * @param text A target string + * @param substring The substring to search for + * @return the number of times the substring is found in the target. 0 if no occurances are found. + */ + public static int countOccurrences(@NonNull String text, @NonNull String substring) { + + if (text.isEmpty() || substring.isEmpty()) { + return 0; + } + + int count = 0; + for (int index = text.indexOf(substring); index >= 0; index = text.indexOf(substring, index + substring.length())) { + count++; + } + return count; + } + + /** + * This method will search and replace the first occurrence of a matching substring. There is a a replaceFirst method + * on the String class but that version leverages regular expressions and is a magnitude slower than this simple + * replacement. + * + * @param text The source string to search + * @param match The substring that is being searched for + * @param replacement The replacement. + * @return The original string with the first occurrence replaced or the original text if a match is not found. + */ + public static String replaceFirst(@NonNull String text, @NonNull String match, @NonNull String replacement) { + int start = text.indexOf(match); + if (match.isEmpty() || text.isEmpty() || start == -1) { + return text; + } else { + StringBuilder newValue = new StringBuilder(text.length()); + newValue.append(text, 0, start); + newValue.append(replacement); + int end = start + match.length(); + if (end < text.length()) { + newValue.append(text, end, text.length()); + } + return newValue.toString(); + } + } + + public static String repeat(String s, int count) { + if (count == 1) { + return s; + } + + byte[] value = s.getBytes(); + int len = value.length; + if (len == 0 || count == 0) { + return ""; + } + if (len == 1) { + final byte[] single = new byte[count]; + Arrays.fill(single, value[0]); + return new String(single); + } + int limit = len * count; + byte[] multiple = new byte[limit]; + System.arraycopy(value, 0, multiple, 0, len); + int copied = len; + for (; copied < limit - copied; copied <<= 1) { + System.arraycopy(multiple, 0, multiple, copied, copied); + } + System.arraycopy(multiple, 0, multiple, copied, limit - copied); + return new String(multiple); + } + + public static boolean matchesGlob(@Nullable String value, @Nullable String globPattern) { + if ("*".equals(globPattern)) { + return true; + } + if (null == globPattern) { + return false; + } + if (null == value) { + value = ""; + } + PathMatcher pm = FS.getPathMatcher("glob:" + globPattern); + Path path = Paths.get(""); + if (value.contains("/")) { + String[] parts = value.split("/"); + if (parts.length > 1) { + for (int i = 0, len = parts.length; i < len; i++) { + path = Paths.get("", copyOfRange(parts, i, parts.length)); + if (!isBlank(parts[i])) { + break; + } + } + } else { + path = Paths.get(parts[0]); + } + } else { + path = Paths.get(value); + } + return pm.matches(path); + } + + public static String indent(String text) { + StringBuilder indent = new StringBuilder(); + for (char c : text.toCharArray()) { + if (c == '\n' || c == '\r') { + return indent.toString(); + } else if (Character.isWhitespace(c)) { + indent.append(c); + } else { + return indent.toString(); + } + } + return indent.toString(); + } + + /** + * Locate the greatest common margin of a multi-line string + * + * @param multiline A string of one or more lines. + * @return The greatest common margin consisting only of whitespace characters. + */ + public static String greatestCommonMargin(String multiline) { + String gcm = null; + StringBuilder margin = new StringBuilder(); + boolean skipRestOfLine = false; + char[] charArray = multiline.toCharArray(); + for (int i = 0; i < charArray.length; i++) { + char c = charArray[i]; + if (c == '\n') { + if (i < charArray.length - 1 && charArray[i + 1] == '\n') { + i++; + continue; + } else if (i > 0) { + if (margin.length() == 0) { + return ""; + } else { + gcm = commonMargin(gcm, margin); + margin = new StringBuilder(); + } + } + skipRestOfLine = false; + } else if (Character.isWhitespace(c) && !skipRestOfLine) { + margin.append(c); + } else { + skipRestOfLine = true; + } + } + return gcm == null ? "" : gcm; + } + + public static String commonMargin(@Nullable CharSequence s1, CharSequence s2) { + if (s1 == null) { + String s = s2.toString(); + return s.substring(s.lastIndexOf('\n') + 1); + } + for (int i = 0; i < s1.length() && i < s2.length(); i++) { + if (s1.charAt(i) != s2.charAt(i) || !Character.isWhitespace(s1.charAt(i))) { + return s1.toString().substring(0, i); + } + } + return s2.length() < s1.length() ? s2.toString() : s1.toString(); + } + + public static boolean isNumeric(String str) { + if (str == null) { + return false; + } + int sz = str.length(); + for (int i = 0; i < sz; i++) { + if (!Character.isDigit(str.charAt(i))) { + return false; + } + } + return true; + } + + /** + * See https://eclipse.org/aspectj/doc/next/progguide/semantics-pointcuts.html#type-patterns + *

+ * An embedded * in an identifier matches any sequence of characters, but + * does not match the package (or inner-type) separator ".". + *

+ * The ".." wildcard matches any sequence of characters that start and end with a ".", so it can be used to pick out all + * types in any subpackage, or all inner types. e.g. within(com.xerox..*) picks out all join points where + * the code is in any declaration of a type whose name begins with "com.xerox.". + */ + public static String aspectjNameToPattern(String name) { + return name + .replace("$", "\\$") + .replace("[", "\\[") + .replace("]", "\\]") + .replaceAll("([^.]*)\\.([^.]*)", "$1\\.$2") + .replace("*", "[^.]*") + .replace("..", "\\.(.+\\.)?"); + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/CaretRange.java b/rewrite-core/src/main/java/org/openrewrite/semver/CaretRange.java index d252e8d780c..d5282f9f931 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/CaretRange.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/CaretRange.java @@ -1,100 +1,100 @@ -/* - * 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 org.openrewrite.Validated; -import org.openrewrite.internal.lang.Nullable; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static java.lang.Integer.parseInt; - -/** - * Allows changes that do not modify the left-most non-zero element in the [major, minor, patch] tuple. - * Caret ranges. - */ -public class CaretRange extends LatestRelease { - private static final Pattern CARET_RANGE_PATTERN = Pattern.compile("\\^(\\d+)(?:\\.([*xX]|\\d+))?(?:\\.([*xX]|\\d+))?(?:\\.([*xX]|\\d+))?"); - - private final String upperExclusive; - private final String lower; - - private CaretRange(String lower, String upperExclusive, @Nullable String metadataPattern) { - super(metadataPattern); - this.lower = lower; - this.upperExclusive = upperExclusive; - } - - @Override - public boolean isValid(@Nullable String currentVersion, String version) { - return super.isValid(currentVersion, version) && - super.compare(currentVersion, version, upperExclusive) < 0 && - super.compare(currentVersion, version, lower) >= 0; - } - - public static Validated build(String pattern, @Nullable String metadataPattern) { - Matcher matcher = CARET_RANGE_PATTERN.matcher(pattern); - if (!matcher.matches()) { - return Validated.invalid("caretRange", pattern, "not a caret range"); - } - - String major = matcher.group(1); - String minor = normalizeWildcard(matcher.group(2)); - String patch = normalizeWildcard(matcher.group(3)); - String micro = normalizeWildcard(matcher.group(4)); - - if ("*".equals(minor) && (matcher.group(3) != null || matcher.group(4) != null)) { - return Validated.invalid("caretRange", pattern, "not a caret range: nothing can follow a wildcard"); - } else if ("*".equals(patch) && (matcher.group(4) != null)) { - return Validated.invalid("caretRange", pattern, "not a caret range: nothing can follow a wildcard"); - } - - String lower; - String upper; - - if (minor == null) { - // A missing patch value will desugar to the number 0, but will allow flexibility - // within that value, even if the major and minor versions are both 0. - lower = major; - } else if (patch == null) { - // A missing minor and patch values will desugar to zero, but also allow flexibility - // within those values, even if the major version is zero. - lower = major + "." + minor; - } else if (micro == null) { - lower = major + "." + minor + "." + patch; - } else { - lower = major + "." + minor + "." + patch + "." + micro; - } - - if (!"0".equals(major) || minor == null) { - upper = Integer.toString(parseInt(major) + 1); - } else if (!"0".equals(minor) || patch == null) { - upper = major + "." + (parseInt(minor) + 1); - } else if (!"0".equals(patch) && micro == null) { - upper = major + "." + minor + "." + patch; - } else { - upper = major + "." + minor + "." + patch + "." + micro; - } - - return Validated.valid("caretRange", new CaretRange(lower, upper, metadataPattern)); - } - - @Nullable - private static String normalizeWildcard(@Nullable String part) { - return "*".equals(part) || "x".equals(part) || "X".equals(part) ? null : part; - } -} +/* + * 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 org.openrewrite.Validated; +import org.openrewrite.internal.lang.Nullable; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.lang.Integer.parseInt; + +/** + * Allows changes that do not modify the left-most non-zero element in the [major, minor, patch] tuple. + * Caret ranges. + */ +public class CaretRange extends LatestRelease { + private static final Pattern CARET_RANGE_PATTERN = Pattern.compile("\\^(\\d+)(?:\\.([*xX]|\\d+))?(?:\\.([*xX]|\\d+))?(?:\\.([*xX]|\\d+))?"); + + private final String upperExclusive; + private final String lower; + + private CaretRange(String lower, String upperExclusive, @Nullable String metadataPattern) { + super(metadataPattern); + this.lower = lower; + this.upperExclusive = upperExclusive; + } + + @Override + public boolean isValid(@Nullable String currentVersion, String version) { + return super.isValid(currentVersion, version) && + super.compare(currentVersion, version, upperExclusive) < 0 && + super.compare(currentVersion, version, lower) >= 0; + } + + public static Validated build(String pattern, @Nullable String metadataPattern) { + Matcher matcher = CARET_RANGE_PATTERN.matcher(pattern); + if (!matcher.matches()) { + return Validated.invalid("caretRange", pattern, "not a caret range"); + } + + String major = matcher.group(1); + String minor = normalizeWildcard(matcher.group(2)); + String patch = normalizeWildcard(matcher.group(3)); + String micro = normalizeWildcard(matcher.group(4)); + + if ("*".equals(minor) && (matcher.group(3) != null || matcher.group(4) != null)) { + return Validated.invalid("caretRange", pattern, "not a caret range: nothing can follow a wildcard"); + } else if ("*".equals(patch) && (matcher.group(4) != null)) { + return Validated.invalid("caretRange", pattern, "not a caret range: nothing can follow a wildcard"); + } + + String lower; + String upper; + + if (minor == null) { + // A missing patch value will desugar to the number 0, but will allow flexibility + // within that value, even if the major and minor versions are both 0. + lower = major; + } else if (patch == null) { + // A missing minor and patch values will desugar to zero, but also allow flexibility + // within those values, even if the major version is zero. + lower = major + "." + minor; + } else if (micro == null) { + lower = major + "." + minor + "." + patch; + } else { + lower = major + "." + minor + "." + patch + "." + micro; + } + + if (!"0".equals(major) || minor == null) { + upper = Integer.toString(parseInt(major) + 1); + } else if (!"0".equals(minor) || patch == null) { + upper = major + "." + (parseInt(minor) + 1); + } else if (!"0".equals(patch) && micro == null) { + upper = major + "." + minor + "." + patch; + } else { + upper = major + "." + minor + "." + patch + "." + micro; + } + + return Validated.valid("caretRange", new CaretRange(lower, upper, metadataPattern)); + } + + @Nullable + private static String normalizeWildcard(@Nullable String part) { + return "*".equals(part) || "x".equals(part) || "X".equals(part) ? null : part; + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersion.java b/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersion.java index 745e91acd13..de3603b742e 100755 --- a/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersion.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/ExactVersion.java @@ -1,51 +1,51 @@ -/* - * 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 org.openrewrite.Validated; -import org.openrewrite.internal.lang.Nullable; - -public class ExactVersion extends LatestRelease { - String version; - - public ExactVersion(String pattern) { - super(pattern); - this.version = pattern; - } - - @Override - public boolean isValid(@Nullable String currentVersion, String version) { - return this.version.equals(version); - } - - public static Validated build(String pattern) { - String versionOnly; - int hyphenIndex = pattern.indexOf('-'); - if(hyphenIndex == -1) { - versionOnly = pattern; - } else { - versionOnly = pattern.substring(0, hyphenIndex); - } - if(versionOnly.startsWith("latest") || - versionOnly.contains("x") || - versionOnly.contains("^") || - versionOnly.contains("~") || - versionOnly.contains(" ")) { - return Validated.invalid("exactVersion", pattern, "not an exact version number"); - } - return Validated.valid("exactVersion", new ExactVersion(pattern)); - } -} +/* + * 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 org.openrewrite.Validated; +import org.openrewrite.internal.lang.Nullable; + +public class ExactVersion extends LatestRelease { + String version; + + public ExactVersion(String pattern) { + super(pattern); + this.version = pattern; + } + + @Override + public boolean isValid(@Nullable String currentVersion, String version) { + return this.version.equals(version); + } + + public static Validated build(String pattern) { + String versionOnly; + int hyphenIndex = pattern.indexOf('-'); + if(hyphenIndex == -1) { + versionOnly = pattern; + } else { + versionOnly = pattern.substring(0, hyphenIndex); + } + if(versionOnly.startsWith("latest") || + versionOnly.contains("x") || + versionOnly.contains("^") || + versionOnly.contains("~") || + versionOnly.contains(" ")) { + return Validated.invalid("exactVersion", pattern, "not an exact version number"); + } + return Validated.valid("exactVersion", new ExactVersion(pattern)); + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/HyphenRange.java b/rewrite-core/src/main/java/org/openrewrite/semver/HyphenRange.java index 10986b0d1c2..4fe08b9c1bc 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/HyphenRange.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/HyphenRange.java @@ -1,53 +1,53 @@ -/* - * 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 org.openrewrite.Validated; -import org.openrewrite.internal.lang.Nullable; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Hyphen ranges. - */ -public class HyphenRange extends LatestRelease { - private static final Pattern HYPHEN_RANGE_PATTERN = Pattern.compile("(\\d+(\\.\\d+)?(\\.\\d+)?(\\.\\d+)?)\\s*-\\s*(\\d+(\\.\\d+)?(\\.\\d+)?(\\.\\d+)?)"); - - private final String upper; - private final String lower; - - private HyphenRange(String lower, String upper, @Nullable String metadataPattern) { - super(metadataPattern); - this.lower = lower; - this.upper = upper; - } - - @Override - public boolean isValid(@Nullable String currentVersion, String version) { - return super.isValid(currentVersion, version) && - super.compare(currentVersion, version, upper) <= 0 && - super.compare(currentVersion, version, lower) >= 0; - } - - public static Validated build(String pattern, @Nullable String metadataPattern) { - Matcher matcher = HYPHEN_RANGE_PATTERN.matcher(pattern); - if (!matcher.matches()) { - return Validated.invalid("hyphenRange", pattern, "not a hyphen range"); - } - return Validated.valid("hyphenRange", new HyphenRange(matcher.group(1), matcher.group(5), metadataPattern)); - } -} +/* + * 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 org.openrewrite.Validated; +import org.openrewrite.internal.lang.Nullable; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Hyphen ranges. + */ +public class HyphenRange extends LatestRelease { + private static final Pattern HYPHEN_RANGE_PATTERN = Pattern.compile("(\\d+(\\.\\d+)?(\\.\\d+)?(\\.\\d+)?)\\s*-\\s*(\\d+(\\.\\d+)?(\\.\\d+)?(\\.\\d+)?)"); + + private final String upper; + private final String lower; + + private HyphenRange(String lower, String upper, @Nullable String metadataPattern) { + super(metadataPattern); + this.lower = lower; + this.upper = upper; + } + + @Override + public boolean isValid(@Nullable String currentVersion, String version) { + return super.isValid(currentVersion, version) && + super.compare(currentVersion, version, upper) <= 0 && + super.compare(currentVersion, version, lower) >= 0; + } + + public static Validated build(String pattern, @Nullable String metadataPattern) { + Matcher matcher = HYPHEN_RANGE_PATTERN.matcher(pattern); + if (!matcher.matches()) { + return Validated.invalid("hyphenRange", pattern, "not a hyphen range"); + } + return Validated.valid("hyphenRange", new HyphenRange(matcher.group(1), matcher.group(5), metadataPattern)); + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/LatestPatch.java b/rewrite-core/src/main/java/org/openrewrite/semver/LatestPatch.java index f5acb8af4a2..34e34ab358f 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/LatestPatch.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/LatestPatch.java @@ -1,48 +1,48 @@ -/* - * 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.openrewrite.Validated; -import org.openrewrite.internal.lang.Nullable; - -@Value -public class LatestPatch implements VersionComparator { - @Nullable - String metadataPattern; - - @Override - public boolean isValid(@Nullable String currentVersion, String version) { - //noinspection ConstantConditions - return TildeRange.build("~" + Semver.majorVersion(currentVersion) + "." + Semver.minorVersion(currentVersion), metadataPattern) - .getValue() - .isValid(currentVersion, version); - } - - @Override - public int compare(@Nullable String currentVersion, String v1, String 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.patch".equalsIgnoreCase(toVersion) ? - Validated.valid("latestPatch", new LatestPatch(metadataPattern)) : - Validated.invalid("latestPatch", toVersion, "not latest release"); - } -} +/* + * 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.openrewrite.Validated; +import org.openrewrite.internal.lang.Nullable; + +@Value +public class LatestPatch implements VersionComparator { + @Nullable + String metadataPattern; + + @Override + public boolean isValid(@Nullable String currentVersion, String version) { + //noinspection ConstantConditions + return TildeRange.build("~" + Semver.majorVersion(currentVersion) + "." + Semver.minorVersion(currentVersion), metadataPattern) + .getValue() + .isValid(currentVersion, version); + } + + @Override + public int compare(@Nullable String currentVersion, String v1, String 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.patch".equalsIgnoreCase(toVersion) ? + Validated.valid("latestPatch", new LatestPatch(metadataPattern)) : + Validated.invalid("latestPatch", 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 1803b7733bb..50b6f059f62 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/LatestRelease.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/LatestRelease.java @@ -1,136 +1,136 @@ -/* - * 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 org.openrewrite.Validated; -import org.openrewrite.internal.StringUtils; -import org.openrewrite.internal.lang.Nullable; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.regex.Matcher; - -import static java.lang.Integer.parseInt; - -public class LatestRelease implements VersionComparator { - @Nullable - private final String metadataPattern; - - public LatestRelease(@Nullable String metadataPattern) { - this.metadataPattern = metadataPattern; - } - - @Override - public boolean isValid(@Nullable String currentVersion, String version) { - Matcher matcher = VersionComparator.RELEASE_PATTERN.matcher(normalizeVersion(version)); - if (!matcher.matches() || PRE_RELEASE_ENDING.matcher(version).find()) { - return false; - } - return metadataPattern == null || - (StringUtils.isBlank(metadataPattern) && matcher.group(5) == null) || - (matcher.group(5) != null && matcher.group(5).matches(metadataPattern)); - } - - static String normalizeVersion(String version) { - if (version.endsWith(".RELEASE")) { - return version.substring(0, version.length() - ".RELEASE".length()); - } else if (version.endsWith(".FINAL") || version.endsWith(".Final")) { - return version.substring(0, version.length() - ".FINAL".length()); - } - - long versionParts = countVersionParts(version); - - if (versionParts < 2) { - String[] versionAndMetadata = version.split("(?=[-+])"); - for (; versionParts < 2; versionParts++) { - versionAndMetadata[0] += ".0"; - } - version = versionAndMetadata[0] + (versionAndMetadata.length > 1 ? - versionAndMetadata[1] : ""); - } - - return version; - } - - static long countVersionParts(String version) { - AtomicBoolean beforeMetadata = new AtomicBoolean(true); - return version.chars() - .filter(c -> { - if (c == '-' || c == '+') { - beforeMetadata.set(false); - } - return beforeMetadata.get(); - }) - .filter(c -> c == '.') - .count(); - } - - @SuppressWarnings("ResultOfMethodCallIgnored") - @Override - public int compare(@Nullable String currentVersion, String v1, String v2) { - StringBuilder nv1 = new StringBuilder(normalizeVersion(v1)); - StringBuilder nv2 = new StringBuilder(normalizeVersion(v2)); - - long vp1 = countVersionParts(nv1.toString()); - long vp2 = countVersionParts(nv2.toString()); - - long abs = Math.abs(vp1 - vp2); - if (vp1 > vp2) { - for (int i = 1; i <= abs; i++) { - nv2.append(".0"); - } - } else if (vp2 > vp1) { - for (int i = 1; i <= abs; i++) { - nv1.append(".0"); - } - } - - Matcher v1Gav = VersionComparator.RELEASE_PATTERN.matcher(nv1.toString()); - Matcher v2Gav = VersionComparator.RELEASE_PATTERN.matcher(nv2.toString()); - - v1Gav.matches(); - v2Gav.matches(); - - //Remove the metadata pattern from the normalized versions, this only impacts the comparison when all version - //parts are the same: - // - // HyphenRange [25-28] should include "28-jre" and "28-android" as possible candidates. - String normalized1 = metadataPattern == null ? nv1.toString() : nv1.toString().replace(metadataPattern, ""); - String normalized2 = metadataPattern == null ? nv2.toString() : nv1.toString().replace(metadataPattern, ""); - - for (int i = 1; i < nv1.length(); i++) { - String v1Part = v1Gav.group(i); - String v2Part = v2Gav.group(i); - if (v1Part == null) { - return v2Part == null ? normalized1.compareTo(normalized2) : -1; - } else if (v2Part == null) { - return 1; - } - - int diff = parseInt(v1Part) - parseInt(v2Part); - if (diff != 0) { - return diff; - } - } - - return normalized1.compareTo(normalized2); - } - - public static Validated build(String toVersion, @Nullable String metadataPattern) { - return "latest.release".equalsIgnoreCase(toVersion) ? - Validated.valid("latestRelease", new LatestRelease(metadataPattern)) : - Validated.invalid("latestRelease", toVersion, "not latest release"); - } -} +/* + * 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 org.openrewrite.Validated; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.internal.lang.Nullable; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; + +import static java.lang.Integer.parseInt; + +public class LatestRelease implements VersionComparator { + @Nullable + private final String metadataPattern; + + public LatestRelease(@Nullable String metadataPattern) { + this.metadataPattern = metadataPattern; + } + + @Override + public boolean isValid(@Nullable String currentVersion, String version) { + Matcher matcher = VersionComparator.RELEASE_PATTERN.matcher(normalizeVersion(version)); + if (!matcher.matches() || PRE_RELEASE_ENDING.matcher(version).find()) { + return false; + } + return metadataPattern == null || + (StringUtils.isBlank(metadataPattern) && matcher.group(5) == null) || + (matcher.group(5) != null && matcher.group(5).matches(metadataPattern)); + } + + static String normalizeVersion(String version) { + if (version.endsWith(".RELEASE")) { + return version.substring(0, version.length() - ".RELEASE".length()); + } else if (version.endsWith(".FINAL") || version.endsWith(".Final")) { + return version.substring(0, version.length() - ".FINAL".length()); + } + + long versionParts = countVersionParts(version); + + if (versionParts < 2) { + String[] versionAndMetadata = version.split("(?=[-+])"); + for (; versionParts < 2; versionParts++) { + versionAndMetadata[0] += ".0"; + } + version = versionAndMetadata[0] + (versionAndMetadata.length > 1 ? + versionAndMetadata[1] : ""); + } + + return version; + } + + static long countVersionParts(String version) { + AtomicBoolean beforeMetadata = new AtomicBoolean(true); + return version.chars() + .filter(c -> { + if (c == '-' || c == '+') { + beforeMetadata.set(false); + } + return beforeMetadata.get(); + }) + .filter(c -> c == '.') + .count(); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Override + public int compare(@Nullable String currentVersion, String v1, String v2) { + StringBuilder nv1 = new StringBuilder(normalizeVersion(v1)); + StringBuilder nv2 = new StringBuilder(normalizeVersion(v2)); + + long vp1 = countVersionParts(nv1.toString()); + long vp2 = countVersionParts(nv2.toString()); + + long abs = Math.abs(vp1 - vp2); + if (vp1 > vp2) { + for (int i = 1; i <= abs; i++) { + nv2.append(".0"); + } + } else if (vp2 > vp1) { + for (int i = 1; i <= abs; i++) { + nv1.append(".0"); + } + } + + Matcher v1Gav = VersionComparator.RELEASE_PATTERN.matcher(nv1.toString()); + Matcher v2Gav = VersionComparator.RELEASE_PATTERN.matcher(nv2.toString()); + + v1Gav.matches(); + v2Gav.matches(); + + //Remove the metadata pattern from the normalized versions, this only impacts the comparison when all version + //parts are the same: + // + // HyphenRange [25-28] should include "28-jre" and "28-android" as possible candidates. + String normalized1 = metadataPattern == null ? nv1.toString() : nv1.toString().replace(metadataPattern, ""); + String normalized2 = metadataPattern == null ? nv2.toString() : nv1.toString().replace(metadataPattern, ""); + + for (int i = 1; i < nv1.length(); i++) { + String v1Part = v1Gav.group(i); + String v2Part = v2Gav.group(i); + if (v1Part == null) { + return v2Part == null ? normalized1.compareTo(normalized2) : -1; + } else if (v2Part == null) { + return 1; + } + + int diff = parseInt(v1Part) - parseInt(v2Part); + if (diff != 0) { + return diff; + } + } + + return normalized1.compareTo(normalized2); + } + + public static Validated build(String toVersion, @Nullable String metadataPattern) { + return "latest.release".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 ba5a75c0381..956f7d7341a 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/Semver.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/Semver.java @@ -1,77 +1,77 @@ -/* - * 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 org.openrewrite.Incubating; -import org.openrewrite.Validated; -import org.openrewrite.internal.lang.Nullable; - -import java.util.Scanner; -import java.util.regex.Pattern; - -import static org.openrewrite.Validated.test; - -public class Semver { - private Semver() { - } - - public static Validated validate(String toVersion, @Nullable String metadataPattern) { - return test( - "metadataPattern", - "must be a valid regular expression", - metadataPattern, metadata -> { - try { - if (metadata != null) { - Pattern.compile(metadata); - } - return true; - } catch (Throwable e) { - return false; - } - } - ).and(LatestRelease.build(toVersion, metadataPattern) - .or(LatestPatch.build(toVersion, metadataPattern)) - .or(HyphenRange.build(toVersion, metadataPattern)) - .or(XRange.build(toVersion, metadataPattern)) - .or(TildeRange.build(toVersion, metadataPattern)) - .or(CaretRange.build(toVersion, metadataPattern)) - .or(ExactVersion.build(toVersion)) - ); - } - - @Incubating(since = "7.16.0") - public static String majorVersion(String version) { - Scanner scanner = new Scanner(version); - scanner.useDelimiter("[.$]"); - if (scanner.hasNext()) { - return scanner.next(); - } - return version; - } - - @Incubating(since = "7.16.0") - public static String minorVersion(String version) { - Scanner scanner = new Scanner(version); - scanner.useDelimiter("[.$]"); - if (scanner.hasNext()) { - scanner.next(); - } - if (scanner.hasNext()) { - return scanner.next(); - } - return version; - } -} +/* + * 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 org.openrewrite.Incubating; +import org.openrewrite.Validated; +import org.openrewrite.internal.lang.Nullable; + +import java.util.Scanner; +import java.util.regex.Pattern; + +import static org.openrewrite.Validated.test; + +public class Semver { + private Semver() { + } + + public static Validated validate(String toVersion, @Nullable String metadataPattern) { + return test( + "metadataPattern", + "must be a valid regular expression", + metadataPattern, metadata -> { + try { + if (metadata != null) { + Pattern.compile(metadata); + } + return true; + } catch (Throwable e) { + return false; + } + } + ).and(LatestRelease.build(toVersion, metadataPattern) + .or(LatestPatch.build(toVersion, metadataPattern)) + .or(HyphenRange.build(toVersion, metadataPattern)) + .or(XRange.build(toVersion, metadataPattern)) + .or(TildeRange.build(toVersion, metadataPattern)) + .or(CaretRange.build(toVersion, metadataPattern)) + .or(ExactVersion.build(toVersion)) + ); + } + + @Incubating(since = "7.16.0") + public static String majorVersion(String version) { + Scanner scanner = new Scanner(version); + scanner.useDelimiter("[.$]"); + if (scanner.hasNext()) { + return scanner.next(); + } + return version; + } + + @Incubating(since = "7.16.0") + public static String minorVersion(String version) { + Scanner scanner = new Scanner(version); + scanner.useDelimiter("[.$]"); + if (scanner.hasNext()) { + scanner.next(); + } + if (scanner.hasNext()) { + return scanner.next(); + } + return version; + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/TildeRange.java b/rewrite-core/src/main/java/org/openrewrite/semver/TildeRange.java index 6d4733302cb..f0fa2e52e0b 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/TildeRange.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/TildeRange.java @@ -1,79 +1,79 @@ -/* - * 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 org.openrewrite.Validated; -import org.openrewrite.internal.lang.Nullable; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static java.lang.Integer.parseInt; - -/** - * Allows patch-level changes if a minor version is specified on the comparator. Allows minor-level changes if not. - * Tilde ranges. - */ -public class TildeRange extends LatestRelease { - private static final Pattern TILDE_RANGE_PATTERN = Pattern.compile("~(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:\\.(\\d+))?"); - - private final String upperExclusive; - private final String lower; - - private TildeRange(String lower, String upperExclusive, @Nullable String metadataPattern) { - super(metadataPattern); - this.lower = lower; - this.upperExclusive = upperExclusive; - } - - @Override - public boolean isValid(@Nullable String currentVersion, String version) { - return super.isValid(currentVersion, version) && - super.compare(currentVersion, version, upperExclusive) < 0 && - super.compare(currentVersion, version, lower) >= 0; - } - - public static Validated build(String pattern, @Nullable String metadataPattern) { - Matcher matcher = TILDE_RANGE_PATTERN.matcher(pattern); - if (!matcher.matches()) { - return Validated.invalid("tildeRange", pattern, "not a tilde range"); - } - - String major = matcher.group(1); - String minor = matcher.group(2); - String patch = matcher.group(3); - String micro = matcher.group(4); - - String lower; - String upper; - - if (minor == null) { - lower = major; - upper = Integer.toString(parseInt(major) + 1); - } else if (patch == null) { - lower = major + "." + minor; - upper = major + "." + (parseInt(minor) + 1); - } else if (micro == null) { - lower = major + "." + minor + "." + patch; - upper = major + "." + (parseInt(minor) + 1); - } else { - lower = major + "." + minor + "." + patch + "." + micro; - upper = major + "." + minor + "." + (parseInt(patch) + 1); - } - - return Validated.valid("tildeRange", new TildeRange(lower, upper, metadataPattern)); - } -} +/* + * 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 org.openrewrite.Validated; +import org.openrewrite.internal.lang.Nullable; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.lang.Integer.parseInt; + +/** + * Allows patch-level changes if a minor version is specified on the comparator. Allows minor-level changes if not. + * Tilde ranges. + */ +public class TildeRange extends LatestRelease { + private static final Pattern TILDE_RANGE_PATTERN = Pattern.compile("~(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:\\.(\\d+))?"); + + private final String upperExclusive; + private final String lower; + + private TildeRange(String lower, String upperExclusive, @Nullable String metadataPattern) { + super(metadataPattern); + this.lower = lower; + this.upperExclusive = upperExclusive; + } + + @Override + public boolean isValid(@Nullable String currentVersion, String version) { + return super.isValid(currentVersion, version) && + super.compare(currentVersion, version, upperExclusive) < 0 && + super.compare(currentVersion, version, lower) >= 0; + } + + public static Validated build(String pattern, @Nullable String metadataPattern) { + Matcher matcher = TILDE_RANGE_PATTERN.matcher(pattern); + if (!matcher.matches()) { + return Validated.invalid("tildeRange", pattern, "not a tilde range"); + } + + String major = matcher.group(1); + String minor = matcher.group(2); + String patch = matcher.group(3); + String micro = matcher.group(4); + + String lower; + String upper; + + if (minor == null) { + lower = major; + upper = Integer.toString(parseInt(major) + 1); + } else if (patch == null) { + lower = major + "." + minor; + upper = major + "." + (parseInt(minor) + 1); + } else if (micro == null) { + lower = major + "." + minor + "." + patch; + upper = major + "." + (parseInt(minor) + 1); + } else { + lower = major + "." + minor + "." + patch + "." + micro; + upper = major + "." + minor + "." + (parseInt(patch) + 1); + } + + return Validated.valid("tildeRange", new TildeRange(lower, upper, metadataPattern)); + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/VersionComparator.java b/rewrite-core/src/main/java/org/openrewrite/semver/VersionComparator.java index 52394d1cf79..cb00339fe00 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/VersionComparator.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/VersionComparator.java @@ -1,60 +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 org.openrewrite.internal.lang.Nullable; - -import java.util.Collection; -import java.util.Comparator; -import java.util.Optional; -import java.util.regex.Pattern; - -public interface VersionComparator extends Comparator { - Pattern RELEASE_PATTERN = Pattern.compile("(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:\\.(\\d+))?([-+].*)?"); - Pattern PRE_RELEASE_ENDING = Pattern.compile("[.-](SNAPSHOT|RC|rc|M|m|beta|alpha)[.-]?\\d*$"); - - @Deprecated - default boolean isValid(String version) { - return isValid(null, version); - } - - boolean isValid(@Nullable String currentVersion, String version); - - @Deprecated - @Override - default int compare(String v1, String v2) { - return compare(null, v1, v2); - } - - int compare(@Nullable String currentVersion, String v1, String v2); - - default Optional upgrade(String currentVersion, Collection availableVersions) { - boolean seen = false; - String best = null; - for (String availableVersion : availableVersions) { - if (isValid(currentVersion, availableVersion)) { - if (compare(currentVersion, currentVersion, availableVersion) <= 0) { - if (!seen || compare(currentVersion, availableVersion, best) > 0) { - seen = true; - best = availableVersion; - } - } - } - } - return (seen ? Optional.of(best) : Optional.empty()) - .filter(v -> !v.equals(currentVersion)); - } -} +/* + * 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 org.openrewrite.internal.lang.Nullable; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Optional; +import java.util.regex.Pattern; + +public interface VersionComparator extends Comparator { + Pattern RELEASE_PATTERN = Pattern.compile("(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:\\.(\\d+))?([-+].*)?"); + Pattern PRE_RELEASE_ENDING = Pattern.compile("[.-](SNAPSHOT|RC|rc|M|m|beta|alpha)[.-]?\\d*$"); + + @Deprecated + default boolean isValid(String version) { + return isValid(null, version); + } + + boolean isValid(@Nullable String currentVersion, String version); + + @Deprecated + @Override + default int compare(String v1, String v2) { + return compare(null, v1, v2); + } + + int compare(@Nullable String currentVersion, String v1, String v2); + + default Optional upgrade(String currentVersion, Collection availableVersions) { + boolean seen = false; + String best = null; + for (String availableVersion : availableVersions) { + if (isValid(currentVersion, availableVersion)) { + if (compare(currentVersion, currentVersion, availableVersion) <= 0) { + if (!seen || compare(currentVersion, availableVersion, best) > 0) { + seen = true; + best = availableVersion; + } + } + } + } + return (seen ? Optional.of(best) : Optional.empty()) + .filter(v -> !v.equals(currentVersion)); + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/semver/XRange.java b/rewrite-core/src/main/java/org/openrewrite/semver/XRange.java index acc79145aa8..04d963b9393 100644 --- a/rewrite-core/src/main/java/org/openrewrite/semver/XRange.java +++ b/rewrite-core/src/main/java/org/openrewrite/semver/XRange.java @@ -1,102 +1,102 @@ -/* - * 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 org.openrewrite.Validated; -import org.openrewrite.internal.lang.Nullable; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple. - * X-Ranges. - */ -public class XRange extends LatestRelease { - private static final Pattern X_RANGE_PATTERN = Pattern.compile("([*xX]|\\d+)(?:\\.([*xX]|\\d+)(?:\\.([*xX]|\\d+))?(?:\\.([*xX]|\\d+))?)?"); - - private final String major; - private final String minor; - private final String patch; - private final String micro; - - XRange(String major, String minor, String patch, String micro, @Nullable String metadataPattern) { - super(metadataPattern); - this.major = major; - this.minor = minor; - this.patch = patch; - this.micro = micro; - } - - @SuppressWarnings("ResultOfMethodCallIgnored") - @Override - public boolean isValid(@Nullable String currentVersion, String version) { - if (!super.isValid(currentVersion, version)) { - return false; - } - - if ("*".equals(major)) { - return true; - } - - Matcher gav = VersionComparator.RELEASE_PATTERN.matcher(normalizeVersion(version)); - gav.matches(); - - if (!gav.group(1).equals(major)) { - return false; - } - - if ("*".equals(minor)) { - return true; - } else if (gav.group(2) == null || !gav.group(2).equals(minor)) { - return false; - } - - if ("*".equals(patch)) { - return true; - } else if (gav.group(3) == null || !gav.group(3).equals(patch)) { - return false; - } - - return gav.group(4) == null || !gav.group(4).equals(micro); - } - - public static Validated build(String pattern, @Nullable String metadataPattern) { - Matcher matcher = X_RANGE_PATTERN.matcher(pattern); - if (!matcher.matches() || !(pattern.contains("x") || pattern.contains("X") || pattern.contains("*"))) { - return Validated.invalid("xRange", pattern, "not an x-range"); - } - - String major = normalizeWildcard(matcher.group(1)); - String minor = normalizeWildcard(matcher.group(2) == null ? "0" : matcher.group(2)); - String patch = normalizeWildcard(matcher.group(3) == null ? "0" : matcher.group(3)); - String micro = normalizeWildcard(matcher.group(4) == null ? "0" : matcher.group(4)); - - if ("*".equals(major) && (matcher.group(2) != null || matcher.group(3) != null || matcher.group(4) != null)) { - return Validated.invalid("xRange", pattern, "not an x-range: nothing can follow a wildcard"); - } else if ("*".equals(minor) && (matcher.group(3) != null || matcher.group(4) != null)) { - return Validated.invalid("xRange", pattern, "not an x-range: nothing can follow a wildcard"); - } else if ("*".equals(patch) && matcher.group(4) != null) { - return Validated.invalid("xRange", pattern, "not an x-range: nothing can follow a wildcard"); - } - - return Validated.valid("xRange", new XRange(major, minor, patch, micro, metadataPattern)); - } - - private static String normalizeWildcard(String part) { - return "*".equals(part) || "x".equals(part) || "X".equals(part) ? "*" : part; - } -} +/* + * 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 org.openrewrite.Validated; +import org.openrewrite.internal.lang.Nullable; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Any of X, x, or * may be used to "stand in" for one of the numeric values in the [major, minor, patch] tuple. + * X-Ranges. + */ +public class XRange extends LatestRelease { + private static final Pattern X_RANGE_PATTERN = Pattern.compile("([*xX]|\\d+)(?:\\.([*xX]|\\d+)(?:\\.([*xX]|\\d+))?(?:\\.([*xX]|\\d+))?)?"); + + private final String major; + private final String minor; + private final String patch; + private final String micro; + + XRange(String major, String minor, String patch, String micro, @Nullable String metadataPattern) { + super(metadataPattern); + this.major = major; + this.minor = minor; + this.patch = patch; + this.micro = micro; + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Override + public boolean isValid(@Nullable String currentVersion, String version) { + if (!super.isValid(currentVersion, version)) { + return false; + } + + if ("*".equals(major)) { + return true; + } + + Matcher gav = VersionComparator.RELEASE_PATTERN.matcher(normalizeVersion(version)); + gav.matches(); + + if (!gav.group(1).equals(major)) { + return false; + } + + if ("*".equals(minor)) { + return true; + } else if (gav.group(2) == null || !gav.group(2).equals(minor)) { + return false; + } + + if ("*".equals(patch)) { + return true; + } else if (gav.group(3) == null || !gav.group(3).equals(patch)) { + return false; + } + + return gav.group(4) == null || !gav.group(4).equals(micro); + } + + public static Validated build(String pattern, @Nullable String metadataPattern) { + Matcher matcher = X_RANGE_PATTERN.matcher(pattern); + if (!matcher.matches() || !(pattern.contains("x") || pattern.contains("X") || pattern.contains("*"))) { + return Validated.invalid("xRange", pattern, "not an x-range"); + } + + String major = normalizeWildcard(matcher.group(1)); + String minor = normalizeWildcard(matcher.group(2) == null ? "0" : matcher.group(2)); + String patch = normalizeWildcard(matcher.group(3) == null ? "0" : matcher.group(3)); + String micro = normalizeWildcard(matcher.group(4) == null ? "0" : matcher.group(4)); + + if ("*".equals(major) && (matcher.group(2) != null || matcher.group(3) != null || matcher.group(4) != null)) { + return Validated.invalid("xRange", pattern, "not an x-range: nothing can follow a wildcard"); + } else if ("*".equals(minor) && (matcher.group(3) != null || matcher.group(4) != null)) { + return Validated.invalid("xRange", pattern, "not an x-range: nothing can follow a wildcard"); + } else if ("*".equals(patch) && matcher.group(4) != null) { + return Validated.invalid("xRange", pattern, "not an x-range: nothing can follow a wildcard"); + } + + return Validated.valid("xRange", new XRange(major, minor, patch, micro, metadataPattern)); + } + + private static String normalizeWildcard(String part) { + return "*".equals(part) || "x".equals(part) || "X".equals(part) ? "*" : part; + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/style/Style.java b/rewrite-core/src/main/java/org/openrewrite/style/Style.java index 1485ccfbe4c..4b2614a2280 100644 --- a/rewrite-core/src/main/java/org/openrewrite/style/Style.java +++ b/rewrite-core/src/main/java/org/openrewrite/style/Style.java @@ -1,43 +1,43 @@ -/* - * 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.style; - -import com.fasterxml.jackson.annotation.JsonIdentityInfo; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.ObjectIdGenerators; -import org.openrewrite.SourceFile; - -/** - * Styles represent project-level standards that each source file is expected to follow, e.g. - * import ordering. They are provided to parser implementations and expected to be stored on - * {@link SourceFile} instances so that any modifications to those source files can conform - * to the source's expected styles. - */ -@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "@ref") -@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@c") -public interface Style { - @JsonProperty("@c") - default String getJacksonPolymorphicTypeTag() { - return getClass().getName(); - } - - default Style merge(Style lowerPrecedence) { - return this; - } - - default Style applyDefaults() { return this; } -} +/* + * 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.style; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.ObjectIdGenerators; +import org.openrewrite.SourceFile; + +/** + * Styles represent project-level standards that each source file is expected to follow, e.g. + * import ordering. They are provided to parser implementations and expected to be stored on + * {@link SourceFile} instances so that any modifications to those source files can conform + * to the source's expected styles. + */ +@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "@ref") +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@c") +public interface Style { + @JsonProperty("@c") + default String getJacksonPolymorphicTypeTag() { + return getClass().getName(); + } + + default Style merge(Style lowerPrecedence) { + return this; + } + + default Style applyDefaults() { return this; } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/style/package-info.java b/rewrite-core/src/main/java/org/openrewrite/style/package-info.java index ff766edd910..8fe368b70ae 100755 --- a/rewrite-core/src/main/java/org/openrewrite/style/package-info.java +++ b/rewrite-core/src/main/java/org/openrewrite/style/package-info.java @@ -1,19 +1,19 @@ -/* - * 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. - */ -@NonNullApi -package org.openrewrite.style; - -import org.openrewrite.internal.lang.NonNullApi; +/* + * 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. + */ +@NonNullApi +package org.openrewrite.style; + +import org.openrewrite.internal.lang.NonNullApi; diff --git a/rewrite-core/src/main/java/org/openrewrite/text/ChangeText.java b/rewrite-core/src/main/java/org/openrewrite/text/ChangeText.java index 2adfe121e13..c132ddd6d9e 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/ChangeText.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/ChangeText.java @@ -1,67 +1,67 @@ -/* - * 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.text; - -import org.openrewrite.*; - -import java.util.Collections; -import java.util.Set; - -import static org.openrewrite.Validated.required; - -public class ChangeText extends Recipe { - - @Option(displayName = "Text after change", - description = "The text file will have only this text after the change.", - example = "Some text.") - private final String toText; - - public ChangeText(String toText) { - this.toText = toText; - } - - @Override - public Set getTags() { - return Collections.singleton("plain text"); - } - - @Override - public String getDisplayName() { - return "Change text"; - } - - @Override - public String getDescription() { - return "Completely replaces the contents of the text file with other text."; - } - - @Override - protected TreeVisitor getVisitor() { - return new ChangeTextVisitor(); - } - - @Override - public Validated validate() { - return required("toText", toText); - } - - private class ChangeTextVisitor extends PlainTextVisitor { - @Override - public PlainText preVisit(PlainText tree, ExecutionContext ctx) { - return tree.withText(toText); - } - } -} +/* + * 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.text; + +import org.openrewrite.*; + +import java.util.Collections; +import java.util.Set; + +import static org.openrewrite.Validated.required; + +public class ChangeText extends Recipe { + + @Option(displayName = "Text after change", + description = "The text file will have only this text after the change.", + example = "Some text.") + private final String toText; + + public ChangeText(String toText) { + this.toText = toText; + } + + @Override + public Set getTags() { + return Collections.singleton("plain text"); + } + + @Override + public String getDisplayName() { + return "Change text"; + } + + @Override + public String getDescription() { + return "Completely replaces the contents of the text file with other text."; + } + + @Override + protected TreeVisitor getVisitor() { + return new ChangeTextVisitor(); + } + + @Override + public Validated validate() { + return required("toText", toText); + } + + private class ChangeTextVisitor extends PlainTextVisitor { + @Override + public PlainText preVisit(PlainText tree, ExecutionContext ctx) { + return tree.withText(toText); + } + } +} 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 c77e46e7d5d..fe17551ae55 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/PlainText.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/PlainText.java @@ -1,77 +1,77 @@ -/* - * 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.text; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Value; -import lombok.With; -import org.openrewrite.*; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.marker.Markers; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.util.UUID; - -/** - * The simplest of all ASTs representing nothing more than just unstructured text. - */ -@Value -@With -public class PlainText implements SourceFile, Tree { - UUID id; - - Path sourcePath; - - @Nullable // for backwards compatibility - @With(AccessLevel.PRIVATE) - String charsetName; - - @With - @Getter - boolean charsetBomMarked; - - @Override - public Charset getCharset() { - return charsetName == null ? StandardCharsets.UTF_8 : Charset.forName(charsetName); - } - - @Override - public SourceFile withCharset(Charset charset) { - return withCharsetName(charset.name()); - } - - Markers markers; - String text; - - @Override - public

boolean isAcceptable(TreeVisitor v, P p) { - return v instanceof PlainTextVisitor; - } - - @SuppressWarnings("unchecked") - @Override - public R accept(TreeVisitor v, P p) { - return (R) ((PlainTextVisitor

) v).visitText(this, p); - } - - @Override - public

TreeVisitor> printer(Cursor cursor) { - return new PlainTextPrinter<>(); - } -} +/* + * 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.text; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Value; +import lombok.With; +import org.openrewrite.*; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.marker.Markers; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.UUID; + +/** + * The simplest of all ASTs representing nothing more than just unstructured text. + */ +@Value +@With +public class PlainText implements SourceFile, Tree { + UUID id; + + Path sourcePath; + + @Nullable // for backwards compatibility + @With(AccessLevel.PRIVATE) + String charsetName; + + @With + @Getter + boolean charsetBomMarked; + + @Override + public Charset getCharset() { + return charsetName == null ? StandardCharsets.UTF_8 : Charset.forName(charsetName); + } + + @Override + public SourceFile withCharset(Charset charset) { + return withCharsetName(charset.name()); + } + + Markers markers; + String text; + + @Override + public

boolean isAcceptable(TreeVisitor v, P p) { + return v instanceof PlainTextVisitor; + } + + @SuppressWarnings("unchecked") + @Override + public R accept(TreeVisitor v, P p) { + return (R) ((PlainTextVisitor

) v).visitText(this, p); + } + + @Override + public

TreeVisitor> printer(Cursor cursor) { + return new PlainTextPrinter<>(); + } +} diff --git a/rewrite-core/src/main/java/org/openrewrite/text/TextStyle.java b/rewrite-core/src/main/java/org/openrewrite/text/TextStyle.java index 7b549b3bd1c..aeb02f5e316 100644 --- a/rewrite-core/src/main/java/org/openrewrite/text/TextStyle.java +++ b/rewrite-core/src/main/java/org/openrewrite/text/TextStyle.java @@ -1,30 +1,30 @@ -/* - * 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.text; - -import org.openrewrite.style.Style; - -public class TextStyle implements Style { - private String charset; - - public String getCharset() { - return charset; - } - - public void setCharset(String charset) { - this.charset = charset; - } -} +/* + * 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.text; + +import org.openrewrite.style.Style; + +public class TextStyle implements Style { + private String charset; + + public String getCharset() { + return charset; + } + + public void setCharset(String charset) { + this.charset = charset; + } +} diff --git a/rewrite-core/src/test/kotlin/org/openrewrite/internal/NameCaseConventionTest.kt b/rewrite-core/src/test/kotlin/org/openrewrite/internal/NameCaseConventionTest.kt index caf4d5c819b..178c6fa8406 100644 --- a/rewrite-core/src/test/kotlin/org/openrewrite/internal/NameCaseConventionTest.kt +++ b/rewrite-core/src/test/kotlin/org/openrewrite/internal/NameCaseConventionTest.kt @@ -1,135 +1,135 @@ -/* - * 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.internal - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.CsvSource - -@Suppress("SpellCheckingInspection") -class NameCaseConventionTest { - - @ParameterizedTest - @CsvSource( - value = [ - "foo.config-client.enabled:foo.config-client.enabled", - "com.fooBar.FooBar:com.foo-bar.foo-bar", - "foo_bar.bar:foo-bar.bar", - "FooBar:foo-bar", - "com.bar.FooBar:com.bar.foo-bar", - "Foo:foo", - "FooBBar:foo-bbar", - "fooBBar:foo-bbar", - "fooBar:foo-bar", - "foo bar:foo-bar", - " foo bar :foo-bar", - ], delimiter = ':' - ) - fun lowerHyphen(input: String, expected: String) { - assertThat(NameCaseConvention.LOWER_HYPHEN.format(input)).isEqualTo(expected) - } - - @ParameterizedTest - @CsvSource( - value = [ - "a:a", - "abc:abc", - "1:1", - "123:123", - "1a:1a", - "a1:a1", - "\$:\$", - "\$a:\$a", - "a\$:a\$", - "a\$a:a\$a", - "a_a:a_a", - "Foo:foo", - "Foo-Bar:foo_bar", - "FOO.FOO-BAR:foo.foo_bar", - "foo bar:foo_bar", - " foo bar :foo_bar", - ], delimiter = ':' - ) - fun lowerUnderscore(input: String, expected: String) { - assertThat(NameCaseConvention.LOWER_UNDERSCORE.format(input)).isEqualTo(expected) - } - - @ParameterizedTest - @CsvSource( - value = [ - "rename_one:renameOne", - "RenameTwo:renameTwo", - "__rename__three__:renameThree", - "_Rename___Four_:renameFour", - "\$a:\$a", - "a\$:a\$", - "a\$a:a\$a", - "a_a:aA", - "_a:a", - "foo.config-client.enabled:foo.configClient.enabled", - "foo-bar:fooBar", - "foo bar:fooBar", - " foo bar :fooBar", - ], delimiter = ':' - ) - fun lowerCamel(input: String, expected: String) { - assertThat(NameCaseConvention.LOWER_CAMEL.format(input)).isEqualTo(expected) - } - - @ParameterizedTest - @CsvSource( - value = [ - "rename_one:RenameOne", - "RenameTwo:RenameTwo", - "__rename__three__:RenameThree", - "_Rename__Four:RenameFour", - "foo-bar:FooBar", - "foo bar:FooBar", - " foo bar :FooBar", - ], delimiter = ':' - ) - fun upperCamel(input: String, expected: String) { - assertThat(NameCaseConvention.UPPER_CAMEL.format(input)).isEqualTo(expected) - } - - @ParameterizedTest - @CsvSource( - value = [ - "foo:FOO", - "foo-bar:FOO_BAR", - "foo_bar:FOO_BAR", - "FooBar:FOO_BAR", - "Foo.fooBar:FOO.FOO_BAR", - "foo bar:FOO_BAR", - " foo bar :FOO_BAR", - ], delimiter = ':' - ) - fun upperUnderscore(input: String, expected: String) { - assertThat(NameCaseConvention.UPPER_UNDERSCORE.format(input)).isEqualTo(expected) - } - - @ParameterizedTest - @CsvSource( - value = [ - "foo.fooBar:foo.foo-bar", - "foo.foo-bar:foo.fooBar", - ], delimiter = ':' - ) - fun equalsRelaxedBinding(input: String, expected: String) { - assertThat(NameCaseConvention.equalsRelaxedBinding(input, expected)).isTrue - } - -} +/* + * 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.internal + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.CsvSource + +@Suppress("SpellCheckingInspection") +class NameCaseConventionTest { + + @ParameterizedTest + @CsvSource( + value = [ + "foo.config-client.enabled:foo.config-client.enabled", + "com.fooBar.FooBar:com.foo-bar.foo-bar", + "foo_bar.bar:foo-bar.bar", + "FooBar:foo-bar", + "com.bar.FooBar:com.bar.foo-bar", + "Foo:foo", + "FooBBar:foo-bbar", + "fooBBar:foo-bbar", + "fooBar:foo-bar", + "foo bar:foo-bar", + " foo bar :foo-bar", + ], delimiter = ':' + ) + fun lowerHyphen(input: String, expected: String) { + assertThat(NameCaseConvention.LOWER_HYPHEN.format(input)).isEqualTo(expected) + } + + @ParameterizedTest + @CsvSource( + value = [ + "a:a", + "abc:abc", + "1:1", + "123:123", + "1a:1a", + "a1:a1", + "\$:\$", + "\$a:\$a", + "a\$:a\$", + "a\$a:a\$a", + "a_a:a_a", + "Foo:foo", + "Foo-Bar:foo_bar", + "FOO.FOO-BAR:foo.foo_bar", + "foo bar:foo_bar", + " foo bar :foo_bar", + ], delimiter = ':' + ) + fun lowerUnderscore(input: String, expected: String) { + assertThat(NameCaseConvention.LOWER_UNDERSCORE.format(input)).isEqualTo(expected) + } + + @ParameterizedTest + @CsvSource( + value = [ + "rename_one:renameOne", + "RenameTwo:renameTwo", + "__rename__three__:renameThree", + "_Rename___Four_:renameFour", + "\$a:\$a", + "a\$:a\$", + "a\$a:a\$a", + "a_a:aA", + "_a:a", + "foo.config-client.enabled:foo.configClient.enabled", + "foo-bar:fooBar", + "foo bar:fooBar", + " foo bar :fooBar", + ], delimiter = ':' + ) + fun lowerCamel(input: String, expected: String) { + assertThat(NameCaseConvention.LOWER_CAMEL.format(input)).isEqualTo(expected) + } + + @ParameterizedTest + @CsvSource( + value = [ + "rename_one:RenameOne", + "RenameTwo:RenameTwo", + "__rename__three__:RenameThree", + "_Rename__Four:RenameFour", + "foo-bar:FooBar", + "foo bar:FooBar", + " foo bar :FooBar", + ], delimiter = ':' + ) + fun upperCamel(input: String, expected: String) { + assertThat(NameCaseConvention.UPPER_CAMEL.format(input)).isEqualTo(expected) + } + + @ParameterizedTest + @CsvSource( + value = [ + "foo:FOO", + "foo-bar:FOO_BAR", + "foo_bar:FOO_BAR", + "FooBar:FOO_BAR", + "Foo.fooBar:FOO.FOO_BAR", + "foo bar:FOO_BAR", + " foo bar :FOO_BAR", + ], delimiter = ':' + ) + fun upperUnderscore(input: String, expected: String) { + assertThat(NameCaseConvention.UPPER_UNDERSCORE.format(input)).isEqualTo(expected) + } + + @ParameterizedTest + @CsvSource( + value = [ + "foo.fooBar:foo.foo-bar", + "foo.foo-bar:foo.fooBar", + ], delimiter = ':' + ) + fun equalsRelaxedBinding(input: String, expected: String) { + assertThat(NameCaseConvention.equalsRelaxedBinding(input, expected)).isTrue + } + +} diff --git a/rewrite-core/src/test/kotlin/org/openrewrite/internal/StringUtilsTest.kt b/rewrite-core/src/test/kotlin/org/openrewrite/internal/StringUtilsTest.kt index 367ea80ef77..1ef4647bcb7 100644 --- a/rewrite-core/src/test/kotlin/org/openrewrite/internal/StringUtilsTest.kt +++ b/rewrite-core/src/test/kotlin/org/openrewrite/internal/StringUtilsTest.kt @@ -1,276 +1,276 @@ -/* - * 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.internal - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.openrewrite.internal.StringUtils.* - -class StringUtilsTest { - @Test - fun detectIndentLevel() { - assertThat(indentLevel(""" - |< - | < - | < - | < - |< - """.trimMargin())).isEqualTo(0) - - assertThat(indentLevel(""" - |< - | < - """.trimMargin())).isEqualTo(3) - - assertThat(indentLevel(""" - |< - | < - | < - """.trimMargin())).isEqualTo(4) - - // ignores the last line if it is all blank - assertThat(indentLevel(""" - class { - A field; - } - """)).isEqualTo(12) - - assertThat(indentLevel(""" - | < - | < - | < - | < - """.trimMargin())).isEqualTo(1) - - assertThat(indentLevel(""" - | < - | < - | < - | < - | < - """.trimMargin())).isEqualTo(1) - - assertThat(indentLevel(""" - |< - |< - """.trimMargin())).isEqualTo(0) - - // doesn't consider newlines that occur as the first character on the first line or terminating newlines - assertThat(indentLevel(""" - | - | < - | < - | < - | - """.trimMargin())).isEqualTo(2) - } - - @Test - fun trimIndentBlankLines() { - val input = """ - - class { - - A field; - } - """ - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun trimIndentEndLineNonWhitespace() { - val input = """ - - class { - - A field; - } - hello""" - System.out.println("Kotlin : '" + input.trimIndent() + "'") - - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun trimIndentFirstLineSameAsIndent() { - val input = """ - - class { - - A field; - } - """ - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun trimIndentFirstLineGreaterThanIndent() { - val input = """ - - class { - - A field; - } - """ - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun trimIndentFirstLineEmpty() { - val input = """ - - class { - - A field; - } - """ - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun trimIndentNoNewLine() { - val input = " a" - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun trimIndentOneCharacter() { - val input = "a" - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun trimIndentFirstLineNotEmpty() { - val input = """ - fred - class { - - A field; - } - """ - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun trimIndentFirstCharacterNotLineBreak() { - val input = """fred - class { - - A field; - } - """ - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun trimIndentMinimalIndent() { - val input = """ - class { - A field; - } - """ - - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun trimIndentNoIndent() { - val input = "class{\n A field;\n}" - - assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) - } - - @Test - fun containsOnlyWhitespaceAndCommentsTest() { - assertThat(containsOnlyWhitespaceAndComments("")).isTrue - assertThat(containsOnlyWhitespaceAndComments(" \n\r\t")).isTrue - assertThat(containsOnlyWhitespaceAndComments(" // hello ")).isTrue - assertThat(containsOnlyWhitespaceAndComments("//")).isTrue - assertThat(containsOnlyWhitespaceAndComments("/**/")).isTrue - assertThat(containsOnlyWhitespaceAndComments(""" - /** - asdf - */ - """)).isTrue - - assertThat(containsOnlyWhitespaceAndComments("a")).isFalse - assertThat(containsOnlyWhitespaceAndComments( """ - // hello - goodbye - """)).isFalse - assertThat(containsOnlyWhitespaceAndComments("a//")).isFalse - assertThat(containsOnlyWhitespaceAndComments( - """ - /* - */ - a - """)).isFalse - } - - @Test - fun replaceFirst() { - var result = replaceFirst("#{} Fred #{}", "#{}", "I am") - assertThat(result).isEqualTo("I am Fred #{}") - result = replaceFirst(result, "#{}", "surely.") - assertThat(result).isEqualTo("I am Fred surely.") - result = replaceFirst("#{}#{}#{}", "#{}", "yo") - assertThat(result).isEqualTo("yo#{}#{}") - result = replaceFirst(result, "#{}", "yo") - assertThat(result).isEqualTo("yoyo#{}") - result = replaceFirst(result, "#{}", "yo") - assertThat(result).isEqualTo("yoyoyo") - result = replaceFirst("Nothing to see here", "#{}", "nonsense") - assertThat(result).isEqualTo("Nothing to see here") - result = replaceFirst("Nothing to see here", "", "nonsense") - assertThat(result).isEqualTo("Nothing to see here") - result = replaceFirst("", "", "nonsense") - assertThat(result).isEqualTo("") - } - - @Test - fun occurrenceCount() { - assertThat(countOccurrences("yoyoyoyoyo", "yo")).isEqualTo(5) - assertThat(countOccurrences("yoyoyoyoyo", "yoyo")).isEqualTo(2) - assertThat(countOccurrences("nonononono", "yo")).isEqualTo(0) - assertThat(countOccurrences("", "")).isEqualTo(0) - } - - @Test - fun globMatching() { - assertThat(matchesGlob("expression", "expr*")).isTrue() - assertThat(matchesGlob("some/xpath", "some/*")).isTrue() - assertThat(matchesGlob("some/xpath/expression", "some/**")).isTrue() - assertThat(matchesGlob("//some/xpath/expression", "**/xpath/*")).isTrue() - } - - @Test - fun greatestCommonMargin() { - assertThat(greatestCommonMargin(""" - | - | - | - """.trimMargin("|"))).isEqualTo(" ") - - assertThat(greatestCommonMargin(""" - | - | s - | - """.trimMargin("|"))).isEqualTo(" ") - - assertThat(greatestCommonMargin("")).isEqualTo("") - assertThat(greatestCommonMargin("\n\n")).isEqualTo("") - } -} +/* + * 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.internal + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.openrewrite.internal.StringUtils.* + +class StringUtilsTest { + @Test + fun detectIndentLevel() { + assertThat(indentLevel(""" + |< + | < + | < + | < + |< + """.trimMargin())).isEqualTo(0) + + assertThat(indentLevel(""" + |< + | < + """.trimMargin())).isEqualTo(3) + + assertThat(indentLevel(""" + |< + | < + | < + """.trimMargin())).isEqualTo(4) + + // ignores the last line if it is all blank + assertThat(indentLevel(""" + class { + A field; + } + """)).isEqualTo(12) + + assertThat(indentLevel(""" + | < + | < + | < + | < + """.trimMargin())).isEqualTo(1) + + assertThat(indentLevel(""" + | < + | < + | < + | < + | < + """.trimMargin())).isEqualTo(1) + + assertThat(indentLevel(""" + |< + |< + """.trimMargin())).isEqualTo(0) + + // doesn't consider newlines that occur as the first character on the first line or terminating newlines + assertThat(indentLevel(""" + | + | < + | < + | < + | + """.trimMargin())).isEqualTo(2) + } + + @Test + fun trimIndentBlankLines() { + val input = """ + + class { + + A field; + } + """ + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun trimIndentEndLineNonWhitespace() { + val input = """ + + class { + + A field; + } + hello""" + System.out.println("Kotlin : '" + input.trimIndent() + "'") + + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun trimIndentFirstLineSameAsIndent() { + val input = """ + + class { + + A field; + } + """ + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun trimIndentFirstLineGreaterThanIndent() { + val input = """ + + class { + + A field; + } + """ + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun trimIndentFirstLineEmpty() { + val input = """ + + class { + + A field; + } + """ + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun trimIndentNoNewLine() { + val input = " a" + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun trimIndentOneCharacter() { + val input = "a" + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun trimIndentFirstLineNotEmpty() { + val input = """ + fred + class { + + A field; + } + """ + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun trimIndentFirstCharacterNotLineBreak() { + val input = """fred + class { + + A field; + } + """ + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun trimIndentMinimalIndent() { + val input = """ + class { + A field; + } + """ + + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun trimIndentNoIndent() { + val input = "class{\n A field;\n}" + + assertThat(trimIndent(input)).isEqualTo(input.trimIndent()) + } + + @Test + fun containsOnlyWhitespaceAndCommentsTest() { + assertThat(containsOnlyWhitespaceAndComments("")).isTrue + assertThat(containsOnlyWhitespaceAndComments(" \n\r\t")).isTrue + assertThat(containsOnlyWhitespaceAndComments(" // hello ")).isTrue + assertThat(containsOnlyWhitespaceAndComments("//")).isTrue + assertThat(containsOnlyWhitespaceAndComments("/**/")).isTrue + assertThat(containsOnlyWhitespaceAndComments(""" + /** + asdf + */ + """)).isTrue + + assertThat(containsOnlyWhitespaceAndComments("a")).isFalse + assertThat(containsOnlyWhitespaceAndComments( """ + // hello + goodbye + """)).isFalse + assertThat(containsOnlyWhitespaceAndComments("a//")).isFalse + assertThat(containsOnlyWhitespaceAndComments( + """ + /* + */ + a + """)).isFalse + } + + @Test + fun replaceFirst() { + var result = replaceFirst("#{} Fred #{}", "#{}", "I am") + assertThat(result).isEqualTo("I am Fred #{}") + result = replaceFirst(result, "#{}", "surely.") + assertThat(result).isEqualTo("I am Fred surely.") + result = replaceFirst("#{}#{}#{}", "#{}", "yo") + assertThat(result).isEqualTo("yo#{}#{}") + result = replaceFirst(result, "#{}", "yo") + assertThat(result).isEqualTo("yoyo#{}") + result = replaceFirst(result, "#{}", "yo") + assertThat(result).isEqualTo("yoyoyo") + result = replaceFirst("Nothing to see here", "#{}", "nonsense") + assertThat(result).isEqualTo("Nothing to see here") + result = replaceFirst("Nothing to see here", "", "nonsense") + assertThat(result).isEqualTo("Nothing to see here") + result = replaceFirst("", "", "nonsense") + assertThat(result).isEqualTo("") + } + + @Test + fun occurrenceCount() { + assertThat(countOccurrences("yoyoyoyoyo", "yo")).isEqualTo(5) + assertThat(countOccurrences("yoyoyoyoyo", "yoyo")).isEqualTo(2) + assertThat(countOccurrences("nonononono", "yo")).isEqualTo(0) + assertThat(countOccurrences("", "")).isEqualTo(0) + } + + @Test + fun globMatching() { + assertThat(matchesGlob("expression", "expr*")).isTrue() + assertThat(matchesGlob("some/xpath", "some/*")).isTrue() + assertThat(matchesGlob("some/xpath/expression", "some/**")).isTrue() + assertThat(matchesGlob("//some/xpath/expression", "**/xpath/*")).isTrue() + } + + @Test + fun greatestCommonMargin() { + assertThat(greatestCommonMargin(""" + | + | + | + """.trimMargin("|"))).isEqualTo(" ") + + assertThat(greatestCommonMargin(""" + | + | s + | + """.trimMargin("|"))).isEqualTo(" ") + + assertThat(greatestCommonMargin("")).isEqualTo("") + assertThat(greatestCommonMargin("\n\n")).isEqualTo("") + } +} diff --git a/rewrite-core/src/test/kotlin/org/openrewrite/semver/CaretRangeTest.kt b/rewrite-core/src/test/kotlin/org/openrewrite/semver/CaretRangeTest.kt index 2cfee0290a5..a0acc87ac10 100644 --- a/rewrite-core/src/test/kotlin/org/openrewrite/semver/CaretRangeTest.kt +++ b/rewrite-core/src/test/kotlin/org/openrewrite/semver/CaretRangeTest.kt @@ -1,104 +1,104 @@ -/* - * 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 org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class CaretRangeTest { - @Test - fun pattern() { - assertThat(CaretRange.build("^1", null).isValid).isTrue - assertThat(CaretRange.build("^1.2", null).isValid).isTrue - assertThat(CaretRange.build("^1.2.3", null).isValid).isTrue - assertThat(CaretRange.build("^1.2.3.4", null).isValid).isTrue - assertThat(CaretRange.build("^1.2.3.4.5", null).isValid).isFalse - } - - @Test - fun updateMicro() { - val caretRange: CaretRange = CaretRange.build("^1.2.3.4", null).getValue()!! - - assertThat(caretRange.isValid("1.0", "1.2.3.4")).isTrue - assertThat(caretRange.isValid("1.0", "1.2.3.4.RELEASE")).isTrue - assertThat(caretRange.isValid("1.0", "1.2.3.5")).isTrue - assertThat(caretRange.isValid("1.0", "1.2.4")).isTrue - assertThat(caretRange.isValid("1.0", "1.9.0")).isTrue - assertThat(caretRange.isValid("1.0", "1.2.3.3")).isFalse - assertThat(caretRange.isValid("1.0", "2.0.0")).isFalse - } - - /** - * ^1.2.3 := >=1.2.3 <2.0.0 - */ - @Test - fun updateMinorAndPatch() { - val caretRange: CaretRange = CaretRange.build("^1.2.3", null).getValue()!! - - assertThat(caretRange.isValid("1.0", "1.2.3")).isTrue - assertThat(caretRange.isValid("1.0", "1.2.3.RELEASE")).isTrue - assertThat(caretRange.isValid("1.0", "1.2.4")).isTrue - assertThat(caretRange.isValid("1.0", "1.9.0")).isTrue - assertThat(caretRange.isValid("1.0", "2.0.0")).isFalse - } - - /** - * ^0.2.3 := >=0.2.3 <0.3.0 - */ - @Test - fun updatePatch() { - val caretRange: CaretRange = CaretRange.build("^0.2.3", null).getValue()!! - - assertThat(caretRange.isValid("1.0", "0.2.3")).isTrue - assertThat(caretRange.isValid("1.0", "0.2.4")).isTrue - assertThat(caretRange.isValid("1.0", "0.3.0")).isFalse - } - - @Test - fun updateNothing() { - val caretRange: CaretRange = CaretRange - .build("^0.0.3", null) - .getValue()!! - - assertThat(caretRange.isValid("1.0", "0.0.3")).isFalse - assertThat(caretRange.isValid("1.0", "0.0.4")).isFalse - } - - /** - * ^1.x := >=1.0.0 <2.0.0 - */ - @Test - fun desugarMinorWildcard() { - val caretRange: CaretRange = CaretRange.build("^1.x", null).getValue()!! - - assertThat(caretRange.isValid("1.0", "1.0.0")).isTrue - assertThat(caretRange.isValid("1.0", "1.0.1")).isTrue - assertThat(caretRange.isValid("1.0", "1.1.0")).isTrue - assertThat(caretRange.isValid("1.0", "2.0.0")).isFalse - } - - /** - * ^0.0.x := >=0.0.0 <0.1.0 - */ - @Test - fun desugarPatchWildcard() { - val caretRange: CaretRange = CaretRange.build("^0.0.x", null).getValue()!! - - assertThat(caretRange.isValid("1.0", "0.0.0")).isTrue - assertThat(caretRange.isValid("1.0", "0.0.1")).isTrue - assertThat(caretRange.isValid("1.0", "0.1.0")).isFalse - } -} +/* + * 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 org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class CaretRangeTest { + @Test + fun pattern() { + assertThat(CaretRange.build("^1", null).isValid).isTrue + assertThat(CaretRange.build("^1.2", null).isValid).isTrue + assertThat(CaretRange.build("^1.2.3", null).isValid).isTrue + assertThat(CaretRange.build("^1.2.3.4", null).isValid).isTrue + assertThat(CaretRange.build("^1.2.3.4.5", null).isValid).isFalse + } + + @Test + fun updateMicro() { + val caretRange: CaretRange = CaretRange.build("^1.2.3.4", null).getValue()!! + + assertThat(caretRange.isValid("1.0", "1.2.3.4")).isTrue + assertThat(caretRange.isValid("1.0", "1.2.3.4.RELEASE")).isTrue + assertThat(caretRange.isValid("1.0", "1.2.3.5")).isTrue + assertThat(caretRange.isValid("1.0", "1.2.4")).isTrue + assertThat(caretRange.isValid("1.0", "1.9.0")).isTrue + assertThat(caretRange.isValid("1.0", "1.2.3.3")).isFalse + assertThat(caretRange.isValid("1.0", "2.0.0")).isFalse + } + + /** + * ^1.2.3 := >=1.2.3 <2.0.0 + */ + @Test + fun updateMinorAndPatch() { + val caretRange: CaretRange = CaretRange.build("^1.2.3", null).getValue()!! + + assertThat(caretRange.isValid("1.0", "1.2.3")).isTrue + assertThat(caretRange.isValid("1.0", "1.2.3.RELEASE")).isTrue + assertThat(caretRange.isValid("1.0", "1.2.4")).isTrue + assertThat(caretRange.isValid("1.0", "1.9.0")).isTrue + assertThat(caretRange.isValid("1.0", "2.0.0")).isFalse + } + + /** + * ^0.2.3 := >=0.2.3 <0.3.0 + */ + @Test + fun updatePatch() { + val caretRange: CaretRange = CaretRange.build("^0.2.3", null).getValue()!! + + assertThat(caretRange.isValid("1.0", "0.2.3")).isTrue + assertThat(caretRange.isValid("1.0", "0.2.4")).isTrue + assertThat(caretRange.isValid("1.0", "0.3.0")).isFalse + } + + @Test + fun updateNothing() { + val caretRange: CaretRange = CaretRange + .build("^0.0.3", null) + .getValue()!! + + assertThat(caretRange.isValid("1.0", "0.0.3")).isFalse + assertThat(caretRange.isValid("1.0", "0.0.4")).isFalse + } + + /** + * ^1.x := >=1.0.0 <2.0.0 + */ + @Test + fun desugarMinorWildcard() { + val caretRange: CaretRange = CaretRange.build("^1.x", null).getValue()!! + + assertThat(caretRange.isValid("1.0", "1.0.0")).isTrue + assertThat(caretRange.isValid("1.0", "1.0.1")).isTrue + assertThat(caretRange.isValid("1.0", "1.1.0")).isTrue + assertThat(caretRange.isValid("1.0", "2.0.0")).isFalse + } + + /** + * ^0.0.x := >=0.0.0 <0.1.0 + */ + @Test + fun desugarPatchWildcard() { + val caretRange: CaretRange = CaretRange.build("^0.0.x", null).getValue()!! + + assertThat(caretRange.isValid("1.0", "0.0.0")).isTrue + assertThat(caretRange.isValid("1.0", "0.0.1")).isTrue + assertThat(caretRange.isValid("1.0", "0.1.0")).isFalse + } +} diff --git a/rewrite-core/src/test/kotlin/org/openrewrite/semver/HyphenRangeTest.kt b/rewrite-core/src/test/kotlin/org/openrewrite/semver/HyphenRangeTest.kt index c37d0b2afec..32003d910e5 100644 --- a/rewrite-core/src/test/kotlin/org/openrewrite/semver/HyphenRangeTest.kt +++ b/rewrite-core/src/test/kotlin/org/openrewrite/semver/HyphenRangeTest.kt @@ -1,71 +1,71 @@ -/* - * 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 org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class HyphenRangeTest { - @Test - fun pattern() { - assertThat(HyphenRange.build("1 - 2", null).isValid).isTrue - assertThat(HyphenRange.build("1.0.0.0 - 2", null).isValid).isTrue - assertThat(HyphenRange.build("1 - 2.0.0.0", null).isValid).isTrue - assertThat(HyphenRange.build("1.0.0.0 - 2.0.0.0", null).isValid).isTrue - assertThat(HyphenRange.build("1", null).isValid).isFalse - assertThat(HyphenRange.build("1 - 2.x", null).isValid).isFalse - assertThat(HyphenRange.build("1.0.0.0.0 - 2", null).isValid).isFalse - } - - /** - * 1.2.3 - 2.3.4 := >=1.2.3 <=2.3.4 - */ - @Test - fun inclusiveSet() { - val hyphenRange: HyphenRange = HyphenRange.build("1.2.3 - 2.3.4", null).getValue()!! - - assertThat(hyphenRange.isValid("1.0", "1.2.2")).isFalse - assertThat(hyphenRange.isValid("1.0", "1.2.2.0")).isFalse - assertThat(hyphenRange.isValid("1.0", "1.2.3.RELEASE")).isTrue - assertThat(hyphenRange.isValid("1.0", "1.2.3.0.RELEASE")).isTrue - assertThat(hyphenRange.isValid("1.0", "1.2.3")).isTrue - assertThat(hyphenRange.isValid("1.0", "1.2.3.0")).isTrue - assertThat(hyphenRange.isValid("1.0", "1.2.3.0.0")).isFalse - assertThat(hyphenRange.isValid("1.0", "2.3.4")).isTrue - assertThat(hyphenRange.isValid("1.0", "2.3.4.0")).isTrue - assertThat(hyphenRange.isValid("1.0", "2.3.4.1")).isFalse - assertThat(hyphenRange.isValid("1.0", "2.3.5")).isFalse - assertThat(hyphenRange.isValid("1.0", "2.3.5.0")).isFalse - } - - /** - * 1.2 - 2 := >=1.2.0 <=2.0.0 - */ - @Test - fun partialVersion() { - val hyphenRange: HyphenRange = HyphenRange.build("1.2 - 2", null).getValue()!! - - assertThat(hyphenRange.isValid("1.0", "1.1.9")).isFalse - assertThat(hyphenRange.isValid("1.0", "1.1.9.9")).isFalse - assertThat(hyphenRange.isValid("1.0", "1.2.0")).isTrue - assertThat(hyphenRange.isValid("1.0", "1.2.0.0")).isTrue - assertThat(hyphenRange.isValid("1.0", "1.2.0.0.0")).isFalse - assertThat(hyphenRange.isValid("1.0", "2.0.0")).isTrue - assertThat(hyphenRange.isValid("1.0", "2.0.0.0")).isTrue - assertThat(hyphenRange.isValid("1.0", "2.0.1")).isFalse - assertThat(hyphenRange.isValid("1.0", "2.0.0.1")).isFalse - } -} +/* + * 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 org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class HyphenRangeTest { + @Test + fun pattern() { + assertThat(HyphenRange.build("1 - 2", null).isValid).isTrue + assertThat(HyphenRange.build("1.0.0.0 - 2", null).isValid).isTrue + assertThat(HyphenRange.build("1 - 2.0.0.0", null).isValid).isTrue + assertThat(HyphenRange.build("1.0.0.0 - 2.0.0.0", null).isValid).isTrue + assertThat(HyphenRange.build("1", null).isValid).isFalse + assertThat(HyphenRange.build("1 - 2.x", null).isValid).isFalse + assertThat(HyphenRange.build("1.0.0.0.0 - 2", null).isValid).isFalse + } + + /** + * 1.2.3 - 2.3.4 := >=1.2.3 <=2.3.4 + */ + @Test + fun inclusiveSet() { + val hyphenRange: HyphenRange = HyphenRange.build("1.2.3 - 2.3.4", null).getValue()!! + + assertThat(hyphenRange.isValid("1.0", "1.2.2")).isFalse + assertThat(hyphenRange.isValid("1.0", "1.2.2.0")).isFalse + assertThat(hyphenRange.isValid("1.0", "1.2.3.RELEASE")).isTrue + assertThat(hyphenRange.isValid("1.0", "1.2.3.0.RELEASE")).isTrue + assertThat(hyphenRange.isValid("1.0", "1.2.3")).isTrue + assertThat(hyphenRange.isValid("1.0", "1.2.3.0")).isTrue + assertThat(hyphenRange.isValid("1.0", "1.2.3.0.0")).isFalse + assertThat(hyphenRange.isValid("1.0", "2.3.4")).isTrue + assertThat(hyphenRange.isValid("1.0", "2.3.4.0")).isTrue + assertThat(hyphenRange.isValid("1.0", "2.3.4.1")).isFalse + assertThat(hyphenRange.isValid("1.0", "2.3.5")).isFalse + assertThat(hyphenRange.isValid("1.0", "2.3.5.0")).isFalse + } + + /** + * 1.2 - 2 := >=1.2.0 <=2.0.0 + */ + @Test + fun partialVersion() { + val hyphenRange: HyphenRange = HyphenRange.build("1.2 - 2", null).getValue()!! + + assertThat(hyphenRange.isValid("1.0", "1.1.9")).isFalse + assertThat(hyphenRange.isValid("1.0", "1.1.9.9")).isFalse + assertThat(hyphenRange.isValid("1.0", "1.2.0")).isTrue + assertThat(hyphenRange.isValid("1.0", "1.2.0.0")).isTrue + assertThat(hyphenRange.isValid("1.0", "1.2.0.0.0")).isFalse + assertThat(hyphenRange.isValid("1.0", "2.0.0")).isTrue + assertThat(hyphenRange.isValid("1.0", "2.0.0.0")).isTrue + assertThat(hyphenRange.isValid("1.0", "2.0.1")).isFalse + assertThat(hyphenRange.isValid("1.0", "2.0.0.1")).isFalse + } +} diff --git a/rewrite-core/src/test/kotlin/org/openrewrite/semver/LatestPatchTest.kt b/rewrite-core/src/test/kotlin/org/openrewrite/semver/LatestPatchTest.kt index 1052960c2e7..4ce1aae253f 100644 --- a/rewrite-core/src/test/kotlin/org/openrewrite/semver/LatestPatchTest.kt +++ b/rewrite-core/src/test/kotlin/org/openrewrite/semver/LatestPatchTest.kt @@ -1,39 +1,39 @@ -/* - * 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 org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class LatestPatchTest { - private val latestPatch = LatestPatch(null) - - @Test - fun isValid() { - assertThat(latestPatch.isValid("1.0.0", "1.0.0")).isTrue - assertThat(latestPatch.isValid("1.0.0", "1.0.0.1")).isTrue - assertThat(latestPatch.isValid("1.0.0", "1.0.1")).isTrue - assertThat(latestPatch.isValid("1.0", "1.0.1")).isTrue - assertThat(latestPatch.isValid("1.0.0", "1.1.0")).isFalse - assertThat(latestPatch.isValid("1.0.0", "2.0.0")).isFalse - } - - @Test - fun compare() { - assertThat(latestPatch.compare("1.0", "1.0.1", "1.0.2")).isLessThan(0) - assertThat(latestPatch.compare("1.0", "1.0.0.1", "1.0.1")).isLessThan(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.semver + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class LatestPatchTest { + private val latestPatch = LatestPatch(null) + + @Test + fun isValid() { + assertThat(latestPatch.isValid("1.0.0", "1.0.0")).isTrue + assertThat(latestPatch.isValid("1.0.0", "1.0.0.1")).isTrue + assertThat(latestPatch.isValid("1.0.0", "1.0.1")).isTrue + assertThat(latestPatch.isValid("1.0", "1.0.1")).isTrue + assertThat(latestPatch.isValid("1.0.0", "1.1.0")).isFalse + assertThat(latestPatch.isValid("1.0.0", "2.0.0")).isFalse + } + + @Test + fun compare() { + assertThat(latestPatch.compare("1.0", "1.0.1", "1.0.2")).isLessThan(0) + assertThat(latestPatch.compare("1.0", "1.0.0.1", "1.0.1")).isLessThan(0) + } +} diff --git a/rewrite-core/src/test/kotlin/org/openrewrite/semver/LatestReleaseTest.kt b/rewrite-core/src/test/kotlin/org/openrewrite/semver/LatestReleaseTest.kt index 2d6988aa7a4..f57228b0001 100644 --- a/rewrite-core/src/test/kotlin/org/openrewrite/semver/LatestReleaseTest.kt +++ b/rewrite-core/src/test/kotlin/org/openrewrite/semver/LatestReleaseTest.kt @@ -1,117 +1,117 @@ -/* - * 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 org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertAll - -class LatestReleaseTest { - private val latestRelease = LatestRelease(null) - - @Test - fun onlyNumericPartsValid() { - assertAll( - { assertThat(latestRelease.isValid("1.0", "1.1.1.1")).isTrue }, - { assertThat(latestRelease.isValid("1.0", "1.1.1")).isTrue }, - { assertThat(latestRelease.isValid("1.0", "1.1")).isTrue }, - { assertThat(latestRelease.isValid("1.0", "1")).isTrue }, - { assertThat(latestRelease.isValid("1.0", "1.1.a")).isFalse }, - { assertThat(latestRelease.isValid("1.0", "1.1.1.1.a")).isFalse }, - { assertThat(latestRelease.isValid("1.0", "1.1.1.1.1")).isFalse }, - { assertThat(latestRelease.isValid("1.0", "1.1.1.1.1-SNAPSHOT")).isFalse }, - { assertThat(latestRelease.isValid("1.0", "1.1.0-SNAPSHOT")).isFalse } - ) - } - - @Test - fun differentMicroVersions() { - assertThat(latestRelease.compare("1.0", "1.1.1.1", "1.1.1.2")).isLessThan(0) - assertThat(latestRelease.compare("1.0", "1", "1.1.1.1")).isLessThan(0) - assertThat(latestRelease.compare("1.0", "1.1.1.1", "2")).isLessThan(0) - } - - @Test - fun differentPatchVersions() { - assertThat(latestRelease.compare("1.0", "1.1.1.1", "1.1.2.1")).isLessThan(0) - assertThat(latestRelease.compare("1.0", "1.1.1", "1.1.2")).isLessThan(0) - } - - @Test - fun differentMinorVersions() { - assertThat(latestRelease.compare("1.0", "1.1.1.1", "1.2.1.1")).isLessThan(0) - assertThat(latestRelease.compare("1.0", "1.1.1", "1.2.1")).isLessThan(0) - assertThat(latestRelease.compare("1.0", "1.1", "1.2")).isLessThan(0) - } - - @Test - fun differentMajorVersions() { - assertThat(latestRelease.compare("1.0", "1.1.1.1", "2.1.1.1")).isLessThan(0) - assertThat(latestRelease.compare("1.0", "1.1.1", "2.1.1")).isLessThan(0) - assertThat(latestRelease.compare("1.0", "1.1", "2.1")).isLessThan(0) - assertThat(latestRelease.compare("1.0", "1", "2")).isLessThan(0) - } - - @Test - fun differentNumberOfParts() { - assertThat(latestRelease.compare("1.0", "1.1.1", "1.1.1.1")).isLessThan(0) - assertThat(latestRelease.compare("1.0", "1.1", "1.1.1")).isLessThan(0) - assertThat(latestRelease.compare("1.0", "1", "1.1")).isLessThan(0) - } - - @Test - fun guavaVariants() { - assertThat(latestRelease.compare("1.0", "25.0-jre", "29.0-jre")).isLessThan(0) - } - - @Test - @Disabled("https://github.com/openrewrite/rewrite/issues/1204") - // feel free to move this under "guavaVariants", todo - fun guavaVariantsMetadataBoundaries() { - assertThat(latestRelease.compare("1.0", "25", "25.0-jre")).isEqualTo(0) - } - - @Test - fun matchMetadata() { - assertThat(LatestRelease("-jre").isValid("1.0", "29.0.0.0-jre")).isTrue - assertThat(LatestRelease("-jre").isValid("1.0", "29.0-jre")).isTrue - assertThat(LatestRelease("-jre").isValid("1.0", "29.0")).isFalse - assertThat(LatestRelease("-jre").isValid("1.0", "29.0-android")).isFalse - assertThat(LatestRelease("").isValid("1.0", "29.0")).isTrue - } - - @Test - fun normalizeVersionStripReleaseSuffix() { - assertThat(LatestRelease.normalizeVersion("1.5.1.2.RELEASE")).isEqualTo("1.5.1.2") - assertThat(LatestRelease.normalizeVersion("1.5.1.RELEASE")).isEqualTo("1.5.1") - assertThat(LatestRelease.normalizeVersion("1.5.1.FINAL")).isEqualTo("1.5.1") - assertThat(LatestRelease.normalizeVersion("1.5.1.Final")).isEqualTo("1.5.1") - } - - @Test - fun normalizeVersionToHaveMajorMinorPatch() { - assertThat(LatestRelease.normalizeVersion("29.0")).isEqualTo("29.0.0") - assertThat(LatestRelease.normalizeVersion("29.0-jre")).isEqualTo("29.0.0-jre") - assertThat(LatestRelease.normalizeVersion("29-jre")).isEqualTo("29.0.0-jre") - } - - @Test - fun datedSnapshotVersions() { - assertThat(latestRelease.compare(null, "7.17.0-20211102.000501-28", - "7.17.0-20211102.012229-29")).isLessThan(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.semver + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertAll + +class LatestReleaseTest { + private val latestRelease = LatestRelease(null) + + @Test + fun onlyNumericPartsValid() { + assertAll( + { assertThat(latestRelease.isValid("1.0", "1.1.1.1")).isTrue }, + { assertThat(latestRelease.isValid("1.0", "1.1.1")).isTrue }, + { assertThat(latestRelease.isValid("1.0", "1.1")).isTrue }, + { assertThat(latestRelease.isValid("1.0", "1")).isTrue }, + { assertThat(latestRelease.isValid("1.0", "1.1.a")).isFalse }, + { assertThat(latestRelease.isValid("1.0", "1.1.1.1.a")).isFalse }, + { assertThat(latestRelease.isValid("1.0", "1.1.1.1.1")).isFalse }, + { assertThat(latestRelease.isValid("1.0", "1.1.1.1.1-SNAPSHOT")).isFalse }, + { assertThat(latestRelease.isValid("1.0", "1.1.0-SNAPSHOT")).isFalse } + ) + } + + @Test + fun differentMicroVersions() { + assertThat(latestRelease.compare("1.0", "1.1.1.1", "1.1.1.2")).isLessThan(0) + assertThat(latestRelease.compare("1.0", "1", "1.1.1.1")).isLessThan(0) + assertThat(latestRelease.compare("1.0", "1.1.1.1", "2")).isLessThan(0) + } + + @Test + fun differentPatchVersions() { + assertThat(latestRelease.compare("1.0", "1.1.1.1", "1.1.2.1")).isLessThan(0) + assertThat(latestRelease.compare("1.0", "1.1.1", "1.1.2")).isLessThan(0) + } + + @Test + fun differentMinorVersions() { + assertThat(latestRelease.compare("1.0", "1.1.1.1", "1.2.1.1")).isLessThan(0) + assertThat(latestRelease.compare("1.0", "1.1.1", "1.2.1")).isLessThan(0) + assertThat(latestRelease.compare("1.0", "1.1", "1.2")).isLessThan(0) + } + + @Test + fun differentMajorVersions() { + assertThat(latestRelease.compare("1.0", "1.1.1.1", "2.1.1.1")).isLessThan(0) + assertThat(latestRelease.compare("1.0", "1.1.1", "2.1.1")).isLessThan(0) + assertThat(latestRelease.compare("1.0", "1.1", "2.1")).isLessThan(0) + assertThat(latestRelease.compare("1.0", "1", "2")).isLessThan(0) + } + + @Test + fun differentNumberOfParts() { + assertThat(latestRelease.compare("1.0", "1.1.1", "1.1.1.1")).isLessThan(0) + assertThat(latestRelease.compare("1.0", "1.1", "1.1.1")).isLessThan(0) + assertThat(latestRelease.compare("1.0", "1", "1.1")).isLessThan(0) + } + + @Test + fun guavaVariants() { + assertThat(latestRelease.compare("1.0", "25.0-jre", "29.0-jre")).isLessThan(0) + } + + @Test + @Disabled("https://github.com/openrewrite/rewrite/issues/1204") + // feel free to move this under "guavaVariants", todo + fun guavaVariantsMetadataBoundaries() { + assertThat(latestRelease.compare("1.0", "25", "25.0-jre")).isEqualTo(0) + } + + @Test + fun matchMetadata() { + assertThat(LatestRelease("-jre").isValid("1.0", "29.0.0.0-jre")).isTrue + assertThat(LatestRelease("-jre").isValid("1.0", "29.0-jre")).isTrue + assertThat(LatestRelease("-jre").isValid("1.0", "29.0")).isFalse + assertThat(LatestRelease("-jre").isValid("1.0", "29.0-android")).isFalse + assertThat(LatestRelease("").isValid("1.0", "29.0")).isTrue + } + + @Test + fun normalizeVersionStripReleaseSuffix() { + assertThat(LatestRelease.normalizeVersion("1.5.1.2.RELEASE")).isEqualTo("1.5.1.2") + assertThat(LatestRelease.normalizeVersion("1.5.1.RELEASE")).isEqualTo("1.5.1") + assertThat(LatestRelease.normalizeVersion("1.5.1.FINAL")).isEqualTo("1.5.1") + assertThat(LatestRelease.normalizeVersion("1.5.1.Final")).isEqualTo("1.5.1") + } + + @Test + fun normalizeVersionToHaveMajorMinorPatch() { + assertThat(LatestRelease.normalizeVersion("29.0")).isEqualTo("29.0.0") + assertThat(LatestRelease.normalizeVersion("29.0-jre")).isEqualTo("29.0.0-jre") + assertThat(LatestRelease.normalizeVersion("29-jre")).isEqualTo("29.0.0-jre") + } + + @Test + fun datedSnapshotVersions() { + assertThat(latestRelease.compare(null, "7.17.0-20211102.000501-28", + "7.17.0-20211102.012229-29")).isLessThan(0) + } +} diff --git a/rewrite-core/src/test/kotlin/org/openrewrite/semver/SemverTest.kt b/rewrite-core/src/test/kotlin/org/openrewrite/semver/SemverTest.kt index ac602a4a969..7a6d2f665d6 100644 --- a/rewrite-core/src/test/kotlin/org/openrewrite/semver/SemverTest.kt +++ b/rewrite-core/src/test/kotlin/org/openrewrite/semver/SemverTest.kt @@ -1,35 +1,35 @@ -/* - * 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 org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class SemverTest { - @Test - fun validToVersion() { - assertThat(Semver.validate("latest.release", null).getValue()) - .isInstanceOf(LatestRelease::class.java) - assertThat(Semver.validate("1.5 - 2", null).getValue()) - .isInstanceOf(HyphenRange::class.java) - assertThat(Semver.validate("1.x", null).getValue()) - .isInstanceOf(XRange::class.java) - assertThat(Semver.validate("~1.5", null).getValue()) - .isInstanceOf(TildeRange::class.java) - assertThat(Semver.validate("^1.5", null).getValue()) - .isInstanceOf(CaretRange::class.java) - } -} +/* + * 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 org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class SemverTest { + @Test + fun validToVersion() { + assertThat(Semver.validate("latest.release", null).getValue()) + .isInstanceOf(LatestRelease::class.java) + assertThat(Semver.validate("1.5 - 2", null).getValue()) + .isInstanceOf(HyphenRange::class.java) + assertThat(Semver.validate("1.x", null).getValue()) + .isInstanceOf(XRange::class.java) + assertThat(Semver.validate("~1.5", null).getValue()) + .isInstanceOf(TildeRange::class.java) + assertThat(Semver.validate("^1.5", null).getValue()) + .isInstanceOf(CaretRange::class.java) + } +} diff --git a/rewrite-core/src/test/kotlin/org/openrewrite/semver/TildeRangeTest.kt b/rewrite-core/src/test/kotlin/org/openrewrite/semver/TildeRangeTest.kt index 90ec9a61cdc..ccfc323f8e3 100644 --- a/rewrite-core/src/test/kotlin/org/openrewrite/semver/TildeRangeTest.kt +++ b/rewrite-core/src/test/kotlin/org/openrewrite/semver/TildeRangeTest.kt @@ -1,82 +1,82 @@ -/* - * 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 org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class TildeRangeTest { - @Test - fun pattern() { - assertThat(TildeRange.build("~1", null).isValid).isTrue - assertThat(TildeRange.build("~1.2", null).isValid).isTrue - assertThat(TildeRange.build("~1.2.3", null).isValid).isTrue - assertThat(TildeRange.build("~1.2.3.4", null).isValid).isTrue - assertThat(TildeRange.build("~1.2.3.4.5", null).isValid).isFalse - } - - /** - * ~1.2.3 := >=1.2.3 <1.(2+1).0 := >=1.2.3 <1.3.0 - */ - @Test - fun updatePatch() { - val tildeRange: TildeRange = TildeRange.build("~1.2.3", null).getValue()!! - - assertThat(tildeRange.isValid("1.0", "1.2.3.0")).isTrue - assertThat(tildeRange.isValid("1.0", "1.2.3.1")).isTrue - assertThat(tildeRange.isValid("1.0", "1.2.3")).isTrue - assertThat(tildeRange.isValid("1.0", "1.2.3.RELEASE")).isTrue - assertThat(tildeRange.isValid("1.0", "1.2.4")).isTrue - assertThat(tildeRange.isValid("1.0", "1.3.0")).isFalse - } - - @Test - fun updateMicro() { - val tildeRange: TildeRange = TildeRange.build("~1.2.3.4", null).getValue()!! - - assertThat(tildeRange.isValid("1.0", "1.2.3.5")).isTrue - assertThat(tildeRange.isValid("1.0", "1.2.3.0")).isFalse - assertThat(tildeRange.isValid("1.0", "1.2.3.5.0")).isFalse - assertThat(tildeRange.isValid("1.0", "1.2.3")).isFalse - assertThat(tildeRange.isValid("1.0", "1.2.4")).isFalse - assertThat(tildeRange.isValid("1.0", "1.2.4.0")).isFalse - assertThat(tildeRange.isValid("1.0", "1.3.0")).isFalse - } - - /** - * ~1.2 := >=1.2.0 <1.(2+1).0 := >=1.2.0 <1.3.0-0 (Same as 1.2.x) - */ - @Test - fun updatePatchImplicitZeroPatch() { - val tildeRange: TildeRange = TildeRange.build("~1.2", null).getValue()!! - - assertThat(tildeRange.isValid("1.0", "1.2.0")).isTrue - assertThat(tildeRange.isValid("1.0", "1.2.4")).isTrue - assertThat(tildeRange.isValid("1.0", "1.3.0")).isFalse - } - - /** - * ~1 := >=1.0.0 <(1+1).0.0 := >=1.0.0 <2.0.0-0 (Same as 1.x) - */ - @Test - fun updateMajor() { - val tildeRange: TildeRange = TildeRange.build("~1", null).getValue()!! - - assertThat(tildeRange.isValid("1.0", "1.0.1")).isTrue - assertThat(tildeRange.isValid("1.0", "1.9.9")).isTrue - assertThat(tildeRange.isValid("1.0", "2.0.0")).isFalse - } -} +/* + * 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 org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class TildeRangeTest { + @Test + fun pattern() { + assertThat(TildeRange.build("~1", null).isValid).isTrue + assertThat(TildeRange.build("~1.2", null).isValid).isTrue + assertThat(TildeRange.build("~1.2.3", null).isValid).isTrue + assertThat(TildeRange.build("~1.2.3.4", null).isValid).isTrue + assertThat(TildeRange.build("~1.2.3.4.5", null).isValid).isFalse + } + + /** + * ~1.2.3 := >=1.2.3 <1.(2+1).0 := >=1.2.3 <1.3.0 + */ + @Test + fun updatePatch() { + val tildeRange: TildeRange = TildeRange.build("~1.2.3", null).getValue()!! + + assertThat(tildeRange.isValid("1.0", "1.2.3.0")).isTrue + assertThat(tildeRange.isValid("1.0", "1.2.3.1")).isTrue + assertThat(tildeRange.isValid("1.0", "1.2.3")).isTrue + assertThat(tildeRange.isValid("1.0", "1.2.3.RELEASE")).isTrue + assertThat(tildeRange.isValid("1.0", "1.2.4")).isTrue + assertThat(tildeRange.isValid("1.0", "1.3.0")).isFalse + } + + @Test + fun updateMicro() { + val tildeRange: TildeRange = TildeRange.build("~1.2.3.4", null).getValue()!! + + assertThat(tildeRange.isValid("1.0", "1.2.3.5")).isTrue + assertThat(tildeRange.isValid("1.0", "1.2.3.0")).isFalse + assertThat(tildeRange.isValid("1.0", "1.2.3.5.0")).isFalse + assertThat(tildeRange.isValid("1.0", "1.2.3")).isFalse + assertThat(tildeRange.isValid("1.0", "1.2.4")).isFalse + assertThat(tildeRange.isValid("1.0", "1.2.4.0")).isFalse + assertThat(tildeRange.isValid("1.0", "1.3.0")).isFalse + } + + /** + * ~1.2 := >=1.2.0 <1.(2+1).0 := >=1.2.0 <1.3.0-0 (Same as 1.2.x) + */ + @Test + fun updatePatchImplicitZeroPatch() { + val tildeRange: TildeRange = TildeRange.build("~1.2", null).getValue()!! + + assertThat(tildeRange.isValid("1.0", "1.2.0")).isTrue + assertThat(tildeRange.isValid("1.0", "1.2.4")).isTrue + assertThat(tildeRange.isValid("1.0", "1.3.0")).isFalse + } + + /** + * ~1 := >=1.0.0 <(1+1).0.0 := >=1.0.0 <2.0.0-0 (Same as 1.x) + */ + @Test + fun updateMajor() { + val tildeRange: TildeRange = TildeRange.build("~1", null).getValue()!! + + assertThat(tildeRange.isValid("1.0", "1.0.1")).isTrue + assertThat(tildeRange.isValid("1.0", "1.9.9")).isTrue + assertThat(tildeRange.isValid("1.0", "2.0.0")).isFalse + } +} diff --git a/rewrite-core/src/test/kotlin/org/openrewrite/semver/XRangeTest.kt b/rewrite-core/src/test/kotlin/org/openrewrite/semver/XRangeTest.kt index b7731ade32b..c8d9bc595c9 100644 --- a/rewrite-core/src/test/kotlin/org/openrewrite/semver/XRangeTest.kt +++ b/rewrite-core/src/test/kotlin/org/openrewrite/semver/XRangeTest.kt @@ -1,93 +1,93 @@ -/* - * 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 org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -class XRangeTest { - @Test - fun pattern() { - assertThat(XRange.build("*", null).isValid).isTrue - assertThat(XRange.build("*.0.0", null).isValid).isFalse - assertThat(XRange.build("1.x", null).isValid).isTrue - assertThat(XRange.build("1.x.0", null).isValid).isFalse - assertThat(XRange.build("1.1.X", null).isValid).isTrue - assertThat(XRange.build("1.1.1.X", null).isValid).isTrue - assertThat(XRange.build("1.1.1.1.X", null).isValid).isFalse - assertThat(XRange.build("1.1.x.1", null).isValid).isFalse - assertThat(XRange.build("a", null).isValid).isFalse - } - - @Test - fun doesNotMatchFixedVersion() { - assertThat(XRange.build("5.3.0", null).isValid).isFalse - } - - /** - * X := >=0.0.0 - */ - @Test - fun anyVersion() { - val xRange: XRange = XRange.build("X", null).getValue()!! - - assertThat(xRange.isValid("1.0", "0.0.0.0")).isTrue - assertThat(xRange.isValid("1.0", "0.0.0")).isTrue - } - - /** - * 1.* := >=1.0.0 <2.0.0-0 - */ - @Test - fun matchingMajorVersion() { - val xRange: XRange = XRange.build("1.*", null).getValue()!! - - assertThat(xRange.isValid("1.0", "1.0.0")).isTrue - assertThat(xRange.isValid("1.0", "1.0.0.1")).isTrue - assertThat(xRange.isValid("1.0", "1.2.3.RELEASE")).isTrue - assertThat(xRange.isValid("1.0", "1.9.9")).isTrue - assertThat(xRange.isValid("1.0", "2.0.0")).isFalse - } - - /** - * 1.2.X := >=1.2.0 <1.3.1 - */ - @Test - fun matchingMajorAndMinorVersions() { - val xRange: XRange = XRange.build("1.2.X", null).getValue()!! - - assertThat(xRange.isValid("1.0", "1.2.0")).isTrue - assertThat(xRange.isValid("1.0", "1.3.0")).isFalse - } - - @Test - fun matchingMicroVersions() { - val xRange: XRange = XRange.build("1.2.3.X", null).getValue()!! - - assertThat(xRange.isValid("1.0", "1.2.3.0")).isTrue - assertThat(xRange.isValid("1.0", "1.2.3")).isTrue - assertThat(xRange.isValid("1.0", "1.2.4.0")).isFalse - assertThat(xRange.isValid("1.0", "1.2.4")).isFalse - } - - @Test - fun matchingJavaxValidation() { - val xRange: XRange = XRange.build("2.X", null).getValue()!! - - // The version pattern of javax.validation:validation-api - assertThat(xRange.isValid("1.0", "2.0.1.Final")).isTrue - } -} +/* + * 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 org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class XRangeTest { + @Test + fun pattern() { + assertThat(XRange.build("*", null).isValid).isTrue + assertThat(XRange.build("*.0.0", null).isValid).isFalse + assertThat(XRange.build("1.x", null).isValid).isTrue + assertThat(XRange.build("1.x.0", null).isValid).isFalse + assertThat(XRange.build("1.1.X", null).isValid).isTrue + assertThat(XRange.build("1.1.1.X", null).isValid).isTrue + assertThat(XRange.build("1.1.1.1.X", null).isValid).isFalse + assertThat(XRange.build("1.1.x.1", null).isValid).isFalse + assertThat(XRange.build("a", null).isValid).isFalse + } + + @Test + fun doesNotMatchFixedVersion() { + assertThat(XRange.build("5.3.0", null).isValid).isFalse + } + + /** + * X := >=0.0.0 + */ + @Test + fun anyVersion() { + val xRange: XRange = XRange.build("X", null).getValue()!! + + assertThat(xRange.isValid("1.0", "0.0.0.0")).isTrue + assertThat(xRange.isValid("1.0", "0.0.0")).isTrue + } + + /** + * 1.* := >=1.0.0 <2.0.0-0 + */ + @Test + fun matchingMajorVersion() { + val xRange: XRange = XRange.build("1.*", null).getValue()!! + + assertThat(xRange.isValid("1.0", "1.0.0")).isTrue + assertThat(xRange.isValid("1.0", "1.0.0.1")).isTrue + assertThat(xRange.isValid("1.0", "1.2.3.RELEASE")).isTrue + assertThat(xRange.isValid("1.0", "1.9.9")).isTrue + assertThat(xRange.isValid("1.0", "2.0.0")).isFalse + } + + /** + * 1.2.X := >=1.2.0 <1.3.1 + */ + @Test + fun matchingMajorAndMinorVersions() { + val xRange: XRange = XRange.build("1.2.X", null).getValue()!! + + assertThat(xRange.isValid("1.0", "1.2.0")).isTrue + assertThat(xRange.isValid("1.0", "1.3.0")).isFalse + } + + @Test + fun matchingMicroVersions() { + val xRange: XRange = XRange.build("1.2.3.X", null).getValue()!! + + assertThat(xRange.isValid("1.0", "1.2.3.0")).isTrue + assertThat(xRange.isValid("1.0", "1.2.3")).isTrue + assertThat(xRange.isValid("1.0", "1.2.4.0")).isFalse + assertThat(xRange.isValid("1.0", "1.2.4")).isFalse + } + + @Test + fun matchingJavaxValidation() { + val xRange: XRange = XRange.build("2.X", null).getValue()!! + + // The version pattern of javax.validation:validation-api + assertThat(xRange.isValid("1.0", "2.0.1.Final")).isTrue + } +} diff --git a/rewrite-gradle/src/main/resources/gradlew.bat b/rewrite-gradle/src/main/resources/gradlew.bat index 3b93aca1ecf..8dae1dee5ae 100755 --- a/rewrite-gradle/src/main/resources/gradlew.bat +++ b/rewrite-gradle/src/main/resources/gradlew.bat @@ -1,105 +1,105 @@ -@REM -@REM Copyright 2022 the original author or authors. -@REM

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

-@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM

-@REM Unless required by applicable law or agreed to in writing, software -@REM distributed under the License is distributed on an "AS IS" BASIS, -@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@REM See the License for the specific language governing permissions and -@REM limitations under the License. -@REM - -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@REM +@REM Copyright 2022 the original author or authors. +@REM

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

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

+@REM Unless required by applicable law or agreed to in writing, software +@REM distributed under the License is distributed on an "AS IS" BASIS, +@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@REM See the License for the specific language governing permissions and +@REM limitations under the License. +@REM + +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclStyle.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclStyle.java index d1913b211dc..09b3527d8cf 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclStyle.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/HclStyle.java @@ -1,21 +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. - */ -package org.openrewrite.hcl; - -import org.openrewrite.style.Style; - -public interface HclStyle extends Style { -} +/* + * 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.hcl; + +import org.openrewrite.style.Style; + +public interface HclStyle extends Style { +} diff --git a/rewrite-hcl/src/main/java/org/openrewrite/hcl/style/TabsAndIndentsStyle.java b/rewrite-hcl/src/main/java/org/openrewrite/hcl/style/TabsAndIndentsStyle.java index 48d82f36a99..d61584a1081 100644 --- a/rewrite-hcl/src/main/java/org/openrewrite/hcl/style/TabsAndIndentsStyle.java +++ b/rewrite-hcl/src/main/java/org/openrewrite/hcl/style/TabsAndIndentsStyle.java @@ -1,40 +1,40 @@ -/* - * 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.hcl.style; - -import lombok.AccessLevel; -import lombok.Value; -import lombok.With; -import lombok.experimental.FieldDefaults; -import org.openrewrite.hcl.HclStyle; -import org.openrewrite.style.Style; -import org.openrewrite.style.StyleHelper; - -@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) -@Value -@With -public class TabsAndIndentsStyle implements HclStyle { - public static final TabsAndIndentsStyle DEFAULT = new TabsAndIndentsStyle(false, 2, 2); - - Boolean useTabCharacter; - Integer tabSize; - Integer indentSize; - - @Override - public Style applyDefaults() { - return StyleHelper.merge(DEFAULT, this); - } -} +/* + * 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.hcl.style; + +import lombok.AccessLevel; +import lombok.Value; +import lombok.With; +import lombok.experimental.FieldDefaults; +import org.openrewrite.hcl.HclStyle; +import org.openrewrite.style.Style; +import org.openrewrite.style.StyleHelper; + +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@Value +@With +public class TabsAndIndentsStyle implements HclStyle { + public static final TabsAndIndentsStyle DEFAULT = new TabsAndIndentsStyle(false, 2, 2); + + Boolean useTabCharacter; + Integer tabSize; + Integer indentSize; + + @Override + public Style applyDefaults() { + return StyleHelper.merge(DEFAULT, this); + } +} diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/Java11ParserInputFileObject.java b/rewrite-java-11/src/main/java/org/openrewrite/java/Java11ParserInputFileObject.java index 0f95973d5a3..352822ab6b8 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/Java11ParserInputFileObject.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/Java11ParserInputFileObject.java @@ -1,120 +1,120 @@ -/* - * 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.java; - -import lombok.EqualsAndHashCode; -import lombok.Getter; -import org.openrewrite.Parser; -import org.openrewrite.internal.lang.Nullable; - -import javax.lang.model.element.Modifier; -import javax.lang.model.element.NestingKind; -import javax.tools.JavaFileObject; -import java.io.*; -import java.net.URI; -import java.nio.file.Path; - -/** - * So that {@link JavaParser} can ingest source files from {@link InputStream} sources - * other than a file on disk. - */ -@EqualsAndHashCode(onlyExplicitlyIncluded = true) -public class Java11ParserInputFileObject implements JavaFileObject { - @EqualsAndHashCode.Include - @Nullable - private final Path path; - - @Getter - private final Parser.Input input; - - public Java11ParserInputFileObject(Parser.Input input) { - this.input = input; - this.path = input.getPath(); - } - - @Override - public URI toUri() { - if (path == null) { - //noinspection ConstantConditions - return null; - } - return path.toUri(); - } - - @Override - public String getName() { - if (path == null) { - //noinspection ConstantConditions - return null; - } - return path.toString(); - } - - @Override - public InputStream openInputStream() { - return input.getSource(); - } - - @Override - public OutputStream openOutputStream() { - throw new UnsupportedOperationException("Should be no need to write output to this file"); - } - - @Override - public Reader openReader(boolean ignoreEncodingErrors) { - return new InputStreamReader(input.getSource()); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return input.getSource().readFully(); - } - - @Override - public Writer openWriter() { - throw new UnsupportedOperationException("Should be no need to write output to this file"); - } - - @Override - public long getLastModified() { - return 0; - } - - @Override - public boolean delete() { - return false; - } - - @Override - public Kind getKind() { - return Kind.SOURCE; - } - - @Override - public boolean isNameCompatible(String simpleName, Kind kind) { - return true; - } - - @Override - public NestingKind getNestingKind() { - return NestingKind.TOP_LEVEL; - } - - @Override - public Modifier getAccessLevel() { - return Modifier.PUBLIC; - } -} +/* + * 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.java; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.openrewrite.Parser; +import org.openrewrite.internal.lang.Nullable; + +import javax.lang.model.element.Modifier; +import javax.lang.model.element.NestingKind; +import javax.tools.JavaFileObject; +import java.io.*; +import java.net.URI; +import java.nio.file.Path; + +/** + * So that {@link JavaParser} can ingest source files from {@link InputStream} sources + * other than a file on disk. + */ +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +public class Java11ParserInputFileObject implements JavaFileObject { + @EqualsAndHashCode.Include + @Nullable + private final Path path; + + @Getter + private final Parser.Input input; + + public Java11ParserInputFileObject(Parser.Input input) { + this.input = input; + this.path = input.getPath(); + } + + @Override + public URI toUri() { + if (path == null) { + //noinspection ConstantConditions + return null; + } + return path.toUri(); + } + + @Override + public String getName() { + if (path == null) { + //noinspection ConstantConditions + return null; + } + return path.toString(); + } + + @Override + public InputStream openInputStream() { + return input.getSource(); + } + + @Override + public OutputStream openOutputStream() { + throw new UnsupportedOperationException("Should be no need to write output to this file"); + } + + @Override + public Reader openReader(boolean ignoreEncodingErrors) { + return new InputStreamReader(input.getSource()); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return input.getSource().readFully(); + } + + @Override + public Writer openWriter() { + throw new UnsupportedOperationException("Should be no need to write output to this file"); + } + + @Override + public long getLastModified() { + return 0; + } + + @Override + public boolean delete() { + return false; + } + + @Override + public Kind getKind() { + return Kind.SOURCE; + } + + @Override + public boolean isNameCompatible(String simpleName, Kind kind) { + return true; + } + + @Override + public NestingKind getNestingKind() { + return NestingKind.TOP_LEVEL; + } + + @Override + public Modifier getAccessLevel() { + return Modifier.PUBLIC; + } +} diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/Java8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/Java8Parser.java index 5395dba090d..13260e3e366 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/Java8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/Java8Parser.java @@ -1,149 +1,149 @@ -/* - * 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.java; - -import org.openrewrite.ExecutionContext; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.marker.JavaSourceSet; -import org.openrewrite.java.tree.J; - -import java.io.File; -import java.lang.reflect.Constructor; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.charset.Charset; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.List; - -public class Java8Parser implements JavaParser { - private final JavaParser delegate; - - Java8Parser(JavaParser delegate) { - this.delegate = delegate; - } - - @Override - public List parseInputs(Iterable sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { - return delegate.parseInputs(sourceFiles, relativeTo, ctx); - } - - @Override - public JavaParser reset() { - return delegate.reset(); - } - - @Override - public void setClasspath(Collection classpath) { - delegate.setClasspath(classpath); - } - - @Override - public void setSourceSet(String sourceSet) { - delegate.setSourceSet(sourceSet); - } - - @Override - public JavaSourceSet getSourceSet(ExecutionContext ctx) { - return delegate.getSourceSet(ctx); - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder extends JavaParser.Builder { - - @Nullable - private static ClassLoader toolsClassLoader; - - @Nullable - private static ClassLoader toolsAwareClassLoader; - - static synchronized void lazyInitClassLoaders() { - if (toolsClassLoader != null && toolsAwareClassLoader != null) { - return; - } - - try { - File tools = Paths.get(System.getProperty("java.home")).resolve("../lib/tools.jar").toFile(); - if (!tools.exists()) { - throw new IllegalStateException("To use Java8Parser, you must run the process with a JDK and not a JRE."); - } - - toolsClassLoader = new URLClassLoader(new URL[]{tools.toURI().toURL()}, Java8Parser.class.getClassLoader()); - URLClassLoader appClassLoader = (URLClassLoader) Java8Parser.class.getClassLoader(); - - toolsAwareClassLoader = new URLClassLoader(appClassLoader.getURLs(), toolsClassLoader) { - @Override - protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - if (!name.contains("ReloadableJava8") && - !name.startsWith("com.sun.tools") && - !name.startsWith("com.sun.source") && - !name.contains("ReloadableTypeMapping")) { - return toolsClassLoader.loadClass(name); - } - - Class loadedClass = findLoadedClass(name); - - if (loadedClass == null) { - try { - loadedClass = findClass(name); - } catch (ClassNotFoundException e) { - loadedClass = super.loadClass(name, resolve); - } - } - - if (resolve) { - resolveClass(loadedClass); - } - - return loadedClass; - } - }; - } catch (MalformedURLException e) { - throw new IllegalStateException("To use Java8Parser, you must run the process with a JDK and not a JRE.", e); - } - } - - @Override - public Java8Parser build() { - lazyInitClassLoaders(); - - try { - // need to reverse this parent/child relationship - Class reloadableParser = Class.forName("org.openrewrite.java.ReloadableJava8Parser", true, - toolsAwareClassLoader); - - Constructor delegateParserConstructor = reloadableParser - .getDeclaredConstructor(Collection.class, Collection.class, Collection.class, Charset.class, - Boolean.TYPE, Collection.class, JavaTypeCache.class); - - delegateParserConstructor.setAccessible(true); - - JavaParser delegate = (JavaParser) delegateParserConstructor - .newInstance(classpath, classBytesClasspath, dependsOn, charset, logCompilationWarningsAndErrors, styles, javaTypeCache); - - return new Java8Parser(delegate); - } catch (Exception e) { - throw new IllegalStateException("Unable to construct Java8Parser.", e); - } - } - } -} +/* + * 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.java; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.internal.JavaTypeCache; +import org.openrewrite.java.marker.JavaSourceSet; +import org.openrewrite.java.tree.J; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; + +public class Java8Parser implements JavaParser { + private final JavaParser delegate; + + Java8Parser(JavaParser delegate) { + this.delegate = delegate; + } + + @Override + public List parseInputs(Iterable sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { + return delegate.parseInputs(sourceFiles, relativeTo, ctx); + } + + @Override + public JavaParser reset() { + return delegate.reset(); + } + + @Override + public void setClasspath(Collection classpath) { + delegate.setClasspath(classpath); + } + + @Override + public void setSourceSet(String sourceSet) { + delegate.setSourceSet(sourceSet); + } + + @Override + public JavaSourceSet getSourceSet(ExecutionContext ctx) { + return delegate.getSourceSet(ctx); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends JavaParser.Builder { + + @Nullable + private static ClassLoader toolsClassLoader; + + @Nullable + private static ClassLoader toolsAwareClassLoader; + + static synchronized void lazyInitClassLoaders() { + if (toolsClassLoader != null && toolsAwareClassLoader != null) { + return; + } + + try { + File tools = Paths.get(System.getProperty("java.home")).resolve("../lib/tools.jar").toFile(); + if (!tools.exists()) { + throw new IllegalStateException("To use Java8Parser, you must run the process with a JDK and not a JRE."); + } + + toolsClassLoader = new URLClassLoader(new URL[]{tools.toURI().toURL()}, Java8Parser.class.getClassLoader()); + URLClassLoader appClassLoader = (URLClassLoader) Java8Parser.class.getClassLoader(); + + toolsAwareClassLoader = new URLClassLoader(appClassLoader.getURLs(), toolsClassLoader) { + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (!name.contains("ReloadableJava8") && + !name.startsWith("com.sun.tools") && + !name.startsWith("com.sun.source") && + !name.contains("ReloadableTypeMapping")) { + return toolsClassLoader.loadClass(name); + } + + Class loadedClass = findLoadedClass(name); + + if (loadedClass == null) { + try { + loadedClass = findClass(name); + } catch (ClassNotFoundException e) { + loadedClass = super.loadClass(name, resolve); + } + } + + if (resolve) { + resolveClass(loadedClass); + } + + return loadedClass; + } + }; + } catch (MalformedURLException e) { + throw new IllegalStateException("To use Java8Parser, you must run the process with a JDK and not a JRE.", e); + } + } + + @Override + public Java8Parser build() { + lazyInitClassLoaders(); + + try { + // need to reverse this parent/child relationship + Class reloadableParser = Class.forName("org.openrewrite.java.ReloadableJava8Parser", true, + toolsAwareClassLoader); + + Constructor delegateParserConstructor = reloadableParser + .getDeclaredConstructor(Collection.class, Collection.class, Collection.class, Charset.class, + Boolean.TYPE, Collection.class, JavaTypeCache.class); + + delegateParserConstructor.setAccessible(true); + + JavaParser delegate = (JavaParser) delegateParserConstructor + .newInstance(classpath, classBytesClasspath, dependsOn, charset, logCompilationWarningsAndErrors, styles, javaTypeCache); + + return new Java8Parser(delegate); + } catch (Exception e) { + throw new IllegalStateException("Unable to construct Java8Parser.", e); + } + } + } +} 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 a911ec3bfef..5a519634871 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 @@ -1,121 +1,121 @@ -/* - * 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.java; - -import lombok.EqualsAndHashCode; -import lombok.Getter; -import org.openrewrite.Parser; -import org.openrewrite.internal.StringUtils; -import org.openrewrite.internal.lang.Nullable; - -import javax.lang.model.element.Modifier; -import javax.lang.model.element.NestingKind; -import javax.tools.JavaFileObject; -import java.io.*; -import java.net.URI; -import java.nio.file.Path; - -/** - * So that {@link JavaParser} can ingest source files from {@link InputStream} sources - * other than a file on disk. - */ -@EqualsAndHashCode(onlyExplicitlyIncluded = true) -public class Java8ParserInputFileObject implements JavaFileObject { - @EqualsAndHashCode.Include - @Nullable - private final Path path; - - @Getter - private final Parser.Input input; - - public Java8ParserInputFileObject(Parser.Input input) { - this.input = input; - this.path = input.getPath(); - } - - @Override - public URI toUri() { - if (path == null) { - //noinspection ConstantConditions - return null; - } - return path.toUri(); - } - - @Override - public String getName() { - if (path == null) { - //noinspection ConstantConditions - return null; - } - return path.toString(); - } - - @Override - public InputStream openInputStream() { - return input.getSource(); - } - - @Override - public OutputStream openOutputStream() { - throw new UnsupportedOperationException("Should be no need to write output to this file"); - } - - @Override - public Reader openReader(boolean ignoreEncodingErrors) { - return new InputStreamReader(input.getSource()); - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return input.getSource().readFully(); - } - - @Override - public Writer openWriter() { - throw new UnsupportedOperationException("Should be no need to write output to this file"); - } - - @Override - public long getLastModified() { - return 0; - } - - @Override - public boolean delete() { - return false; - } - - @Override - public Kind getKind() { - return Kind.SOURCE; - } - - @Override - public boolean isNameCompatible(String simpleName, Kind kind) { - return true; - } - - @Override - public NestingKind getNestingKind() { - return NestingKind.TOP_LEVEL; - } - - @Override - public Modifier getAccessLevel() { - return Modifier.PUBLIC; - } -} +/* + * 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.java; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.openrewrite.Parser; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.internal.lang.Nullable; + +import javax.lang.model.element.Modifier; +import javax.lang.model.element.NestingKind; +import javax.tools.JavaFileObject; +import java.io.*; +import java.net.URI; +import java.nio.file.Path; + +/** + * So that {@link JavaParser} can ingest source files from {@link InputStream} sources + * other than a file on disk. + */ +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +public class Java8ParserInputFileObject implements JavaFileObject { + @EqualsAndHashCode.Include + @Nullable + private final Path path; + + @Getter + private final Parser.Input input; + + public Java8ParserInputFileObject(Parser.Input input) { + this.input = input; + this.path = input.getPath(); + } + + @Override + public URI toUri() { + if (path == null) { + //noinspection ConstantConditions + return null; + } + return path.toUri(); + } + + @Override + public String getName() { + if (path == null) { + //noinspection ConstantConditions + return null; + } + return path.toString(); + } + + @Override + public InputStream openInputStream() { + return input.getSource(); + } + + @Override + public OutputStream openOutputStream() { + throw new UnsupportedOperationException("Should be no need to write output to this file"); + } + + @Override + public Reader openReader(boolean ignoreEncodingErrors) { + return new InputStreamReader(input.getSource()); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return input.getSource().readFully(); + } + + @Override + public Writer openWriter() { + throw new UnsupportedOperationException("Should be no need to write output to this file"); + } + + @Override + public long getLastModified() { + return 0; + } + + @Override + public boolean delete() { + return false; + } + + @Override + public Kind getKind() { + return Kind.SOURCE; + } + + @Override + public boolean isNameCompatible(String simpleName, Kind kind) { + return true; + } + + @Override + public NestingKind getNestingKind() { + return NestingKind.TOP_LEVEL; + } + + @Override + public Modifier getAccessLevel() { + return Modifier.PUBLIC; + } +} 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 6588e7aa3d9..a50245ca871 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 @@ -1,420 +1,420 @@ -/* - * 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.java; - -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.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 org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.Opcodes; -import org.openrewrite.ExecutionContext; -import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.Tree; -import org.openrewrite.internal.ListUtils; -import org.openrewrite.internal.MetricsHelper; -import org.openrewrite.internal.StringUtils; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.marker.JavaSourceSet; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaType; -import org.openrewrite.java.tree.Space; -import org.openrewrite.style.NamedStyles; -import org.openrewrite.tree.ParsingEventListener; -import org.openrewrite.tree.ParsingExecutionContextView; - -import javax.tools.*; -import java.io.*; -import java.net.URI; -import java.nio.charset.Charset; -import java.nio.file.Path; -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 java.util.Collections.emptyList; -import static java.util.stream.Collectors.toList; - -class ReloadableJava8Parser implements JavaParser { - private String sourceSet = "main"; - private final JavaTypeCache typeCache; - - @Nullable - private transient JavaSourceSet sourceSetProvenance; - - @Nullable - private Collection classpath; - - @Nullable - private final Collection dependsOn; - - private final JavacFileManager pfm; - - private final Context context; - private final JavaCompiler compiler; - private final ResettableLog compilerLog; - private final Collection styles; - - ReloadableJava8Parser(@Nullable Collection classpath, - Collection classBytesClasspath, - @Nullable Collection dependsOn, - Charset charset, - boolean logCompilationWarningsAndErrors, - Collection styles, - JavaTypeCache typeCache) { - this.classpath = classpath; - this.dependsOn = dependsOn; - this.styles = styles; - this.typeCache = typeCache; - - this.context = new Context(); - this.compilerLog = new ResettableLog(context); - this.pfm = new ByteArrayCapableJavacFileManager(context, true, charset, classBytesClasspath); - context.put(JavaFileManager.class, this.pfm); - - // otherwise, consecutive string literals in binary expressions are concatenated by the parser, losing the original - // structure of the expression! - Options.instance(context).put("allowStringFolding", "false"); - Options.instance(context).put("compilePolicy", "attr"); - - // JavaCompiler line 452 (call to ImplicitSourcePolicy.decode(..)) - Options.instance(context).put("-implicit", "none"); - - // https://docs.oracle.com/en/java/javacard/3.1/guide/setting-java-compiler-options.html - Options.instance(context).put("-g", "-g"); - Options.instance(context).put("-proc", "none"); - - // MUST be created (registered with the context) after pfm and compilerLog - compiler = new JavaCompiler(context); - - // otherwise, the JavacParser will use EmptyEndPosTable, effectively setting -1 as the end position - // for every tree element - compiler.genEndPos = true; - - compiler.keepComments = true; - - // we don't need this, so as a minor performance improvement, omit these compiler features - compiler.lineDebugInfo = false; - - compilerLog.setWriters(new PrintWriter(new Writer() { - @Override - public void write(char[] cbuf, int off, int len) { - if (logCompilationWarningsAndErrors) { - String log = new String(Arrays.copyOfRange(cbuf, off, len)); - if (!StringUtils.isBlank(log) && !log.contains("warning: a package-info.java file has already")) { - org.slf4j.LoggerFactory.getLogger(ReloadableJava8Parser.class).warn(log); - } - } - } - - @Override - public void flush() { - } - - @Override - public void close() { - } - })); - - compileDependencies(); - } - - @Override - public List 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).stream() - .collect(Collectors.toMap( - Function.identity(), - input -> MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent by the JDK in parsing and tokenizing the source file") - .tag("file.type", "Java") - .tag("step", "(1) JDK parsing")) - .register(Metrics.globalRegistry) - .record(() -> { - try { - return compiler.parse(new Java8ParserInputFileObject(input)); - } 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; - } - }), - (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)); - } - - List mappedCus = cus.entrySet().stream() - .map(cuByPath -> { - Timer.Sample sample = Timer.start(); - Input input = cuByPath.getKey(); - try { - ReloadableJava8ParserVisitor parser = new ReloadableJava8ParserVisitor( - input.getRelativePath(relativeTo), - input.getSource(), - styles, - typeCache, - ctx, - context); - J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); - sample.stop(MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent mapping the OpenJDK AST to Rewrite's AST") - .tag("file.type", "Java") - .tag("step", "(3) Map to Rewrite AST")) - .register(Metrics.globalRegistry)); - parsingListener.parsed(input, cu); - return cu; - } catch (Throwable t) { - sample.stop(MetricsHelper.errorTags( - Timer.builder("rewrite.parse") - .description("The time spent mapping the OpenJDK AST to Rewrite's AST") - .tag("file.type", "Java") - .tag("step", "(3) Map to Rewrite AST"), t) - .register(Metrics.globalRegistry)); - - ctx.getOnError().accept(t); - return null; - } - }) - .filter(Objects::nonNull) - .collect(toList()); - - JavaSourceSet sourceSet = getSourceSet(ctx); - if (!ctx.getMessage(SKIP_SOURCE_SET_TYPE_GENERATION, false)) { - List classpath = sourceSet.getClasspath(); - for (J.CompilationUnit cu : mappedCus) { - for (JavaType type : cu.getTypesInUse().getTypesInUse()) { - if (type instanceof JavaType.FullyQualified) { - classpath.add((JavaType.FullyQualified) type); - } - } - } - sourceSetProvenance = sourceSet.withClasspath(classpath); - } - - assert sourceSetProvenance != null; - return ListUtils.map(mappedCus, cu -> cu.withMarkers(cu.getMarkers().add(sourceSetProvenance))); - } - - @Override - public ReloadableJava8Parser reset() { - typeCache.clear(); - compilerLog.reset(); - pfm.flush(); - compileDependencies(); - return this; - } - - @Override - public void setClasspath(Collection classpath) { - this.classpath = classpath; - } - - @Override - public void setSourceSet(String sourceSet) { - this.sourceSetProvenance = null; - this.sourceSet = sourceSet; - } - - @Override - public JavaSourceSet getSourceSet(ExecutionContext ctx) { - if (sourceSetProvenance == null) { - if (ctx.getMessage(SKIP_SOURCE_SET_TYPE_GENERATION, false)) { - sourceSetProvenance = new JavaSourceSet(Tree.randomId(), sourceSet, emptyList()); - } else { - sourceSetProvenance = JavaSourceSet.build(sourceSet, classpath == null ? emptyList() : classpath, - typeCache, false); - } - } - return sourceSetProvenance; - } - - private void compileDependencies() { - if (dependsOn != null) { - InMemoryExecutionContext ctx = new InMemoryExecutionContext(); - ctx.putMessage("org.openrewrite.java.skipSourceSetMarker", true); - parseInputs(dependsOn, null, ctx); - } - Check.instance(context).compiled.clear(); - } - - /** - * Enter symbol definitions into each compilation unit's scope - */ - private void enterAll(Collection cus) { - Enter enter = Enter.instance(context); - com.sun.tools.javac.util.List compilationUnits = com.sun.tools.javac.util.List.from( - cus.toArray(new JCTree.JCCompilationUnit[0])); - enter.main(compilationUnits); - } - - private static class ResettableLog extends Log { - protected ResettableLog(Context context) { - super(context); - } - - public void reset() { - sourceMap.clear(); - } - } - - private static class TimedTodo extends Todo { - private final Todo todo; - private @Nullable Timer.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; - - public ByteArrayCapableJavacFileManager(Context context, - boolean register, - Charset charset, - Collection classByteClasspath) { - super(context, register, charset); - this.classByteClasspath = classByteClasspath.stream() - .map(PackageAwareJavaFileObject::new) - .collect(toList()); - } - - @Override - public boolean isSameFile(FileObject fileObject, FileObject fileObject1) { - return fileObject.equals(fileObject1); - } - - @Override - public String inferBinaryName(Location location, JavaFileObject file) { - if (file instanceof PackageAwareJavaFileObject) { - return ((PackageAwareJavaFileObject) file).getClassName(); - } - return super.inferBinaryName(location, file); - } - - @Override - 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() - .filter(jfo -> jfo.getPackage().equals(packageName)), - StreamSupport.stream(listed.spliterator(), false) - ).collect(toList()); - } - return super.list(location, packageName, kinds, recurse); - } - } - - private static class PackageAwareJavaFileObject extends SimpleJavaFileObject { - private final String pkg; - private final String className; - private final byte[] classBytes; - - private PackageAwareJavaFileObject(byte[] classBytes) { - super(URI.create("file:///.byteArray"), Kind.CLASS); - - AtomicReference pkgRef = new AtomicReference<>(); - AtomicReference nameRef = new AtomicReference<>(); - - ClassReader classReader = new ClassReader(classBytes); - classReader.accept(new ClassVisitor(Opcodes.ASM9) { - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - if (name.contains("/")) { - pkgRef.set(name.substring(0, name.lastIndexOf('/')) - .replace('/', '.')); - nameRef.set(name.substring(name.lastIndexOf('/') + 1)); - } else { - pkgRef.set(name); - nameRef.set(name); - } - } - }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); - - this.pkg = pkgRef.get(); - this.className = nameRef.get(); - this.classBytes = classBytes; - } - - public String getPackage() { - return pkg; - } - - public String getClassName() { - return className; - } - - @Override - public InputStream openInputStream() { - return new ByteArrayInputStream(classBytes); - } - } -} +/* + * 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.java; + +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.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 org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; +import org.openrewrite.ExecutionContext; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.Tree; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.MetricsHelper; +import org.openrewrite.internal.StringUtils; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.internal.JavaTypeCache; +import org.openrewrite.java.marker.JavaSourceSet; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.Space; +import org.openrewrite.style.NamedStyles; +import org.openrewrite.tree.ParsingEventListener; +import org.openrewrite.tree.ParsingExecutionContextView; + +import javax.tools.*; +import java.io.*; +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.file.Path; +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 java.util.Collections.emptyList; +import static java.util.stream.Collectors.toList; + +class ReloadableJava8Parser implements JavaParser { + private String sourceSet = "main"; + private final JavaTypeCache typeCache; + + @Nullable + private transient JavaSourceSet sourceSetProvenance; + + @Nullable + private Collection classpath; + + @Nullable + private final Collection dependsOn; + + private final JavacFileManager pfm; + + private final Context context; + private final JavaCompiler compiler; + private final ResettableLog compilerLog; + private final Collection styles; + + ReloadableJava8Parser(@Nullable Collection classpath, + Collection classBytesClasspath, + @Nullable Collection dependsOn, + Charset charset, + boolean logCompilationWarningsAndErrors, + Collection styles, + JavaTypeCache typeCache) { + this.classpath = classpath; + this.dependsOn = dependsOn; + this.styles = styles; + this.typeCache = typeCache; + + this.context = new Context(); + this.compilerLog = new ResettableLog(context); + this.pfm = new ByteArrayCapableJavacFileManager(context, true, charset, classBytesClasspath); + context.put(JavaFileManager.class, this.pfm); + + // otherwise, consecutive string literals in binary expressions are concatenated by the parser, losing the original + // structure of the expression! + Options.instance(context).put("allowStringFolding", "false"); + Options.instance(context).put("compilePolicy", "attr"); + + // JavaCompiler line 452 (call to ImplicitSourcePolicy.decode(..)) + Options.instance(context).put("-implicit", "none"); + + // https://docs.oracle.com/en/java/javacard/3.1/guide/setting-java-compiler-options.html + Options.instance(context).put("-g", "-g"); + Options.instance(context).put("-proc", "none"); + + // MUST be created (registered with the context) after pfm and compilerLog + compiler = new JavaCompiler(context); + + // otherwise, the JavacParser will use EmptyEndPosTable, effectively setting -1 as the end position + // for every tree element + compiler.genEndPos = true; + + compiler.keepComments = true; + + // we don't need this, so as a minor performance improvement, omit these compiler features + compiler.lineDebugInfo = false; + + compilerLog.setWriters(new PrintWriter(new Writer() { + @Override + public void write(char[] cbuf, int off, int len) { + if (logCompilationWarningsAndErrors) { + String log = new String(Arrays.copyOfRange(cbuf, off, len)); + if (!StringUtils.isBlank(log) && !log.contains("warning: a package-info.java file has already")) { + org.slf4j.LoggerFactory.getLogger(ReloadableJava8Parser.class).warn(log); + } + } + } + + @Override + public void flush() { + } + + @Override + public void close() { + } + })); + + compileDependencies(); + } + + @Override + public List 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).stream() + .collect(Collectors.toMap( + Function.identity(), + input -> MetricsHelper.successTags( + Timer.builder("rewrite.parse") + .description("The time spent by the JDK in parsing and tokenizing the source file") + .tag("file.type", "Java") + .tag("step", "(1) JDK parsing")) + .register(Metrics.globalRegistry) + .record(() -> { + try { + return compiler.parse(new Java8ParserInputFileObject(input)); + } 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; + } + }), + (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)); + } + + List mappedCus = cus.entrySet().stream() + .map(cuByPath -> { + Timer.Sample sample = Timer.start(); + Input input = cuByPath.getKey(); + try { + ReloadableJava8ParserVisitor parser = new ReloadableJava8ParserVisitor( + input.getRelativePath(relativeTo), + input.getSource(), + styles, + typeCache, + ctx, + context); + J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); + sample.stop(MetricsHelper.successTags( + Timer.builder("rewrite.parse") + .description("The time spent mapping the OpenJDK AST to Rewrite's AST") + .tag("file.type", "Java") + .tag("step", "(3) Map to Rewrite AST")) + .register(Metrics.globalRegistry)); + parsingListener.parsed(input, cu); + return cu; + } catch (Throwable t) { + sample.stop(MetricsHelper.errorTags( + Timer.builder("rewrite.parse") + .description("The time spent mapping the OpenJDK AST to Rewrite's AST") + .tag("file.type", "Java") + .tag("step", "(3) Map to Rewrite AST"), t) + .register(Metrics.globalRegistry)); + + ctx.getOnError().accept(t); + return null; + } + }) + .filter(Objects::nonNull) + .collect(toList()); + + JavaSourceSet sourceSet = getSourceSet(ctx); + if (!ctx.getMessage(SKIP_SOURCE_SET_TYPE_GENERATION, false)) { + List classpath = sourceSet.getClasspath(); + for (J.CompilationUnit cu : mappedCus) { + for (JavaType type : cu.getTypesInUse().getTypesInUse()) { + if (type instanceof JavaType.FullyQualified) { + classpath.add((JavaType.FullyQualified) type); + } + } + } + sourceSetProvenance = sourceSet.withClasspath(classpath); + } + + assert sourceSetProvenance != null; + return ListUtils.map(mappedCus, cu -> cu.withMarkers(cu.getMarkers().add(sourceSetProvenance))); + } + + @Override + public ReloadableJava8Parser reset() { + typeCache.clear(); + compilerLog.reset(); + pfm.flush(); + compileDependencies(); + return this; + } + + @Override + public void setClasspath(Collection classpath) { + this.classpath = classpath; + } + + @Override + public void setSourceSet(String sourceSet) { + this.sourceSetProvenance = null; + this.sourceSet = sourceSet; + } + + @Override + public JavaSourceSet getSourceSet(ExecutionContext ctx) { + if (sourceSetProvenance == null) { + if (ctx.getMessage(SKIP_SOURCE_SET_TYPE_GENERATION, false)) { + sourceSetProvenance = new JavaSourceSet(Tree.randomId(), sourceSet, emptyList()); + } else { + sourceSetProvenance = JavaSourceSet.build(sourceSet, classpath == null ? emptyList() : classpath, + typeCache, false); + } + } + return sourceSetProvenance; + } + + private void compileDependencies() { + if (dependsOn != null) { + InMemoryExecutionContext ctx = new InMemoryExecutionContext(); + ctx.putMessage("org.openrewrite.java.skipSourceSetMarker", true); + parseInputs(dependsOn, null, ctx); + } + Check.instance(context).compiled.clear(); + } + + /** + * Enter symbol definitions into each compilation unit's scope + */ + private void enterAll(Collection cus) { + Enter enter = Enter.instance(context); + com.sun.tools.javac.util.List compilationUnits = com.sun.tools.javac.util.List.from( + cus.toArray(new JCTree.JCCompilationUnit[0])); + enter.main(compilationUnits); + } + + private static class ResettableLog extends Log { + protected ResettableLog(Context context) { + super(context); + } + + public void reset() { + sourceMap.clear(); + } + } + + private static class TimedTodo extends Todo { + private final Todo todo; + private @Nullable Timer.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; + + public ByteArrayCapableJavacFileManager(Context context, + boolean register, + Charset charset, + Collection classByteClasspath) { + super(context, register, charset); + this.classByteClasspath = classByteClasspath.stream() + .map(PackageAwareJavaFileObject::new) + .collect(toList()); + } + + @Override + public boolean isSameFile(FileObject fileObject, FileObject fileObject1) { + return fileObject.equals(fileObject1); + } + + @Override + public String inferBinaryName(Location location, JavaFileObject file) { + if (file instanceof PackageAwareJavaFileObject) { + return ((PackageAwareJavaFileObject) file).getClassName(); + } + return super.inferBinaryName(location, file); + } + + @Override + 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() + .filter(jfo -> jfo.getPackage().equals(packageName)), + StreamSupport.stream(listed.spliterator(), false) + ).collect(toList()); + } + return super.list(location, packageName, kinds, recurse); + } + } + + private static class PackageAwareJavaFileObject extends SimpleJavaFileObject { + private final String pkg; + private final String className; + private final byte[] classBytes; + + private PackageAwareJavaFileObject(byte[] classBytes) { + super(URI.create("file:///.byteArray"), Kind.CLASS); + + AtomicReference pkgRef = new AtomicReference<>(); + AtomicReference nameRef = new AtomicReference<>(); + + ClassReader classReader = new ClassReader(classBytes); + classReader.accept(new ClassVisitor(Opcodes.ASM9) { + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + if (name.contains("/")) { + pkgRef.set(name.substring(0, name.lastIndexOf('/')) + .replace('/', '.')); + nameRef.set(name.substring(name.lastIndexOf('/') + 1)); + } else { + pkgRef.set(name); + nameRef.set(name); + } + } + }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); + + this.pkg = pkgRef.get(); + this.className = nameRef.get(); + this.classBytes = classBytes; + } + + 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/test/kotlin/org/openrewrite/java/Java8Test.kt b/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8Test.kt index ae527298947..cfdc513ca95 100644 --- a/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8Test.kt +++ b/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8Test.kt @@ -1,20 +1,20 @@ -/* - * 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.java - -interface Java8Test { - fun javaParser(): Java8Parser.Builder = Java8Parser.builder() -} +/* + * 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.java + +interface Java8Test { + fun javaParser(): Java8Parser.Builder = Java8Parser.builder() +} diff --git a/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8TreeCompatibilityTest.kt b/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8TreeCompatibilityTest.kt index 82dbd96c7ac..c4283879ba0 100644 --- a/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8TreeCompatibilityTest.kt +++ b/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8TreeCompatibilityTest.kt @@ -1,20 +1,20 @@ -/* - * 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.java - -class Java8TreeCompatibilityTest: JavaTreeCompatibilityKit() { - override fun javaParser(): Java8Parser.Builder = Java8Parser.builder() -} +/* + * 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.java + +class Java8TreeCompatibilityTest: JavaTreeCompatibilityKit() { + override fun javaParser(): Java8Parser.Builder = Java8Parser.builder() +} diff --git a/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8TreeDebugTest.kt b/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8TreeDebugTest.kt index 4cb552bbebf..36d39db9907 100755 --- a/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8TreeDebugTest.kt +++ b/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8TreeDebugTest.kt @@ -1,216 +1,216 @@ -/* - * 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.java - -import org.junit.jupiter.api.extension.ExtendWith -import org.openrewrite.DebugOnly -import org.openrewrite.java.tree.* - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8AnnotationTest: Java8Test, AnnotationTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8ArrayAccessTest: Java8Test, ArrayAccessTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8ArrayTypeTest: Java8Test, ArrayTypeTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8AssertTest: Java8Test, AssertTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8AssignmentOperationTest: Java8Test, AssignmentOperationTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8AssignmentTest: Java8Test, AssignmentTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8BinaryTest: Java8Test, BinaryTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8BlockTest: Java8Test, BlockTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8BreakTest: Java8Test, BreakTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8ClassDeclarationTest: Java8Test, ClassDeclarationTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8CommentTest: Java8Test, CommentTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8CompilationUnitTest: Java8Test, CompilationUnitTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8ContinueTest: Java8Test, ContinueTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8DoWhileLoopTest: Java8Test, DoWhileLoopTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8EmptyTest: Java8Test, EmptyTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8EnumTest: Java8Test, EnumTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8FieldAccessTest: Java8Test, FieldAccessTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8ForLoopTest: Java8Test, ForLoopTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8ForEachLoopTest: Java8Test, ForEachLoopTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8IdentifierTest: Java8Test, IdentifierTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8IfTest: Java8Test, IfTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8ImportTest: Java8Test, ImportTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8InstanceOfTest: Java8Test, InstanceOfTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8JavadocTest: Java8Test, JavadocTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8JavaParserTest: Java8Test, JavaParserTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8LabelTest: Java8Test, LabelTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8LambdaTest: Java8Test, LambdaTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8LiteralTest: Java8Test, LiteralTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8MemberReferenceTest: Java8Test, MemberReferenceTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8MethodDeclarationTest: Java8Test, MethodDeclarationTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8MethodInvocationTest: Java8Test, MethodInvocationTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8MethodMatcherTest: Java8Test, MethodMatcherTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8MethodParamPadTest: Java8Test, MethodParamPadTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8NewArrayTest: Java8Test, NewArrayTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8NewClassTest: Java8Test, NewClassTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8PackageTest: Java8Test, PackageTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8ParenthesesTest: Java8Test, ParenthesesTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8PrimitiveTest: Java8Test, PrimitiveTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8ReturnTest: Java8Test, ReturnTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8SwitchTest: Java8Test, SwitchTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8SynchronizedTest: Java8Test, SynchronizedTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8TernaryTest: Java8Test, TernaryTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8ThrowTest: Java8Test, ThrowTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8TryCatchTest: Java8Test, TryCatchTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8TypeCastTest: Java8Test, TypeCastTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8TypeParameterAndWildcardTest: Java8Test, TypeParameterAndWildcardTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8UnaryTest: Java8Test, UnaryTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8VariableDeclarationsTest: Java8Test, VariableDeclarationsTest - -@DebugOnly -@ExtendWith(JavaParserResolver::class) -class Java8WhileLoopTest: Java8Test, WhileLoopTest +/* + * 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.java + +import org.junit.jupiter.api.extension.ExtendWith +import org.openrewrite.DebugOnly +import org.openrewrite.java.tree.* + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8AnnotationTest: Java8Test, AnnotationTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8ArrayAccessTest: Java8Test, ArrayAccessTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8ArrayTypeTest: Java8Test, ArrayTypeTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8AssertTest: Java8Test, AssertTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8AssignmentOperationTest: Java8Test, AssignmentOperationTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8AssignmentTest: Java8Test, AssignmentTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8BinaryTest: Java8Test, BinaryTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8BlockTest: Java8Test, BlockTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8BreakTest: Java8Test, BreakTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8ClassDeclarationTest: Java8Test, ClassDeclarationTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8CommentTest: Java8Test, CommentTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8CompilationUnitTest: Java8Test, CompilationUnitTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8ContinueTest: Java8Test, ContinueTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8DoWhileLoopTest: Java8Test, DoWhileLoopTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8EmptyTest: Java8Test, EmptyTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8EnumTest: Java8Test, EnumTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8FieldAccessTest: Java8Test, FieldAccessTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8ForLoopTest: Java8Test, ForLoopTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8ForEachLoopTest: Java8Test, ForEachLoopTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8IdentifierTest: Java8Test, IdentifierTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8IfTest: Java8Test, IfTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8ImportTest: Java8Test, ImportTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8InstanceOfTest: Java8Test, InstanceOfTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8JavadocTest: Java8Test, JavadocTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8JavaParserTest: Java8Test, JavaParserTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8LabelTest: Java8Test, LabelTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8LambdaTest: Java8Test, LambdaTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8LiteralTest: Java8Test, LiteralTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8MemberReferenceTest: Java8Test, MemberReferenceTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8MethodDeclarationTest: Java8Test, MethodDeclarationTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8MethodInvocationTest: Java8Test, MethodInvocationTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8MethodMatcherTest: Java8Test, MethodMatcherTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8MethodParamPadTest: Java8Test, MethodParamPadTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8NewArrayTest: Java8Test, NewArrayTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8NewClassTest: Java8Test, NewClassTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8PackageTest: Java8Test, PackageTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8ParenthesesTest: Java8Test, ParenthesesTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8PrimitiveTest: Java8Test, PrimitiveTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8ReturnTest: Java8Test, ReturnTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8SwitchTest: Java8Test, SwitchTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8SynchronizedTest: Java8Test, SynchronizedTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8TernaryTest: Java8Test, TernaryTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8ThrowTest: Java8Test, ThrowTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8TryCatchTest: Java8Test, TryCatchTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8TypeCastTest: Java8Test, TypeCastTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8TypeParameterAndWildcardTest: Java8Test, TypeParameterAndWildcardTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8UnaryTest: Java8Test, UnaryTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8VariableDeclarationsTest: Java8Test, VariableDeclarationsTest + +@DebugOnly +@ExtendWith(JavaParserResolver::class) +class Java8WhileLoopTest: Java8Test, WhileLoopTest diff --git a/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8VisitorCompatibilityTest.kt b/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8VisitorCompatibilityTest.kt index 604d8dd70db..739a418445b 100755 --- a/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8VisitorCompatibilityTest.kt +++ b/rewrite-java-8/src/test/kotlin/org/openrewrite/java/Java8VisitorCompatibilityTest.kt @@ -1,20 +1,20 @@ -/* - * 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.java - -class Java8VisitorCompatibilityTest: JavaVisitorCompatibilityKit() { - override fun javaParser(): Java8Parser.Builder = Java8Parser.builder() -} +/* + * 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.java + +class Java8VisitorCompatibilityTest: JavaVisitorCompatibilityKit() { + override fun javaParser(): Java8Parser.Builder = Java8Parser.builder() +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodAccessLevel.java b/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodAccessLevel.java index c5e046a3e89..ae04d32e390 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodAccessLevel.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodAccessLevel.java @@ -1,89 +1,89 @@ -/* - * 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.java; - -import lombok.EqualsAndHashCode; -import lombok.Value; -import org.openrewrite.ExecutionContext; -import org.openrewrite.Option; -import org.openrewrite.Recipe; -import org.openrewrite.Validated; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.search.DeclaresMethod; -import org.openrewrite.java.tree.J; - -@Value -@EqualsAndHashCode(callSuper = true) -public class ChangeMethodAccessLevel 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 access level", - description = "New method access level to apply to the method.", - example = "public", - valid = {"private", "protected", "package", "public"}) - String newAccessLevel; - - @Option(displayName = "Match on overrides", - description = "When enabled, find methods that are overrides of the method pattern.", - required = false) - @Nullable - Boolean matchOverrides; - - @Override - public String getDisplayName() { - return "Change method access level"; - } - - @Override - public String getDescription() { - return "Change the access level (public, protected, private, package private) of a method."; - } - - @Override - public Validated validate() { - return super.validate().and(Validated.test("newAccessLevel", "Must be one of 'private', 'protected', 'package', 'public'", - newAccessLevel, level -> "private".equals(level) || "protected".equals(level) || "package".equals(level) || "public".equals(level))); - } - - @Override - protected JavaVisitor getSingleSourceApplicableTest() { - return new DeclaresMethod<>(methodPattern, matchOverrides); - } - - @Override - public JavaVisitor getVisitor() { - J.Modifier.Type type; - switch (newAccessLevel) { - case "public": - type = J.Modifier.Type.Public; - break; - case "protected": - type = J.Modifier.Type.Protected; - break; - case "private": - type = J.Modifier.Type.Private; - break; - default: - type = null; - } - - return new ChangeMethodAccessLevelVisitor<>(new MethodMatcher(methodPattern, matchOverrides), type); - } -} +/* + * 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.java; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.Validated; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.search.DeclaresMethod; +import org.openrewrite.java.tree.J; + +@Value +@EqualsAndHashCode(callSuper = true) +public class ChangeMethodAccessLevel 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 access level", + description = "New method access level to apply to the method.", + example = "public", + valid = {"private", "protected", "package", "public"}) + String newAccessLevel; + + @Option(displayName = "Match on overrides", + description = "When enabled, find methods that are overrides of the method pattern.", + required = false) + @Nullable + Boolean matchOverrides; + + @Override + public String getDisplayName() { + return "Change method access level"; + } + + @Override + public String getDescription() { + return "Change the access level (public, protected, private, package private) of a method."; + } + + @Override + public Validated validate() { + return super.validate().and(Validated.test("newAccessLevel", "Must be one of 'private', 'protected', 'package', 'public'", + newAccessLevel, level -> "private".equals(level) || "protected".equals(level) || "package".equals(level) || "public".equals(level))); + } + + @Override + protected JavaVisitor getSingleSourceApplicableTest() { + return new DeclaresMethod<>(methodPattern, matchOverrides); + } + + @Override + public JavaVisitor getVisitor() { + J.Modifier.Type type; + switch (newAccessLevel) { + case "public": + type = J.Modifier.Type.Public; + break; + case "protected": + type = J.Modifier.Type.Protected; + break; + case "private": + type = J.Modifier.Type.Private; + break; + default: + type = null; + } + + return new ChangeMethodAccessLevelVisitor<>(new MethodMatcher(methodPattern, matchOverrides), type); + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodAccessLevelVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodAccessLevelVisitor.java index a2ec4f74c22..7372d098c06 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodAccessLevelVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/ChangeMethodAccessLevelVisitor.java @@ -1,129 +1,129 @@ -/* - * 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.java; - -import lombok.EqualsAndHashCode; -import lombok.Value; -import org.openrewrite.Tree; -import org.openrewrite.internal.ListUtils; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.tree.Comment; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.Space; -import org.openrewrite.java.tree.TypeTree; -import org.openrewrite.marker.Markers; - -import java.util.*; - -import static java.util.Collections.emptyList; - -@Value -@EqualsAndHashCode(callSuper = true) -public class ChangeMethodAccessLevelVisitor

extends JavaIsoVisitor

{ - private static final Collection EXPLICIT_ACCESS_LEVELS = Arrays.asList(J.Modifier.Type.Public, - J.Modifier.Type.Private, J.Modifier.Type.Protected); - - MethodMatcher methodMatcher; - - @Nullable - J.Modifier.Type newAccessLevel; - - @Override - public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, P p) { - J.MethodDeclaration m = super.visitMethodDeclaration(method, p); - J.ClassDeclaration classDecl = getCursor().firstEnclosingOrThrow(J.ClassDeclaration.class); - if (methodMatcher.matches(method, classDecl)) { - J.Modifier.Type currentMethodAccessLevel = m.getModifiers().stream() - .map(J.Modifier::getType) - .filter(EXPLICIT_ACCESS_LEVELS::contains) - .findAny() - .orElse(null); - - if (currentMethodAccessLevel == newAccessLevel) { - // No changes required - return m; - } - - // Replace former modifier by new modifier if package-private is not involved - if (EXPLICIT_ACCESS_LEVELS.contains(currentMethodAccessLevel) && EXPLICIT_ACCESS_LEVELS.contains(newAccessLevel)) { - m = m.withModifiers( - ListUtils.map(m.getModifiers(), mod -> mod.getType() == currentMethodAccessLevel ? - mod.withType(newAccessLevel) : mod) - ); - } - - // If current access level is package-private (no modifier), add the new modifier - else if (currentMethodAccessLevel == null) { - J.Modifier mod = new J.Modifier(Tree.randomId(), Space.build(" ", emptyList()), Markers.EMPTY, newAccessLevel, Collections.emptyList()); - m = m.withModifiers(ListUtils.concat(mod, m.getModifiers())); - - if(method.getModifiers().isEmpty()) { - J.TypeParameters typeParams = m.getPadding().getTypeParameters(); - if(typeParams == null) { - TypeTree returnExpr = m.getReturnTypeExpression(); - if(returnExpr == null) { - m = m.withModifiers(Space.formatFirstPrefix(m.getModifiers(), m.getName().getPrefix())); - m = m.withName(m.getName().withPrefix(Space.format(" "))); - } else { - m = m.withModifiers(Space.formatFirstPrefix(m.getModifiers(), returnExpr.getPrefix())); - m = m.withReturnTypeExpression(returnExpr.withPrefix(Space.format(" "))); - } - } else { - m = m.withModifiers(Space.formatFirstPrefix(m.getModifiers(), typeParams.getPrefix())); - m = m.getPadding().withTypeParameters(typeParams.withPrefix(Space.format(" "))); - } - } - else { - m = m.withModifiers(ListUtils.map(m.getModifiers(), (i, mod2) -> { - if (i == 0) { - return mod2.withPrefix(method.getModifiers().get(0).getPrefix()); - } else if (i == 1) { - return mod2.withPrefix(Space.format(" ")); - } - return mod2; - })); - } - } - - // If target access level is package-private (no modifier), remove the current access level modifier - // and copy any associated comments - else if (newAccessLevel == null) { - final List modifierComments = new ArrayList<>(); - List modifiers = ListUtils.map(m.getModifiers(), mod -> { - if (mod.getType() == currentMethodAccessLevel) { - modifierComments.addAll(mod.getComments()); - return null; - } - - // copy access level modifier comment to next modifier if it exists - if (!modifierComments.isEmpty()) { - J.Modifier nextModifier = mod.withComments(ListUtils.concatAll(new ArrayList<>(modifierComments), mod.getComments())); - modifierComments.clear(); - return nextModifier; - } - return mod; - }); - - // if no following modifier exists, add comments to method itself - if (!modifierComments.isEmpty()) { - m = m.withComments(ListUtils.concatAll(m.getComments(), modifierComments)); - } - m = maybeAutoFormat(m, m.withModifiers(modifiers), p, getCursor().dropParentUntil(J.class::isInstance)); - } - } - return m; - } -} +/* + * 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.java; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.Tree; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.tree.Comment; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.Space; +import org.openrewrite.java.tree.TypeTree; +import org.openrewrite.marker.Markers; + +import java.util.*; + +import static java.util.Collections.emptyList; + +@Value +@EqualsAndHashCode(callSuper = true) +public class ChangeMethodAccessLevelVisitor

extends JavaIsoVisitor

{ + private static final Collection EXPLICIT_ACCESS_LEVELS = Arrays.asList(J.Modifier.Type.Public, + J.Modifier.Type.Private, J.Modifier.Type.Protected); + + MethodMatcher methodMatcher; + + @Nullable + J.Modifier.Type newAccessLevel; + + @Override + public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, P p) { + J.MethodDeclaration m = super.visitMethodDeclaration(method, p); + J.ClassDeclaration classDecl = getCursor().firstEnclosingOrThrow(J.ClassDeclaration.class); + if (methodMatcher.matches(method, classDecl)) { + J.Modifier.Type currentMethodAccessLevel = m.getModifiers().stream() + .map(J.Modifier::getType) + .filter(EXPLICIT_ACCESS_LEVELS::contains) + .findAny() + .orElse(null); + + if (currentMethodAccessLevel == newAccessLevel) { + // No changes required + return m; + } + + // Replace former modifier by new modifier if package-private is not involved + if (EXPLICIT_ACCESS_LEVELS.contains(currentMethodAccessLevel) && EXPLICIT_ACCESS_LEVELS.contains(newAccessLevel)) { + m = m.withModifiers( + ListUtils.map(m.getModifiers(), mod -> mod.getType() == currentMethodAccessLevel ? + mod.withType(newAccessLevel) : mod) + ); + } + + // If current access level is package-private (no modifier), add the new modifier + else if (currentMethodAccessLevel == null) { + J.Modifier mod = new J.Modifier(Tree.randomId(), Space.build(" ", emptyList()), Markers.EMPTY, newAccessLevel, Collections.emptyList()); + m = m.withModifiers(ListUtils.concat(mod, m.getModifiers())); + + if(method.getModifiers().isEmpty()) { + J.TypeParameters typeParams = m.getPadding().getTypeParameters(); + if(typeParams == null) { + TypeTree returnExpr = m.getReturnTypeExpression(); + if(returnExpr == null) { + m = m.withModifiers(Space.formatFirstPrefix(m.getModifiers(), m.getName().getPrefix())); + m = m.withName(m.getName().withPrefix(Space.format(" "))); + } else { + m = m.withModifiers(Space.formatFirstPrefix(m.getModifiers(), returnExpr.getPrefix())); + m = m.withReturnTypeExpression(returnExpr.withPrefix(Space.format(" "))); + } + } else { + m = m.withModifiers(Space.formatFirstPrefix(m.getModifiers(), typeParams.getPrefix())); + m = m.getPadding().withTypeParameters(typeParams.withPrefix(Space.format(" "))); + } + } + else { + m = m.withModifiers(ListUtils.map(m.getModifiers(), (i, mod2) -> { + if (i == 0) { + return mod2.withPrefix(method.getModifiers().get(0).getPrefix()); + } else if (i == 1) { + return mod2.withPrefix(Space.format(" ")); + } + return mod2; + })); + } + } + + // If target access level is package-private (no modifier), remove the current access level modifier + // and copy any associated comments + else if (newAccessLevel == null) { + final List modifierComments = new ArrayList<>(); + List modifiers = ListUtils.map(m.getModifiers(), mod -> { + if (mod.getType() == currentMethodAccessLevel) { + modifierComments.addAll(mod.getComments()); + return null; + } + + // copy access level modifier comment to next modifier if it exists + if (!modifierComments.isEmpty()) { + J.Modifier nextModifier = mod.withComments(ListUtils.concatAll(new ArrayList<>(modifierComments), mod.getComments())); + modifierComments.clear(); + return nextModifier; + } + return mod; + }); + + // if no following modifier exists, add comments to method itself + if (!modifierComments.isEmpty()) { + m = m.withComments(ListUtils.concatAll(m.getComments(), modifierComments)); + } + m = maybeAutoFormat(m, m.withModifiers(modifiers), p, getCursor().dropParentUntil(J.class::isInstance)); + } + } + return m; + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/ImplementInterface.java b/rewrite-java/src/main/java/org/openrewrite/java/ImplementInterface.java index cbfd256e731..62e0c340916 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/ImplementInterface.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/ImplementInterface.java @@ -1,64 +1,64 @@ -/* - * 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.java; - -import org.openrewrite.internal.ListUtils; -import org.openrewrite.java.tree.*; -import org.openrewrite.marker.Markers; - -import static org.openrewrite.Tree.randomId; -import static org.openrewrite.java.tree.Space.format; - -public class ImplementInterface

extends JavaIsoVisitor

{ - private final J.ClassDeclaration scope; - private final JavaType.FullyQualified interfaceType; - - public ImplementInterface(J.ClassDeclaration scope, JavaType.FullyQualified interfaceType) { - this.scope = scope; - this.interfaceType = interfaceType; - } - - public ImplementInterface(J.ClassDeclaration scope, String interfaze) { - this(scope, JavaType.ShallowClass.build(interfaze)); - } - - @Override - public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, P p) { - J.ClassDeclaration c = super.visitClassDeclaration(classDecl, p); - if (c.isScope(scope) && (c.getImplements() == null || c.getImplements().stream() - .noneMatch(f -> TypeUtils.isAssignableTo(f.getType(), interfaceType)))) { - - if(!classDecl.getSimpleName().equals(interfaceType.getClassName())) { - maybeAddImport(interfaceType); - } - - TypeTree impl = TypeTree.build(classDecl.getSimpleName().equals(interfaceType.getClassName()) ? - interfaceType.getFullyQualifiedName() : interfaceType.getClassName()) - .withType(interfaceType) - .withPrefix(format(" ")); - - c = c.withImplements(ListUtils.concat(c.getImplements(), impl)); - - JContainer anImplements = c.getPadding().getImplements(); - assert anImplements != null; - if (anImplements.getBefore().getWhitespace().isEmpty()) { - c = c.getPadding().withImplements(anImplements.withBefore(Space.format(" "))); - } - } - - return c; - } -} +/* + * 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.java; + +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.tree.*; +import org.openrewrite.marker.Markers; + +import static org.openrewrite.Tree.randomId; +import static org.openrewrite.java.tree.Space.format; + +public class ImplementInterface

extends JavaIsoVisitor

{ + private final J.ClassDeclaration scope; + private final JavaType.FullyQualified interfaceType; + + public ImplementInterface(J.ClassDeclaration scope, JavaType.FullyQualified interfaceType) { + this.scope = scope; + this.interfaceType = interfaceType; + } + + public ImplementInterface(J.ClassDeclaration scope, String interfaze) { + this(scope, JavaType.ShallowClass.build(interfaze)); + } + + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, P p) { + J.ClassDeclaration c = super.visitClassDeclaration(classDecl, p); + if (c.isScope(scope) && (c.getImplements() == null || c.getImplements().stream() + .noneMatch(f -> TypeUtils.isAssignableTo(f.getType(), interfaceType)))) { + + if(!classDecl.getSimpleName().equals(interfaceType.getClassName())) { + maybeAddImport(interfaceType); + } + + TypeTree impl = TypeTree.build(classDecl.getSimpleName().equals(interfaceType.getClassName()) ? + interfaceType.getFullyQualifiedName() : interfaceType.getClassName()) + .withType(interfaceType) + .withPrefix(format(" ")); + + c = c.withImplements(ListUtils.concat(c.getImplements(), impl)); + + JContainer anImplements = c.getPadding().getImplements(); + assert anImplements != null; + if (anImplements.getBefore().getWhitespace().isEmpty()) { + c = c.getPadding().withImplements(anImplements.withBefore(Space.format(" "))); + } + } + + return c; + } +} 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 84051343234..1a8f2e7b4cd 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaParser.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaParser.java @@ -1,261 +1,261 @@ -/* - * 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.java; - -import io.github.classgraph.ClassGraph; -import org.intellij.lang.annotations.Language; -import org.openrewrite.ExecutionContext; -import org.openrewrite.InMemoryExecutionContext; -import org.openrewrite.Parser; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.marker.JavaSourceSet; -import org.openrewrite.java.tree.J; -import org.openrewrite.style.NamedStyles; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.net.URI; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static java.util.stream.Collectors.*; - -public interface JavaParser extends Parser { - /** - * Set to true on an {@link ExecutionContext} supplied to parsing to skip generation of - * type attribution from the class in {@link JavaSourceSet} marker. - */ - String SKIP_SOURCE_SET_TYPE_GENERATION = "org.openrewrite.java.skipSourceSetTypeGeneration"; - - /** - * @deprecated Won't work in isolated classloaders. - */ - @Deprecated - List runtimeClasspath = Collections.unmodifiableList(Arrays.stream(System.getProperty("java.class.path").split("\\Q" + System.getProperty("path.separator") + "\\E")) - .map(cpEntry -> new File(cpEntry).toPath()) - .collect(toList())); - - static List runtimeClasspath() { - return new ClassGraph() - .disableNestedJarScanning() - .getClasspathURIs().stream() - .map(Paths::get).collect(toList()); - } - - /** - * Convenience utility for constructing a parser with binary dependencies on the runtime classpath of the process - * constructing the parser. - * - * @param artifactNames The "artifact name" of the dependency to look for. Artifact name is the artifact portion of - * group:artifact:version coordinates. For example, for Google's Guava (com.google.guava:guava:VERSION), - * the artifact name is "guava". - * @return A set of paths of jars on the runtime classpath matching the provided artifact names, to the extent such - * matching jars can be found. - */ - static List dependenciesFromClasspath(String... artifactNames) { - Map artifactNamePatterns = Arrays.stream(artifactNames) - .collect(toMap(Function.identity(), name -> Pattern.compile(name + "-.*?\\.jar$"))); - - Set foundArtifacts = new HashSet<>(); - List artifacts = new ArrayList<>(); - List runtimeClasspath = new ClassGraph().getClasspathURIs(); - for (URI cpEntry : runtimeClasspath) { - for (Map.Entry artifactNamePattern : artifactNamePatterns.entrySet()) { - if (artifactNamePattern.getValue().matcher(cpEntry.toString()).find()) { - artifacts.add(Paths.get(cpEntry)); - foundArtifacts.add(artifactNamePattern.getKey()); - } - } - } - - for (String foundArtifact : foundArtifacts) { - artifactNamePatterns.remove(foundArtifact); - } - - if (!artifactNamePatterns.isEmpty()) { - throw new IllegalArgumentException("Unable to find runtime dependencies beginning with: " + - artifactNamePatterns.keySet().stream().map(a -> "'" + a + "'").sorted().collect(joining(", "))); - } - - return artifacts; - } - - /** - * Builds a Java parser with a language level equal to that of the JDK running this JVM process. - */ - static JavaParser.Builder fromJavaVersion() { - JavaParser.Builder javaParser; - try { - if (System.getProperty("java.version").startsWith("1.8")) { - javaParser = (JavaParser.Builder) Class - .forName("org.openrewrite.java.Java8Parser") - .getDeclaredMethod("builder") - .invoke(null); - } else { - javaParser = (JavaParser.Builder) Class - .forName("org.openrewrite.java.Java11Parser") - .getDeclaredMethod("builder") - .invoke(null); - } - } catch (Exception e) { - throw new IllegalStateException("Unable to create a Java parser instance. " + - "`rewrite-java-8` or `rewrite-java-11` must be on the classpath.", e); - } - - return javaParser; - } - - @Override - default List parse(ExecutionContext ctx, @Language("java") String... sources) { - return parseInputs( - Arrays.stream(sources) - .map(sourceFile -> new Input( - sourcePathFromSourceText(Paths.get(""), sourceFile), - () -> new ByteArrayInputStream(sourceFile.getBytes(StandardCharsets.UTF_8)) - )) - .collect(toList()), - null, - ctx - ); - } - - @Override - default List parse(@Language("java") String... sources) { - InMemoryExecutionContext ctx = new InMemoryExecutionContext(); - return parse(ctx, sources); - } - - @Override - default boolean accept(Path path) { - return path.toString().endsWith(".java"); - } - - /** - * Clear any in-memory parser caches that may prevent re-parsing of classes with the same fully qualified name in - * different rounds - */ - JavaParser reset(); - - /** - * Changes the classpath on the parser. Intended for use in multiple pass parsing, where we want to keep the - * compiler symbol table intact for type attribution on later parses, i.e. for maven multi-module projects. - * - * @param classpath new classpath to use - */ - void setClasspath(Collection classpath); - - /** - * Changes the source set on the parser. Intended for use in multiple pass parsing, where we want to keep the - * compiler symbol table intact for type attribution on later parses, i.e. for maven multi-module projects. - * - * @param sourceSet source set used to set {@link org.openrewrite.java.marker.JavaSourceSet} markers on - * subsequently parsed {@link J.CompilationUnit} - */ - void setSourceSet(String sourceSet); - - JavaSourceSet getSourceSet(ExecutionContext ctx); - - @SuppressWarnings("unchecked") - abstract class Builder

> { - protected Collection classpath = Collections.emptyList(); - protected Collection classBytesClasspath = Collections.emptyList(); - protected JavaTypeCache javaTypeCache = new JavaTypeCache(); - - @Nullable - protected Collection dependsOn; - - protected Charset charset = Charset.defaultCharset(); - protected boolean logCompilationWarningsAndErrors = false; - protected final List styles = new ArrayList<>(); - - public B logCompilationWarningsAndErrors(boolean logCompilationWarningsAndErrors) { - this.logCompilationWarningsAndErrors = logCompilationWarningsAndErrors; - return (B) this; - } - - public B typeCache(JavaTypeCache javaTypeCache) { - this.javaTypeCache = javaTypeCache; - return (B) this; - } - - public B charset(Charset charset) { - this.charset = charset; - return (B) this; - } - - public B dependsOn(Collection inputs) { - this.dependsOn = inputs; - return (B) this; - } - - public B dependsOn(@Language("java") String... inputsAsStrings) { - this.dependsOn = Arrays.stream(inputsAsStrings) - .map(Input::fromString) - .collect(toList()); - return (B) this; - } - - public B classpath(Collection classpath) { - this.classpath = classpath; - return (B) this; - } - - public B classpath(String... classpath) { - this.classpath = dependenciesFromClasspath(classpath); - return (B) this; - } - - public B classpath(byte[]... classpath) { - this.classBytesClasspath = Arrays.asList(classpath); - return (B) this; - } - - public B styles(Iterable styles) { - for (NamedStyles style : styles) { - this.styles.add(style); - } - return (B) this; - } - - public abstract P build(); - } - - @Override - default Path sourcePathFromSourceText(Path prefix, String sourceCode) { - Pattern packagePattern = Pattern.compile("^package\\s+([^;]+);"); - Pattern classPattern = Pattern.compile("(class|interface|enum)\\s*(<[^>]*>)?\\s+(\\w+)"); - - Function simpleName = sourceStr -> { - Matcher classMatcher = classPattern.matcher(sourceStr); - return classMatcher.find() ? classMatcher.group(3) : null; - }; - - Matcher packageMatcher = packagePattern.matcher(sourceCode); - String pkg = packageMatcher.find() ? packageMatcher.group(1).replace('.', '/') + "/" : ""; - - String className = Optional.ofNullable(simpleName.apply(sourceCode)) - .orElse(Long.toString(System.nanoTime())) + ".java"; - - return prefix.resolve(Paths.get(pkg + className)); - } -} +/* + * 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.java; + +import io.github.classgraph.ClassGraph; +import org.intellij.lang.annotations.Language; +import org.openrewrite.ExecutionContext; +import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.Parser; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.internal.JavaTypeCache; +import org.openrewrite.java.marker.JavaSourceSet; +import org.openrewrite.java.tree.J; +import org.openrewrite.style.NamedStyles; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.net.URI; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.util.stream.Collectors.*; + +public interface JavaParser extends Parser { + /** + * Set to true on an {@link ExecutionContext} supplied to parsing to skip generation of + * type attribution from the class in {@link JavaSourceSet} marker. + */ + String SKIP_SOURCE_SET_TYPE_GENERATION = "org.openrewrite.java.skipSourceSetTypeGeneration"; + + /** + * @deprecated Won't work in isolated classloaders. + */ + @Deprecated + List runtimeClasspath = Collections.unmodifiableList(Arrays.stream(System.getProperty("java.class.path").split("\\Q" + System.getProperty("path.separator") + "\\E")) + .map(cpEntry -> new File(cpEntry).toPath()) + .collect(toList())); + + static List runtimeClasspath() { + return new ClassGraph() + .disableNestedJarScanning() + .getClasspathURIs().stream() + .map(Paths::get).collect(toList()); + } + + /** + * Convenience utility for constructing a parser with binary dependencies on the runtime classpath of the process + * constructing the parser. + * + * @param artifactNames The "artifact name" of the dependency to look for. Artifact name is the artifact portion of + * group:artifact:version coordinates. For example, for Google's Guava (com.google.guava:guava:VERSION), + * the artifact name is "guava". + * @return A set of paths of jars on the runtime classpath matching the provided artifact names, to the extent such + * matching jars can be found. + */ + static List dependenciesFromClasspath(String... artifactNames) { + Map artifactNamePatterns = Arrays.stream(artifactNames) + .collect(toMap(Function.identity(), name -> Pattern.compile(name + "-.*?\\.jar$"))); + + Set foundArtifacts = new HashSet<>(); + List artifacts = new ArrayList<>(); + List runtimeClasspath = new ClassGraph().getClasspathURIs(); + for (URI cpEntry : runtimeClasspath) { + for (Map.Entry artifactNamePattern : artifactNamePatterns.entrySet()) { + if (artifactNamePattern.getValue().matcher(cpEntry.toString()).find()) { + artifacts.add(Paths.get(cpEntry)); + foundArtifacts.add(artifactNamePattern.getKey()); + } + } + } + + for (String foundArtifact : foundArtifacts) { + artifactNamePatterns.remove(foundArtifact); + } + + if (!artifactNamePatterns.isEmpty()) { + throw new IllegalArgumentException("Unable to find runtime dependencies beginning with: " + + artifactNamePatterns.keySet().stream().map(a -> "'" + a + "'").sorted().collect(joining(", "))); + } + + return artifacts; + } + + /** + * Builds a Java parser with a language level equal to that of the JDK running this JVM process. + */ + static JavaParser.Builder fromJavaVersion() { + JavaParser.Builder javaParser; + try { + if (System.getProperty("java.version").startsWith("1.8")) { + javaParser = (JavaParser.Builder) Class + .forName("org.openrewrite.java.Java8Parser") + .getDeclaredMethod("builder") + .invoke(null); + } else { + javaParser = (JavaParser.Builder) Class + .forName("org.openrewrite.java.Java11Parser") + .getDeclaredMethod("builder") + .invoke(null); + } + } catch (Exception e) { + throw new IllegalStateException("Unable to create a Java parser instance. " + + "`rewrite-java-8` or `rewrite-java-11` must be on the classpath.", e); + } + + return javaParser; + } + + @Override + default List parse(ExecutionContext ctx, @Language("java") String... sources) { + return parseInputs( + Arrays.stream(sources) + .map(sourceFile -> new Input( + sourcePathFromSourceText(Paths.get(""), sourceFile), + () -> new ByteArrayInputStream(sourceFile.getBytes(StandardCharsets.UTF_8)) + )) + .collect(toList()), + null, + ctx + ); + } + + @Override + default List parse(@Language("java") String... sources) { + InMemoryExecutionContext ctx = new InMemoryExecutionContext(); + return parse(ctx, sources); + } + + @Override + default boolean accept(Path path) { + return path.toString().endsWith(".java"); + } + + /** + * Clear any in-memory parser caches that may prevent re-parsing of classes with the same fully qualified name in + * different rounds + */ + JavaParser reset(); + + /** + * Changes the classpath on the parser. Intended for use in multiple pass parsing, where we want to keep the + * compiler symbol table intact for type attribution on later parses, i.e. for maven multi-module projects. + * + * @param classpath new classpath to use + */ + void setClasspath(Collection classpath); + + /** + * Changes the source set on the parser. Intended for use in multiple pass parsing, where we want to keep the + * compiler symbol table intact for type attribution on later parses, i.e. for maven multi-module projects. + * + * @param sourceSet source set used to set {@link org.openrewrite.java.marker.JavaSourceSet} markers on + * subsequently parsed {@link J.CompilationUnit} + */ + void setSourceSet(String sourceSet); + + JavaSourceSet getSourceSet(ExecutionContext ctx); + + @SuppressWarnings("unchecked") + abstract class Builder

> { + protected Collection classpath = Collections.emptyList(); + protected Collection classBytesClasspath = Collections.emptyList(); + protected JavaTypeCache javaTypeCache = new JavaTypeCache(); + + @Nullable + protected Collection dependsOn; + + protected Charset charset = Charset.defaultCharset(); + protected boolean logCompilationWarningsAndErrors = false; + protected final List styles = new ArrayList<>(); + + public B logCompilationWarningsAndErrors(boolean logCompilationWarningsAndErrors) { + this.logCompilationWarningsAndErrors = logCompilationWarningsAndErrors; + return (B) this; + } + + public B typeCache(JavaTypeCache javaTypeCache) { + this.javaTypeCache = javaTypeCache; + return (B) this; + } + + public B charset(Charset charset) { + this.charset = charset; + return (B) this; + } + + public B dependsOn(Collection inputs) { + this.dependsOn = inputs; + return (B) this; + } + + public B dependsOn(@Language("java") String... inputsAsStrings) { + this.dependsOn = Arrays.stream(inputsAsStrings) + .map(Input::fromString) + .collect(toList()); + return (B) this; + } + + public B classpath(Collection classpath) { + this.classpath = classpath; + return (B) this; + } + + public B classpath(String... classpath) { + this.classpath = dependenciesFromClasspath(classpath); + return (B) this; + } + + public B classpath(byte[]... classpath) { + this.classBytesClasspath = Arrays.asList(classpath); + return (B) this; + } + + public B styles(Iterable styles) { + for (NamedStyles style : styles) { + this.styles.add(style); + } + return (B) this; + } + + public abstract P build(); + } + + @Override + default Path sourcePathFromSourceText(Path prefix, String sourceCode) { + Pattern packagePattern = Pattern.compile("^package\\s+([^;]+);"); + Pattern classPattern = Pattern.compile("(class|interface|enum)\\s*(<[^>]*>)?\\s+(\\w+)"); + + Function simpleName = sourceStr -> { + Matcher classMatcher = classPattern.matcher(sourceStr); + return classMatcher.find() ? classMatcher.group(3) : null; + }; + + Matcher packageMatcher = packagePattern.matcher(sourceCode); + String pkg = packageMatcher.find() ? packageMatcher.group(1).replace('.', '/') + "/" : ""; + + String className = Optional.ofNullable(simpleName.apply(sourceCode)) + .orElse(Long.toString(System.nanoTime())) + ".java"; + + return prefix.resolve(Paths.get(pkg + className)); + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/JavaStyle.java b/rewrite-java/src/main/java/org/openrewrite/java/JavaStyle.java index 6f0051e0375..efca1cd4a09 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/JavaStyle.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/JavaStyle.java @@ -1,21 +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. - */ -package org.openrewrite.java; - -import org.openrewrite.style.Style; - -public interface JavaStyle extends Style { -} +/* + * 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.java; + +import org.openrewrite.style.Style; + +public interface JavaStyle extends Style { +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/RemoveAnnotationVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/RemoveAnnotationVisitor.java index 4cf6d012492..93dfb9335b4 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/RemoveAnnotationVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/RemoveAnnotationVisitor.java @@ -1,137 +1,137 @@ -/* - * 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.java; - -import lombok.EqualsAndHashCode; -import lombok.Value; -import org.openrewrite.ExecutionContext; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.Space; -import org.openrewrite.java.tree.TypeUtils; - -import java.util.ArrayList; -import java.util.List; - -@Value -@EqualsAndHashCode(callSuper = true) -public class RemoveAnnotationVisitor extends JavaIsoVisitor { - AnnotationMatcher annotationMatcher; - - @Override - public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { - J.ClassDeclaration c = super.visitClassDeclaration(classDecl, ctx); - J.Annotation annotationRemoved = getCursor().pollMessage("annotationRemoved"); - - List leadingAnnotations = classDecl.getLeadingAnnotations(); - if (annotationRemoved != null && !leadingAnnotations.isEmpty()) { - if (leadingAnnotations.get(0) == annotationRemoved && leadingAnnotations.size() == 1) { - if (!c.getModifiers().isEmpty()) { - c = c.withModifiers(Space.formatFirstPrefix(c.getModifiers(), Space.firstPrefix(c.getModifiers()).withWhitespace(""))); - } else if (c.getPadding().getTypeParameters() != null) { - c = c.getPadding().withTypeParameters(c.getPadding().getTypeParameters().withBefore(c.getPadding().getTypeParameters().getBefore().withWhitespace(""))); - } else { - c = c.getAnnotations().withKind(c.getAnnotations().getKind().withPrefix(c.getAnnotations().getKind().getPrefix().withWhitespace(""))); - } - } else { - List newLeadingAnnotations = removeAnnotationOrEmpty(leadingAnnotations, annotationRemoved); - if (!newLeadingAnnotations.isEmpty()) { - c = c.withLeadingAnnotations(newLeadingAnnotations); - } - } - } - return c; - } - - @Override - public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) { - J.MethodDeclaration m = super.visitMethodDeclaration(method, ctx); - J.Annotation annotationRemoved = getCursor().pollMessage("annotationRemoved"); - - List leadingAnnotations = method.getLeadingAnnotations(); - if (annotationRemoved != null && !leadingAnnotations.isEmpty()) { - if (leadingAnnotations.get(0) == annotationRemoved && leadingAnnotations.size() == 1) { - if (!m.getModifiers().isEmpty()) { - m = m.withModifiers(Space.formatFirstPrefix(m.getModifiers(), Space.firstPrefix(m.getModifiers()).withWhitespace(""))); - } else if (m.getPadding().getTypeParameters() != null) { - m = m.getPadding().withTypeParameters(m.getPadding().getTypeParameters().withPrefix(m.getPadding().getTypeParameters().getPrefix().withWhitespace(""))); - } else if (m.getReturnTypeExpression() != null) { - m = m.withReturnTypeExpression(m.getReturnTypeExpression().withPrefix(m.getReturnTypeExpression().getPrefix().withWhitespace(""))); - } else { - m = m.withName(m.getName().withPrefix(m.getName().getPrefix().withWhitespace(""))); - } - } else { - List newLeadingAnnotations = removeAnnotationOrEmpty(leadingAnnotations, annotationRemoved); - if (!newLeadingAnnotations.isEmpty()) { - m = m.withLeadingAnnotations(newLeadingAnnotations); - } - } - } - return m; - } - - @Override - public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) { - J.VariableDeclarations v = super.visitVariableDeclarations(multiVariable, ctx); - J.Annotation annotationRemoved = getCursor().pollMessage("annotationRemoved"); - - List leadingAnnotations = multiVariable.getLeadingAnnotations(); - if (annotationRemoved != null && !leadingAnnotations.isEmpty()) { - if (leadingAnnotations.get(0) == annotationRemoved && leadingAnnotations.size() == 1) { - if (!v.getModifiers().isEmpty()) { - v = v.withModifiers(Space.formatFirstPrefix(v.getModifiers(), Space.firstPrefix(v.getModifiers()).withWhitespace(""))); - } else if (v.getTypeExpression() != null) { - v = v.withTypeExpression(v.getTypeExpression().withPrefix(v.getTypeExpression().getPrefix().withWhitespace(""))); - } - } else { - List newLeadingAnnotations = removeAnnotationOrEmpty(leadingAnnotations, annotationRemoved); - if (!newLeadingAnnotations.isEmpty()) { - v = v.withLeadingAnnotations(newLeadingAnnotations); - } - } - } - - return v; - } - - @Override - public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) { - if (annotationMatcher.matches(annotation)) { - getCursor().getParentOrThrow().putMessage("annotationRemoved", annotation); - maybeRemoveImport(TypeUtils.asFullyQualified(annotation.getType())); - //noinspection ConstantConditions - return null; - } - return super.visitAnnotation(annotation, ctx); - } - - /* Returns a list of leading annotations with the target removed or an empty list if no changes are necessary. - * A prefix only needs to change if the index == 0 and the prefixes of the target annotation and next annotation are not equal. - */ - private List removeAnnotationOrEmpty(List leadingAnnotations, J.Annotation targetAnnotation) { - int index = leadingAnnotations.indexOf(targetAnnotation); - List newLeadingAnnotations = new ArrayList<>(); - if (index == 0) { - J.Annotation nextAnnotation = leadingAnnotations.get(1); - if (!nextAnnotation.getPrefix().equals(targetAnnotation.getPrefix())) { - newLeadingAnnotations.add(nextAnnotation.withPrefix(targetAnnotation.getPrefix())); - for (int i = 2; i < leadingAnnotations.size(); ++i) { - newLeadingAnnotations.add(leadingAnnotations.get(i)); - } - } - } - return newLeadingAnnotations; - } -} +/* + * 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.java; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.ExecutionContext; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.Space; +import org.openrewrite.java.tree.TypeUtils; + +import java.util.ArrayList; +import java.util.List; + +@Value +@EqualsAndHashCode(callSuper = true) +public class RemoveAnnotationVisitor extends JavaIsoVisitor { + AnnotationMatcher annotationMatcher; + + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { + J.ClassDeclaration c = super.visitClassDeclaration(classDecl, ctx); + J.Annotation annotationRemoved = getCursor().pollMessage("annotationRemoved"); + + List leadingAnnotations = classDecl.getLeadingAnnotations(); + if (annotationRemoved != null && !leadingAnnotations.isEmpty()) { + if (leadingAnnotations.get(0) == annotationRemoved && leadingAnnotations.size() == 1) { + if (!c.getModifiers().isEmpty()) { + c = c.withModifiers(Space.formatFirstPrefix(c.getModifiers(), Space.firstPrefix(c.getModifiers()).withWhitespace(""))); + } else if (c.getPadding().getTypeParameters() != null) { + c = c.getPadding().withTypeParameters(c.getPadding().getTypeParameters().withBefore(c.getPadding().getTypeParameters().getBefore().withWhitespace(""))); + } else { + c = c.getAnnotations().withKind(c.getAnnotations().getKind().withPrefix(c.getAnnotations().getKind().getPrefix().withWhitespace(""))); + } + } else { + List newLeadingAnnotations = removeAnnotationOrEmpty(leadingAnnotations, annotationRemoved); + if (!newLeadingAnnotations.isEmpty()) { + c = c.withLeadingAnnotations(newLeadingAnnotations); + } + } + } + return c; + } + + @Override + public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) { + J.MethodDeclaration m = super.visitMethodDeclaration(method, ctx); + J.Annotation annotationRemoved = getCursor().pollMessage("annotationRemoved"); + + List leadingAnnotations = method.getLeadingAnnotations(); + if (annotationRemoved != null && !leadingAnnotations.isEmpty()) { + if (leadingAnnotations.get(0) == annotationRemoved && leadingAnnotations.size() == 1) { + if (!m.getModifiers().isEmpty()) { + m = m.withModifiers(Space.formatFirstPrefix(m.getModifiers(), Space.firstPrefix(m.getModifiers()).withWhitespace(""))); + } else if (m.getPadding().getTypeParameters() != null) { + m = m.getPadding().withTypeParameters(m.getPadding().getTypeParameters().withPrefix(m.getPadding().getTypeParameters().getPrefix().withWhitespace(""))); + } else if (m.getReturnTypeExpression() != null) { + m = m.withReturnTypeExpression(m.getReturnTypeExpression().withPrefix(m.getReturnTypeExpression().getPrefix().withWhitespace(""))); + } else { + m = m.withName(m.getName().withPrefix(m.getName().getPrefix().withWhitespace(""))); + } + } else { + List newLeadingAnnotations = removeAnnotationOrEmpty(leadingAnnotations, annotationRemoved); + if (!newLeadingAnnotations.isEmpty()) { + m = m.withLeadingAnnotations(newLeadingAnnotations); + } + } + } + return m; + } + + @Override + public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) { + J.VariableDeclarations v = super.visitVariableDeclarations(multiVariable, ctx); + J.Annotation annotationRemoved = getCursor().pollMessage("annotationRemoved"); + + List leadingAnnotations = multiVariable.getLeadingAnnotations(); + if (annotationRemoved != null && !leadingAnnotations.isEmpty()) { + if (leadingAnnotations.get(0) == annotationRemoved && leadingAnnotations.size() == 1) { + if (!v.getModifiers().isEmpty()) { + v = v.withModifiers(Space.formatFirstPrefix(v.getModifiers(), Space.firstPrefix(v.getModifiers()).withWhitespace(""))); + } else if (v.getTypeExpression() != null) { + v = v.withTypeExpression(v.getTypeExpression().withPrefix(v.getTypeExpression().getPrefix().withWhitespace(""))); + } + } else { + List newLeadingAnnotations = removeAnnotationOrEmpty(leadingAnnotations, annotationRemoved); + if (!newLeadingAnnotations.isEmpty()) { + v = v.withLeadingAnnotations(newLeadingAnnotations); + } + } + } + + return v; + } + + @Override + public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) { + if (annotationMatcher.matches(annotation)) { + getCursor().getParentOrThrow().putMessage("annotationRemoved", annotation); + maybeRemoveImport(TypeUtils.asFullyQualified(annotation.getType())); + //noinspection ConstantConditions + return null; + } + return super.visitAnnotation(annotation, ctx); + } + + /* Returns a list of leading annotations with the target removed or an empty list if no changes are necessary. + * A prefix only needs to change if the index == 0 and the prefixes of the target annotation and next annotation are not equal. + */ + private List removeAnnotationOrEmpty(List leadingAnnotations, J.Annotation targetAnnotation) { + int index = leadingAnnotations.indexOf(targetAnnotation); + List newLeadingAnnotations = new ArrayList<>(); + if (index == 0) { + J.Annotation nextAnnotation = leadingAnnotations.get(1); + if (!nextAnnotation.getPrefix().equals(targetAnnotation.getPrefix())) { + newLeadingAnnotations.add(nextAnnotation.withPrefix(targetAnnotation.getPrefix())); + for (int i = 2; i < leadingAnnotations.size(); ++i) { + newLeadingAnnotations.add(leadingAnnotations.get(i)); + } + } + } + return newLeadingAnnotations; + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/UseStaticImport.java b/rewrite-java/src/main/java/org/openrewrite/java/UseStaticImport.java index 76a3520731f..da2d12f28d7 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/UseStaticImport.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/UseStaticImport.java @@ -1,90 +1,90 @@ -/* - * 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.java; - -import lombok.*; -import lombok.experimental.FieldDefaults; -import org.openrewrite.ExecutionContext; -import org.openrewrite.Option; -import org.openrewrite.Recipe; -import org.openrewrite.java.search.UsesMethod; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaType; - -@ToString -@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) -@Getter -@RequiredArgsConstructor -@EqualsAndHashCode(callSuper = true) -public class UseStaticImport extends Recipe { - - /** - * A method pattern that is used to find matching method invocations. - * See {@link MethodMatcher} for details on the expression's syntax. - */ - @Option(displayName = "Method pattern", - description = "A method pattern that is used to find matching method invocations.", - example = "java.util.Collections emptyList()") - String methodPattern; - - @Override - public String getDisplayName() { - return "Use static import"; - } - - @Override - public String getDescription() { - return "Removes unnecessary receiver types from static method invocations. For example, `Collections.emptyList()` becomes `emptyList()`."; - } - - @Override - protected JavaVisitor getSingleSourceApplicableTest() { - return new UsesMethod<>(methodPattern); - } - - @Override - public JavaVisitor getVisitor() { - return new UseStaticImportVisitor(); - } - - private class UseStaticImportVisitor extends JavaIsoVisitor { - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - MethodMatcher methodMatcher = new MethodMatcher(methodPattern); - J.MethodInvocation m = super.visitMethodInvocation(method, ctx); - if (methodMatcher.matches(m)) { - if (m.getMethodType() != null) { - JavaType.FullyQualified receiverType = m.getMethodType().getDeclaringType(); - maybeRemoveImport(receiverType); - - AddImport addStatic = new AddImport<>( - receiverType.getFullyQualifiedName(), - m.getSimpleName(), - false); - - if (!getAfterVisit().contains(addStatic)) { - doAfterVisit(addStatic); - } - } - - if (m.getSelect() != null) { - m = m.withSelect(null).withName(m.getName().withPrefix(m.getSelect().getPrefix())); - } - } - return m; - } - } -} +/* + * 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.java; + +import lombok.*; +import lombok.experimental.FieldDefaults; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Option; +import org.openrewrite.Recipe; +import org.openrewrite.java.search.UsesMethod; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; + +@ToString +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@Getter +@RequiredArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class UseStaticImport extends Recipe { + + /** + * A method pattern that is used to find matching method invocations. + * See {@link MethodMatcher} for details on the expression's syntax. + */ + @Option(displayName = "Method pattern", + description = "A method pattern that is used to find matching method invocations.", + example = "java.util.Collections emptyList()") + String methodPattern; + + @Override + public String getDisplayName() { + return "Use static import"; + } + + @Override + public String getDescription() { + return "Removes unnecessary receiver types from static method invocations. For example, `Collections.emptyList()` becomes `emptyList()`."; + } + + @Override + protected JavaVisitor getSingleSourceApplicableTest() { + return new UsesMethod<>(methodPattern); + } + + @Override + public JavaVisitor getVisitor() { + return new UseStaticImportVisitor(); + } + + private class UseStaticImportVisitor extends JavaIsoVisitor { + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + MethodMatcher methodMatcher = new MethodMatcher(methodPattern); + J.MethodInvocation m = super.visitMethodInvocation(method, ctx); + if (methodMatcher.matches(m)) { + if (m.getMethodType() != null) { + JavaType.FullyQualified receiverType = m.getMethodType().getDeclaringType(); + maybeRemoveImport(receiverType); + + AddImport addStatic = new AddImport<>( + receiverType.getFullyQualifiedName(), + m.getSimpleName(), + false); + + if (!getAfterVisit().contains(addStatic)) { + doAfterVisit(addStatic); + } + } + + if (m.getSelect() != null) { + m = m.withSelect(null).withName(m.getName().withPrefix(m.getSelect().getPrefix())); + } + } + return m; + } + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/CatchClauseOnlyRethrows.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/CatchClauseOnlyRethrows.java index 41756f6ae3d..9c3b5af58c9 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/CatchClauseOnlyRethrows.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/CatchClauseOnlyRethrows.java @@ -1,115 +1,115 @@ -/* - * 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.java.cleanup; - -import org.openrewrite.ExecutionContext; -import org.openrewrite.Recipe; -import org.openrewrite.internal.ListUtils; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.tree.Expression; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.J.Try.Catch; -import org.openrewrite.java.tree.JavaType; -import org.openrewrite.java.tree.TypeUtils; - -import java.time.Duration; -import java.util.Set; - -import static java.util.Collections.singleton; - -public class CatchClauseOnlyRethrows extends Recipe { - - @Override - public String getDisplayName() { - return "Catch clause should do more than just rethrow"; - } - - @Override - public String getDescription() { - return "A `catch` clause that only rethrows the caught exception is unnecessary. " + - "Letting the exception bubble up as normal achieves the same result with less code."; - } - - @Override - public Set getTags() { - return singleton("RSPEC-2737"); - } - - @Override - public Duration getEstimatedEffortPerOccurrence() { - return Duration.ofMinutes(5); - } - - @Override - protected JavaIsoVisitor getVisitor() { - return new JavaIsoVisitor() { - - @Override - public J.Block visitBlock(J.Block block, ExecutionContext ctx) { - J.Block b = super.visitBlock(block, ctx); - return b.withStatements(ListUtils.flatMap(b.getStatements(), statement -> { - if (statement instanceof J.Try) { - // if a try has no catches, no finally, and no resources get rid of it and merge its statements into the current block - J.Try aTry = (J.Try) statement; - if (aTry.getCatches().isEmpty() && aTry.getResources() == null && aTry.getFinally() == null) { - return ListUtils.map(aTry.getBody().getStatements(), tryStat -> autoFormat(tryStat, ctx, getCursor())); - } - } - return statement; - })); - } - - @Override - public J.Try visitTry(J.Try tryable, ExecutionContext executionContext) { - J.Try t = super.visitTry(tryable, executionContext); - return t.withCatches(ListUtils.map(t.getCatches(), (i, aCatch) -> { - if (onlyRethrows(aCatch)) { - // if a subsequent catch is a wider exception type and doesn't rethrow, we should - // keep this one - for (int j = i + 1; j < tryable.getCatches().size(); j++) { - Catch next = tryable.getCatches().get(j); - if (!onlyRethrows(next) && TypeUtils.isAssignableTo(next.getParameter().getType(), - aCatch.getParameter().getType())) { - return aCatch; - } - } - return null; - } - return aCatch; - })); - } - - private boolean onlyRethrows(Catch aCatch) { - if (aCatch.getBody().getStatements().size() != 1 || - !(aCatch.getBody().getStatements().get(0) instanceof J.Throw)) { - return false; - } - - Expression exception = ((J.Throw) aCatch.getBody().getStatements().get(0)).getException(); - JavaType.FullyQualified catchType = TypeUtils.asFullyQualified(aCatch.getParameter().getType()); - if (catchType == null || !catchType.equals(exception.getType())) { - return false; - } - - if (exception instanceof J.Identifier) { - return ((J.Identifier) exception).getSimpleName().equals(aCatch.getParameter().getTree().getVariables().get(0).getSimpleName()); - } - - return false; - } - }; - } -} +/* + * 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.java.cleanup; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.tree.Expression; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.J.Try.Catch; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.TypeUtils; + +import java.time.Duration; +import java.util.Set; + +import static java.util.Collections.singleton; + +public class CatchClauseOnlyRethrows extends Recipe { + + @Override + public String getDisplayName() { + return "Catch clause should do more than just rethrow"; + } + + @Override + public String getDescription() { + return "A `catch` clause that only rethrows the caught exception is unnecessary. " + + "Letting the exception bubble up as normal achieves the same result with less code."; + } + + @Override + public Set getTags() { + return singleton("RSPEC-2737"); + } + + @Override + public Duration getEstimatedEffortPerOccurrence() { + return Duration.ofMinutes(5); + } + + @Override + protected JavaIsoVisitor getVisitor() { + return new JavaIsoVisitor() { + + @Override + public J.Block visitBlock(J.Block block, ExecutionContext ctx) { + J.Block b = super.visitBlock(block, ctx); + return b.withStatements(ListUtils.flatMap(b.getStatements(), statement -> { + if (statement instanceof J.Try) { + // if a try has no catches, no finally, and no resources get rid of it and merge its statements into the current block + J.Try aTry = (J.Try) statement; + if (aTry.getCatches().isEmpty() && aTry.getResources() == null && aTry.getFinally() == null) { + return ListUtils.map(aTry.getBody().getStatements(), tryStat -> autoFormat(tryStat, ctx, getCursor())); + } + } + return statement; + })); + } + + @Override + public J.Try visitTry(J.Try tryable, ExecutionContext executionContext) { + J.Try t = super.visitTry(tryable, executionContext); + return t.withCatches(ListUtils.map(t.getCatches(), (i, aCatch) -> { + if (onlyRethrows(aCatch)) { + // if a subsequent catch is a wider exception type and doesn't rethrow, we should + // keep this one + for (int j = i + 1; j < tryable.getCatches().size(); j++) { + Catch next = tryable.getCatches().get(j); + if (!onlyRethrows(next) && TypeUtils.isAssignableTo(next.getParameter().getType(), + aCatch.getParameter().getType())) { + return aCatch; + } + } + return null; + } + return aCatch; + })); + } + + private boolean onlyRethrows(Catch aCatch) { + if (aCatch.getBody().getStatements().size() != 1 || + !(aCatch.getBody().getStatements().get(0) instanceof J.Throw)) { + return false; + } + + Expression exception = ((J.Throw) aCatch.getBody().getStatements().get(0)).getException(); + JavaType.FullyQualified catchType = TypeUtils.asFullyQualified(aCatch.getParameter().getType()); + if (catchType == null || !catchType.equals(exception.getType())) { + return false; + } + + if (exception instanceof J.Identifier) { + return ((J.Identifier) exception).getSimpleName().equals(aCatch.getParameter().getTree().getVariables().get(0).getSimpleName()); + } + + return false; + } + }; + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/ExplicitLambdaArgumentTypes.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/ExplicitLambdaArgumentTypes.java index 6aa47ccd98c..e909141730d 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/ExplicitLambdaArgumentTypes.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/ExplicitLambdaArgumentTypes.java @@ -1,146 +1,146 @@ -/* - * 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.java.cleanup; - -import org.openrewrite.*; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaType; -import org.openrewrite.java.tree.Space; -import org.openrewrite.java.tree.TypeUtils; -import org.openrewrite.marker.Markers; - -import java.time.Duration; -import java.util.Collections; -import java.util.Set; - -public class ExplicitLambdaArgumentTypes extends Recipe { - @Override - public String getDisplayName() { - return "Use explicit types on lambda arguments"; - } - - @Override - public String getDescription() { - return "Adds explicit types on lambda arguments, which are otherwise optional. This can make the code clearer and easier to read. " + - "This does not add explicit types on arguments when the lambda has one or two parameters and does not have a block body, as things are considered more readable in those cases. " + - "For example, `stream.map((a, b) -> a.length);` will not have explicit types added."; - } - - @Override - public Set getTags() { - return Collections.singleton("RSPEC-2211"); - } - - @Override - public Duration getEstimatedEffortPerOccurrence() { - return Duration.ofMinutes(5); - } - - @Override - protected TreeVisitor getVisitor() { - return new ExplicitLambdaArgumentTypesVisitor(); - } - - private static class ExplicitLambdaArgumentTypesVisitor extends JavaIsoVisitor { - private static final String ADDED_EXPLICIT_TYPE_KEY = "ADDED_EXPLICIT_TYPE"; - - @Nullable - private static String buildName(@Nullable JavaType type) { - if (type != null) { - if (type instanceof JavaType.FullyQualified && type != JavaType.Unknown.getInstance()) { - JavaType.FullyQualified asFQN = TypeUtils.asFullyQualified(type); - assert asFQN != null; - return asFQN.getClassName(); - } else if (type instanceof JavaType.Primitive) { - JavaType.Primitive asPrimitive = TypeUtils.asPrimitive(type); - assert asPrimitive != null; - return asPrimitive.getKeyword(); - } else if (type instanceof JavaType.Array) { - JavaType.Array arrayType = TypeUtils.asArray(type); - assert arrayType != null; - StringBuilder typeAsString = new StringBuilder(); - JavaType elemType = arrayType.getElemType(); - if (elemType instanceof JavaType.Primitive) { - typeAsString.append(buildName(elemType)); - } else if (elemType instanceof JavaType.FullyQualified) { - typeAsString.append(buildName(elemType)); - } else if (elemType instanceof JavaType.Array) { - JavaType typeOfArray = ((JavaType.Array) elemType).getElemType(); - typeAsString.append(buildName(typeOfArray)); - for (; arrayType.getElemType() instanceof JavaType.Array; arrayType = (JavaType.Array) arrayType.getElemType()) { - typeAsString.append("[]"); - } - } - typeAsString.append("[]"); - return typeAsString.toString(); - } else if(type instanceof JavaType.Variable) { - return buildName(((JavaType.Variable) type).getType()); - } - } - return null; - } - - @Override - public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) { - // if the type expression is null, it implies the types on the lambda arguments are implicit. - if (multiVariable.getTypeExpression() == null && getCursor().dropParentUntil(J.class::isInstance).getValue() instanceof J.Lambda) { - J.VariableDeclarations.NamedVariable nv = multiVariable.getVariables().get(0); - String name = nv.getType() instanceof JavaType.GenericTypeVariable ? - ((JavaType.GenericTypeVariable) nv.getType()).getName() : buildName(nv.getType()); - if (name != null) { - multiVariable = multiVariable.withTypeExpression( - new J.Identifier(Tree.randomId(), - Space.EMPTY, - Markers.EMPTY, - name, - nv.getType(), - null - ) - ); - maybeAddImport(TypeUtils.asFullyQualified(nv.getType())); - getCursor().dropParentUntil(J.Lambda.class::isInstance).putMessage(ADDED_EXPLICIT_TYPE_KEY, true); - } - } - return super.visitVariableDeclarations(multiVariable, ctx); - } - - @Override - public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, ExecutionContext ctx) { - J.VariableDeclarations.NamedVariable nv = super.visitVariable(variable, ctx); - Cursor c = getCursor().dropParentUntil(J.class::isInstance).dropParentUntil(J.class::isInstance); - if (c.getValue() instanceof J.Lambda && c.getMessage(ADDED_EXPLICIT_TYPE_KEY) != null) { - nv = nv.withPrefix(nv.getPrefix().withWhitespace(" ")); - } - return nv; - } - - @Override - public J.Lambda visitLambda(J.Lambda lambda, ExecutionContext ctx) { - if (lambda.getParameters().getParameters().size() <= 2 && !(lambda.getBody() instanceof J.Block)) { - return lambda; - } - J.Lambda l = super.visitLambda(lambda, ctx); - if (getCursor().getMessage(ADDED_EXPLICIT_TYPE_KEY) != null) { - l = l.withParameters(l.getParameters().withParenthesized(true)); - } - return l; - } - - } - -} +/* + * 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.java.cleanup; + +import org.openrewrite.*; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.Space; +import org.openrewrite.java.tree.TypeUtils; +import org.openrewrite.marker.Markers; + +import java.time.Duration; +import java.util.Collections; +import java.util.Set; + +public class ExplicitLambdaArgumentTypes extends Recipe { + @Override + public String getDisplayName() { + return "Use explicit types on lambda arguments"; + } + + @Override + public String getDescription() { + return "Adds explicit types on lambda arguments, which are otherwise optional. This can make the code clearer and easier to read. " + + "This does not add explicit types on arguments when the lambda has one or two parameters and does not have a block body, as things are considered more readable in those cases. " + + "For example, `stream.map((a, b) -> a.length);` will not have explicit types added."; + } + + @Override + public Set getTags() { + return Collections.singleton("RSPEC-2211"); + } + + @Override + public Duration getEstimatedEffortPerOccurrence() { + return Duration.ofMinutes(5); + } + + @Override + protected TreeVisitor getVisitor() { + return new ExplicitLambdaArgumentTypesVisitor(); + } + + private static class ExplicitLambdaArgumentTypesVisitor extends JavaIsoVisitor { + private static final String ADDED_EXPLICIT_TYPE_KEY = "ADDED_EXPLICIT_TYPE"; + + @Nullable + private static String buildName(@Nullable JavaType type) { + if (type != null) { + if (type instanceof JavaType.FullyQualified && type != JavaType.Unknown.getInstance()) { + JavaType.FullyQualified asFQN = TypeUtils.asFullyQualified(type); + assert asFQN != null; + return asFQN.getClassName(); + } else if (type instanceof JavaType.Primitive) { + JavaType.Primitive asPrimitive = TypeUtils.asPrimitive(type); + assert asPrimitive != null; + return asPrimitive.getKeyword(); + } else if (type instanceof JavaType.Array) { + JavaType.Array arrayType = TypeUtils.asArray(type); + assert arrayType != null; + StringBuilder typeAsString = new StringBuilder(); + JavaType elemType = arrayType.getElemType(); + if (elemType instanceof JavaType.Primitive) { + typeAsString.append(buildName(elemType)); + } else if (elemType instanceof JavaType.FullyQualified) { + typeAsString.append(buildName(elemType)); + } else if (elemType instanceof JavaType.Array) { + JavaType typeOfArray = ((JavaType.Array) elemType).getElemType(); + typeAsString.append(buildName(typeOfArray)); + for (; arrayType.getElemType() instanceof JavaType.Array; arrayType = (JavaType.Array) arrayType.getElemType()) { + typeAsString.append("[]"); + } + } + typeAsString.append("[]"); + return typeAsString.toString(); + } else if(type instanceof JavaType.Variable) { + return buildName(((JavaType.Variable) type).getType()); + } + } + return null; + } + + @Override + public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) { + // if the type expression is null, it implies the types on the lambda arguments are implicit. + if (multiVariable.getTypeExpression() == null && getCursor().dropParentUntil(J.class::isInstance).getValue() instanceof J.Lambda) { + J.VariableDeclarations.NamedVariable nv = multiVariable.getVariables().get(0); + String name = nv.getType() instanceof JavaType.GenericTypeVariable ? + ((JavaType.GenericTypeVariable) nv.getType()).getName() : buildName(nv.getType()); + if (name != null) { + multiVariable = multiVariable.withTypeExpression( + new J.Identifier(Tree.randomId(), + Space.EMPTY, + Markers.EMPTY, + name, + nv.getType(), + null + ) + ); + maybeAddImport(TypeUtils.asFullyQualified(nv.getType())); + getCursor().dropParentUntil(J.Lambda.class::isInstance).putMessage(ADDED_EXPLICIT_TYPE_KEY, true); + } + } + return super.visitVariableDeclarations(multiVariable, ctx); + } + + @Override + public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, ExecutionContext ctx) { + J.VariableDeclarations.NamedVariable nv = super.visitVariable(variable, ctx); + Cursor c = getCursor().dropParentUntil(J.class::isInstance).dropParentUntil(J.class::isInstance); + if (c.getValue() instanceof J.Lambda && c.getMessage(ADDED_EXPLICIT_TYPE_KEY) != null) { + nv = nv.withPrefix(nv.getPrefix().withWhitespace(" ")); + } + return nv; + } + + @Override + public J.Lambda visitLambda(J.Lambda lambda, ExecutionContext ctx) { + if (lambda.getParameters().getParameters().size() <= 2 && !(lambda.getBody() instanceof J.Block)) { + return lambda; + } + J.Lambda l = super.visitLambda(lambda, ctx); + if (getCursor().getMessage(ADDED_EXPLICIT_TYPE_KEY) != null) { + l = l.withParameters(l.getParameters().withParenthesized(true)); + } + return l; + } + + } + +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/FinalClass.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/FinalClass.java index e42bb650fda..261876a5272 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/FinalClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/FinalClass.java @@ -1,51 +1,51 @@ -/* - * 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.java.cleanup; - -import org.openrewrite.ExecutionContext; -import org.openrewrite.Recipe; -import org.openrewrite.java.JavaIsoVisitor; - -import java.time.Duration; -import java.util.Collections; -import java.util.Set; - -public class FinalClass extends Recipe { - @Override - public String getDisplayName() { - return "Finalize classes with private constructors"; - } - - @Override - public String getDescription() { - return "Adds the `final` modifier to classes that expose no public or package-private constructors."; - } - - @Override - public Set getTags() { - return Collections.singleton("RSPEC-2974"); - } - - @Override - public Duration getEstimatedEffortPerOccurrence() { - return Duration.ofMinutes(5); - } - - @Override - protected JavaIsoVisitor getVisitor() { - return new FinalClassVisitor(); - } -} +/* + * 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.java.cleanup; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.java.JavaIsoVisitor; + +import java.time.Duration; +import java.util.Collections; +import java.util.Set; + +public class FinalClass extends Recipe { + @Override + public String getDisplayName() { + return "Finalize classes with private constructors"; + } + + @Override + public String getDescription() { + return "Adds the `final` modifier to classes that expose no public or package-private constructors."; + } + + @Override + public Set getTags() { + return Collections.singleton("RSPEC-2974"); + } + + @Override + public Duration getEstimatedEffortPerOccurrence() { + return Duration.ofMinutes(5); + } + + @Override + protected JavaIsoVisitor getVisitor() { + return new FinalClassVisitor(); + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/FinalClassVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/FinalClassVisitor.java index 0232e4d847f..fe6d67b2525 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/FinalClassVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/FinalClassVisitor.java @@ -1,71 +1,71 @@ -/* - * 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.java.cleanup; - -import org.openrewrite.ExecutionContext; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.Space; -import org.openrewrite.java.tree.Statement; -import org.openrewrite.marker.Markers; - -import java.util.ArrayList; -import java.util.List; - -import static java.util.Collections.emptyList; -import static org.openrewrite.Tree.randomId; -import static org.openrewrite.java.cleanup.ModifierOrder.sortModifiers; -import static org.openrewrite.java.tree.J.ClassDeclaration.Kind.Type.Interface; - -public class FinalClassVisitor extends JavaIsoVisitor { - @Override - public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDeclaration, ExecutionContext executionContext) { - if(classDeclaration.getKind() == Interface || classDeclaration.hasModifier(J.Modifier.Type.Abstract)) { - return classDeclaration; - } - J.ClassDeclaration cd = super.visitClassDeclaration(classDeclaration, executionContext); - - if(cd.hasModifier(J.Modifier.Type.Final) || cd.getKind() != J.ClassDeclaration.Kind.Type.Class) { - return cd; - } - - boolean allPrivate = true; - int constructorCount = 0; - for(Statement s : cd.getBody().getStatements()) { - if(s instanceof J.MethodDeclaration && ((J.MethodDeclaration)s).isConstructor()) { - J.MethodDeclaration constructor = (J.MethodDeclaration)s; - constructorCount++; - if(!constructor.hasModifier(J.Modifier.Type.Private)) { - allPrivate = false; - } - } - if(constructorCount > 0 && !allPrivate) { - return cd; - } - } - - if(constructorCount > 0) { - List modifiers = new ArrayList<>(cd.getModifiers()); - modifiers.add(new J.Modifier(randomId(), Space.EMPTY, Markers.EMPTY, J.Modifier.Type.Final, emptyList())); - modifiers = sortModifiers(modifiers); - cd = cd.withModifiers(modifiers); - - assert getCursor().getParent() != null; - cd = autoFormat(cd, cd.getName(), executionContext, getCursor().getParent()); - } - return cd; - } -} +/* + * 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.java.cleanup; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.Space; +import org.openrewrite.java.tree.Statement; +import org.openrewrite.marker.Markers; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Collections.emptyList; +import static org.openrewrite.Tree.randomId; +import static org.openrewrite.java.cleanup.ModifierOrder.sortModifiers; +import static org.openrewrite.java.tree.J.ClassDeclaration.Kind.Type.Interface; + +public class FinalClassVisitor extends JavaIsoVisitor { + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDeclaration, ExecutionContext executionContext) { + if(classDeclaration.getKind() == Interface || classDeclaration.hasModifier(J.Modifier.Type.Abstract)) { + return classDeclaration; + } + J.ClassDeclaration cd = super.visitClassDeclaration(classDeclaration, executionContext); + + if(cd.hasModifier(J.Modifier.Type.Final) || cd.getKind() != J.ClassDeclaration.Kind.Type.Class) { + return cd; + } + + boolean allPrivate = true; + int constructorCount = 0; + for(Statement s : cd.getBody().getStatements()) { + if(s instanceof J.MethodDeclaration && ((J.MethodDeclaration)s).isConstructor()) { + J.MethodDeclaration constructor = (J.MethodDeclaration)s; + constructorCount++; + if(!constructor.hasModifier(J.Modifier.Type.Private)) { + allPrivate = false; + } + } + if(constructorCount > 0 && !allPrivate) { + return cd; + } + } + + if(constructorCount > 0) { + List modifiers = new ArrayList<>(cd.getModifiers()); + modifiers.add(new J.Modifier(randomId(), Space.EMPTY, Markers.EMPTY, J.Modifier.Type.Final, emptyList())); + modifiers = sortModifiers(modifiers); + cd = cd.withModifiers(modifiers); + + assert getCursor().getParent() != null; + cd = autoFormat(cd, cd.getName(), executionContext, getCursor().getParent()); + } + return cd; + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/MethodParamPad.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/MethodParamPad.java index 2ac83e4565b..f4f41510af2 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/MethodParamPad.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/MethodParamPad.java @@ -1,113 +1,113 @@ -/* - * 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.java.cleanup; - -import org.openrewrite.ExecutionContext; -import org.openrewrite.Recipe; -import org.openrewrite.SourceFile; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.format.SpacesVisitor; -import org.openrewrite.java.style.*; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaSourceFile; - -public class MethodParamPad extends Recipe { - @Override - public String getDisplayName() { - return "Method parameter padding"; - } - - @Override - public String getDescription() { - return "Fixes whitespace padding between the identifier of a method definition or method invocation and the left parenthesis of the parameter list. " + - "For example, when configured to remove spacing, `someMethodInvocation (x);` becomes `someMethodInvocation(x)`."; - } - - @Override - protected JavaIsoVisitor getVisitor() { - return new MethodParamPadVisitor(); - } - - private static class MethodParamPadVisitor extends JavaIsoVisitor { - SpacesStyle spacesStyle; - MethodParamPadStyle methodParamPadStyle; - - @Nullable - EmptyForInitializerPadStyle emptyForInitializerPadStyle; - - @Nullable - EmptyForIteratorPadStyle emptyForIteratorPadStyle; - - @Override - public JavaSourceFile visitJavaSourceFile(JavaSourceFile javaSourceFile, ExecutionContext ctx) { - SourceFile cu = (SourceFile)javaSourceFile; - spacesStyle = cu.getStyle(SpacesStyle.class) == null ? IntelliJ.spaces() : cu.getStyle(SpacesStyle.class); - methodParamPadStyle = cu.getStyle(MethodParamPadStyle.class) == null ? Checkstyle.methodParamPadStyle() : cu.getStyle(MethodParamPadStyle.class); - emptyForInitializerPadStyle = cu.getStyle(EmptyForInitializerPadStyle.class); - emptyForIteratorPadStyle = cu.getStyle(EmptyForIteratorPadStyle.class); - - spacesStyle = spacesStyle.withBeforeParentheses( - spacesStyle.getBeforeParentheses() - .withMethodDeclaration(methodParamPadStyle.getSpace()) - .withMethodCall(methodParamPadStyle.getSpace()) - ); - return super.visitJavaSourceFile((JavaSourceFile) cu, ctx); - } - - @Override - public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) { - J.MethodDeclaration md = super.visitMethodDeclaration(method, ctx); - if (!methodParamPadStyle.getAllowLineBreaks() && md.getPadding().getParameters().getBefore().getWhitespace().contains("\n")) { - md = md.getPadding().withParameters( - md.getPadding().getParameters().withBefore( - md.getPadding().getParameters().getBefore().withWhitespace("") - ) - ); - } - md = (J.MethodDeclaration)new SpacesVisitor<>(spacesStyle, emptyForInitializerPadStyle, emptyForIteratorPadStyle, md).visitNonNull(md, ctx); - return md; - } - - @Override - public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { - J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); - if (!methodParamPadStyle.getAllowLineBreaks() && mi.getPadding().getArguments().getBefore().getWhitespace().contains("\n")) { - mi = mi.getPadding().withArguments( - mi.getPadding().getArguments().withBefore( - mi.getPadding().getArguments().getBefore().withWhitespace("") - ) - ); - } - mi = (J.MethodInvocation)new SpacesVisitor<>(spacesStyle, emptyForInitializerPadStyle, emptyForIteratorPadStyle, mi).visitNonNull(mi, ctx); - return mi; - } - - @Override - public J.NewClass visitNewClass(J.NewClass newClass, ExecutionContext ctx) { - J.NewClass nc = super.visitNewClass(newClass, ctx); - if (!methodParamPadStyle.getAllowLineBreaks() && nc.getPadding().getArguments() != null && nc.getPadding().getArguments().getBefore().getWhitespace().contains("\n")) { - nc = nc.getPadding().withArguments( - nc.getPadding().getArguments().withBefore( - nc.getPadding().getArguments().getBefore().withWhitespace("") - ) - ); - } - nc = (J.NewClass)new SpacesVisitor<>(spacesStyle, emptyForInitializerPadStyle, emptyForIteratorPadStyle, nc).visitNonNull(nc, ctx); - return nc; - } - } -} +/* + * 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.java.cleanup; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.SourceFile; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.format.SpacesVisitor; +import org.openrewrite.java.style.*; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaSourceFile; + +public class MethodParamPad extends Recipe { + @Override + public String getDisplayName() { + return "Method parameter padding"; + } + + @Override + public String getDescription() { + return "Fixes whitespace padding between the identifier of a method definition or method invocation and the left parenthesis of the parameter list. " + + "For example, when configured to remove spacing, `someMethodInvocation (x);` becomes `someMethodInvocation(x)`."; + } + + @Override + protected JavaIsoVisitor getVisitor() { + return new MethodParamPadVisitor(); + } + + private static class MethodParamPadVisitor extends JavaIsoVisitor { + SpacesStyle spacesStyle; + MethodParamPadStyle methodParamPadStyle; + + @Nullable + EmptyForInitializerPadStyle emptyForInitializerPadStyle; + + @Nullable + EmptyForIteratorPadStyle emptyForIteratorPadStyle; + + @Override + public JavaSourceFile visitJavaSourceFile(JavaSourceFile javaSourceFile, ExecutionContext ctx) { + SourceFile cu = (SourceFile)javaSourceFile; + spacesStyle = cu.getStyle(SpacesStyle.class) == null ? IntelliJ.spaces() : cu.getStyle(SpacesStyle.class); + methodParamPadStyle = cu.getStyle(MethodParamPadStyle.class) == null ? Checkstyle.methodParamPadStyle() : cu.getStyle(MethodParamPadStyle.class); + emptyForInitializerPadStyle = cu.getStyle(EmptyForInitializerPadStyle.class); + emptyForIteratorPadStyle = cu.getStyle(EmptyForIteratorPadStyle.class); + + spacesStyle = spacesStyle.withBeforeParentheses( + spacesStyle.getBeforeParentheses() + .withMethodDeclaration(methodParamPadStyle.getSpace()) + .withMethodCall(methodParamPadStyle.getSpace()) + ); + return super.visitJavaSourceFile((JavaSourceFile) cu, ctx); + } + + @Override + public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) { + J.MethodDeclaration md = super.visitMethodDeclaration(method, ctx); + if (!methodParamPadStyle.getAllowLineBreaks() && md.getPadding().getParameters().getBefore().getWhitespace().contains("\n")) { + md = md.getPadding().withParameters( + md.getPadding().getParameters().withBefore( + md.getPadding().getParameters().getBefore().withWhitespace("") + ) + ); + } + md = (J.MethodDeclaration)new SpacesVisitor<>(spacesStyle, emptyForInitializerPadStyle, emptyForIteratorPadStyle, md).visitNonNull(md, ctx); + return md; + } + + @Override + public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + J.MethodInvocation mi = super.visitMethodInvocation(method, ctx); + if (!methodParamPadStyle.getAllowLineBreaks() && mi.getPadding().getArguments().getBefore().getWhitespace().contains("\n")) { + mi = mi.getPadding().withArguments( + mi.getPadding().getArguments().withBefore( + mi.getPadding().getArguments().getBefore().withWhitespace("") + ) + ); + } + mi = (J.MethodInvocation)new SpacesVisitor<>(spacesStyle, emptyForInitializerPadStyle, emptyForIteratorPadStyle, mi).visitNonNull(mi, ctx); + return mi; + } + + @Override + public J.NewClass visitNewClass(J.NewClass newClass, ExecutionContext ctx) { + J.NewClass nc = super.visitNewClass(newClass, ctx); + if (!methodParamPadStyle.getAllowLineBreaks() && nc.getPadding().getArguments() != null && nc.getPadding().getArguments().getBefore().getWhitespace().contains("\n")) { + nc = nc.getPadding().withArguments( + nc.getPadding().getArguments().withBefore( + nc.getPadding().getArguments().getBefore().withWhitespace("") + ) + ); + } + nc = (J.NewClass)new SpacesVisitor<>(spacesStyle, emptyForInitializerPadStyle, emptyForIteratorPadStyle, nc).visitNonNull(nc, ctx); + return nc; + } + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/OperatorWrap.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/OperatorWrap.java index 78add753d00..76f80e9f04e 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/OperatorWrap.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/OperatorWrap.java @@ -1,419 +1,419 @@ -/* - * 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.java.cleanup; - -import org.openrewrite.ExecutionContext; -import org.openrewrite.Recipe; -import org.openrewrite.SourceFile; -import org.openrewrite.internal.ListUtils; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.style.Checkstyle; -import org.openrewrite.java.style.OperatorWrapStyle; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JRightPadded; -import org.openrewrite.java.tree.JavaSourceFile; -import org.openrewrite.java.tree.TypeTree; - -public class OperatorWrap extends Recipe { - @Override - public String getDisplayName() { - return "Operator wrapping"; - } - - @Override - public String getDescription() { - return "Fixes line wrapping policies on operators."; - } - - @Override - protected JavaIsoVisitor getVisitor() { - return new OperatorWrapVisitor(); - } - - private static class OperatorWrapVisitor extends JavaIsoVisitor { - OperatorWrapStyle operatorWrapStyle; - - @Override - public JavaSourceFile visitJavaSourceFile(JavaSourceFile javaSourceFile, ExecutionContext ctx) { - SourceFile cu = (SourceFile)javaSourceFile; - operatorWrapStyle = cu.getStyle(OperatorWrapStyle.class) == null ? Checkstyle.operatorWrapStyle() : cu.getStyle(OperatorWrapStyle.class); - return super.visitJavaSourceFile((JavaSourceFile) cu, ctx); - } - - @Override - public J.Binary visitBinary(J.Binary binary, ExecutionContext ctx) { - J.Binary b = super.visitBinary(binary, ctx); - J.Binary.Type op = b.getOperator(); - if ((Boolean.TRUE.equals(operatorWrapStyle.getDiv()) && op == J.Binary.Type.Division) || - (Boolean.TRUE.equals(operatorWrapStyle.getStar()) && op == J.Binary.Type.Multiplication) || - (Boolean.TRUE.equals(operatorWrapStyle.getPlus()) && op == J.Binary.Type.Addition) || - (Boolean.TRUE.equals(operatorWrapStyle.getMinus()) && op == J.Binary.Type.Subtraction) || - (Boolean.TRUE.equals(operatorWrapStyle.getMod()) && op == J.Binary.Type.Modulo) || - (Boolean.TRUE.equals(operatorWrapStyle.getSr()) && op == J.Binary.Type.RightShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getSl()) && op == J.Binary.Type.LeftShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getBsr()) && op == J.Binary.Type.UnsignedRightShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getEqual()) && op == J.Binary.Type.Equal) || - (Boolean.TRUE.equals(operatorWrapStyle.getNotEqual()) && op == J.Binary.Type.NotEqual) || - (Boolean.TRUE.equals(operatorWrapStyle.getGt()) && op == J.Binary.Type.GreaterThan) || - (Boolean.TRUE.equals(operatorWrapStyle.getGe()) && op == J.Binary.Type.GreaterThanOrEqual) || - (Boolean.TRUE.equals(operatorWrapStyle.getLt()) && op == J.Binary.Type.LessThan) || - (Boolean.TRUE.equals(operatorWrapStyle.getLe()) && op == J.Binary.Type.LessThanOrEqual) || - (Boolean.TRUE.equals(operatorWrapStyle.getBand()) && op == J.Binary.Type.BitAnd) || - (Boolean.TRUE.equals(operatorWrapStyle.getBxor()) && op == J.Binary.Type.BitXor) || - (Boolean.TRUE.equals(operatorWrapStyle.getBor()) && op == J.Binary.Type.BitOr) || - (Boolean.TRUE.equals(operatorWrapStyle.getLand()) && op == J.Binary.Type.And) || - (Boolean.TRUE.equals(operatorWrapStyle.getLor()) && op == J.Binary.Type.Or)) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (b.getRight().getPrefix().getWhitespace().contains("\n")) { - b = b.getPadding().withOperator( - b.getPadding().getOperator().withBefore( - b.getRight().getPrefix() - ) - ); - b = b.withRight( - b.getRight().withPrefix( - b.getRight().getPrefix().withWhitespace(" ") - ) - ); - } - } else if (b.getPadding().getOperator().getBefore().getWhitespace().contains("\n")) { - b = b.withRight( - b.getRight().withPrefix( - b.getPadding().getOperator().getBefore() - ) - ); - b = b.getPadding().withOperator( - b.getPadding().getOperator().withBefore( - b.getRight().getPrefix().withWhitespace(" ") - ) - ); - } - } - return b; - } - - @Override - public J.TypeParameter visitTypeParameter(J.TypeParameter typeParam, ExecutionContext ctx) { - J.TypeParameter tp = super.visitTypeParameter(typeParam, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getTypeExtensionAnd()) && tp.getPadding().getBounds() != null) { - int typeBoundsSize = tp.getPadding().getBounds().getPadding().getElements().size(); - tp = tp.getPadding().withBounds( - tp.getPadding().getBounds().getPadding().withElements( - ListUtils.map(tp.getPadding().getBounds().getPadding().getElements(), - (index, elemContainer) -> { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (index != typeBoundsSize - 1 && typeParam.getPadding().getBounds() != null) { - JRightPadded next = typeParam.getPadding().getBounds().getPadding().getElements().get(index + 1); - if (next.getElement().getPrefix().getWhitespace().contains("\n")) { - elemContainer = elemContainer.withAfter( - next.getElement().getPrefix() - ); - } - } else { - if (elemContainer.getElement().getPrefix().getWhitespace().contains("\n")) { - elemContainer = elemContainer.withElement( - elemContainer.getElement().withPrefix( - elemContainer.getElement().getPrefix().withWhitespace(" ") - ) - ); - } - } - } else { - if (index != typeBoundsSize - 1) { - if (elemContainer.getAfter().getWhitespace().contains("\n")) { - elemContainer = elemContainer.withAfter( - elemContainer.getAfter().withWhitespace(" ") - ); - } - } else if (typeBoundsSize > 1 && typeParam.getPadding().getBounds() != null) { - JRightPadded previous = typeParam.getPadding().getBounds().getPadding().getElements().get(index - 1); - if (previous.getAfter().getWhitespace().contains("\n")) { - elemContainer = elemContainer.withElement( - elemContainer.getElement().withPrefix( - previous.getAfter() - ) - ); - } - } - } - return elemContainer; - } - ) - ) - ); - } - return tp; - } - - @Override - public J.InstanceOf visitInstanceOf(J.InstanceOf instanceOf, ExecutionContext ctx) { - J.InstanceOf i = super.visitInstanceOf(instanceOf, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getLiteralInstanceof())) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (i.getClazz().getPrefix().getWhitespace().contains("\n")) { - i = i.getPadding().withExpr( - i.getPadding().getExpr().withAfter( - i.getClazz().getPrefix() - ) - ); - i = i.withClazz( - i.getClazz().withPrefix( - i.getClazz().getPrefix().withWhitespace(" ") - ) - ); - } - } else if (i.getPadding().getExpr().getAfter().getWhitespace().contains("\n")) { - i = i.withClazz( - i.getClazz().withPrefix( - i.getPadding().getExpr().getAfter() - ) - ); - i = i.getPadding().withExpr( - i.getPadding().getExpr().withAfter( - i.getPadding().getExpr().getAfter().withWhitespace(" ") - ) - ); - } - } - return i; - } - - @Override - public J.Ternary visitTernary(J.Ternary ternary, ExecutionContext ctx) { - J.Ternary t = super.visitTernary(ternary, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getQuestion())) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (t.getTruePart().getPrefix().getWhitespace().contains("\n")) { - t = t.getPadding().withTruePart( - t.getPadding().getTruePart().withBefore( - t.getPadding().getTruePart().getElement().getPrefix() - ) - ); - t = t.getPadding().withTruePart( - t.getPadding().getTruePart().withElement( - t.getPadding().getTruePart().getElement().withPrefix( - t.getPadding().getTruePart().getElement().getPrefix().withWhitespace(" ") - ) - ) - ); - } - } else if (t.getPadding().getTruePart().getBefore().getWhitespace().contains("\n")) { - t = t.getPadding().withTruePart( - t.getPadding().getTruePart().withElement( - t.getPadding().getTruePart().getElement().withPrefix( - t.getPadding().getTruePart().getBefore() - ) - ) - ); - t = t.getPadding().withTruePart( - t.getPadding().getTruePart().withBefore( - t.getPadding().getTruePart().getElement().getPrefix().withWhitespace(" ") - ) - ); - } - } - if (Boolean.TRUE.equals(operatorWrapStyle.getColon())) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (t.getPadding().getFalsePart().getElement().getPrefix().getWhitespace().contains("\n")) { - t = t.getPadding().withFalsePart( - t.getPadding().getFalsePart().withBefore( - t.getPadding().getFalsePart().getElement().getPrefix() - ) - ); - t = t.getPadding().withFalsePart( - t.getPadding().getFalsePart().withElement( - t.getPadding().getFalsePart().getElement().withPrefix( - t.getPadding().getFalsePart().getElement().getPrefix().withWhitespace(" ") - ) - ) - ); - } - } else if (t.getPadding().getFalsePart().getBefore().getWhitespace().contains("\n")) { - t = t.getPadding().withFalsePart( - t.getPadding().getFalsePart().withElement( - t.getPadding().getFalsePart().getElement().withPrefix( - t.getPadding().getFalsePart().getBefore() - ) - ) - ); - t = t.getPadding().withFalsePart( - t.getPadding().getFalsePart().withBefore( - t.getPadding().getFalsePart().getElement().getPrefix().withWhitespace(" ") - ) - ); - } - } - return t; - } - - @Override - public J.MemberReference visitMemberReference(J.MemberReference memberRef, ExecutionContext ctx) { - J.MemberReference m = super.visitMemberReference(memberRef, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getMethodRef())) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (m.getPadding().getReference().getBefore().getWhitespace().contains("\n")) { - m = m.getPadding().withContaining( - m.getPadding().getContaining().withAfter( - m.getPadding().getReference().getBefore() - ) - ); - m = m.getPadding().withReference( - m.getPadding().getReference().withBefore( - m.getPadding().getReference().getBefore().withWhitespace("") - ) - ); - } - } else if (m.getPadding().getContaining().getAfter().getWhitespace().contains("\n")) { - m = m.getPadding().withReference( - m.getPadding().getReference().withBefore( - m.getPadding().getContaining().getAfter() - ) - ); - m = m.getPadding().withContaining( - m.getPadding().getContaining().withAfter( - m.getPadding().getReference().getBefore().withWhitespace("") - ) - ); - } - } - return m; - } - - @Override - public J.Assignment visitAssignment(J.Assignment assignment, ExecutionContext ctx) { - J.Assignment a = super.visitAssignment(assignment, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getAssign())) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (a.getPadding().getAssignment().getElement().getPrefix().getWhitespace().contains("\n")) { - a = a.getPadding().withAssignment( - a.getPadding().getAssignment().withBefore( - a.getPadding().getAssignment().getElement().getPrefix() - ) - ); - a = a.getPadding().withAssignment( - a.getPadding().getAssignment().withElement( - a.getPadding().getAssignment().getElement().withPrefix( - a.getPadding().getAssignment().getElement().getPrefix().withWhitespace(" ") - ) - ) - ); - } - } else if (a.getPadding().getAssignment().getBefore().getWhitespace().contains("\n")) { - a = a.getPadding().withAssignment( - a.getPadding().getAssignment().withElement( - a.getPadding().getAssignment().getElement().withPrefix( - a.getPadding().getAssignment().getBefore() - ) - ) - ); - a = a.getPadding().withAssignment( - a.getPadding().getAssignment().withBefore( - a.getPadding().getAssignment().getBefore().withWhitespace(" ") - ) - ); - } - } - return a; - } - - @Override - public J.AssignmentOperation visitAssignmentOperation(J.AssignmentOperation assignOp, ExecutionContext ctx) { - J.AssignmentOperation a = super.visitAssignmentOperation(assignOp, ctx); - J.AssignmentOperation.Type op = a.getOperator(); - if ((Boolean.TRUE.equals(operatorWrapStyle.getPlusAssign()) && op == J.AssignmentOperation.Type.Addition) || - (Boolean.TRUE.equals(operatorWrapStyle.getMinusAssign()) && op == J.AssignmentOperation.Type.Subtraction) || - (Boolean.TRUE.equals(operatorWrapStyle.getStarAssign()) && op == J.AssignmentOperation.Type.Multiplication) || - (Boolean.TRUE.equals(operatorWrapStyle.getDivAssign()) && op == J.AssignmentOperation.Type.Division) || - (Boolean.TRUE.equals(operatorWrapStyle.getModAssign()) && op == J.AssignmentOperation.Type.Modulo) || - (Boolean.TRUE.equals(operatorWrapStyle.getSrAssign()) && op == J.AssignmentOperation.Type.RightShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getSlAssign()) && op == J.AssignmentOperation.Type.LeftShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getBsrAssign()) && op == J.AssignmentOperation.Type.UnsignedRightShift) || - (Boolean.TRUE.equals(operatorWrapStyle.getBandAssign()) && op == J.AssignmentOperation.Type.BitAnd) || - (Boolean.TRUE.equals(operatorWrapStyle.getBxorAssign()) && op == J.AssignmentOperation.Type.BitXor) || - (Boolean.TRUE.equals(operatorWrapStyle.getBorAssign()) && op == J.AssignmentOperation.Type.BitOr)) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (a.getAssignment().getPrefix().getWhitespace().contains("\n")) { - a = a.getPadding().withOperator( - a.getPadding().getOperator().withBefore( - a.getAssignment().getPrefix() - ) - ); - a = a.withAssignment( - a.getAssignment().withPrefix( - a.getAssignment().getPrefix().withWhitespace(" ") - ) - ); - } - } else if (a.getPadding().getOperator().getBefore().getWhitespace().contains("\n")) { - a = a.withAssignment( - a.getAssignment().withPrefix( - a.getPadding().getOperator().getBefore() - ) - ); - a = a.getPadding().withOperator( - a.getPadding().getOperator().withBefore( - a.getAssignment().getPrefix().withWhitespace(" ") - ) - ); - } - } - return a; - } - - @Override - public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, ExecutionContext ctx) { - J.VariableDeclarations.NamedVariable v = super.visitVariable(variable, ctx); - if (Boolean.TRUE.equals(operatorWrapStyle.getAssign()) && v.getPadding().getInitializer() != null) { - if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { - if (v.getPadding().getInitializer().getElement().getPrefix().getWhitespace().contains("\n")) { - v = v.getPadding().withInitializer( - v.getPadding().getInitializer().withBefore( - v.getPadding().getInitializer().getElement().getPrefix() - ) - ); - if (v.getPadding().getInitializer() != null && v.getPadding().getInitializer().getElement() != null) { - v = v.getPadding().withInitializer( - v.getPadding().getInitializer().withElement( - v.getPadding().getInitializer().getElement().withPrefix( - v.getPadding().getInitializer().getElement().getPrefix().withWhitespace(" ") - ) - ) - ); - } - } - } else if (v.getPadding().getInitializer().getBefore().getWhitespace().contains("\n")) { - v = v.getPadding().withInitializer( - v.getPadding().getInitializer().withElement( - v.getPadding().getInitializer().getElement().withPrefix( - v.getPadding().getInitializer().getBefore() - ) - ) - ); - if (v.getPadding().getInitializer() != null && v.getPadding().getInitializer().getBefore() != null) { - v = v.getPadding().withInitializer( - v.getPadding().getInitializer().withBefore( - v.getPadding().getInitializer().getElement().getPrefix().withWhitespace(" ") - ) - ); - } - } - } - return v; - } - - } - -} +/* + * 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.java.cleanup; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.SourceFile; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.style.Checkstyle; +import org.openrewrite.java.style.OperatorWrapStyle; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JRightPadded; +import org.openrewrite.java.tree.JavaSourceFile; +import org.openrewrite.java.tree.TypeTree; + +public class OperatorWrap extends Recipe { + @Override + public String getDisplayName() { + return "Operator wrapping"; + } + + @Override + public String getDescription() { + return "Fixes line wrapping policies on operators."; + } + + @Override + protected JavaIsoVisitor getVisitor() { + return new OperatorWrapVisitor(); + } + + private static class OperatorWrapVisitor extends JavaIsoVisitor { + OperatorWrapStyle operatorWrapStyle; + + @Override + public JavaSourceFile visitJavaSourceFile(JavaSourceFile javaSourceFile, ExecutionContext ctx) { + SourceFile cu = (SourceFile)javaSourceFile; + operatorWrapStyle = cu.getStyle(OperatorWrapStyle.class) == null ? Checkstyle.operatorWrapStyle() : cu.getStyle(OperatorWrapStyle.class); + return super.visitJavaSourceFile((JavaSourceFile) cu, ctx); + } + + @Override + public J.Binary visitBinary(J.Binary binary, ExecutionContext ctx) { + J.Binary b = super.visitBinary(binary, ctx); + J.Binary.Type op = b.getOperator(); + if ((Boolean.TRUE.equals(operatorWrapStyle.getDiv()) && op == J.Binary.Type.Division) || + (Boolean.TRUE.equals(operatorWrapStyle.getStar()) && op == J.Binary.Type.Multiplication) || + (Boolean.TRUE.equals(operatorWrapStyle.getPlus()) && op == J.Binary.Type.Addition) || + (Boolean.TRUE.equals(operatorWrapStyle.getMinus()) && op == J.Binary.Type.Subtraction) || + (Boolean.TRUE.equals(operatorWrapStyle.getMod()) && op == J.Binary.Type.Modulo) || + (Boolean.TRUE.equals(operatorWrapStyle.getSr()) && op == J.Binary.Type.RightShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getSl()) && op == J.Binary.Type.LeftShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getBsr()) && op == J.Binary.Type.UnsignedRightShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getEqual()) && op == J.Binary.Type.Equal) || + (Boolean.TRUE.equals(operatorWrapStyle.getNotEqual()) && op == J.Binary.Type.NotEqual) || + (Boolean.TRUE.equals(operatorWrapStyle.getGt()) && op == J.Binary.Type.GreaterThan) || + (Boolean.TRUE.equals(operatorWrapStyle.getGe()) && op == J.Binary.Type.GreaterThanOrEqual) || + (Boolean.TRUE.equals(operatorWrapStyle.getLt()) && op == J.Binary.Type.LessThan) || + (Boolean.TRUE.equals(operatorWrapStyle.getLe()) && op == J.Binary.Type.LessThanOrEqual) || + (Boolean.TRUE.equals(operatorWrapStyle.getBand()) && op == J.Binary.Type.BitAnd) || + (Boolean.TRUE.equals(operatorWrapStyle.getBxor()) && op == J.Binary.Type.BitXor) || + (Boolean.TRUE.equals(operatorWrapStyle.getBor()) && op == J.Binary.Type.BitOr) || + (Boolean.TRUE.equals(operatorWrapStyle.getLand()) && op == J.Binary.Type.And) || + (Boolean.TRUE.equals(operatorWrapStyle.getLor()) && op == J.Binary.Type.Or)) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (b.getRight().getPrefix().getWhitespace().contains("\n")) { + b = b.getPadding().withOperator( + b.getPadding().getOperator().withBefore( + b.getRight().getPrefix() + ) + ); + b = b.withRight( + b.getRight().withPrefix( + b.getRight().getPrefix().withWhitespace(" ") + ) + ); + } + } else if (b.getPadding().getOperator().getBefore().getWhitespace().contains("\n")) { + b = b.withRight( + b.getRight().withPrefix( + b.getPadding().getOperator().getBefore() + ) + ); + b = b.getPadding().withOperator( + b.getPadding().getOperator().withBefore( + b.getRight().getPrefix().withWhitespace(" ") + ) + ); + } + } + return b; + } + + @Override + public J.TypeParameter visitTypeParameter(J.TypeParameter typeParam, ExecutionContext ctx) { + J.TypeParameter tp = super.visitTypeParameter(typeParam, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getTypeExtensionAnd()) && tp.getPadding().getBounds() != null) { + int typeBoundsSize = tp.getPadding().getBounds().getPadding().getElements().size(); + tp = tp.getPadding().withBounds( + tp.getPadding().getBounds().getPadding().withElements( + ListUtils.map(tp.getPadding().getBounds().getPadding().getElements(), + (index, elemContainer) -> { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (index != typeBoundsSize - 1 && typeParam.getPadding().getBounds() != null) { + JRightPadded next = typeParam.getPadding().getBounds().getPadding().getElements().get(index + 1); + if (next.getElement().getPrefix().getWhitespace().contains("\n")) { + elemContainer = elemContainer.withAfter( + next.getElement().getPrefix() + ); + } + } else { + if (elemContainer.getElement().getPrefix().getWhitespace().contains("\n")) { + elemContainer = elemContainer.withElement( + elemContainer.getElement().withPrefix( + elemContainer.getElement().getPrefix().withWhitespace(" ") + ) + ); + } + } + } else { + if (index != typeBoundsSize - 1) { + if (elemContainer.getAfter().getWhitespace().contains("\n")) { + elemContainer = elemContainer.withAfter( + elemContainer.getAfter().withWhitespace(" ") + ); + } + } else if (typeBoundsSize > 1 && typeParam.getPadding().getBounds() != null) { + JRightPadded previous = typeParam.getPadding().getBounds().getPadding().getElements().get(index - 1); + if (previous.getAfter().getWhitespace().contains("\n")) { + elemContainer = elemContainer.withElement( + elemContainer.getElement().withPrefix( + previous.getAfter() + ) + ); + } + } + } + return elemContainer; + } + ) + ) + ); + } + return tp; + } + + @Override + public J.InstanceOf visitInstanceOf(J.InstanceOf instanceOf, ExecutionContext ctx) { + J.InstanceOf i = super.visitInstanceOf(instanceOf, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getLiteralInstanceof())) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (i.getClazz().getPrefix().getWhitespace().contains("\n")) { + i = i.getPadding().withExpr( + i.getPadding().getExpr().withAfter( + i.getClazz().getPrefix() + ) + ); + i = i.withClazz( + i.getClazz().withPrefix( + i.getClazz().getPrefix().withWhitespace(" ") + ) + ); + } + } else if (i.getPadding().getExpr().getAfter().getWhitespace().contains("\n")) { + i = i.withClazz( + i.getClazz().withPrefix( + i.getPadding().getExpr().getAfter() + ) + ); + i = i.getPadding().withExpr( + i.getPadding().getExpr().withAfter( + i.getPadding().getExpr().getAfter().withWhitespace(" ") + ) + ); + } + } + return i; + } + + @Override + public J.Ternary visitTernary(J.Ternary ternary, ExecutionContext ctx) { + J.Ternary t = super.visitTernary(ternary, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getQuestion())) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (t.getTruePart().getPrefix().getWhitespace().contains("\n")) { + t = t.getPadding().withTruePart( + t.getPadding().getTruePart().withBefore( + t.getPadding().getTruePart().getElement().getPrefix() + ) + ); + t = t.getPadding().withTruePart( + t.getPadding().getTruePart().withElement( + t.getPadding().getTruePart().getElement().withPrefix( + t.getPadding().getTruePart().getElement().getPrefix().withWhitespace(" ") + ) + ) + ); + } + } else if (t.getPadding().getTruePart().getBefore().getWhitespace().contains("\n")) { + t = t.getPadding().withTruePart( + t.getPadding().getTruePart().withElement( + t.getPadding().getTruePart().getElement().withPrefix( + t.getPadding().getTruePart().getBefore() + ) + ) + ); + t = t.getPadding().withTruePart( + t.getPadding().getTruePart().withBefore( + t.getPadding().getTruePart().getElement().getPrefix().withWhitespace(" ") + ) + ); + } + } + if (Boolean.TRUE.equals(operatorWrapStyle.getColon())) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (t.getPadding().getFalsePart().getElement().getPrefix().getWhitespace().contains("\n")) { + t = t.getPadding().withFalsePart( + t.getPadding().getFalsePart().withBefore( + t.getPadding().getFalsePart().getElement().getPrefix() + ) + ); + t = t.getPadding().withFalsePart( + t.getPadding().getFalsePart().withElement( + t.getPadding().getFalsePart().getElement().withPrefix( + t.getPadding().getFalsePart().getElement().getPrefix().withWhitespace(" ") + ) + ) + ); + } + } else if (t.getPadding().getFalsePart().getBefore().getWhitespace().contains("\n")) { + t = t.getPadding().withFalsePart( + t.getPadding().getFalsePart().withElement( + t.getPadding().getFalsePart().getElement().withPrefix( + t.getPadding().getFalsePart().getBefore() + ) + ) + ); + t = t.getPadding().withFalsePart( + t.getPadding().getFalsePart().withBefore( + t.getPadding().getFalsePart().getElement().getPrefix().withWhitespace(" ") + ) + ); + } + } + return t; + } + + @Override + public J.MemberReference visitMemberReference(J.MemberReference memberRef, ExecutionContext ctx) { + J.MemberReference m = super.visitMemberReference(memberRef, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getMethodRef())) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (m.getPadding().getReference().getBefore().getWhitespace().contains("\n")) { + m = m.getPadding().withContaining( + m.getPadding().getContaining().withAfter( + m.getPadding().getReference().getBefore() + ) + ); + m = m.getPadding().withReference( + m.getPadding().getReference().withBefore( + m.getPadding().getReference().getBefore().withWhitespace("") + ) + ); + } + } else if (m.getPadding().getContaining().getAfter().getWhitespace().contains("\n")) { + m = m.getPadding().withReference( + m.getPadding().getReference().withBefore( + m.getPadding().getContaining().getAfter() + ) + ); + m = m.getPadding().withContaining( + m.getPadding().getContaining().withAfter( + m.getPadding().getReference().getBefore().withWhitespace("") + ) + ); + } + } + return m; + } + + @Override + public J.Assignment visitAssignment(J.Assignment assignment, ExecutionContext ctx) { + J.Assignment a = super.visitAssignment(assignment, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getAssign())) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (a.getPadding().getAssignment().getElement().getPrefix().getWhitespace().contains("\n")) { + a = a.getPadding().withAssignment( + a.getPadding().getAssignment().withBefore( + a.getPadding().getAssignment().getElement().getPrefix() + ) + ); + a = a.getPadding().withAssignment( + a.getPadding().getAssignment().withElement( + a.getPadding().getAssignment().getElement().withPrefix( + a.getPadding().getAssignment().getElement().getPrefix().withWhitespace(" ") + ) + ) + ); + } + } else if (a.getPadding().getAssignment().getBefore().getWhitespace().contains("\n")) { + a = a.getPadding().withAssignment( + a.getPadding().getAssignment().withElement( + a.getPadding().getAssignment().getElement().withPrefix( + a.getPadding().getAssignment().getBefore() + ) + ) + ); + a = a.getPadding().withAssignment( + a.getPadding().getAssignment().withBefore( + a.getPadding().getAssignment().getBefore().withWhitespace(" ") + ) + ); + } + } + return a; + } + + @Override + public J.AssignmentOperation visitAssignmentOperation(J.AssignmentOperation assignOp, ExecutionContext ctx) { + J.AssignmentOperation a = super.visitAssignmentOperation(assignOp, ctx); + J.AssignmentOperation.Type op = a.getOperator(); + if ((Boolean.TRUE.equals(operatorWrapStyle.getPlusAssign()) && op == J.AssignmentOperation.Type.Addition) || + (Boolean.TRUE.equals(operatorWrapStyle.getMinusAssign()) && op == J.AssignmentOperation.Type.Subtraction) || + (Boolean.TRUE.equals(operatorWrapStyle.getStarAssign()) && op == J.AssignmentOperation.Type.Multiplication) || + (Boolean.TRUE.equals(operatorWrapStyle.getDivAssign()) && op == J.AssignmentOperation.Type.Division) || + (Boolean.TRUE.equals(operatorWrapStyle.getModAssign()) && op == J.AssignmentOperation.Type.Modulo) || + (Boolean.TRUE.equals(operatorWrapStyle.getSrAssign()) && op == J.AssignmentOperation.Type.RightShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getSlAssign()) && op == J.AssignmentOperation.Type.LeftShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getBsrAssign()) && op == J.AssignmentOperation.Type.UnsignedRightShift) || + (Boolean.TRUE.equals(operatorWrapStyle.getBandAssign()) && op == J.AssignmentOperation.Type.BitAnd) || + (Boolean.TRUE.equals(operatorWrapStyle.getBxorAssign()) && op == J.AssignmentOperation.Type.BitXor) || + (Boolean.TRUE.equals(operatorWrapStyle.getBorAssign()) && op == J.AssignmentOperation.Type.BitOr)) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (a.getAssignment().getPrefix().getWhitespace().contains("\n")) { + a = a.getPadding().withOperator( + a.getPadding().getOperator().withBefore( + a.getAssignment().getPrefix() + ) + ); + a = a.withAssignment( + a.getAssignment().withPrefix( + a.getAssignment().getPrefix().withWhitespace(" ") + ) + ); + } + } else if (a.getPadding().getOperator().getBefore().getWhitespace().contains("\n")) { + a = a.withAssignment( + a.getAssignment().withPrefix( + a.getPadding().getOperator().getBefore() + ) + ); + a = a.getPadding().withOperator( + a.getPadding().getOperator().withBefore( + a.getAssignment().getPrefix().withWhitespace(" ") + ) + ); + } + } + return a; + } + + @Override + public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, ExecutionContext ctx) { + J.VariableDeclarations.NamedVariable v = super.visitVariable(variable, ctx); + if (Boolean.TRUE.equals(operatorWrapStyle.getAssign()) && v.getPadding().getInitializer() != null) { + if (OperatorWrapStyle.WrapOption.NL.equals(operatorWrapStyle.getWrapOption())) { + if (v.getPadding().getInitializer().getElement().getPrefix().getWhitespace().contains("\n")) { + v = v.getPadding().withInitializer( + v.getPadding().getInitializer().withBefore( + v.getPadding().getInitializer().getElement().getPrefix() + ) + ); + if (v.getPadding().getInitializer() != null && v.getPadding().getInitializer().getElement() != null) { + v = v.getPadding().withInitializer( + v.getPadding().getInitializer().withElement( + v.getPadding().getInitializer().getElement().withPrefix( + v.getPadding().getInitializer().getElement().getPrefix().withWhitespace(" ") + ) + ) + ); + } + } + } else if (v.getPadding().getInitializer().getBefore().getWhitespace().contains("\n")) { + v = v.getPadding().withInitializer( + v.getPadding().getInitializer().withElement( + v.getPadding().getInitializer().getElement().withPrefix( + v.getPadding().getInitializer().getBefore() + ) + ) + ); + if (v.getPadding().getInitializer() != null && v.getPadding().getInitializer().getBefore() != null) { + v = v.getPadding().withInitializer( + v.getPadding().getInitializer().withBefore( + v.getPadding().getInitializer().getElement().getPrefix().withWhitespace(" ") + ) + ); + } + } + } + return v; + } + + } + +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/PadEmptyForLoopComponents.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/PadEmptyForLoopComponents.java index f5bb984f3e5..eb879250143 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/PadEmptyForLoopComponents.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/PadEmptyForLoopComponents.java @@ -1,107 +1,107 @@ -/* - * 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.java.cleanup; - -import org.openrewrite.ExecutionContext; -import org.openrewrite.Recipe; -import org.openrewrite.SourceFile; -import org.openrewrite.internal.ListUtils; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.style.EmptyForInitializerPadStyle; -import org.openrewrite.java.style.EmptyForIteratorPadStyle; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaSourceFile; -import org.openrewrite.java.tree.Statement; -import org.openrewrite.marker.SearchResult; - -import java.util.List; - -import static java.util.Collections.singletonList; -import static org.openrewrite.Tree.randomId; - -public class PadEmptyForLoopComponents extends Recipe { - - @Override - public String getDisplayName() { - return "Pad empty `for` loop components"; - } - - @Override - public String getDescription() { - return "Fixes padding on empty `for` loop iterators and initializers to match Checkstyle policies."; - } - - @Override - protected @Nullable JavaIsoVisitor getSingleSourceApplicableTest() { - return new JavaIsoVisitor() { - @Override - public JavaSourceFile visitJavaSourceFile(JavaSourceFile javaSourceFile, ExecutionContext executionContext) { - SourceFile cu = (SourceFile) javaSourceFile; - if(cu.getStyle(EmptyForIteratorPadStyle.class) != null || cu.getStyle(EmptyForInitializerPadStyle.class) != null) { - return cu.withMarkers(cu.getMarkers().add(new SearchResult(randomId(), null))); - } - return (JavaSourceFile) cu; - } - }; - } - - @Override - protected JavaIsoVisitor getVisitor() { - return new JavaIsoVisitor() { - - @Nullable - EmptyForIteratorPadStyle emptyForIteratorPadStyle; - - @Nullable - EmptyForInitializerPadStyle emptyForInitializerPadStyle; - - @Override - public JavaSourceFile visitJavaSourceFile(JavaSourceFile javaSourceFile, ExecutionContext executionContext) { - SourceFile cu = (SourceFile)javaSourceFile; - emptyForInitializerPadStyle = cu.getStyle(EmptyForInitializerPadStyle.class); - emptyForIteratorPadStyle = cu.getStyle(EmptyForIteratorPadStyle.class); - return super.visitJavaSourceFile((JavaSourceFile)cu, executionContext); - } - - @Override - public J.ForLoop visitForLoop(J.ForLoop forLoop, ExecutionContext executionContext) { - J.ForLoop fl = super.visitForLoop(forLoop, executionContext); - List updates = forLoop.getControl().getUpdate(); - if(emptyForIteratorPadStyle != null && updates.size() == 1 && updates.get(0) instanceof J.Empty) { - Statement update = updates.get(0); - if(emptyForIteratorPadStyle.getSpace() && update.getPrefix().getWhitespace().isEmpty()) { - update = update.withPrefix(update.getPrefix().withWhitespace(" ")); - } else if(!emptyForIteratorPadStyle.getSpace() && !update.getPrefix().getWhitespace().isEmpty()) { - update = update.withPrefix(update.getPrefix().withWhitespace("")); - } - fl = fl.withControl(fl.getControl().withUpdate(singletonList(update))); - } - - List init = forLoop.getControl().getInit(); - if(emptyForInitializerPadStyle != null && init.get(0) instanceof J.Empty) { - if(emptyForInitializerPadStyle.getSpace() && init.get(0).getPrefix().getWhitespace().isEmpty()) { - init = ListUtils.mapFirst(init, i -> i.withPrefix(i.getPrefix().withWhitespace(" "))); - } else if(!emptyForInitializerPadStyle.getSpace() && !init.get(0).getPrefix().getWhitespace().isEmpty()) { - init = ListUtils.mapFirst(init, i -> i.withPrefix(i.getPrefix().withWhitespace(""))); - } - fl = fl.withControl(fl.getControl().withInit(init)); - } - return fl; - } - }; - } -} +/* + * 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.java.cleanup; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.SourceFile; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.style.EmptyForInitializerPadStyle; +import org.openrewrite.java.style.EmptyForIteratorPadStyle; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaSourceFile; +import org.openrewrite.java.tree.Statement; +import org.openrewrite.marker.SearchResult; + +import java.util.List; + +import static java.util.Collections.singletonList; +import static org.openrewrite.Tree.randomId; + +public class PadEmptyForLoopComponents extends Recipe { + + @Override + public String getDisplayName() { + return "Pad empty `for` loop components"; + } + + @Override + public String getDescription() { + return "Fixes padding on empty `for` loop iterators and initializers to match Checkstyle policies."; + } + + @Override + protected @Nullable JavaIsoVisitor getSingleSourceApplicableTest() { + return new JavaIsoVisitor() { + @Override + public JavaSourceFile visitJavaSourceFile(JavaSourceFile javaSourceFile, ExecutionContext executionContext) { + SourceFile cu = (SourceFile) javaSourceFile; + if(cu.getStyle(EmptyForIteratorPadStyle.class) != null || cu.getStyle(EmptyForInitializerPadStyle.class) != null) { + return cu.withMarkers(cu.getMarkers().add(new SearchResult(randomId(), null))); + } + return (JavaSourceFile) cu; + } + }; + } + + @Override + protected JavaIsoVisitor getVisitor() { + return new JavaIsoVisitor() { + + @Nullable + EmptyForIteratorPadStyle emptyForIteratorPadStyle; + + @Nullable + EmptyForInitializerPadStyle emptyForInitializerPadStyle; + + @Override + public JavaSourceFile visitJavaSourceFile(JavaSourceFile javaSourceFile, ExecutionContext executionContext) { + SourceFile cu = (SourceFile)javaSourceFile; + emptyForInitializerPadStyle = cu.getStyle(EmptyForInitializerPadStyle.class); + emptyForIteratorPadStyle = cu.getStyle(EmptyForIteratorPadStyle.class); + return super.visitJavaSourceFile((JavaSourceFile)cu, executionContext); + } + + @Override + public J.ForLoop visitForLoop(J.ForLoop forLoop, ExecutionContext executionContext) { + J.ForLoop fl = super.visitForLoop(forLoop, executionContext); + List updates = forLoop.getControl().getUpdate(); + if(emptyForIteratorPadStyle != null && updates.size() == 1 && updates.get(0) instanceof J.Empty) { + Statement update = updates.get(0); + if(emptyForIteratorPadStyle.getSpace() && update.getPrefix().getWhitespace().isEmpty()) { + update = update.withPrefix(update.getPrefix().withWhitespace(" ")); + } else if(!emptyForIteratorPadStyle.getSpace() && !update.getPrefix().getWhitespace().isEmpty()) { + update = update.withPrefix(update.getPrefix().withWhitespace("")); + } + fl = fl.withControl(fl.getControl().withUpdate(singletonList(update))); + } + + List init = forLoop.getControl().getInit(); + if(emptyForInitializerPadStyle != null && init.get(0) instanceof J.Empty) { + if(emptyForInitializerPadStyle.getSpace() && init.get(0).getPrefix().getWhitespace().isEmpty()) { + init = ListUtils.mapFirst(init, i -> i.withPrefix(i.getPrefix().withWhitespace(" "))); + } else if(!emptyForInitializerPadStyle.getSpace() && !init.get(0).getPrefix().getWhitespace().isEmpty()) { + init = ListUtils.mapFirst(init, i -> i.withPrefix(i.getPrefix().withWhitespace(""))); + } + fl = fl.withControl(fl.getControl().withInit(init)); + } + return fl; + } + }; + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/TypecastParenPad.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/TypecastParenPad.java index a7e10be9921..838c87ba9a5 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/TypecastParenPad.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/TypecastParenPad.java @@ -1,75 +1,75 @@ -/* - * 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.java.cleanup; - -import org.openrewrite.ExecutionContext; -import org.openrewrite.Recipe; -import org.openrewrite.SourceFile; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.java.JavaIsoVisitor; -import org.openrewrite.java.format.SpacesVisitor; -import org.openrewrite.java.style.*; -import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaSourceFile; - -public class TypecastParenPad extends Recipe { - @Override - public String getDisplayName() { - return "Typecast parenthesis padding"; - } - - @Override - public String getDescription() { - return "Fixes whitespace padding between a typecast type identifier and the enclosing left and right parenthesis. " + - "For example, when configured to remove spacing, `( int ) 0L;` becomes `(int) 0L;`."; - } - - @Override - protected JavaIsoVisitor getVisitor() { - return new TypecastParenPadVisitor(); - } - - private static class TypecastParenPadVisitor extends JavaIsoVisitor { - SpacesStyle spacesStyle; - TypecastParenPadStyle typecastParenPadStyle; - - @Nullable - EmptyForInitializerPadStyle emptyForInitializerPadStyle; - - @Nullable - EmptyForIteratorPadStyle emptyForIteratorPadStyle; - - @Override - public JavaSourceFile visitJavaSourceFile(JavaSourceFile javaSourceFile, ExecutionContext ctx) { - SourceFile cu = (SourceFile)javaSourceFile; - spacesStyle = cu.getStyle(SpacesStyle.class) == null ? IntelliJ.spaces() : cu.getStyle(SpacesStyle.class); - typecastParenPadStyle = cu.getStyle(TypecastParenPadStyle.class) == null ? Checkstyle.typecastParenPadStyle() : cu.getStyle(TypecastParenPadStyle.class); - emptyForInitializerPadStyle = cu.getStyle(EmptyForInitializerPadStyle.class); - emptyForIteratorPadStyle = cu.getStyle(EmptyForIteratorPadStyle.class); - - spacesStyle = spacesStyle.withWithin(spacesStyle.getWithin().withTypeCastParentheses(typecastParenPadStyle.getSpace())); - return super.visitJavaSourceFile((JavaSourceFile)cu, ctx); - } - - @Override - public J.TypeCast visitTypeCast(J.TypeCast typeCast, ExecutionContext ctx) { - J.TypeCast tc = super.visitTypeCast(typeCast, ctx); - doAfterVisit(new SpacesVisitor<>(spacesStyle, emptyForInitializerPadStyle, emptyForIteratorPadStyle, tc)); - return tc; - } - } - -} +/* + * 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.java.cleanup; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.SourceFile; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.format.SpacesVisitor; +import org.openrewrite.java.style.*; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaSourceFile; + +public class TypecastParenPad extends Recipe { + @Override + public String getDisplayName() { + return "Typecast parenthesis padding"; + } + + @Override + public String getDescription() { + return "Fixes whitespace padding between a typecast type identifier and the enclosing left and right parenthesis. " + + "For example, when configured to remove spacing, `( int ) 0L;` becomes `(int) 0L;`."; + } + + @Override + protected JavaIsoVisitor getVisitor() { + return new TypecastParenPadVisitor(); + } + + private static class TypecastParenPadVisitor extends JavaIsoVisitor { + SpacesStyle spacesStyle; + TypecastParenPadStyle typecastParenPadStyle; + + @Nullable + EmptyForInitializerPadStyle emptyForInitializerPadStyle; + + @Nullable + EmptyForIteratorPadStyle emptyForIteratorPadStyle; + + @Override + public JavaSourceFile visitJavaSourceFile(JavaSourceFile javaSourceFile, ExecutionContext ctx) { + SourceFile cu = (SourceFile)javaSourceFile; + spacesStyle = cu.getStyle(SpacesStyle.class) == null ? IntelliJ.spaces() : cu.getStyle(SpacesStyle.class); + typecastParenPadStyle = cu.getStyle(TypecastParenPadStyle.class) == null ? Checkstyle.typecastParenPadStyle() : cu.getStyle(TypecastParenPadStyle.class); + emptyForInitializerPadStyle = cu.getStyle(EmptyForInitializerPadStyle.class); + emptyForIteratorPadStyle = cu.getStyle(EmptyForIteratorPadStyle.class); + + spacesStyle = spacesStyle.withWithin(spacesStyle.getWithin().withTypeCastParentheses(typecastParenPadStyle.getSpace())); + return super.visitJavaSourceFile((JavaSourceFile)cu, ctx); + } + + @Override + public J.TypeCast visitTypeCast(J.TypeCast typeCast, ExecutionContext ctx) { + J.TypeCast tc = super.visitTypeCast(typeCast, ctx); + doAfterVisit(new SpacesVisitor<>(spacesStyle, emptyForInitializerPadStyle, emptyForIteratorPadStyle, tc)); + return tc; + } + } + +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/marker/package-info.java b/rewrite-java/src/main/java/org/openrewrite/java/marker/package-info.java index 42d82bfdd6d..5870908821d 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/marker/package-info.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/marker/package-info.java @@ -1,19 +1,19 @@ -/* - * 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. - */ -@NonNullApi -package org.openrewrite.java.marker; - -import org.openrewrite.internal.lang.NonNullApi; +/* + * 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. + */ +@NonNullApi +package org.openrewrite.java.marker; + +import org.openrewrite.internal.lang.NonNullApi; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/style/Checkstyle.java b/rewrite-java/src/main/java/org/openrewrite/java/style/Checkstyle.java index 2996416103b..50de2cd42e2 100755 --- a/rewrite-java/src/main/java/org/openrewrite/java/style/Checkstyle.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/style/Checkstyle.java @@ -1,149 +1,149 @@ -/* - * 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.java.style; - -import com.fasterxml.jackson.annotation.JsonCreator; -import org.openrewrite.style.NamedStyles; -import org.openrewrite.style.Style; - -import java.util.Arrays; -import java.util.Collection; - -import static java.util.Collections.emptySet; -import static org.openrewrite.Tree.randomId; - -public class Checkstyle extends NamedStyles { - private static final Checkstyle INSTANCE = new Checkstyle(); - private static final String NAME = "org.openrewrite.java.Checkstyle"; - private static final String DISPLAY_NAME = "Checkstyle"; - private static final String DESCRIPTION = "Checkstyle defaults for styles"; - - private Checkstyle() { - super(randomId(), - NAME, - DISPLAY_NAME, - DESCRIPTION, - emptySet(), - Arrays.asList( - defaultComesLast(), - emptyBlock(), - emptyForInitializerPadStyle(), - emptyForIteratorPadStyle(), - equalsAvoidsNull(), - explicitInitialization(), - fallThrough(), - hiddenFieldStyle(), - hideUtilityClassConstructorStyle(), - methodParamPadStyle(), - needBracesStyle(), - noWhitespaceAfterStyle(), - noWhitespaceBeforeStyle(), - operatorWrapStyle(), - typecastParenPadStyle(), - unnecessaryParentheses() - )); - } - - Checkstyle(Collection