commit b10f4f289d0b93741dabb916dbf01168c264ae74 Merge: afb12ac1 596459af Author: Brice Jaglin Date: Tue May 23 23:30:18 2023 +0200 Merge remote-tracking branch 'organize-imports/master' into organize-imports diff --combined CONTRIBUTING.md index 3b3f5d92,00000000..2561dc95 mode 100644,000000..100644 --- a/CONTRIBUTING.md --- /dev/null ++ b/CONTRIBUTING.md @@@ -1,175 -1,0 +1,176 @@@ # Contributing Contributions to Scalafix are welcome! This document is a guide to help you get familiar with the Scalafix build, if you are unsure about anything, don't hesitate to ask in the [Discord channel](https://discord.gg/8AHaqGx3Qj). ## Modules - `scalafix-interfaces` Java facade to run rules within an existing JVM instance. - `scalafix-core/` data structures for rewriting and linting Scala source code. - `scalafix-reflect/` utilities to compile and classload rules from configuration. - `scalafix-rules/` built-in rules such as `RemoveUnused`. - `scalafix-cli/` command-line interface. - `scalafix-tests/` projects for unit and integration tests. - `scalafix-docs/` documentation code for the Scalafix website. ## IntelliJ import The project should import normally into IntelliJ and there should not be any false red squiggles. To use the debugger or run tests from within IntelliJ, run at least once tests through sbt to generate a `BuildInfo` file and property files for Scalafix testkit. ## Testing Start the SBT shell with `$ sbt`. The commands below assume you have a running sbt shell. ```sh # Fast unit tests for rules, cli, core. > unit2_13/test # Integration tests for rules, cli, core. Contains a lot # of different test suites, so it's recommended to use testOnly # and/or testQuick. > integration2_13/test # Use testWindows to exclude tests that are not expected to succeed # on that OS. > unit2_13/testWindows > integration2_13/testWindows # Only run tests for built-in rules, using scalafix-testkit. > expect2_13Target2_13_10/test # Only run ProcedureSyntax unit tests. > expect2_13Target2_13_10/testOnly -- -z ProcedureSyntax ``` [sbt-projectmatrix](https://github.com/sbt/sbt-projectmatrix) is used to generate several sbt projects `expectTargetY` with the same source code, but for a combination of Scala versions: - used for compiling the framework and rules (`X`) - used for compiling and generating SemanticDB files for the test input (`Y`) Unit tests for rules are written using scalafix-testkit ``` scalafix-tests | ├── unit # Unit test suites | ├── integration # Integration test suites | +├── shared # Code that is shared between input and unit projects ├── input # Source files to be analyzed and fixed by rules ├── output # Expected output from running rewrite rules └── expect # Verify expectations defined in input/output using testkit ``` ## Formatting We use scalafix to apply some rules that are configured in .scalafix.conf. Make sure to run `sbt scalafixAll` to apply those rules. Be sure to run `scalafmt` (available in the `bin` folder) to ensure code formatting. `./bin/scalafmt --diff` formats only the files that have changed from the main branch. You can read more about it at http://scalafmt.org ## Documentation The scalafix documentation website uses [Docusaurus](https://docusaurus.io/) and [mdoc](https://github.com/olafurpg/mdoc). First, make sure you have the [yarn](https://yarnpkg.com/en/) package manager installed. Next, start sbt and compile the markdown documentation. The documentation will re-generate on file save. ```sh $ sbt > docs/run -w ``` To view the website in your browser, start the Docusaurus live reload server ```sh cd website yarn install yarn start ``` Consult the Docusaurus website for instructions on how to customize the sidebar or tweak the landing page. ## Binary Compatibility To avoid breaking binary compatibility we use [sbt-version-policy](https://github.com/scalacenter/sbt-version-policy). Anything under the package `scalafix.internal._` does not have compatibility restrictions. Run `sbt versionPolicyCheck` to check for any compatibility issues. ## Publish setup Scalafix uses [sbt-ci-release](https://github.com/olafurpg/sbt-ci-release) to automate Sonatype releases. A new SNAPSHOT release is published on every merge into main. A stable release is published to Maven Central on every git tag. ## Releasing First, kickstart a CI release to Sonatype by pushing a git tag that correspond to the desired commit ```sh git fetch && git log origin/main --pretty=oneline # choose the commit hash you want to tag COMMIT_HASH=14a069a3765739f5540129e8220104b17f233020 # change this variable VERSION=0.9.15 # change this variable git tag -af "v$VERSION" $COMMIT_HASH -m "v$VERSION" && git push -f origin v$VERSION ``` While the CI is running, update the release notes at https://github.com/scalacenter/scalafix/releases After the CI completes, confirm that the release has successfully finished ``` ./bin/test-release.sh $VERSION ``` You may need to update the test-release.sh script to include new cross-build artifacts (for example a new Scala version). Next, open a PR to sbt-scalafix that updates the version here https://github.com/scalacenter/sbt-scalafix/blob/7a4b51ae520c26ab2b09c9bedb6e3962f809ac53/project/Dependencies.scala#L5. Once the CI for this change is green, merge and push a new git tag to sbt-scalafix. Validate that the sbt-scalafix release completed successfully by running the test-release.sh script in the sbt-scalafix repository. When scalafix and sbt-scalafix have both completed the release, edit the release draft in the GitHub web UI to point to the tag that you pushed and then click on "Publish release". Confirm that the documentation is advertising the new versions - https://scalacenter.github.io/scalafix/docs/users/installation.html#sbt - https://scalacenter.github.io/scalafix/docs/users/installation.html#help If everything went smoothly, congrats! Tweet about the release and comment on Discord linking to the release notes. If something goes wrong for any reason making the artifacts not reach maven, delete the pushed tag with the following command ```sh TAG=??? # for example "v0.5.3" git tag -d $TAG git push origin :refs/tags/$TAG ``` It's important that the latest tag always has an accompanying release on Maven. If there is no release matching the latest tag then the docs will point to scalafix artifacts that cannot be resolved. diff --combined build.sbt index 35dc5ca4,881349c1..e2e27af5 --- a/build.sbt --- a/build.sbt ++ b/build.sbt @@@ -1,365 -1,153 +1,377 @@@ -lazy val v = _root_.scalafix.sbt.BuildInfo -lazy val rulesCrossVersions = Seq(v.scala213, v.scala212, v.scala211) -lazy val scala3Version = "3.2.1" import Dependencies._ import TargetAxis.TargetProjectMatrix import sbt.Keys.scalacOptions inThisBuild( List( - organization := "com.github.liancheng", - homepage := Some(url("https://github.com/liancheng/scalafix-organize-imports")), - licenses := List("MIT" -> url("https://opensource.org/licenses/MIT")), - developers := List( - Developer( - "liancheng", - "Cheng Lian", - "lian.cs.zju@gmail.com", - url("https://github.com/liancheng") - ) - ), - scalacOptions ++= List( - "-deprecation" - ), onLoadMessage := s"Welcome to scalafix ${version.value}", semanticdbEnabled := true, - // semanticdbTargetRoot makes it hard to have several input modules - semanticdbIncludeInJar := true, - semanticdbVersion := scalafixSemanticdb.revision, - scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.5.0", - // Super shell output often messes up Scalafix test output. - useSuperShell := false semanticdbVersion := scalametaV, scalafixScalaBinaryVersion := "2.13", scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.5.0" ) ) -lazy val `scalafix-organize-imports` = project - .in(file(".")) - .aggregate( - rules.projectRefs ++ - input.projectRefs ++ - output.projectRefs ++ - tests.projectRefs: _* Global / cancelable := true noPublishAndNoMima // force javac to fork by setting javaHome to get error messages during compilation, // see https://github.com/sbt/zinc/issues/520 def inferJavaHome() = { val home = file(sys.props("java.home")) val actualHome = if (System.getProperty("java.version").startsWith("1.8")) home.getParentFile else home Some(actualHome) } lazy val interfaces = projectMatrix .in(file("scalafix-interfaces")) .settings( Compile / resourceGenerators += Def.task { val props = new java.util.Properties() props.put("scalafixVersion", version.value) props.put("scalafixStableVersion", stableVersion.value) props.put("scalametaVersion", scalametaV) props.put("scala213", scala213) props.put("scala212", scala212) val out = (Compile / managedResourceDirectories).value.head / "scalafix-interfaces.properties" IO.write(props, "Scalafix version constants", out) List(out) }, (Compile / javacOptions) ++= List( "-Xlint:all", "-Werror" ), (Compile / doc / javacOptions) := List("-Xdoclint:none"), (Compile / javaHome) := inferJavaHome(), (Compile / doc / javaHome) := inferJavaHome(), libraryDependencies += coursierInterfaces, moduleName := "scalafix-interfaces", crossPaths := false, autoScalaLibrary := false ) .defaultAxes(VirtualAxis.jvm) .jvmPlatform(false) .disablePlugins(ScalafixPlugin) lazy val core = projectMatrix .in(file("scalafix-core")) .settings( - publish / skip := true moduleName := "scalafix-core", buildInfoSettingsForCore, libraryDependencies += googleDiff, libraryDependencies ++= { if (isScala3.value) { List( scalameta .exclude("com.lihaoyi", "sourcecode_2.13") .exclude("org.scala-lang.modules", "scala-collection-compat_2.13") ) } else { List( scalameta, collectionCompat ) } }, libraryDependencies += metaconfig ) .defaultAxes(VirtualAxis.jvm) .jvmPlatform(buildScalaVersions) .enablePlugins(BuildInfoPlugin) lazy val rules = projectMatrix .in(file("scalafix-rules")) .settings( - moduleName := "organize-imports", - conflictManager := ConflictManager.strict, - dependencyOverrides ++= List( - "org.scala-lang.modules" %% "scala-collection-compat" % "2.1.6", - "com.lihaoyi" %% "sourcecode" % "0.2.1" moduleName := "scalafix-rules", description := "Built-in Scalafix rules", buildInfoSettingsForRules, libraryDependencies ++= { if (!isScala3.value) List( "org.scala-lang" % "scala-compiler" % scalaVersion.value, "org.scala-lang" % "scala-reflect" % scalaVersion.value, semanticdbScalacCore, collectionCompat ) else Nil } ) .defaultAxes(VirtualAxis.jvm) .jvmPlatform(buildScalaVersions) .dependsOn(core) .enablePlugins(BuildInfoPlugin) lazy val reflect = projectMatrix .in(file("scalafix-reflect")) .settings( moduleName := "scalafix-reflect", isFullCrossVersion, libraryDependencies ++= { if (!isScala3.value) List( "org.scala-lang" % "scala-compiler" % scalaVersion.value, "org.scala-lang" % "scala-reflect" % scalaVersion.value ) else List( "org.scala-lang" %% "scala3-compiler" % scalaVersion.value, "org.scala-lang" %% "scala3-library" % scalaVersion.value ) } ) .defaultAxes(VirtualAxis.jvm) .jvmPlatform(buildScalaVersions) .dependsOn(core) lazy val cli = projectMatrix .in(file("scalafix-cli")) .settings( moduleName := "scalafix-cli", isFullCrossVersion, libraryDependencies ++= Seq( nailgunServer, jgit, commonText ), - libraryDependencies += "ch.epfl.scala" %% "scalafix-core" % v.scalafixVersion, - scalacOptions ++= List("-Ywarn-unused"), - scalafixOnCompile := true libraryDependencies ++= { if (!isScala3.value) Seq(java8Compat) else Seq() }, libraryDependencies ++= { if (isScala3.value) Seq() else Seq( // metaconfig 0.10.0 shaded pprint but rules built with an old // scalafix-core must have the original package in the classpath to link // https://github.com/scalameta/metaconfig/pull/154/files#r794005161 pprint % Runtime ) }, publishLocalTransitive := Def.taskDyn { val ref = thisProjectRef.value publishLocal.all(ScopeFilter(inDependencies(ref))) }.value ) .defaultAxes(VirtualAxis.jvm) .jvmPlatform(buildScalaVersions) .dependsOn(reflect, interfaces, rules) lazy val testkit = projectMatrix .in(file("scalafix-testkit")) .settings( moduleName := "scalafix-testkit", isFullCrossVersion, libraryDependencies += googleDiff, libraryDependencies += scalatestDep.value ) .defaultAxes(VirtualAxis.jvm) - .jvmPlatform(rulesCrossVersions) .jvmPlatform(buildScalaVersions) .dependsOn(cli) lazy val shared = projectMatrix + .in(file("scalafix-tests/shared")) .settings( - publish / skip := true, + noPublishAndNoMima, coverageEnabled := false ) .defaultAxes(VirtualAxis.jvm) - .jvmPlatform(scalaVersions = rulesCrossVersions :+ scala3Version) + .jvmPlatformFull(buildWithTargetVersions.map(_._2)) + .disablePlugins(ScalafixPlugin) lazy val input = projectMatrix - .dependsOn(shared) .in(file("scalafix-tests/input")) .settings( - publish / skip := true, noPublishAndNoMima, scalacOptions ~= (_.filterNot(_ == "-Yno-adapted-args")), scalacOptions ++= warnAdaptedArgs.value, // For NoAutoTupling scalacOptions ++= warnUnusedImports.value, // For RemoveUnused scalacOptions ++= warnUnused.value, // For RemoveUnusedTerms logLevel := Level.Error, // avoid flood of compiler warnings libraryDependencies ++= testsDependencies.value, coverageEnabled := false ) .defaultAxes(VirtualAxis.jvm) - .jvmPlatform(scalaVersions = rulesCrossVersions :+ scala3Version) .jvmPlatformFull(buildWithTargetVersions.map(_._2)) .disablePlugins(ScalafixPlugin) + .dependsOn(shared) lazy val output = projectMatrix - .dependsOn(shared) .in(file("scalafix-tests/output")) .settings( - publish / skip := true, noPublishAndNoMima, scalacOptions --= warnUnusedImports.value, libraryDependencies ++= testsDependencies.value, coverageEnabled := false ) .defaultAxes(VirtualAxis.jvm) - .jvmPlatform(scalaVersions = rulesCrossVersions :+ scala3Version) - -lazy val inputUnusedImports = projectMatrix .jvmPlatform(buildScalaVersions) .disablePlugins(ScalafixPlugin) .dependsOn(shared) lazy val unit = projectMatrix .in(file("scalafix-tests/unit")) .settings( - publish / skip := true, - coverageEnabled := false, - scalacOptions += { - if (scalaVersion.value.startsWith("2.11.")) - "-Ywarn-unused-import" - else - "-Ywarn-unused" noPublishAndNoMima, libraryDependencies ++= List( jgit, munit, scalatest.withRevision(scalatestLatestV) ), libraryDependencies += { if (!isScala3.value) { scalametaTeskit } else { // exclude _2.13 artifacts that have their _3 counterpart in the classpath scalametaTeskit .exclude("com.lihaoyi", "sourcecode_2.13") .exclude("org.scala-lang.modules", "scala-collection-compat_2.13") .exclude("org.scalameta", "munit_2.13") } }, buildInfoPackage := "scalafix.tests", buildInfoKeys := Seq[BuildInfoKey]( "scalaVersion" -> scalaVersion.value ) ) .defaultAxes(VirtualAxis.jvm) - .jvmPlatform(scalaVersions = rulesCrossVersions :+ scala3Version) .jvmPlatform(buildScalaVersions) .enablePlugins(BuildInfoPlugin) .dependsOn(testkit % Test) -lazy val testsAggregate = Project("tests", file("target/testsAggregate")) - .aggregate(tests.projectRefs: _*) - -lazy val tests = projectMatrix - .dependsOn(rules) - .enablePlugins(ScalafixTestkitPlugin) lazy val integration = projectMatrix .in(file("scalafix-tests/integration")) .settings( - publish / skip := true, - coverageEnabled := false, - libraryDependencies += - "ch.epfl.scala" % "scalafix-testkit" % v.scalafixVersion % Test cross CrossVersion.full, - scalafixTestkitOutputSourceDirectories := - TargetAxis.resolve(output, Compile / unmanagedSourceDirectories).value, - scalafixTestkitInputSourceDirectories := { - val inputSrc = - TargetAxis.resolve(input, Compile / unmanagedSourceDirectories).value - val inputUnusedImportsSrc = - TargetAxis.resolve(inputUnusedImports, Compile / unmanagedSourceDirectories).value - inputSrc ++ inputUnusedImportsSrc noPublishAndNoMima, Test / parallelExecution := false, libraryDependencies += { if (!isScala3.value) { coursier } else { // exclude _2.13 artifacts that have their _3 counterpart in the classpath coursier .exclude("org.scala-lang.modules", "scala-xml_2.13") .exclude("org.scala-lang.modules", "scala-collection-compat_2.13") } }, - scalafixTestkitInputClasspath := { - val inputClasspath = - TargetAxis.resolve(input, Compile / fullClasspath).value - val inputUnusedImportsClasspath = - TargetAxis.resolve(inputUnusedImports, Compile / fullClasspath).value - inputClasspath ++ inputUnusedImportsClasspath buildInfoPackage := "scalafix.tests", buildInfoObject := "BuildInfo", // create a local alias for input / Compile / fullClasspath at an // arbitrary, unused scope to be able to reference it (as a TaskKey) in // buildInfoKeys (since the macro only accepts TaskKeys) buildInfoKeys / fullClasspath := resolve(input, Compile / fullClasspath).value, buildInfoKeys := Seq[BuildInfoKey]( "scalametaVersion" -> scalametaV, "scalaVersion" -> scalaVersion.value, "baseDirectory" -> (ThisBuild / baseDirectory).value, "resourceDirectory" -> (Compile / resourceDirectory).value, "semanticClasspath" -> Seq((Compile / semanticdbTargetRoot).value), "sourceroot" -> (Compile / sourceDirectory).value, "classDirectory" -> (Compile / classDirectory).value, BuildInfoKey.map(buildInfoKeys / fullClasspath) { case (_, v) => "inputClasspath" -> v }, - scalafixTestkitInputScalacOptions := - TargetAxis.resolve(inputUnusedImports, Compile / scalacOptions).value, - scalafixTestkitInputScalaVersion := - TargetAxis.resolve(inputUnusedImports, Compile / scalaVersion).value "inputSemanticClasspath" -> Seq(resolve(input, Compile / semanticdbTargetRoot).value), "inputSourceroot" -> resolve(input, Compile / sourceDirectory).value, "outputSourceroot" -> resolve(output, Compile / sourceDirectory).value ), Test / test := (Test / test) .dependsOn(cli.projectRefs.map(_ / publishLocalTransitive): _*) .value, Test / testWindows := (Test / testWindows) .dependsOn(cli.projectRefs.map(_ / publishLocalTransitive): _*) .value ) - .defaultAxes( - rulesCrossVersions.map(VirtualAxis.scalaABIVersion) :+ VirtualAxis.jvm: _* .defaultAxes(VirtualAxis.jvm) .jvmPlatform(buildScalaVersions) .enablePlugins(BuildInfoPlugin) .dependsOn(unit % "compile->test") lazy val expect = projectMatrix .in(file("scalafix-tests/expect")) .settings( noPublishAndNoMima, Test / resourceGenerators += Def.task { // make sure the output can be compiled val _ = TargetAxis.resolve(output, Compile / compile).value // copy-pasted code from ScalafixTestkitPlugin to avoid cyclic dependencies between build and sbt-scalafix. val props = new java.util.Properties() def put(key: String, files: Seq[File]): Unit = { val value = files.iterator .filter(_.exists()) .mkString(java.io.File.pathSeparator) props.put(key, value) } put( "inputClasspath", TargetAxis .resolve(input, Compile / fullClasspath) .value .map(_.data) ) put( "inputSourceDirectories", TargetAxis .resolve(input, Compile / unmanagedSourceDirectories) .value ) - .customRow( - scalaVersions = Seq(v.scala212), - axisValues = Seq(TargetAxis(scala3Version), VirtualAxis.jvm), - settings = Seq() put( "outputSourceDirectories", TargetAxis .resolve(output, Compile / unmanagedSourceDirectories) .value ) - .customRow( - scalaVersions = Seq(v.scala213), - axisValues = Seq(TargetAxis(v.scala213), VirtualAxis.jvm), - settings = Seq() props.put( "scalaVersion", TargetAxis.resolve(input, Compile / scalaVersion).value ) - .customRow( - scalaVersions = Seq(v.scala212), - axisValues = Seq(TargetAxis(v.scala212), VirtualAxis.jvm), - settings = Seq() props.put( "scalacOptions", TargetAxis .resolve(input, Compile / scalacOptions) .value .mkString("|") ) val out = (Test / managedResourceDirectories).value.head / "scalafix-testkit.properties" IO.write(props, "Input data for scalafix testkit", out) List(out) } ) - .customRow( - scalaVersions = Seq(v.scala211), - axisValues = Seq(TargetAxis(v.scala211), VirtualAxis.jvm), - settings = Seq() .defaultAxes(VirtualAxis.jvm) .jvmPlatformWithTargets(buildWithTargetVersions) .dependsOn(integration) lazy val docs = projectMatrix .in(file("scalafix-docs")) .settings( noPublishAndNoMima, fork := true, run / baseDirectory := (ThisBuild / baseDirectory).value, moduleName := "scalafix-docs", scalacOptions += "-Wconf:msg='match may not be exhaustive':s", // silence exhaustive pattern matching warning for documentation scalacOptions += "-Xfatal-warnings", mdoc := (Compile / run).evaluated, libraryDependencies += metaconfigDoc ) .defaultAxes(VirtualAxis.jvm) .jvmPlatform(scalaVersions = Seq(scala213)) .dependsOn(testkit, core, cli) .enablePlugins(DocusaurusPlugin) .disablePlugins(ScalafixPlugin) diff --combined docs/rules/OrganizeImports.md index 00000000,908b190f..05844bf0 mode 000000,100644..100644 --- /dev/null --- a/README.adoc ++ b/docs/rules/OrganizeImports.md @@@ -1,0 -1,1393 +1,1330 @@@ -:latest-release: 0.6.0 - -ifdef::env-github[] -:caution-caption: :construction: -:important-caption: :exclamation: -:warning-caption: :warning: -:tip-caption: :bulb: -:note-caption: :notebook: -endif::[] - -= OrganizeImports -:icons: font -:sectnums: -:toc-placement!: -:toc-title: -:toc: -:toclevels: 2 - -image:https://github.com/liancheng/scalafix-organize-imports/workflows/Build/badge.svg[] -https://github.com/liancheng/scalafix-organize-imports/releases/latest[image:https://img.shields.io/github/v/tag/liancheng/scalafix-organize-imports[]] -https://github.com/liancheng/scalafix-organize-imports/blob/master/LICENSE[image:https://img.shields.io/github/license/liancheng/scalafix-organize-imports[]] -https://scala-steward.org[image:https://img.shields.io/badge/Scala_Steward-helping-blue.svg[]] -https://codecov.io/gh/liancheng/scalafix-organize-imports[image:https://img.shields.io/codecov/c/github/liancheng/scalafix-organize-imports[]] - -toc::[] - -`OrganizeImports` is a CI-friendly https://scalacenter.github.io/scalafix[Scalafix] semantic rule that helps you organize Scala import statements. - -https://scalameta.org/metals/[Metals], the Scala language server, also uses `OrganizeImports` to power its "organize imports" code action starting from version https://scalameta.org/metals/blog/2020/11/10/lithium.html#organize-imports-code-action[v0.9.5]. - -image:https://i.imgur.com/8YBdjjC.gif[] - -== Getting started - -=== sbt - -Please refer to https://scalacenter.github.io/scalafix/docs/users/installation.html[the Scalafix documentation] for how to install Scalafix and invoking it in your sbt build. - -To try this rule in the sbt console without adding this rule to your sbt build: - -[source,subs="attributes+"] ----- -sbt> scalafix dependency:OrganizeImports@com.github.liancheng:organize-imports:{latest-release} ----- - -To include this rule in your sbt build: - -[source,scala,subs="attributes+"] ----- -ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "{latest-release}" ----- - -=== Mill - -You can also include this rule in your http://www.lihaoyi.com/mill/[Mill] build using https://github.com/joan38/mill-scalafix[mill-scalafix]: - -[source,scala,subs="attributes+"] ----- -def scalafixIvyDeps = Agg(ivy"com.github.liancheng::organize-imports:{latest-release}") ----- - -=== For IntelliJ Scala plugin users - -`OrganizeImports` allows you to specify a preset style via the <>. To make it easier to add `OrganizeImports` into existing Scala projects built using the IntelliJ Scala plugin, `OrganizeImports` provides a preset style compatible with the default configuration of the IntelliJ Scala import optimizer. Please check the <> preset style for more details. - -=== Source formatting tools - -The `OrganizeImports` rule respects source-formatting tools like https://scalameta.org/scalafmt/[Scalafmt]. If an import statement is already organized according to the configuration, its original source level format is preserved. Therefore, in an sbt project, if you run the following command sequence: - -[source] ----- +--- +id: OrganizeImports +title: OrganizeImports +--- + +OrganizeImports was originally a [community rule](https://github.com/liancheng/scalafix-organize-imports), +created and maintained by [Cheng Lian](https://github.com/liancheng). +Considering its [popularity, maturity and the lack of bandwidth from the +author](https://github.com/liancheng/scalafix-organize-imports/discussions/215), +it is now a built-in rule, since Scalafix 0.11.0. + +Getting started +--------------- + +### For IntelliJ Scala plugin users + +`OrganizeImports` allows you to specify a preset style via the [`preset` +option](#preset). To make it easier to add `OrganizeImports` into +existing Scala projects built using the IntelliJ Scala plugin, +`OrganizeImports` provides a preset style compatible with the default +configuration of the IntelliJ Scala import optimizer. Please check the +[`INTELLIJ_2020_3`](#intellij-2020-3) preset style for more details. + +### Source formatting tools + +The `OrganizeImports` rule respects source-formatting tools like +[Scalafmt](https://scalameta.org/scalafmt/). If an import statement is +already organized according to the configuration, its original source +level format is preserved. Therefore, in an sbt project, if you run the +following command sequence: + +``` sbt> scalafixAll ... sbt> scalafmtAll ... sbt> scalafixAll --check ... ----- +``` -Assuming that the first two commands run successfully, the last `scalafixAll --check` command should not fail even if some import statements are reformatted by the `scalafmtAll` command. +Assuming that the first two commands run successfully, the last +`scalafixAll --check` command should not fail even if some import +statements are reformatted by the `scalafmtAll` command. -However, you should make sure that the source-formatting tools you use do not rewrite import statements in ways that conflict with `OrganizeImports`. For example, when using Scalafmt together with `OrganizeImports`, the `ExpandImportSelectors`, `SortImports`, and `AsciiSortImports` rewriting rules should not be used. +However, you should make sure that the source-formatting tools you use +do not rewrite import statements in ways that conflict with +`OrganizeImports`. For example, when using Scalafmt together with +`OrganizeImports`, the `ExpandImportSelectors`, `SortImports`, and +`AsciiSortImports` rewriting rules should not be used. -=== Scala 3 - -Available since v0.6.0. - -Running the rule on source files compiled with Scala 3 is still experimental. +### Scala 3 Known limitations: -. You must use Scalafix 0.9.28 or later -. The <> option must be explicitly set to `false` - the rule currently doesn't remove unused imports as it's currently not supported by the compiler. -. Usage of http://dotty.epfl.ch/docs/reference/dropped-features/package-objects.html[deprecated package objects] may result in incorrect imports -. The <> option has no effect - -== Configuration - -=== Default Configuration values - -[source,hocon,subs=+macros] ----- -OrganizeImports { - <> = Auto - <> = null - <> = false - <> = false - <> = Explode - <> = [ - "*" - "re:(javax?|scala)\\." - ] - <> = Ascii - <> = Ascii - <> = DEFAULT - <> = true -} ----- - -[[remove-unused-warning]] -[WARNING] -==== -Please do NOT use the Scalafix built-in https://scalacenter.github.io/scalafix/docs/rules/RemoveUnused.html[`RemoveUnused.imports`] together with `OrganizeImports` to remove unused imports. You may end up with broken code! It is still safe to use `RemoveUnused` to remove unused private members or local definitions, though. - -Scalafix rewrites source files by applying patches generated by invoked rules. Each rule generates a patch based on the _original_ text of the source files. When two patches generated by different rules conflict with each other, Scalafix is not able to reconcile the conflicts, and may produce broken code. It is very likely to happen when `RemoveUnused` and `OrganizeImports` are used together, since both rules rewrite import statements. - -By default, `OrganizeImports` already removes unused imports for you (see the <> option). It locates unused imports via compilation diagnostics, which is exactly how `RemoveUnused` does it. This mechanism works well in most cases, unless there are new unused imports generated while organizing imports, which is possible when the <> option is set to true. For now, the only reliable workaround for this edge case is to run Scalafix with `OrganizeImports` twice. -==== - -[[blankLines]] -=== `blankLines` - -Available since v0.5.0-alpha.1. - -Configures whether blank lines between adjacent import groups are automatically or manually inserted. This option is used together with the <>. - -==== Value type +1. The [`removeUnused`](OrganizeImports.md#removeunused) option must be + explicitly set to `false` - the rule currently doesn’t remove unused + imports as it is currently not supported by the compiler. + +2. Usage of [deprecated package + objects](http://dotty.epfl.ch/docs/reference/dropped-features/package-objects.html) + may result in incorrect imports. + +3. The + [`groupExplicitlyImportedImplicitsSeparately`](OrganizeImports.md#groupexplicitlyimportedimplicitsseparately) + option has no effect. + +Configuration +------------- + +> Please do NOT use the [`RemoveUnused.imports`](RemoveUnused.md) together with +> `OrganizeImports` to remove unused imports. You may end up with broken code! +> It is still safe to use `RemoveUnused` to remove unused private members or +> local definitions, though. +> +> Scalafix rewrites source files by applying patches generated by invoked +> rules. Each rule generates a patch based on the *original* text of the +> source files. When two patches generated by different rules conflict +> with each other, Scalafix is not able to reconcile the conflicts, and +> may produce broken code. It is very likely to happen when `RemoveUnused` +> and `OrganizeImports` are used together, since both rules rewrite import +> statements. +> +> By default, `OrganizeImports` already removes unused imports for you +> (see the [`removeUnused`](OrganizeImports.md#removeunused) option). It locates unused +> imports via compilation diagnostics, which is exactly how `RemoveUnused` +> does it. This mechanism works well in most cases, unless there are new +> unused imports generated while organizing imports, which is possible +> when the [`expandRelative`](OrganizeImports.md#expandrelative) option is set to true. For +> now, the only reliable workaround for this edge case is to run Scalafix +> with `OrganizeImports` twice. + +```scala mdoc:passthrough +import scalafix.internal.rule._ +import scalafix.website._ +``` + +```scala mdoc:passthrough +println( + defaults( + "OrganizeImports", + flat(OrganizeImportsConfig.default) + ) +) +``` + +`blankLines` +------------ + +Configures whether blank lines between adjacent import groups are +automatically or manually inserted. This option is used together with +the [`---` blank line markers](OrganizeImports.md#a-blank-line-marker). + +### Value type Enum: `Auto | Manual` -Auto:: A blank line is automatically inserted between adjacent import groups. All blank line markers (`---`) configured in the <> are ignored. +#### `Auto` +A blank line is automatically inserted between adjacent import groups. +All blank line markers (`---`) configured in the [`groups` +option](#groups) are ignored. -Manual:: A blank line is inserted at all the positions where blank line markers appear in the <>. +#### `Manual` +A blank line is inserted at all the positions where blank line markers +appear in the [`groups` option](#groups). The following two configurations are equivalent: -[source,hocon] ----- +```conf OrganizeImports { blankLines = Auto groups = [ "re:javax?\\." "scala." "*" ] } +``` +```conf OrganizeImports { blankLines = Manual groups = [ "re:javax?\\." "---" "scala." "---" "*" ] } ----- +``` -==== Default value +### Default value `Auto` -==== Examples +### Examples -`Auto`:: -+ --- -Configuration: +#### `Auto` -[source,hocon] ----- +```conf OrganizeImports { blankLines = Auto groups = [ "re:javax?\\." "scala." "*" ] } ----- +``` Before: -[source,scala] ----- +```scala import scala.collection.JavaConverters._ import java.time.Clock import sun.misc.BASE64Encoder import javax.annotation.Generated import scala.concurrent.ExecutionContext ----- +``` After: -[source,scala] ----- +```scala import java.time.Clock import javax.annotation.Generated import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext import sun.misc.BASE64Encoder ----- --- +``` -`Manual`:: -+ --- -Configuration: +#### `Manual` -[source,hocon] ----- +```conf OrganizeImports { blankLines = Manual groups = [ "re:javax?\\." "scala." "---" "*" ] } ----- +``` Before: -[source,scala] ----- +```scala import scala.collection.JavaConverters._ import java.time.Clock import sun.misc.BASE64Encoder import javax.annotation.Generated import scala.concurrent.ExecutionContext ----- +``` After: -[source,scala] ----- +```scala import java.time.Clock import javax.annotation.Generated import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext import sun.misc.BASE64Encoder ----- --- - -[[coalesceToWildcardImportThreshold]] -=== `coalesceToWildcardImportThreshold` - -When the number of imported names exceeds a certain threshold, coalesce them into a wildcard import. Renames and unimports are left untouched. - -[CAUTION] -==== -Having this feature in `OrganizeImports` is mostly for feature parity with the IntelliJ IDEA Scala import optimizer, but coalescing grouped import selectors into a wildcard import may introduce _compilation errors_! - -Here is an example to illustrate the risk. The following snippet compiles successfully: - -[source,scala] ----- -import scala.collection.immutable._ -import scala.collection.mutable.{ArrayBuffer, Map, Set} - -object Example { - val m: Map[Int, Int] = ??? -} ----- -The type of `Example.m` above is not ambiguous because the mutable `Map` explicitly imported in the second import takes higher precedence than the immutable `Map` imported via wildcard in the first import. - -However, if we coalesce the grouped imports in the second import statement into a wildcard, there will be a compilation error: -[source,scala] ----- -import scala.collection.immutable._ -import scala.collection.mutable._ - -object Example { - val m: Map[Int, Int] = ??? -} ----- -This is because the type of `Example.m` becomes ambiguous now since both the mutable and immutable `Map` are imported via a wildcard and have the same precedence. -==== - -==== Value type +``` + +`coalesceToWildcardImportThreshold` +----------------------------------- + +When the number of imported names exceeds a certain threshold, coalesce +them into a wildcard import. Renames and unimports are left untouched. + +> Having this feature in `OrganizeImports` is mostly for feature parity +> with the IntelliJ IDEA Scala import optimizer, but coalescing grouped +> import selectors into a wildcard import may introduce *compilation +> errors*! +> +> Here is an example to illustrate the risk. The following snippet +> compiles successfully: +> +> ```scala +> import scala.collection.immutable._ +> import scala.collection.mutable.{ArrayBuffer, Map, Set} +> +> object Example { +> val m: Map[Int, Int] = ??? +> } +> ``` +> +> The type of `Example.m` above is not ambiguous because the mutable `Map` +> explicitly imported in the second import takes higher precedence than +> the immutable `Map` imported via wildcard in the first import. +> +> However, if we coalesce the grouped imports in the second import +> statement into a wildcard, there will be a compilation error: +> +> ```scala +> import scala.collection.immutable._ +> import scala.collection.mutable._ +> +> object Example { +> val m: Map[Int, Int] = ??? +> } +> ``` +> +> This is because the type of `Example.m` becomes ambiguous now since both +> the mutable and immutable `Map` are imported via a wildcard and have the +> same precedence. + +### Value type Integer. Not setting it or setting it to `null` disables this feature. -==== Default value +### Default value `null` -==== Examples +### Examples -Configuration: - -[source,scala] ----- +```conf OrganizeImports { groupedImports = Keep coalesceToWildcardImportThreshold = 3 } ----- +``` Before: -[source,scala] ----- +```scala import scala.collection.immutable.{Seq, Map, Vector, Set} import scala.collection.immutable.{Seq, Map, Vector} import scala.collection.immutable.{Seq, Map, Vector => Vec, Set, Stream} import scala.collection.immutable.{Seq, Map, Vector => _, Set, Stream} ----- +``` After: -[source,scala] ----- +```scala import scala.collection.immutable._ import scala.collection.immutable.{Map, Seq, Vector} import scala.collection.immutable.{Vector => Vec, _} import scala.collection.immutable.{Vector => _, _} ----- +``` -[[expandRelative]] -=== `expandRelative` +`expandRelative` +---------------- Expand relative imports into fully-qualified one. -[CAUTION] -==== -Expanding relative imports may introduce new unused imports. For instance, relative imports in the following snippet +> Expanding relative imports may introduce new unused imports. For +> instance, relative imports in the following snippet +> +> ```scala +> import scala.util +> import util.control +> import control.NonFatal +> ``` +> +> are expanded into +> +> ```scala +> import scala.util +> import scala.util.control +> import scala.util.control.NonFatal +> ``` +> +> If neither `scala.util` nor `scala.util.control` is referenced anywhere +> after the expansion, they become unused imports. +> +> Unfortunately, these newly introduced unused imports cannot be removed +> by setting `removeUnused` to `true`. Please refer to the +> [`removeUnused`](OrganizeImports.md#removeunused) option for more details. -[source,scala] ----- -import scala.util -import util.control -import control.NonFatal ----- - -are expanded into - -[source,scala] ----- -import scala.util -import scala.util.control -import scala.util.control.NonFatal ----- - -If neither `scala.util` nor `scala.util.control` is referenced anywhere after the expansion, they become unused imports. - -Unfortunately, these newly introduced unused imports cannot be removed by setting `removeUnused` to `true`. Please refer to the <> option for more details. -==== - -==== Value type +### Value type Boolean -==== Default value +### Default value `false` -==== Examples +### Examples -Configuration: - -[source,hocon] ----- +```conf OrganizeImports { expandRelative = true groups = ["re:javax?\\.", "scala.", "*"] } ----- +``` Before: -[source,scala] ----- +```scala import scala.util import util.control import control.NonFatal import scala.collection.JavaConverters._ import java.time.Clock import sun.misc.BASE64Encoder import javax.annotation.Generated import scala.concurrent.ExecutionContext ----- +``` After: -[source,scala] ----- +```scala import java.time.Clock import javax.annotation.Generated import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext import scala.util import scala.util.control import scala.util.control.NonFatal import sun.misc.BASE64Encoder ----- +``` -[[groupExplicitlyImportedImplicitsSeparately]] -=== `groupExplicitlyImportedImplicitsSeparately` +`groupExplicitlyImportedImplicitsSeparately` +-------------------------------------------- -This option provides a workaround to a subtle and rarely seen correctness issue related to explicitly imported implicit names. +This option provides a workaround to a subtle and rarely seen +correctness issue related to explicitly imported implicit names. The following snippet helps illustrate the problem: -[source,scala] ----- +```scala package a import c._ import b.i object b { implicit def i: Int = 1 } object c { implicit def i: Int = 2 } object Imports { def f()(implicit i: Int) = println(1) def main() = f() } ----- +``` -The above snippet compiles successfully and outputs `1`, because the explicitly imported implicit value `b.i` overrides `c.i`, which is made available via a wildcard import. However, if we reorder the two imports into: +The above snippet compiles successfully and outputs `1`, because the +explicitly imported implicit value `b.i` overrides `c.i`, which is made +available via a wildcard import. However, if we reorder the two imports +into: -[source,scala] ----- +```scala import b.i import c._ ----- +``` The Scala compiler starts complaining: ----- +``` error: could not find implicit value for parameter i: Int def main() = f() ^ ----- +``` -This behavior could be due to a Scala compiler bug since https://scala-lang.org/files/archive/spec/2.13/02-identifiers-names-and-scopes.html[the Scala language specification] requires that explicitly imported names should have higher precedence than names made available via a wildcard. +This behavior could be due to a Scala compiler bug since [the Scala +language +specification](https://scala-lang.org/files/archive/spec/2.13/02-identifiers-names-and-scopes.html) +requires that explicitly imported names should have higher precedence +than names made available via a wildcard. -Unfortunately, Scalafix is not able to surgically identify conflicting implicit values behind a wildcard import. In order to guarantee correctness in all cases, when the `groupExplicitlyImportedImplicitsSeparately` option is set to `true`, all explicitly imported implicit names are moved into the trailing order-preserving import group together with relative imports, if any (see the <> section for more details). +Unfortunately, Scalafix is not able to surgically identify conflicting +implicit values behind a wildcard import. In order to guarantee +correctness in all cases, when the +`groupExplicitlyImportedImplicitsSeparately` option is set to `true`, +all explicitly imported implicit names are moved into the trailing +order-preserving import group together with relative imports, if any +(see the [trailing order-preserving import +group](OrganizeImports.md#groups) section for more +details). -CAUTION: In general, order-sensitive imports are fragile, and can easily be broken by either human collaborators or tools (e.g., the IntelliJ IDEA Scala import optimizer does not handle this case correctly). They should be eliminated whenever possible. This option is mostly useful when you are dealing with a large trunk of legacy codebase, and you want to minimize manual intervention and guarantee correctness in all cases. +> In general, order-sensitive imports are fragile, and can easily be +> broken by either human collaborators or tools (e.g., the IntelliJ IDEA +> Scala import optimizer does not handle this case correctly). They should +> be eliminated whenever possible. This option is mostly useful when you +> are dealing with a large trunk of legacy codebase, and you want to +> minimize manual intervention and guarantee correctness in all cases. +> The `groupExplicitlyImportedImplicitsSeparately` option has currently no +> effect on source files compiled with Scala 3, as the [compiler does not +> expose full signature +> information](https://github.com/lampepfl/dotty/issues/12766), preventing +> the rule to identify imported implicits. -[IMPORTANT] -==== -The `groupExplicitlyImportedImplicitsSeparately` option has currently no effect on source files compiled with Scala 3, as the https://github.com/lampepfl/dotty/issues/12766[compiler does not expose full signature information], preventing the rule to identify imported implicits. -==== - - -==== Value type +### Value type Boolean -==== Default value +### Default value `false` -Rationale:: -+ --- -This option defaults to `false` due to the following reasons: +Rationale: -. Although setting it to `true` avoids the aforementioned correctness issue, the result is unintuitive and confusing for many users since it looks like the `groups` option is not respected. -+ -E.g., why my `scala.concurrent.ExecutionContext.Implicits.global` import is moved to a separate group even if I have a `scala.` group defined in the `groups` option? +1. Although setting it to `true` avoids the aforementioned correctness + issue, the result is unintuitive and confusing for many users since + it looks like the `groups` option is not respected. -. The concerned correctness issue is rarely seen in real life. When it really happens, it is usually a sign of bad coding style, and you may want to tweak your imports to eliminate the root cause. --- + E.g., why my `scala.concurrent.ExecutionContext.Implicits.global` + import is moved to a separate group even if I have a `scala.` group + defined in the `groups` option? -==== Examples +2. The concerned correctness issue is rarely seen in real life. When it + really happens, it is usually a sign of bad coding style, and you + may want to tweak your imports to eliminate the root cause. -Configuration: +### Examples -[source,hocon] ----- +```conf OrganizeImports { groups = ["scala.", "*"] groupExplicitlyImportedImplicitsSeparately = true // not supported in Scala 3 } ----- +``` Before: -[source,scala] ----- +```scala import org.apache.spark.SparkContext import org.apache.spark.RDD import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.Buffer import scala.concurrent.ExecutionContext.Implicits.global import scala.sys.process.stringToProcess ----- +``` After: - -[source,scala] ----- +```scala import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.Buffer import org.apache.spark.RDD import org.apache.spark.SparkContext import scala.concurrent.ExecutionContext.Implicits.global import scala.sys.process.stringToProcess ----- +``` -[[groupedImports]] -=== `groupedImports` +`groupedImports` +---------------- Configure how to handle grouped imports. -==== Value type +### Value type Enum: `Explode | Merge | AggressiveMerge | Keep` -`Explode`:: Explode grouped imports into separate import statements. - -`Merge`:: -+ --- -Merge imports sharing the same prefix into a single grouped import statement. - -[TIP] -==== -You may want to check the <> option for more concise results despite a relatively low risk of introducing compilation errors. -==== - -[IMPORTANT] -==== -`OrganizeImports` does not support cases where one name is renamed to multiple aliases within the same source file when `groupedImports` is set to `Merge`. (The IntelliJ IDEA Scala import optimizer does not support this either.) - -Scala allows a name to be renamed to multiple aliases within a single source file, which makes merging import statements tricky. For example: - -[source,scala] ----- -import java.lang.{Double => JDouble} -import java.lang.{Double => JavaDouble} -import java.lang.Integer ----- - -The above three imports can be merged into: - -[source,scala] ----- -import java.lang.{Double => JDouble} -import java.lang.{Double => JavaDouble, Integer} ----- - -but not: - -[source,scala] ----- -import java.lang.{Double => JDouble, Double => JavaDouble, Integer} ----- - -because Scala disallow a name (in this case, `Double`) to appear in one import multiple times. - -Here's a more complicated example: - -[source,scala] ----- -import p.{A => A1} -import p.{A => A2} -import p.{A => A3} - -import p.{B => B1} -import p.{B => B2} - -import p.{C => C1} -import p.{C => C2} -import p.{C => C3} -import p.{C => C4} ----- - -While merging these imports, we may want to "bin-pack" them to minimize the number of the result import statements: - -[source,scala] ----- -import p.{A => A1, B => B1, C => C1} -import p.{A => A2, B => B2, C => C2} -import p.{A => A3, C3 => C3} -import p.{C => C4} ----- - -However, in reality, renaming aliasing a name multiple times in the same source file is rarely a practical need. Therefore, `OrganizeImports` does not support this when `groupedImports` is set to `Merge` to avoid the extra complexity. -==== --- - -[[aggressive-merge]] -`AggressiveMerge`:: -+ --- -Similar to `Merge`, but merges imports more aggressively and produces more concise results, despite a relatively low risk of introducing compilation errors. - -The `OrganizeImports` rule tries hard to guarantee correctness in all cases. This forces it to be more conservative when merging imports, and may sometimes produce suboptimal output. Here is a concrete example about correctness: - -[source,scala] ----- +#### `Explode` +Explode grouped imports into separate import statements. + +#### `Merge` +Merge imports sharing the same prefix into a single grouped import +statement. + +> You may want to check the [`AggressiveMerge`](OrganizeImports.md#aggressivemerge) +> option for more concise results despite a relatively low risk of introducing +> compilation errors. + +> `OrganizeImports` does not support cases where one name is renamed to +> multiple aliases within the same source file when `groupedImports` is +> set to `Merge`. (The IntelliJ IDEA Scala import optimizer does not +> support this either.) +> +> Scala allows a name to be renamed to multiple aliases within a single +> source file, which makes merging import statements tricky. For example: +> +> ```scala +> import java.lang.{Double => JDouble} +> import java.lang.{Double => JavaDouble} +> import java.lang.Integer +> ``` +> +> The above three imports can be merged into: +> +> ```scala +> import java.lang.{Double => JDouble} +> import java.lang.{Double => JavaDouble, Integer} +> ``` +> +> but not: +> +> ```scala +> import java.lang.{Double => JDouble, Double => JavaDouble, Integer} +> ``` +> +> because Scala disallow a name (in this case, `Double`) to appear in one +> import multiple times. +> +> Here’s a more complicated example: +> +> ```scala +> import p.{A => A1} +> import p.{A => A2} +> import p.{A => A3} +> +> import p.{B => B1} +> import p.{B => B2} +> +> import p.{C => C1} +> import p.{C => C2} +> import p.{C => C3} +> import p.{C => C4} +> ``` +> +> While merging these imports, we may want to "bin-pack" them to minimize +> the number of the result import statements: +> +> ```scala +> import p.{A => A1, B => B1, C => C1} +> import p.{A => A2, B => B2, C => C2} +> import p.{A => A3, C3 => C3} +> import p.{C => C4} +> ``` +> +> However, in reality, renaming aliasing a name multiple times in the same +> source file is rarely a practical need. Therefore, `OrganizeImports` +> does not support this when `groupedImports` is set to `Merge` to avoid +> the extra complexity. + +#### `AggressiveMerge` +Similar to `Merge`, but merges imports more aggressively and produces +more concise results, despite a relatively low risk of introducing +compilation errors. + +The `OrganizeImports` rule tries hard to guarantee correctness in all +cases. This forces it to be more conservative when merging imports, and +may sometimes produce suboptimal output. Here is a concrete example +about correctness: + +```scala import scala.collection.immutable._ import scala.collection.mutable.Map import scala.collection.mutable._ object Example { val m: Map[Int, Int] = ??? } ----- +``` -At a first glance, it seems feasible to simply drop the second import since `mutable._` already covers `mutble.Map`. However, similar to the example illustrated in the section about the <>, the type of `Example.m` above is `mutable.Map`, because the mutable `Map` explicitly imported in the second import takes higher precedence than the immutable `Map` imported via wildcard in the first import. If we merge the last two imports naively, we'll get: +At a first glance, it seems feasible to simply drop the second import +since `mutable._` already covers `mutble.Map`. However, similar to the +example illustrated in the section about the +[`coalesceToWildcardImportThreshold` +option](OrganizeImports.md#coalescetowildcardimportthreshold), the type of `Example.m` +above is `mutable.Map`, because the mutable `Map` explicitly imported in +the second import takes higher precedence than the immutable `Map` +imported via wildcard in the first import. If we merge the last two +imports naively, we’ll get: -[source,scala] ----- +```scala import scala.collection.immutable._ import scala.collection.mutable._ ----- +``` -This triggers in a compilation error, because both `immutable.Map` and `mutable.Map` are now imported via wildcards with the same precedence. This makes the type of `Example.m` ambiguous. The correct result should be: +This triggers in a compilation error, because both `immutable.Map` and +`mutable.Map` are now imported via wildcards with the same precedence. +This makes the type of `Example.m` ambiguous. The correct result should +be: -[source,scala] ----- +```scala import scala.collection.immutable._ import scala.collection.mutable.{Map, _} ----- +``` -On the other hand, the case discussed above is rarely seen in practice. A more commonly seen case is something like: +On the other hand, the case discussed above is rarely seen in practice. +A more commonly seen case is something like: -[source,scala] ----- +```scala import scala.collection.mutable.Map import scala.collection.mutable._ ----- +``` Instead of being conservative and produce a suboptimal output like: -[source,scala] ----- +```scala import scala.collection.mutable.{Map, _} ----- +``` setting `groupedImports` to `AggressiveMerge` produces - -[source,scala] ----- +```scala import scala.collection.mutable._ ----- --- +``` -`Keep`:: Leave grouped imports and imports sharing the same prefix untouched. +#### `Keep` +Leave grouped imports and imports sharing the same prefix untouched. -==== Default value +### Default value `Explode` -Rationale:: Despite making the import section lengthier, exploding grouped imports into separate import statements is made the default behavior because it is more friendly to version control and less likely to create annoying merge conflicts caused by trivial import changes. +Rationale: despite making the import section lengthier, exploding grouped +imports into separate import statements is made the default behavior because +it is more friendly to version control and less likely to create annoying +merge conflicts caused by trivial import changes. -==== Examples +### Examples -`Explode`:: -+ --- -Configuration: +#### `Explode` -[source,hocon] ----- +```conf OrganizeImports.groupedImports = Explode ----- +``` Before: -[source,scala] ----- +```scala import scala.collection.mutable.{ArrayBuffer, Buffer, StringBuilder} ----- +``` After: -[source,scala] ----- +```scala import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.Buffer import scala.collection.mutable.StringBuilder ----- --- +``` -`Merge`:: -+ --- -Configuration: +#### `Merge` -[source,hocon] ----- +```conf OrganizeImports.groupedImports = Merge ----- +``` Before: -[source,scala] ----- +```scala import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.Buffer import scala.collection.mutable.StringBuilder import scala.collection.immutable.Set import scala.collection.immutable._ ----- +``` After: -[source,scala] ----- +```scala import scala.collection.mutable.{ArrayBuffer, Buffer, StringBuilder} import scala.collection.immutable.{Set, _} ----- --- +``` -`AggressiveMerge`:: -+ --- -Configuration: +#### `AggressiveMerge` -[source,hocon] ----- +```conf OrganizeImports.groupedImports = AggressiveMerge ----- +``` Before: -[source,scala] ----- +```scala import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.Buffer import scala.collection.mutable.StringBuilder import scala.collection.immutable.Set import scala.collection.immutable._ ----- +``` After: -[source,scala] ----- +```scala import scala.collection.mutable.{ArrayBuffer, Buffer, StringBuilder} import scala.collection.immutable._ ----- --- - -[[groups]] -=== `groups` - -Defines import groups by prefix patterns. Only global imports are processed. - -All the imports matching the same prefix pattern are gathered into the same group and sorted by the order defined by the <> option. - -CAUTION: Comments living _between_ imports being processed will be _removed_. - -[TIP] -==== -`OrganizeImports` tries to match the longest prefix while grouping imports. For instance, the following configuration groups `scala.meta.` and `scala.` imports into different two groups properly: - -[source,hocon] ----- -OrganizeImports.groups = [ - "re:javax?\\." - "scala." - "scala.meta." - "*" -] ----- -==== - -[[trailing-order-preserving-import-group]] -[IMPORTANT] -==== -No matter how the `groups` option is configured, a special order-preserving import group may appear after all the configured import groups when: - -. The `expandRelative` option is set to `false` and there are relative imports. -. The `groupExplicitlyImportedImplicitsSeparately` option is set to `true` and there are implicit names explicitly imported. - -This special import group is necessary because the above two kinds of imports are order sensitive: - -Relative imports:: -+ --- -For instance, sorting the following imports in alphabetical order introduces compilation errors: - -[source,scala] ----- -import scala.util -import util.control -import control.NonFatal ----- --- - -Explicitly imported implicit names:: Please refer to the <> option for more details. -==== - -==== Value type - -An ordered list of import prefix pattern strings. A prefix pattern can be one of the following: - -A plain-text pattern:: For instance, `"scala."` is a plain-text pattern that matches imports referring the `scala` package. Please note that the trailing dot is necessary, otherwise you may have `scalafix` and `scala` imports in the same group, which is not what you want in most cases. - -A regular expression pattern:: A regular expression pattern starts with `re:`. For instance, `"re:javax?\\."` is such a pattern that matches both the `java` and the `javax` packages. Please refer to the https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html[`java.util.regex.Pattern`] Javadoc page for the regular expression syntax. Note that special characters like backslashes must be escaped. - -The wildcard pattern:: -+ --- -The wildcard pattern, `"*"`, defines the wildcard group, which matches all fully-qualified imports not belonging to any other groups. It can be omitted when it's the last group. So the following two configurations are equivalent: - -[source,hocon] ----- +``` + +`groups` +-------- + +Defines import groups by prefix patterns. Only global imports are +processed. + +All the imports matching the same prefix pattern are gathered into the +same group and sorted by the order defined by the +[`importsOrder`](OrganizeImports.md#importsorder) option. + +> Comments living *between* imports being processed will be *removed*. + +> `OrganizeImports` tries to match the longest prefix while grouping +> imports. For instance, the following configuration groups `scala.meta.` +> and `scala.` imports into different two groups properly: +> +> ```conf +> OrganizeImports.groups = [ +> "re:javax?\\." +> "scala." +> "scala.meta." +> "*" +> ] +> ``` + +> No matter how the `groups` option is configured, a special +> order-preserving import group may appear after all the configured import +> groups when: +> +> 1. The `expandRelative` option is set to `false` and there are relative +> imports. +> +> 2. The `groupExplicitlyImportedImplicitsSeparately` option is set to +> `true` and there are implicit names explicitly imported. +> +> This special import group is necessary because the above two kinds of +> imports are order sensitive: +> +> #### Relative imports +> For instance, sorting the following imports in alphabetical order +> introduces compilation errors: +> +> ```scala +> import scala.util +> import util.control +> import control.NonFatal +> ``` +> #### Explicitly imported implicit names +> Please refer to the +> [`groupExplicitlyImportedImplicitsSeparately`](OrganizeImports.md#groupexplicitlyimportedimplicitsseparately) +> option for more details. + +### Value type + +An ordered list of import prefix pattern strings. A prefix pattern can +be one of the following: + +#### A plain-text pattern +For instance, `"scala."` is a plain-text pattern that matches imports +referring the `scala` package. Please note that the trailing dot is +necessary, otherwise you may have `scalafix` and `scala` imports in the +same group, which is not what you want in most cases. + +#### A regular expression pattern +A regular expression pattern starts with `re:`. For instance, +`"re:javax?\\."` is such a pattern that matches both the `java` and the +`javax` packages. Please refer to the +[`java.util.regex.Pattern`](https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html) +Javadoc page for the regular expression syntax. Note that special +characters like backslashes must be escaped. + +#### The wildcard pattern +The wildcard pattern, `"*"`, defines the wildcard group, which matches +all fully-qualified imports not belonging to any other groups. It can be +omitted when it’s the last group. So the following two configurations +are equivalent: + +```conf OrganizeImports.groups = ["re:javax?\\.", "scala.", "*"] OrganizeImports.groups = ["re:javax?\\.", "scala."] ----- --- +``` -[[blank-line-marker]] -A blank line marker:: -+ --- -Available since v0.5.0-alpha.1. +#### A blank line marker +A blank line marker, `"---"`, defines a blank line between two adjacent +import groups when [`blankLines`](OrganizeImports.md#blanklines) is +set to `Manual`. It is ignored when `blankLines` is `Auto`. Leading and +trailing blank line markers are always ignored. Multiple consecutive blank +line markers are treated as a single one. So the following three configurations +are all equivalent: -A blank line marker, `"---"`, defines a blank line between two adjacent import groups when <> is set to `Manual`. It is ignored when `blankLines` is `Auto`. Leading and trailing blank line markers are always ignored. Multiple consecutive blank line markers are treated as a single one. So the following three configurations are all equivalent: - -[source,hocon] ----- +```conf OrganizeImports { blankLines = Manual groups = [ "---" "re:javax?\\." "---" "scala." "---" "---" "*" "---" ] } OrganizeImports { blankLines = Manual groups = [ "re:javax?\\." "---" "scala." "---" "*" ] } OrganizeImports { blankLines = Auto groups = [ "re:javax?\\." "scala." "*" ] } ----- --- +``` -==== Default value +### Default value -[source,hocon] ----- +```conf [ "*" "re:(javax?|scala)\\." ] ----- +``` -Rationale:: This aligns with the default configuration of the IntelliJ Scala plugin version 2020.3. +Rationale: this aligns with the default configuration of the IntelliJ Scala plugin +version 2020.3. -==== Examples +### Examples -Fully-qualified imports only:: -+ --- -Configuration: +#### Fully-qualified imports only -[source,hocon] ----- +```conf OrganizeImports.groups = ["re:javax?\\.", "scala.", "*"] ----- +``` Before: -[source,scala] ----- +```scala import scala.collection.JavaConverters._ import java.time.Clock import sun.misc.BASE64Encoder import javax.annotation.Generated import scala.concurrent.ExecutionContext ----- +``` After: -[source,scala] ----- +```scala import java.time.Clock import javax.annotation.Generated import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext import sun.misc.BASE64Encoder ----- --- +``` -With relative imports:: -+ --- -Configuration: +#### With relative imports -[source,hocon] ----- +```conf OrganizeImports.groups = ["re:javax?\\.", "scala.", "*"] ----- +``` Before: -[source,scala] ----- -import scala.util +```scala +import scala.utilRationale import util.control import control.NonFatal import scala.collection.JavaConverters._ import java.time.Clock import sun.misc.BASE64Encoder import javax.annotation.Generated import scala.concurrent.ExecutionContext ----- +``` After: - -[source,scala] ----- +```scala import java.time.Clock import javax.annotation.Generated import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext import scala.util import sun.misc.BASE64Encoder import util.control import control.NonFatal ----- --- +``` -With relative imports and an explicitly imported implicit name:: -+ --- -Configuration: +#### With relative imports and an explicitly imported implicit name -[source,hocon] ----- +```conf OrganizeImports { groups = ["re:javax?\\.", "scala.", "*"] groupExplicitlyImportedImplicitsSeparately = true } ----- +``` Before: - -[source,scala] ----- +```scala import scala.util import util.control import control.NonFatal import scala.collection.JavaConverters._ import java.time.Clock import sun.misc.BASE64Encoder import javax.annotation.Generated import scala.concurrent.ExecutionContext.Implicits.global ----- +``` After: -[source,scala] ----- +```scala import java.time.Clock import javax.annotation.Generated import scala.collection.JavaConverters._ import scala.util import sun.misc.BASE64Encoder import util.control import control.NonFatal import scala.concurrent.ExecutionContext.Implicits.global ----- --- +``` -Regular expression:: -+ --- -Defining import groups using regular expressions can be quite flexible. For instance, the `scala.meta` package is not part of the Scala standard library, but the default groups defined in the `OrganizeImports.groups` option move imports from this package into the `scala.` group. The following example illustrates how to move them into the wildcard group using regular expression. +#### Regular expression +Defining import groups using regular expressions can be quite flexible. +For instance, the `scala.meta` package is not part of the Scala standard +library, but the default groups defined in the `OrganizeImports.groups` +option move imports from this package into the `scala.` group. The +following example illustrates how to move them into the wildcard group +using regular expression. -Configuration: -[source,hocon] ----- +```conf OrganizeImports.groups = [ "re:javax?\\." "re:scala.(?!meta\\.)" "*" ] ----- +``` Before: -[source,scala] ----- + +```scala import scala.collection.JavaConverters._ import java.time.Clock import sun.misc.BASE64Encoder import scala.meta.Tree import javax.annotation.Generated import scala.concurrent.ExecutionContext import scala.meta.Import import scala.meta.Pkg ----- +``` After: -[source,scala] ----- + +```scala import java.time.Clock import javax.annotation.Generated import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext import scala.meta.Import import scala.meta.Pkg import scala.meta.Tree import sun.misc.BASE64Encoder ----- --- +``` -With manually configured blank lines:: -+ --- -Configuration: +#### With manually configured blank lines -[source,hocon] ----- +```conf OrganizeImports { blankLines = Manual groups = [ "*" "---" "re:javax?\\." "scala." ] } ----- +``` Before: -[source,scala] ----- +```scala import scala.collection.JavaConverters._ import java.time.Clock import sun.misc.BASE64Encoder import javax.annotation.Generated import scala.concurrent.ExecutionContext ----- +``` After: -[source,scala] ----- +```scala import sun.misc.BASE64Encoder import java.time.Clock import javax.annotation.Generated import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext ----- --- +``` -[[importSelectorsOrder]] -=== `importSelectorsOrder` +`importSelectorsOrder` +---------------------- -Specifies the order of grouped import selectors within a single import expression. +Specifies the order of grouped import selectors within a single import +expression. -==== Value type +### Value type Enum: `Ascii | SymbolsFirst | Keep` -`Ascii`:: Sort import selectors by ASCII codes, equivalent to the https://scalameta.org/scalafmt/docs/configuration.html#asciisortimports[`AsciiSortImports`] rewriting rule in Scalafmt. +#### `Ascii` +Sort import selectors by ASCII codes, equivalent to the +[`AsciiSortImports`](https://scalameta.org/scalafmt/docs/configuration.html#asciisortimports) +rewriting rule in Scalafmt. -`SymbolsFirst`:: Sort import selectors by the groups: symbols, lower-case, upper-case, equivalent to the https://scalameta.org/scalafmt/docs/configuration.html#sortimports[`SortImports`] rewriting rule in Scalafmt. +#### `SymbolsFirst` +Sort import selectors by the groups: symbols, lower-case, upper-case, +equivalent to the +[`SortImports`](https://scalameta.org/scalafmt/docs/configuration.html#sortimports) +rewriting rule in Scalafmt. -`Keep`:: Keep the original order. +#### `Keep` +Keep the original order. -==== Default value +### Default value `Ascii` -==== Examples +### Examples -`Ascii`:: -+ --- -Configuration: +#### `Ascii` -[source,hocon] ----- +```conf OrganizeImports { groupedImports = Keep importSelectorsOrder = Ascii } ----- +``` Before: -[source,scala] ----- +```scala import foo.{~>, `symbol`, bar, Random} ----- +``` After: -[source,scala] ----- +```scala import foo.{Random, `symbol`, bar, ~>} ----- --- +``` -`SymbolsFirst`:: -+ --- -Configuration: +#### `SymbolsFirst` -[source,hocon] ----- +```conf OrganizeImports { groupedImports = Keep importSelectorsOrder = SymbolsFirst } ----- +``` Before: -[source,scala] ----- +```scala import foo.{Random, `symbol`, bar, ~>} ----- +``` After: - -[source,scala] ----- +```scala import foo.{~>, `symbol`, bar, Random} ----- --- +``` -[[importsOrder]] -=== `importsOrder` +`importsOrder` +-------------- -Specifies the order of import statements within import groups defined by the <> option. +Specifies the order of import statements within import groups defined by +the [`OrganizeImports.groups`](#groups) option. -==== Value type +### Value type Enum: `Ascii | SymbolsFirst | Keep` -`Ascii`:: Sort import statements by ASCII codes. This is the default sorting order that the IntelliJ IDEA Scala import optimizer picks ("lexicographically" option). +#### `Ascii` +Sort import statements by ASCII codes. This is the default sorting order +that the IntelliJ IDEA Scala import optimizer picks ("lexicographically" +option). -`SymbolsFirst`:: Put wildcard imports and grouped imports with braces first, otherwise same as `Ascii`. This replicates IntelliJ IDEA Scala's "scalastyle consistent" option. +#### `SymbolsFirst` +Put wildcard imports and grouped imports with braces first, otherwise +same as `Ascii`. This replicates IntelliJ IDEA Scala’s "scalastyle +consistent" option. -`Keep`:: Keep the original order. +#### `Keep` +Keep the original order. -==== Default value +### Default value `Ascii` -==== Examples +### Examples -`Ascii`:: -+ --- -Configuration: +#### `Ascii` -[source,hocon] ----- +```conf OrganizeImports { groupedImports = Keep importsOrder = Ascii } ----- +``` Before: -[source,scala] ----- +```scala import scala.concurrent._ import scala.concurrent.{Future, Promise} import scala.concurrent.ExecutionContext.Implicits._ import scala.concurrent.duration ----- +``` After: -[source,scala] ----- +```scala import scala.concurrent.ExecutionContext.Implicits._ import scala.concurrent._ import scala.concurrent.duration import scala.concurrent.{Promise, Future} ----- --- +``` -`SymbolsFirst`:: -+ --- -Configuration: +#### `SymbolsFirst` -[source,hocon] ----- +```conf OrganizeImports { groupedImports = Keep importsOrder = SymbolsFirst } ----- +``` Before: -[source,scala] ----- +```scala import scala.concurrent.ExecutionContext.Implicits._ import scala.concurrent._ import scala.concurrent.duration import scala.concurrent.{Promise, Future} ----- +``` After: -[source,scala] ----- +```scala import scala.concurrent._ import scala.concurrent.{Future, Promise} import scala.concurrent.ExecutionContext.Implicits._ import scala.concurrent.duration ----- --- +``` -[[preset]] -=== `preset` - -Available since v0.5.0. +`preset` +-------- Specify a preset style. -==== Value type +### Value type Enum: `DEFAULT | INTELLIJ_2020_3` -`DEFAULT`:: -+ --- -An opinionated style recommended for new projects. The `OrganizeImports` rule tries its best to ensure correctness in all cases when possible. This default style aligns with this principal. In addition, by setting `groupedImports` to `Explode`, this style is also more friendly to version control and less likely to create annoying merge conflicts caused by trivial import changes. +#### `DEFAULT` +An opinionated style recommended for new projects. The `OrganizeImports` +rule tries its best to ensure correctness in all cases when possible. +This default style aligns with this principal. In addition, by setting +`groupedImports` to `Explode`, this style is also more friendly to +version control and less likely to create annoying merge conflicts +caused by trivial import changes. -[source,hocon] ----- +```conf OrganizeImports { blankLines = Auto coalesceToWildcardImportThreshold = null expandRelative = false groupExplicitlyImportedImplicitsSeparately = false groupedImports = Explode groups = [ "*" "re:(javax?|scala)\\." ] importSelectorsOrder = Ascii importsOrder = Ascii preset = DEFAULT removeUnused = true } ----- --- +``` -[[intellij-2020-3]] -`INTELLIJ_2020_3`:: -+ --- -A style that is compatible with the default configuration of the IntelliJ Scala 2020.3 import optimizer. It is mostly useful for adding `OrganizeImports` to existing projects developed using the IntelliJ Scala plugin. However, the configuration of this style may introduce subtle correctness issues (so does the default configuration of the IntelliJ Scala plugin). Please see the <> for more details. +#### `INTELLIJ_2020_3` +A style that is compatible with the default configuration of the +IntelliJ Scala 2020.3 import optimizer. It is mostly useful for adding +`OrganizeImports` to existing projects developed using the IntelliJ +Scala plugin. However, the configuration of this style may introduce +subtle correctness issues (so does the default configuration of the +IntelliJ Scala plugin). Please see the +[`coalesceToWildcardImportThreshold` +option](OrganizeImports.md#coalescetowildcardimportthreshold) +for more details. -[source,hocon] ----- +```conf OrganizeImports { blankLines = Auto coalesceToWildcardImportThreshold = 5 expandRelative = false groupExplicitlyImportedImplicitsSeparately = false groupedImports = Merge groups = [ "*" "re:(javax?|scala)\\." ] importSelectorsOrder = Ascii importsOrder = Ascii preset = INTELLIJ_2020_3 removeUnused = true } ----- --- +``` -==== Default value +### Default value `DEFAULT` -[[removeUnused]] -=== `removeUnused` +`removeUnused` +-------------- Remove unused imports. -[CAUTION] -==== -As mentioned in <>, the `removeUnused` option doesn't play perfectly with the `expandRelative` option. Setting `expandRelative` to `true` might introduce new unused imports (see <>). These newly introduced unused imports cannot be removed by setting `removeUnused` to `true`. This is because unused imports are identified using Scala compilation diagnostics information, and the compilation phase happens before Scalafix rules get applied. -==== +> The `removeUnused` option doesn’t play perfectly with the `expandRelative` +> option. Setting `expandRelative` to `true` might introduce new unused +> imports (see [`expandRelative`](OrganizeImports.md#expandrelative)). +> These newly introduced unused imports cannot be removed by setting +> `removeUnused` to `true`. This is because unused imports are identified +> using Scala compilation diagnostics information, and the compilation phase +> happens before Scalafix rules get applied. -[IMPORTANT] -==== -The `removeUnused` option is currently not supported for source files compiled with Scala 3, as the https://docs.scala-lang.org/scala3/guides/migration/options-lookup.html#warning-settings[compiler cannot issue warnings for unused imports yet]. As a result, you must set `removeUnused` to `false` when running the rule on source files compiled with Scala 3. -==== +> The `removeUnused` option is currently not supported for source files +> compiled with Scala 3, as the [compiler cannot issue warnings for unused +> imports +> yet](https://docs.scala-lang.org/scala3/guides/migration/options-lookup.html#warning-settings). +> As a result, you must set `removeUnused` to `false` when running the +> rule on source files compiled with Scala 3. -==== Value type +### Value type Boolean -==== Default value +### Default value `true` -==== Examples +### Examples -Configuration: - -[source,hocon] ----- +```conf OrganizeImports { groups = ["javax?\\.", "scala.", "*"] removeUnused = true // not supported in Scala 3 } ----- +``` Before: -[source,scala] ----- +```scala import scala.collection.mutable.{Buffer, ArrayBuffer} import java.time.Clock import java.lang.{Long => JLong, Double => JDouble} object RemoveUnused { val buffer: ArrayBuffer[Int] = ArrayBuffer.empty[Int] val long: JLong = JLong.parseLong("0") } ----- +``` After: -[source,scala] ----- +```scala import java.lang.{Long => JLong} import scala.collection.mutable.ArrayBuffer object RemoveUnused { val buffer: ArrayBuffer[Int] = ArrayBuffer.empty[Int] val long: JLong = JLong.parseLong("0") } ----- +``` diff --combined docs/rules/community-rules.md index 3a0c7868,00000000..ee2a247c mode 100644,000000..100644 --- a/docs/rules/community-rules.md --- /dev/null ++ b/docs/rules/community-rules.md @@@ -1,58 -1,0 +1,57 @@@ --- id: community-rules sidebar_label: Community rules title: Community rules --- Many rules have been developed and published by the community. Follow [this documentation](external-rules.md) to use them in your project. > Help us increase visibility & foster collaboration by > [submitting your favorite rule(s) via pull requests](https://github.com/scalacenter/scalafix/edit/main/docs/rules/community-rules.md)! ## Hygiene rules Hygiene rules enforce conventions, failing the build on violation or rewriting the code when possible. | Repository | Artifact | Description | | - | - | - | [ghostbuster91/scalafix-unified](https://github.com/ghostbuster91/scalafix-unified) | `io.github.ghostbuster91.scalafix-unified::unified` | Set of opinionated rules to unify your codebase [jatcwang/scalafix-named-params](https://github.com/jatcwang/scalafix-named-params) | `com.github.jatcwang::scalafix-named-params` | Add named parameters for your constructor and method calls - [liancheng/scalafix-organize-imports](https://github.com/liancheng/scalafix-organize-imports) | `com.github.liancheng::organize-imports` | Help you organize Scala import statements [vovapolu/scaluzzi](https://github.com/vovapolu/scaluzzi) | `com.github.vovapolu::scaluzzi` | Ensure a subset of [scalazzi](http://yowconference.com.au/slides/yowwest2014/Morris-ParametricityTypesDocumentationCodeReadability.pdf) [xuwei-k/scalafix-rules](https://github.com/xuwei-k/scalafix-rules) | `com.github.xuwei-k::scalafix-rules` | Avoid ambiguous or redundant Scala syntax & features [pixiv/scalafix-pixiv-rule](https://github.com/pixiv/scalafix-pixiv-rule) | `net.pixiv::scalafix-pixiv-rule` | Redundant Scala code rewriting and anti-pattern warnings ## Migration rules Migration rules make it easier for library users to cope with deprecations and breaking changes. Official migrations provided by library authors are not advertized here as they are usually well documented in the project itself. Note that [Scala Steward](https://github.com/scala-steward-org/scala-steward) [keeps track of many of them](https://github.com/scala-steward-org/scala-steward/blob/main/modules/core/src/main/resources/scalafix-migrations.conf), to provide a seamless experience to library users opting-in for the service. | Repository | Artifact | Description | | - | - | - | [ohze/scala-rewrites](https://github.com/ohze/scala-rewrites) | `com.sandinh::scala-rewrites` | Rewrites for Scala [OlegYch/enumeratum-scalafix](https://github.com/OlegYch/enumeratum-scalafix) | `io.github.olegych::enumeratum-scalafix` | Replace `scala.Enumeration` with enumeratum [scala/scala-collection-compat](https://github.com/scala/scala-collection-compat) | `org.scala-lang.modules::scala-collection-migrations` | Rewrite upgrades to the 2.13 collections [scala/scala-rewrites](https://github.com/scala/scala-rewrites) | `org.scala-lang::scala-rewrites` | Rewrites for Scala [xuwei-k/play-ws-scalafix](https://github.com/xuwei-k/play-ws-scalafix) | `com.github.xuwei-k::play-ws-scalafix` | Migrate to play-ws-standalone [tersesystems/echopraxia-scalafix](https://github.com/tersesystems/echopraxia-scalafix) | `com.tersesystems.echopraxia::scalafix` | Rewrite [Echopraxia](https://github.com/tersesystems/echopraxia) logging statements ## Code generation rules Code generation rules extend the possibilities of the Scala language by taking a route similar, yet parallel to macros. | Repository | Artifact | Description | | - | - | - | [earldouglas/linear-scala](https://github.com/earldouglas/linear-scala) | `com.earldouglas::linear-scala-scalafix` | Add support for linear types in Scala [rtimush/zio-magic-comments](https://github.com/rtimush/zio-magic-comments) | `com.timushev::zio-magic-comments` | Add explanatory graphs as comments to zio-magic methods [sake92/kalem](https://github.com/sake92/kalem) | `ba.sake::kalem-rules` | Generate `with*` methods for classes [typelevel/simulacrum-scalafix](https://github.com/typelevel/simulacrum-scalafix) | `org.typelevel::simulacrum-scalafix-annotations` | Simulacrum as Scalafix rules diff --combined scalafix-docs/src/main/scala/docs/website.scala index 841de916,00000000..8878d507 mode 100644,000000..100644 --- a/scalafix-docs/src/main/scala/docs/website.scala --- /dev/null ++ b/scalafix-docs/src/main/scala/docs/website.scala @@@ -1,193 -1,0 +1,193 @@@ package scalafix import java.nio.file.Files import scala.meta.internal.io.PathIO import mdoc.Reporter import metaconfig.generic.Setting import metaconfig.generic.Settings import scalafix.internal.v1.Rules import scalafix.v0._ import scalatags.Text import scalatags.Text.all._ package object website { import scalafix.internal.rule.SimpleDefinitions def url(name: String, relpath: String): Text.TypedTag[String] = a(href := s"/scalafix/$relpath", name) def ruleLink(name: String): Text.TypedTag[String] = { url(name, s"docs/rules/$name.html") } def allRulesTable(reporter: Reporter): String = { val rules = Rules .all() .filterNot(_.name.isDeprecated) .filterNot(_.isExperimental) .sortBy(_.name.value) val (semantic, syntactic) = rules.partition(_.isInstanceOf[v1.SemanticRule]) def buildTable(rules: List[v1.Rule]): Text.TypedTag[String] = { val rows: List[Text.TypedTag[String]] = rules.map { rule => val docPath = PathIO.workingDirectory .resolve("docs") .resolve("rules") .resolve(rule.name.value + ".md") if (!rule.isExperimental && !Files.isRegularFile(docPath.toNIO)) { reporter.warning(s"Missing $docPath") } tr( td(ruleLink(rule.name.value)), td(rule.description) ) } val header = thead( tr( th("Name"), th("Description") ) ) table( header, tbody(rows) ) } div( h2("Semantic Rules"), buildTable(semantic), h2("Syntactic Rules"), buildTable(syntactic) ).toString } // TODO(olafur) replace this hack with ConfEncoder[T] typeclass. def render(any: Any): String = any match { case s: Symbol => val syntax = s.syntax.stripPrefix("_root_.").stripSuffix("#").stripSuffix(".") new StringBuilder() .append("\"") .append(syntax) .append("\"") .toString() case _ => any.toString } - private def flat[T]( + def flat[T]( default: T )(implicit settings: Settings[T], ev: T <:< Product): List[(Setting, Any)] = { settings.settings .zip(default.productIterator.iterator.to(Iterable)) .filterNot { case (setting, _) => setting.isHidden } .flatMap { case (s, d: SimpleDefinitions) => (s, d.kinds.mkString("['", "', '", "']")) :: Nil case (deepSetting, defaultSetting: Product) if deepSetting.underlying.nonEmpty => deepSetting.flat.zip( defaultSetting.productIterator.iterator.to(Iterable) ) case (s, lst: Iterable[_]) => val rendered = lst.map(render) val string = if (lst.size < 2) rendered.mkString("[", ", ", "]") else rendered.mkString("[\n ", ",\n ", "\n]") (s, string) :: Nil case (s, defaultValue) => (s, defaultValue) :: Nil } } def htmlSetting(setting: Setting): Text.TypedTag[String] = { val tpe = setting.field.tpe .replace("scalafix.v0.Symbol.Global", "Symbol") .replace("java.util.regex.", "") .replace("scalafix.CustomMessage", "Message") .replace("scalafix.internal.config.", "") tr( td(code(setting.name)), td(code(tpe)), td(setting.description) ) } def html(all: List[Setting]): String = { val fields = all.map { setting => htmlSetting(setting) } table( thead( tr( th("Name"), th("Type"), th("Description") ) ), tbody(fields) ).toString() } def config[T](name: String)(implicit settings: Settings[T]): String = s"\n\n### $name\n\n" + html(settings.settings) def defaults[T](ruleName: String, all: List[(Setting, Any)]): String = { val sb = new StringBuilder sb.append("\n\n### Defaults\n\n```") all.foreach { case (setting, default) => sb.append("\n") .append(ruleName) .append(".") .append(setting.name) .append(" = ") .append(default) } sb.append("\n```\n\n") sb.toString() } def examples[T](ruleName: String)(implicit settings: Settings[T]): String = { if (settings.settings.forall(_.exampleValues.isEmpty)) "" else { val sb = new StringBuilder sb.append("\n\n### Examples\n\n```") settings.settings.foreach { setting => setting.exampleValues match { case Nil => case example :: _ => sb.append("\n") .append(ruleName) .append(".") .append(setting.name) .append(" = ") .append(example) } } sb.append("\n```\n\n") sb.toString() } } def rule[T]( ruleName: String, default: T )(implicit settings: Settings[T], ev: T <:< Product ): String = { val sb = new StringBuilder val all = flat(default) sb.append(html(all.map(_._1))) sb.append(defaults(ruleName, all)) sb.append(examples[T](ruleName)) sb.toString() } } diff --combined scalafix-rules/src/main/resources-2/META-INF/services/scalafix.v1.Rule index c3d34973,00000000..f2526029 mode 100644,000000..100644 --- a/scalafix-rules/src/main/resources-2/META-INF/services/scalafix.v1.Rule --- /dev/null ++ b/scalafix-rules/src/main/resources-2/META-INF/services/scalafix.v1.Rule @@@ -1,8 -1,0 +1,9 @@@ scalafix.internal.rule.DisableSyntax scalafix.internal.rule.ExplicitResultTypes scalafix.internal.rule.NoAutoTupling scalafix.internal.rule.NoValInForComprehension +scalafix.internal.rule.OrganizeImports scalafix.internal.rule.ProcedureSyntax scalafix.internal.rule.RedundantSyntax scalafix.internal.rule.RemoveUnused scalafix.internal.rule.LeakingImplicitClassVal diff --combined scalafix-rules/src/main/resources-3/META-INF/services/scalafix.v1.Rule index 2578d8ae,00000000..6c02c66e mode 100644,000000..100644 --- a/scalafix-rules/src/main/resources-3/META-INF/services/scalafix.v1.Rule --- /dev/null ++ b/scalafix-rules/src/main/resources-3/META-INF/services/scalafix.v1.Rule @@@ -1,6 -1,0 +1,7 @@@ scalafix.internal.rule.DisableSyntax scalafix.internal.rule.NoAutoTupling scalafix.internal.rule.NoValInForComprehension +scalafix.internal.rule.OrganizeImports scalafix.internal.rule.RedundantSyntax scalafix.internal.rule.RemoveUnused scalafix.internal.rule.LeakingImplicitClassVal diff --combined scalafix-rules/src/main/scala/scalafix/internal/rule/ImportMatcher.scala index 00000000,5d3689eb..b1341e85 mode 000000,100644..100644 --- /dev/null --- a/rules/src/main/scala/fix/ImportMatcher.scala ++ b/scalafix-rules/src/main/scala/scalafix/internal/rule/ImportMatcher.scala @@@ -1,0 -1,40 +1,42 @@@ -package fix +package scalafix.internal.rule import scala.util.matching.Regex import scala.meta.Importer +import scala.meta.XtensionSyntax sealed trait ImportMatcher { def matches(i: Importer): Int } object ImportMatcher { def parse(pattern: String): ImportMatcher = pattern match { case p if p startsWith "re:" => RE(new Regex(p stripPrefix "re:")) case "---" => --- case "*" => * case p => PlainText(p) } case class RE(pattern: Regex) extends ImportMatcher { override def matches(i: Importer): Int = pattern findPrefixMatchOf i.syntax map (_.end) getOrElse 0 } case class PlainText(pattern: String) extends ImportMatcher { - override def matches(i: Importer): Int = if (i.syntax startsWith pattern) pattern.length else 0 + override def matches(i: Importer): Int = + if (i.syntax startsWith pattern) pattern.length else 0 } case object * extends ImportMatcher { // The wildcard matcher matches nothing. It is special-cased at the end of the import group // matching process. def matches(importer: Importer): Int = 0 } case object --- extends ImportMatcher { // Blank line matchers are pseudo matchers matching nothing. They are special-cased at the end // of the import group matching process. override def matches(i: Importer): Int = 0 } } diff --combined scalafix-rules/src/main/scala/scalafix/internal/rule/OrganizeImports.scala index 00000000,e88c54f7..9abbb301 mode 000000,100644..100644 --- /dev/null --- a/rules/src/main/scala/fix/OrganizeImports.scala ++ b/scalafix-rules/src/main/scala/scalafix/internal/rule/OrganizeImports.scala @@@ -1,0 -1,914 +1,1006 @@@ -package fix +package scalafix.internal.rule import scala.annotation.tailrec import scala.collection.mutable import scala.collection.mutable.ArrayBuffer import scala.util.Try -import fix.ImportMatcher.* -import fix.ImportMatcher.--- -import fix.ImportMatcher.parse -import metaconfig.Conf -import metaconfig.ConfDecoder -import metaconfig.ConfEncoder -import metaconfig.ConfOps -import metaconfig.Configured -import metaconfig.internal.ConfGet import scala.meta.Import import scala.meta.Importee import scala.meta.Importee.GivenAll import scala.meta.Importee.Wildcard import scala.meta.Importer import scala.meta.Name import scala.meta.Pkg import scala.meta.Source import scala.meta.Stat import scala.meta.Term import scala.meta.Tree +import scala.meta.XtensionClassifiable +import scala.meta.XtensionCollectionLikeUI +import scala.meta.XtensionSyntax import scala.meta.inputs.Position import scala.meta.tokens.Token + +import metaconfig.Conf +import metaconfig.ConfDecoder +import metaconfig.ConfEncoder +import metaconfig.ConfOps +import metaconfig.Configured +import metaconfig.internal.ConfGet +import scalafix.internal.rule.ImportMatcher.* +import scalafix.internal.rule.ImportMatcher.--- +import scalafix.internal.rule.ImportMatcher.parse import scalafix.lint.Diagnostic import scalafix.patch.Patch import scalafix.v1.Configuration import scalafix.v1.Rule import scalafix.v1.RuleName.stringToRuleName import scalafix.v1.SemanticDocument import scalafix.v1.SemanticRule import scalafix.v1.Symbol import scalafix.v1.SymbolInformation +import scalafix.v1.XtensionSeqPatch import scalafix.v1.XtensionTreeScalafix -class OrganizeImports(config: OrganizeImportsConfig) extends SemanticRule("OrganizeImports") { +class OrganizeImports(config: OrganizeImportsConfig) + extends SemanticRule("OrganizeImports") { import OrganizeImports._ import ImportMatcher._ private val matchers = buildImportMatchers(config) private val wildcardGroupIndex: Int = matchers indexOf * - private val unusedImporteePositions: mutable.Set[Position] = mutable.Set.empty[Position] + private val unusedImporteePositions: mutable.Set[Position] = + mutable.Set.empty[Position] - private val diagnostics: ArrayBuffer[Diagnostic] = ArrayBuffer.empty[Diagnostic] + private val diagnostics: ArrayBuffer[Diagnostic] = + ArrayBuffer.empty[Diagnostic] def this() = this(OrganizeImportsConfig()) override def isLinter: Boolean = true override def isRewrite: Boolean = true - override def isExperimental: Boolean = true - override def withConfiguration(config: Configuration): Configured[Rule] = config.conf .getOrElse("OrganizeImports")(OrganizeImportsConfig()) .andThen(patchPreset(_, config.conf)) .andThen(checkScalacOptions(_, config.scalacOptions, config.scalaVersion)) override def fix(implicit doc: SemanticDocument): Patch = { unusedImporteePositions ++= doc.diagnostics.collect { case d if d.message == "Unused import" => d.position } val (globalImports, localImports) = collectImports(doc.tree) val globalImportsPatch = if (globalImports.isEmpty) Patch.empty else organizeGlobalImports(globalImports) val localImportsPatch = if (!config.removeUnused || localImports.isEmpty) Patch.empty else removeUnused(localImports) diagnostics.map(Patch.lint).asPatch + globalImportsPatch + localImportsPatch } private def isUnused(importee: Importee): Boolean = unusedImporteePositions contains positionOf(importee) - private def organizeGlobalImports(imports: Seq[Import])(implicit doc: SemanticDocument): Patch = { + private def organizeGlobalImports( + imports: Seq[Import] + )(implicit doc: SemanticDocument): Patch = { val noUnused = imports flatMap (_.importers) flatMap (removeUnused(_).toSeq) val (implicits, noImplicits) = if (!config.groupExplicitlyImportedImplicitsSeparately) (Nil, noUnused) else partitionImplicits(noUnused) - val (fullyQualifiedImporters, relativeImporters) = noImplicits partition isFullyQualified + val (fullyQualifiedImporters, relativeImporters) = + noImplicits partition isFullyQualified // Organizes all the fully-qualified global importers. val fullyQualifiedGroups: Seq[ImportGroup] = { - val expanded = if (config.expandRelative) relativeImporters map expandRelative else Nil + val expanded = + if (config.expandRelative) relativeImporters map expandRelative else Nil groupImporters(fullyQualifiedImporters ++ expanded) } - // Moves relative imports (when `config.expandRelative` is false) and explicitly imported - // implicit names into a separate order preserving group. This group will be appended after - // all the other groups. + // Moves relative imports (when `config.expandRelative` is false) and + // explicitly imported implicit names into a separate order preserving + // group. This group will be appended after all the other groups. // - // See https://github.com/liancheng/scalafix-organize-imports/issues/30 for why implicits - // require special handling. + // See https://github.com/liancheng/scalafix-organize-imports/issues/30 + // for why implicits require special handling. val orderPreservingGroup = { val relatives = if (config.expandRelative) Nil else relativeImporters - Option(relatives ++ implicits sortBy (_.importees.head.pos.start)) filter (_.nonEmpty) + Option( + relatives ++ implicits sortBy (_.importees.head.pos.start) + ) filter (_.nonEmpty) } // Builds a patch that inserts the organized imports. val insertionPatch = insertOrganizedImports( imports.head.tokens.head, - fullyQualifiedGroups ++ orderPreservingGroup.map(ImportGroup(matchers.length, _)) + fullyQualifiedGroups ++ + orderPreservingGroup.map(ImportGroup(matchers.length, _)) ) // Builds a patch that removes all the tokens forming the original imports. val removalPatch = Patch.removeTokens( doc.tree.tokens.slice( imports.head.tokens.start, imports.last.tokens.end ) ) (insertionPatch + removalPatch).atomic } private def removeUnused(imports: Seq[Import]): Patch = Patch.fromIterable { imports flatMap (_.importers) flatMap { case Importer(_, importees) => - val hasUsedWildcard = importees exists { i => i.is[Importee.Wildcard] && !isUnused(i) } + val hasUsedWildcard = importees exists { i => + i.is[Importee.Wildcard] && !isUnused(i) + } importees collect { case i @ Importee.Rename(_, to) if isUnused(i) && hasUsedWildcard => - // Unimport the identifier instead of removing the importee since unused renamed may - // still impact compilation by shadowing an identifier. + // Unimport the identifier instead of removing the importee since + // unused renamed may still impact compilation by shadowing an + // identifier. // // See https://github.com/scalacenter/scalafix/issues/614 Patch.replaceTree(to, "_").atomic case i if isUnused(i) => Patch.removeImportee(i).atomic } } } private def removeUnused(importer: Importer): Option[Importer] = if (!config.removeUnused) Some(importer) else { val hasUsedWildcard = importer.importees exists { i => i.is[Importee.Wildcard] && !isUnused(i) } var rewritten = false val noUnused = importer.importees.flatMap { case i @ Importee.Rename(from, _) if isUnused(i) && hasUsedWildcard => - // Unimport the identifier instead of removing the importee since unused renamed may still - // impact compilation by shadowing an identifier. + // Unimport the identifier instead of removing the importee since + // unused renamed may still impact compilation by shadowing an + // identifier. // // See https://github.com/scalacenter/scalafix/issues/614 rewritten = true Importee.Unimport(from) :: Nil case i if isUnused(i) => rewritten = true Nil case i => i :: Nil } if (!rewritten) Some(importer) else if (noUnused.isEmpty) None else Some(importer.copy(importees = noUnused)) } private def partitionImplicits( importers: Seq[Importer] )(implicit doc: SemanticDocument): (Seq[Importer], Seq[Importer]) = { val (implicits, implicitPositions) = importers.flatMap { case importer @ Importer(_, importees) => importees collect { case i: Importee.Name if i.symbol.infoNoThrow exists (_.isImplicit) => importer.copy(importees = i :: Nil) -> i.pos } }.unzip val noImplicits = importers.flatMap { - _.filterImportees { importee => !implicitPositions.contains(importee.pos) }.toSeq + _.filterImportees { importee => + !implicitPositions.contains(importee.pos) + }.toSeq } (implicits, noImplicits) } - private def isFullyQualified(importer: Importer)(implicit doc: SemanticDocument): Boolean = { + private def isFullyQualified( + importer: Importer + )(implicit doc: SemanticDocument): Boolean = { val topQualifier = topQualifierOf(importer.ref) val topQualifierSymbol = topQualifier.symbol val owner = topQualifierSymbol.owner ( // The owner of the top qualifier is `_root_`, e.g.: `import scala.util` owner.isRootPackage || // The top qualifier is a top-level class/trait/object defined under no packages. In this // case, Scalameta defines the owner to be the empty package. owner.isEmptyPackage || // The top qualifier itself is `_root_`, e.g.: `import _root_.scala.util` topQualifier.value == "_root_" || - // Issue #64: Sometimes, the symbol of the top qualifier can be missing due to unknown reasons - // (see https://github.com/liancheng/scalafix-organize-imports/issues/64). In this case, we - // issue a warning and continue processing assuming that the top qualifier is fully-qualified. + // https://github.com/liancheng/scalafix-organize-imports/issues/64: + // Sometimes, the symbol of the top qualifier can be missing due to + // unknown reasons. In this case, we issue a warning and continue + // processing assuming that the top qualifier is fully-qualified. topQualifierSymbol.isNone && { diagnostics += ImporterSymbolNotFound(topQualifier) true } ) } - private def expandRelative(importer: Importer)(implicit doc: SemanticDocument): Importer = { + private def expandRelative( + importer: Importer + )(implicit doc: SemanticDocument): Importer = { /** * Converts a `Symbol` into a fully-qualified `Term.Ref`. * - * NOTE: The returned `Term.Ref` does NOT contain symbol information since it's not parsed from - * the source file. + * NOTE: The returned `Term.Ref` does NOT contain symbol information since + * it's not parsed from the source file. */ def toFullyQualifiedRef(symbol: Symbol): Term.Ref = { val owner = symbol.owner symbol match { // When importing names defined within package objects, skip the `package` part for brevity. // For instance, with the following definition: // // package object foo { val x: Int = ??? } // // when importing `foo.x`, we prefer "import foo.x" instead of "import foo.`package`.x", // which is also valid, but unnecessarily lengthy. // // See https://github.com/liancheng/scalafix-organize-imports/issues/55. case _ if symbol.infoNoThrow exists (_.isPackageObject) => toFullyQualifiedRef(owner) - // See the comment marked with "Issue #64" for the case of `symbol.isNone` - case _ if symbol.isNone || owner.isRootPackage || owner.isEmptyPackage => + // See the comment marked with "issues/64" for the case of `symbol.isNone` + case _ + if symbol.isNone || owner.isRootPackage || owner.isEmptyPackage => Term.Name(symbol.displayName) case _ => Term.Select(toFullyQualifiedRef(owner), Term.Name(symbol.displayName)) } } - val fullyQualifiedTopQualifier = toFullyQualifiedRef(topQualifierOf(importer.ref).symbol) - importer.copy(ref = replaceTopQualifier(importer.ref, fullyQualifiedTopQualifier)) + val fullyQualifiedTopQualifier = + toFullyQualifiedRef(topQualifierOf(importer.ref).symbol) + + importer.copy( + ref = replaceTopQualifier(importer.ref, fullyQualifiedTopQualifier) + ) } private def groupImporters(importers: Seq[Importer]): Seq[ImportGroup] = importers .groupBy(matchImportGroup) // Groups imports by importer prefix. .mapValues(deduplicateImportees _ andThen organizeImportGroup) - .map(ImportGroup.tupled) + .map { case (index, imports) => ImportGroup(index, imports) } .toSeq .sortBy(_.index) private def deduplicateImportees(importers: Seq[Importer]): Seq[Importer] = { // Scalameta `Tree` nodes do not provide structural equality comparisons, here we pretty-print // them and compare the string results. val seenImportees = mutable.Set.empty[(String, String)] importers flatMap { importer => importer filterImportees { importee => importee.is[Importee.Wildcard] || importee.is[Importee.GivenAll] || seenImportees.add(importee.syntax -> importer.ref.syntax) } } } private def organizeImportGroup(importers: Seq[Importer]): Seq[Importer] = { - // Issue #96: For importers with only a single `Importee.Name` importee, if the importee is - // curly-braced, remove the unneeded curly-braces. For example: `import p.{X}` should be - // rewritten into `import p.X`. + // https://github.com/liancheng/scalafix-organize-imports/issues/96: For + // importers with only a single `Importee.Name` importee, if the importee + // is curly-braced, remove the unneeded curly-braces. For example: + // `import p.{X}` should be rewritten into `import p.X`. val noUnneededBraces = importers map removeRedundantBrances val importeesSorted = locally { config.groupedImports match { - case GroupedImports.Merge => mergeImporters(noUnneededBraces, aggressive = false) - case GroupedImports.AggressiveMerge => mergeImporters(noUnneededBraces, aggressive = true) - case GroupedImports.Explode => explodeImportees(noUnneededBraces) - case GroupedImports.Keep => noUnneededBraces + case GroupedImports.Merge => + mergeImporters(noUnneededBraces, aggressive = false) + case GroupedImports.AggressiveMerge => + mergeImporters(noUnneededBraces, aggressive = true) + case GroupedImports.Explode => + explodeImportees(noUnneededBraces) + case GroupedImports.Keep => + noUnneededBraces } } map (coalesceImportees _ andThen sortImportees) config.importsOrder match { - // Issue #84: The Scalameta `Tree` node pretty-printer checks whether the node originates - // directly from the parser. If yes, the original source code text is returned, and may - // interfere imports sort order. The `.copy()` call below erases the source position - // information so that the pretty-printer would actually pretty-print an `Importer` into a - // single line. - // - // See https://github.com/liancheng/scalafix-organize-imports/issues/84 for more details. - case ImportsOrder.Ascii => importeesSorted sortBy (i => importerSyntax(i.copy())) - case ImportsOrder.SymbolsFirst => sortImportersSymbolsFirst(importeesSorted) - case ImportsOrder.Keep => importeesSorted + // https://github.com/liancheng/scalafix-organize-imports/issues/84: The Scalameta `Tree` node pretty-printer + // checks whether the node originates directly from the parser. If yes, the original source + // code text is returned, and may interfere imports sort order. The `.copy()` call below + // erases the source position information so that the pretty-printer would actually + // pretty-print an `Importer` into a single line. + case ImportsOrder.Ascii => + importeesSorted sortBy (i => importerSyntax(i.copy())) + case ImportsOrder.SymbolsFirst => + sortImportersSymbolsFirst(importeesSorted) + case ImportsOrder.Keep => + importeesSorted } } - private def removeRedundantBrances(importer: Importer): Importer = importer match { + private def removeRedundantBrances(importer: Importer): Importer = + importer match { case i @ Importer(_, Importee.Name(_) :: Nil) => import Token.{Ident, LeftBrace, RightBrace} i.tokens.reverse.toList match { // The `.copy()` call erases the source position information from the original importer, so // that instead of returning the original source text, the pretty-printer will reformat // `importer` without the unneeded curly-braces. case RightBrace() :: Ident(_) :: LeftBrace() :: _ => i.copy() case _ => i } case _ => importer } - private def mergeImporters(importers: Seq[Importer], aggressive: Boolean): Seq[Importer] = + private def mergeImporters( + importers: Seq[Importer], + aggressive: Boolean + ): Seq[Importer] = importers.groupBy(_.ref.syntax).values.toSeq.flatMap { case importer :: Nil => // If this group has only one importer, returns it as is to preserve the original source // level formatting. importer :: Nil case group @ Importer(ref, _) :: _ => val importeeLists = group map (_.importees) val hasWildcard = group exists (_.hasWildcard) val hasGivenAll = group exists (_.hasGivenAll) // Collects the last set of unimports with a wildcard, if any. It cancels all previous // unimports. E.g.: // // import p.{A => _} // import p.{B => _, _} // import p.{C => _, _} // // Only `C` is unimported. `A` and `B` are still available. // // TODO: Shall we issue a warning here as using order-sensitive imports is a bad practice? val lastUnimportsWithWildcard = importeeLists.reverse collectFirst { case Importees(_, _, unimports @ _ :: _, _, _, Some(_)) => unimports } val lastUnimportsWithGivenAll = importeeLists.reverse collectFirst { case Importees(_, _, unimports @ _ :: _, _, Some(_), _) => unimports } // Collects all unimports without an accompanying wildcard. - val unimports = importeeLists.collect { case Importees(_, _, unimports, _, None, None) => + val unimports = importeeLists.collect { + case Importees(_, _, unimports, _, None, None) => unimports }.flatten - val (givens, nonGivens) = group.flatMap(_.importees).toList.partition(_.is[Importee.Given]) + val (givens, nonGivens) = + group.flatMap(_.importees).toList.partition(_.is[Importee.Given]) // Here we assume that a name is renamed at most once within a single source file, which is // true in most cases. // // Note that the IntelliJ IDEA Scala import optimizer does not handle this case properly // either. If a name is renamed more than once, it only keeps one of the renames in the // result and may break compilation (unless other renames are not actually referenced). val renames = nonGivens .collect { case rename: Importee.Rename => rename } .groupBy(_.name.value) .map { case (_, rename :: Nil) => rename case (_, renames @ (head @ Importee.Rename(from, _)) :: _) => diagnostics += TooManyAliases(from, renames) head } .toList // Collects distinct explicitly imported names, and filters out those that are also renamed. // If an explicitly imported name is also renamed, both the original name and the new name // are available. This implies that both of them must be preserved in the merged result, but // in two separate import statements (Scala only allows a name to appear in an import at // most once). E.g.: // // import p.A // import p.{A => A1} // import p.B // import p.{B => B1} // // The above snippet should be rewritten into: // // import p.{A, B} // import p.{A => A1, B => B1} val (renamedImportedNames, importedNames) = { - val renamedNames = renames.map { case Importee.Rename(Name(from), _) => + val renamedNames = + renames.map { case Importee.Rename(Name(from), _) => from }.toSet nonGivens .filter(_.is[Importee.Name]) .groupBy { case Importee.Name(Name(name)) => name } .map { case (_, importees) => importees.head } .toList - .partition { case Importee.Name(Name(name)) => renamedNames contains name } + .partition { case Importee.Name(Name(name)) => + renamedNames contains name + } } val mergedNonGivens = (hasWildcard, lastUnimportsWithWildcard) match { case (true, _) => // A few things to note in this case: // // 1. Unimports are discarded because they are canceled by the wildcard. E.g.: // // import scala.collection.mutable.{Set => _, _} // import scala.collection.mutable._ // // The above two imports should be merged into: // // import scala.collection.mutable._ // // 2. Explicitly imported names can NOT be discarded even though they seem to be covered // by the wildcard, unless groupedImports is set to AggressiveMerge. This is because // explicitly imported names have higher precedence than names imported via a // wildcard. Discarding them may introduce ambiguity in some cases. E.g.: // // import scala.collection.immutable._ // import scala.collection.mutable._ // import scala.collection.mutable.Set // // object Main { val s: Set[Int] = ??? } // // The type of `Main.s` above is unambiguous because `mutable.Set` is explicitly // imported, and has higher precedence than `immutable.Set`, which is made available // via a wildcard. In this case, the imports should be merged into: // // import scala.collection.immutable._ // import scala.collection.mutable.{Set, _} // // rather than // // import scala.collection.immutable._ // import scala.collection.mutable._ // // Otherwise, the type of `Main.s` becomes ambiguous and a compilation error is // introduced. // // 3. However, the case discussed above is relatively rare in real life. A more common // case is something like: // // import scala.collection.Set // import scala.collection._ // // In this case, we do want to merge them into: // // import scala.collection._ // // rather than // // import scala.collection.{Set, _} // // To achieve this, users may set `groupedImports` to `AggressiveMerge`. Instead of // being conservative and ensure correctness in all the cases, this option merges // imports aggressively for conciseness. // // 4. Renames must be moved into a separate import statement to make sure that the // original names made available by the wildcard are still preserved. E.g.: // // import p._ // import p.{A => A1} // // The above imports cannot be merged into // // import p.{A => A1, _} // // Otherwise, the original name `A` is no longer available. if (aggressive) Seq(renames, Wildcard() :: Nil) else Seq(renames, importedNames :+ Wildcard()) case (false, Some(lastUnimports)) => // A wildcard must be appended for unimports. - Seq(renamedImportedNames, importedNames ++ renames ++ lastUnimports :+ Wildcard()) + Seq( + renamedImportedNames, + importedNames ++ renames ++ lastUnimports :+ Wildcard() + ) case (false, None) => Seq(renamedImportedNames, importedNames ++ renames ++ unimports) } /* Adjust the result to add givens imports, these are * are the Scala 3 way of importing implicits, which are not imported * with the wildcard import. */ val newImporteeListsWithGivens = if (hasGivenAll) { if (aggressive) mergedNonGivens :+ List(GivenAll()) else mergedNonGivens :+ (givens :+ GivenAll()) } else { lastUnimportsWithGivenAll match { - case Some(unimports) => mergedNonGivens :+ (givens ++ unimports :+ GivenAll()) - case None => mergedNonGivens :+ givens + case Some(unimports) => + mergedNonGivens :+ (givens ++ unimports :+ GivenAll()) + case None => + mergedNonGivens :+ givens } } - preserveOriginalImportersFormatting(group, newImporteeListsWithGivens, ref) + preserveOriginalImportersFormatting( + group, + newImporteeListsWithGivens, + ref + ) } - private def sortImportersSymbolsFirst(importers: Seq[Importer]): Seq[Importer] = + private def sortImportersSymbolsFirst( + importers: Seq[Importer] + ): Seq[Importer] = importers.sortBy { importer => - // See the comment marked with "Issue #84" for why a `.copy()` is needed. + // See the comment marked with "issues/84" for why a `.copy()` is needed. val syntax = importer.copy().syntax importer match { case Importer(_, Importee.Wildcard() :: Nil) => syntax.patch(syntax.lastIndexOfSlice("._"), ".\u0001", 2) case _ if importer.isCurlyBraced => syntax .replaceFirst("[{]", "\u0002") .patch(syntax.lastIndexOf("}"), "\u0002", 1) case _ => syntax } } private def coalesceImportees(importer: Importer): Importer = { val Importees(names, renames, unimports, givens, _, _) = importer.importees config.coalesceToWildcardImportThreshold .filter(importer.importees.length > _) // Skips if there's no `Name`s or `Given`s. `Rename`s and `Unimport`s cannot be coalesced. .filterNot(_ => names.isEmpty && givens.isEmpty) .map { case _ if givens.isEmpty => renames ++ unimports :+ Wildcard() case _ if names.isEmpty => renames ++ unimports :+ GivenAll() case _ => renames ++ unimports :+ GivenAll() :+ Wildcard() } .map(importees => importer.copy(importees = importees)) .getOrElse(importer) } private def sortImportees(importer: Importer): Importer = { import ImportSelectorsOrder._ // The Scala language spec allows an import expression to have at most one final wildcard, which // can only appears in the last position. val (wildcards, others) = - importer.importees partition (i => i.is[Importee.Wildcard] || i.is[Importee.GivenAll]) + importer.importees partition (i => + i.is[Importee.Wildcard] || i.is[Importee.GivenAll] + ) val orderedImportees = config.importSelectorsOrder match { - case Ascii => Seq(others, wildcards) map (_.sortBy(_.syntax)) reduce (_ ++ _) - case SymbolsFirst => Seq(others, wildcards) map sortImporteesSymbolsFirst reduce (_ ++ _) - case Keep => importer.importees + case Ascii => + Seq(others, wildcards) map (_.sortBy(_.syntax)) reduce (_ ++ _) + case SymbolsFirst => + Seq(others, wildcards) map sortImporteesSymbolsFirst reduce (_ ++ _) + case Keep => + importer.importees } // Checks whether importees of the input importer are already sorted. If yes, we should return // the original importer to preserve the original source level formatting. val alreadySorted = config.importSelectorsOrder == Keep || (importer.importees corresponds orderedImportees) { (lhs, rhs) => lhs.syntax == rhs.syntax } if (alreadySorted) importer else importer.copy(importees = orderedImportees) } /** - * Returns the index of the group to which the given importer belongs. Each group is represented - * by an `ImportMatcher`. If multiple `ImporterMatcher`s match the given import, the one matches - * the longest prefix wins. + * Returns the index of the group to which the given importer belongs. Each + * group is represented by an `ImportMatcher`. If multiple `ImporterMatcher`s + * match the given import, the one matches the longest prefix wins. */ private def matchImportGroup(importer: Importer): Int = { val matchedGroups = matchers .map(_ matches importer) .zipWithIndex .filter { case (length, _) => length > 0 } if (matchedGroups.isEmpty) wildcardGroupIndex else { val (_, index) = matchedGroups.maxBy { case (length, _) => length } index } } - private def insertOrganizedImports(token: Token, importGroups: Seq[ImportGroup]): Patch = { - val prettyPrintedGroups = importGroups.map { case ImportGroup(index, imports) => + private def insertOrganizedImports( + token: Token, + importGroups: Seq[ImportGroup] + ): Patch = { + val prettyPrintedGroups = importGroups.map { + case ImportGroup(index, imports) => index -> prettyPrintImportGroup(imports) } val blankLines = { // Indices of all blank lines configured in `OrganizeImports.groups`, either automatically or // manually. - val blankLineIndices = matchers.zipWithIndex.collect { case (`---`, index) => index }.toSet + val blankLineIndices = matchers.zipWithIndex.collect { + case (`---`, index) => index + }.toSet // Checks each pair of adjacent import groups. Inserts a blank line between them if necessary. - importGroups map (_.index) sliding 2 filter (_.length == 2) flatMap { case Seq(lhs, rhs) => + importGroups map (_.index) sliding 2 filter (_.length == 2) flatMap { + case Seq(lhs, rhs) => val hasBlankLine = blankLineIndices exists (i => lhs < i && i < rhs) if (hasBlankLine) Some((lhs + 1) -> "") else None } } val withBlankLines = (prettyPrintedGroups ++ blankLines) .sortBy { case (index, _) => index } .map { case (_, lines) => lines } .mkString("\n") // Global imports within curly-braced packages must be indented accordingly, e.g.: // // package foo { // package bar { // import baz // import qux // } // } val indented = withBlankLines.linesIterator.zipWithIndex.map { // The first line will be inserted at an already indented position. case (line, 0) => line case (line, _) if line.isEmpty => line case (line, _) => " " * token.pos.startColumn + line } Patch.addLeft(token, indented mkString "\n") } } object OrganizeImports { private case class ImportGroup(index: Int, imports: Seq[Importer]) private def patchPreset( ruleConf: OrganizeImportsConfig, conf: Conf ): Configured[OrganizeImportsConfig] = { val preset = OrganizeImportsConfig.presets(ruleConf.preset) val presetConf = ConfEncoder[OrganizeImportsConfig].write(preset) - val userConf = ConfGet.getKey(conf, "OrganizeImports" :: Nil).getOrElse(Conf.Obj.empty) + val userConf = + ConfGet.getKey(conf, "OrganizeImports" :: Nil).getOrElse(Conf.Obj.empty) val mergedConf = ConfOps.merge(presetConf, userConf) ConfDecoder[OrganizeImportsConfig].read(mergedConf) } private def checkScalacOptions( conf: OrganizeImportsConfig, scalacOptions: List[String], scalaVersion: String ): Configured[Rule] = { val hasCompilerSupport = scalaVersion.startsWith("2") val hasWarnUnused = hasCompilerSupport && { val warnUnusedPrefix = Set("-Wunused", "-Ywarn-unused") val warnUnusedString = Set("-Xlint", "-Xlint:unused") scalacOptions exists { option => (warnUnusedPrefix exists option.startsWith) || (warnUnusedString contains option) } } if (!conf.removeUnused || hasWarnUnused) Configured.ok(new OrganizeImports(conf)) else if (hasCompilerSupport) Configured.error( "The Scala compiler option \"-Ywarn-unused\" is required to use OrganizeImports with" + " \"OrganizeImports.removeUnused\" set to true. To fix this problem, update your" + " build to use at least one Scala compiler option like -Ywarn-unused-import (2.11" + " only), -Ywarn-unused, -Xlint:unused (2.12.2 or above) or -Wunused (2.13 only)." ) else Configured.error( "\"OrganizeImports.removeUnused\" is not supported on Scala 3 as the compiler is" + " not providing enough information. Run the rule with" + " \"OrganizeImports.removeUnused\" set to false to organize imports while keeping" + " potentially unused imports." ) } - private def buildImportMatchers(config: OrganizeImportsConfig): Seq[ImportMatcher] = { + private def buildImportMatchers( + config: OrganizeImportsConfig + ): Seq[ImportMatcher] = { val withWildcard = { val parsed = config.groups map parse // The wildcard group should always exist. Appends one at the end if omitted. if (parsed contains *) parsed else parsed :+ * } // Inserts a blank line marker between adjacent import groups when `blankLines` is `Auto`. config.blankLines match { case BlankLines.Manual => withWildcard case BlankLines.Auto => withWildcard.flatMap(_ :: --- :: Nil) } } private def positionOf(importee: Importee): Position = importee match { case Importee.Rename(from, _) => from.pos case _ => importee.pos } - @tailrec private def collectImports(tree: Tree): (Seq[Import], Seq[Import]) = { + @tailrec private def collectImports( + tree: Tree + ): (Seq[Import], Seq[Import]) = { def extractImports(stats: Seq[Stat]): (Seq[Import], Seq[Import]) = { val (importStats, otherStats) = stats.span(_.is[Import]) val globalImports = importStats.map { case i: Import => i } val localImports = otherStats.flatMap(_.collect { case i: Import => i }) (globalImports, localImports) } tree match { case Source(Seq(p: Pkg)) => collectImports(p) case Pkg(_, Seq(p: Pkg)) => collectImports(p) case Source(stats) => extractImports(stats) case Pkg(_, stats) => extractImports(stats) case _ => (Nil, Nil) } } private def prettyPrintImportGroup(group: Seq[Importer]): String = group .map(i => "import " + importerSyntax(i)) .mkString("\n") /** - * HACK: The Scalafix pretty-printer decides to add spaces after open and before close braces in - * imports with multiple importees, i.e., `import a.{ b, c }` instead of `import a.{b, c}`. On the - * other hand, renames are pretty-printed without the extra spaces, e.g., `import a.{b => c}`. - * This behavior is not customizable and makes ordering imports by ASCII order complicated. + * HACK: The Scalafix pretty-printer decides to add spaces after open and + * before close braces in imports with multiple importees, i.e., `import a.{ + * b, c }` instead of `import a.{b, c}`. On the other hand, renames are + * pretty-printed without the extra spaces, e.g., `import a.{b => c}`. This + * behavior is not customizable and makes ordering imports by ASCII order + * complicated. * - * This function removes the unwanted spaces as a workaround. In cases where users do want the - * inserted spaces, Scalafmt should be used after running the `OrganizeImports` rule. + * This function removes the unwanted spaces as a workaround. In cases where + * users do want the inserted spaces, Scalafmt should be used after running + * the `OrganizeImports` rule. */ private def importerSyntax(importer: Importer): String = importer.pos match { case pos: Position.Range => // Position found, implies that `importer` was directly parsed from the source code. Returns // the original parsed text to preserve the original source level formatting. pos.text case Position.None => // Position not found, implies that `importer` is derived from certain existing import // statement(s). Pretty-prints it. val syntax = importer.syntax // NOTE: We need to check whether the input importer is curly braced first and then replace // the first "{ " and the last " }" if any. Naive string replacement is insufficient, e.g., // a quoted-identifier like "`{ d }`" may cause broken output. (importer.isCurlyBraced, syntax lastIndexOfSlice " }") match { - case (_, -1) => syntax - case (true, index) => syntax.patch(index, "}", 2).replaceFirst("\\{ ", "{") - case _ => syntax + case (_, -1) => + syntax + case (true, index) => + syntax.patch(index, "}", 2).replaceFirst("\\{ ", "{") + case _ => + syntax } } @tailrec private def topQualifierOf(term: Term): Term.Name = term match { case Term.Select(qualifier, _) => topQualifierOf(qualifier) case name: Term.Name => name } - /** Replaces the top-qualifier of the input `term` with a new term `newTopQualifier`. */ - private def replaceTopQualifier(term: Term, newTopQualifier: Term.Ref): Term.Ref = + /** + * Replaces the top-qualifier of the input `term` with a new term + * `newTopQualifier`. + */ + private def replaceTopQualifier( + term: Term, + newTopQualifier: Term.Ref + ): Term.Ref = term match { case _: Term.Name => newTopQualifier case Term.Select(qualifier, name) => Term.Select(replaceTopQualifier(qualifier, newTopQualifier), name) } - private def sortImporteesSymbolsFirst(importees: List[Importee]): List[Importee] = { + private def sortImporteesSymbolsFirst( + importees: List[Importee] + ): List[Importee] = { val symbols = ArrayBuffer.empty[Importee] val lowerCases = ArrayBuffer.empty[Importee] val upperCases = ArrayBuffer.empty[Importee] importees.foreach { case i if i.syntax.head.isLower => lowerCases += i case i if i.syntax.head.isUpper => upperCases += i case i => symbols += i } List(symbols, lowerCases, upperCases) flatMap (_ sortBy (_.syntax)) } private def explodeImportees(importers: Seq[Importer]): Seq[Importer] = importers flatMap { case importer @ Importer(_, _ :: Nil) => // If the importer has exactly one importee, returns it as is to preserve the original // source level formatting. importer :: Nil case importer @ Importer( ref, Importees(names, renames, unimports, givens, givenAll, wildcard) ) if givenAll.isDefined || wildcard.isDefined => // When a wildcard exists, all renames, unimports, and the wildcard must appear in the same // importer, e.g.: // // import p.{A => _, B => _, C => D, E, _} // // should be rewritten into // // import p.{A => _, B => _, C => D, _} // import p.E val importeesList = - (names ++ givens).map(_ :: Nil) :+ (renames ++ unimports ++ wildcard ++ givenAll) + (names ++ givens).map( + _ :: Nil + ) :+ (renames ++ unimports ++ wildcard ++ givenAll) preserveOriginalImportersFormatting(Seq(importer), importeesList, ref) case importer => importer.importees map (i => importer.copy(importees = i :: Nil)) } /** - * Issue #127: After merging or exploding imports, checks whether there are any input importers - * left untouched. For those importers, returns the original importer instance to preserve the - * original source level formatting. + * https://github.com/liancheng/scalafix-organize-imports/issues/127: After + * merging or exploding imports, checks whether there are any input importers + * left untouched. For those importers, returns the original importer instance + * to preserve the original source level formatting. */ private def preserveOriginalImportersFormatting( importers: Seq[Importer], newImporteeLists: Seq[List[Importee]], newImporterRef: Term.Ref ) = { val importerSyntaxMap = importers.map { i => i.copy().syntax -> i }.toMap newImporteeLists filter (_.nonEmpty) map { importees => val newImporter = Importer(newImporterRef, importees) importerSyntaxMap.getOrElse(newImporter.syntax, newImporter) } } /** * Categorizes a list of `Importee`s into the following four groups: * * - Names, e.g., `Seq`, `Option`, etc. * - Renames, e.g., `{Long => JLong}`, `{Duration => D}`, etc. * - Unimports, e.g., `{Foo => _}`. * - Givens, e.g., `{given Foo}`. * - GivenAll, i.e., `given`. * - Wildcard, i.e., `_`. */ object Importees { def unapply(importees: Seq[Importee]): Option[ ( List[Importee.Name], List[Importee.Rename], List[Importee.Unimport], List[Importee.Given], Option[Importee.GivenAll], Option[Importee.Wildcard] ) ] = { val names = ArrayBuffer.empty[Importee.Name] val renames = ArrayBuffer.empty[Importee.Rename] val givens = ArrayBuffer.empty[Importee.Given] val unimports = ArrayBuffer.empty[Importee.Unimport] var maybeWildcard: Option[Importee.Wildcard] = None var maybeGivenAll: Option[Importee.GivenAll] = None importees foreach { case i: Importee.Wildcard => maybeWildcard = Some(i) case i: Importee.Unimport => unimports += i case i: Importee.Rename => renames += i case i: Importee.Name => names += i case i: Importee.Given => givens += i case i: Importee.GivenAll => maybeGivenAll = Some(i) } Option( ( names.toList, renames.toList, unimports.toList, givens.toList, maybeGivenAll, maybeWildcard ) ) } } implicit private class SymbolExtension(symbol: Symbol) { /** - * HACK: In certain cases, `Symbol#info` may throw `MissingSymbolException` due to some unknown - * reason. This implicit class adds a safe version of `Symbol#info` to return `None` instead of - * throw an exception when this happens. + * HACK: In certain cases, `Symbol#info` may throw `MissingSymbolException` + * due to some unknown reason. This implicit class adds a safe version of + * `Symbol#info` to return `None` instead of throw an exception when this + * happens. * * See [[https://github.com/scalacenter/scalafix/issues/1123 issue #1123]]. */ def infoNoThrow(implicit doc: SemanticDocument): Option[SymbolInformation] = Try(symbol.info).toOption.flatten } implicit private class ImporterExtension(importer: Importer) { /** Checks whether the `Importer` is curly-braced when pretty-printed. */ def isCurlyBraced: Boolean = { - val importees @ Importees(_, renames, unimports, _, _, _) = importer.importees + val importees @ Importees(_, renames, unimports, _, _, _) = + importer.importees renames.nonEmpty || unimports.nonEmpty || importees.length > 1 } /** - * Returns an `Importer` with all the `Importee`s that are selected from the input `Importer` - * and satisfy a predicate. If all the `Importee`s are selected, the input `Importer` instance - * is returned to preserve the original source level formatting. If none of the `Importee`s are + * Returns an `Importer` with all the `Importee`s that are selected from the + * input `Importer` and satisfy a predicate. If all the `Importee`s are + * selected, the input `Importer` instance is returned to preserve the + * original source level formatting. If none of the `Importee`s are * selected, returns a `None`. */ def filterImportees(f: Importee => Boolean): Option[Importer] = { val filtered = importer.importees filter f if (filtered.length == importer.importees.length) Some(importer) else if (filtered.isEmpty) None else Some(importer.copy(importees = filtered)) } /** Returns true if the `Importer` contains a standalone wildcard. */ def hasWildcard: Boolean = { val Importees(_, _, unimports, _, _, wildcard) = importer.importees unimports.isEmpty && wildcard.nonEmpty } /** Returns true if the `Importer` contains a standalone given wildcard. */ def hasGivenAll: Boolean = { val Importees(_, _, unimports, _, givenAll, _) = importer.importees unimports.isEmpty && givenAll.nonEmpty } } } diff --combined scalafix-rules/src/main/scala/scalafix/internal/rule/OrganizeImportsConfig.scala index 00000000,f91c16a3..d9703df4 mode 000000,100644..100644 --- /dev/null --- a/rules/src/main/scala/fix/OrganizeImportsConfig.scala ++ b/scalafix-rules/src/main/scala/scalafix/internal/rule/OrganizeImportsConfig.scala @@@ -1,0 -1,102 +1,111 @@@ -package fix +package scalafix.internal.rule import metaconfig.Conf import metaconfig.ConfDecoder import metaconfig.ConfEncoder import metaconfig.generic.Surface import metaconfig.generic.deriveDecoder import metaconfig.generic.deriveEncoder import metaconfig.generic.deriveSurface import scalafix.internal.config.ReaderUtil sealed trait ImportsOrder object ImportsOrder { case object Ascii extends ImportsOrder case object SymbolsFirst extends ImportsOrder case object Keep extends ImportsOrder - implicit def reader: ConfDecoder[ImportsOrder] = ReaderUtil.oneOf(Ascii, SymbolsFirst, Keep) - implicit def writer: ConfEncoder[ImportsOrder] = ConfEncoder.instance(v => Conf.Str(v.toString)) + implicit def reader: ConfDecoder[ImportsOrder] = + ReaderUtil.oneOf(Ascii, SymbolsFirst, Keep) + implicit def writer: ConfEncoder[ImportsOrder] = + ConfEncoder.instance(v => Conf.Str(v.toString)) } sealed trait ImportSelectorsOrder object ImportSelectorsOrder { case object Ascii extends ImportSelectorsOrder case object SymbolsFirst extends ImportSelectorsOrder case object Keep extends ImportSelectorsOrder implicit def reader: ConfDecoder[ImportSelectorsOrder] = ReaderUtil.oneOf(Ascii, SymbolsFirst, Keep) implicit def writer: ConfEncoder[ImportSelectorsOrder] = ConfEncoder.instance(v => Conf.Str(v.toString)) } sealed trait GroupedImports object GroupedImports { case object AggressiveMerge extends GroupedImports case object Merge extends GroupedImports case object Explode extends GroupedImports case object Keep extends GroupedImports implicit def reader: ConfDecoder[GroupedImports] = ReaderUtil.oneOf(AggressiveMerge, Merge, Explode, Keep) implicit def writer: ConfEncoder[GroupedImports] = ConfEncoder.instance(v => Conf.Str(v.toString)) } sealed trait BlankLines object BlankLines { case object Auto extends BlankLines case object Manual extends BlankLines - implicit def reader: ConfDecoder[BlankLines] = ReaderUtil.oneOf(Auto, Manual) - implicit def writer: ConfEncoder[BlankLines] = ConfEncoder.instance(v => Conf.Str(v.toString)) + implicit def reader: ConfDecoder[BlankLines] = + ReaderUtil.oneOf(Auto, Manual) + implicit def writer: ConfEncoder[BlankLines] = + ConfEncoder.instance(v => Conf.Str(v.toString)) } sealed trait Preset object Preset { case object DEFAULT extends Preset case object INTELLIJ_2020_3 extends Preset - implicit def reader: ConfDecoder[Preset] = ReaderUtil.oneOf(DEFAULT, INTELLIJ_2020_3) - implicit def writer: ConfEncoder[Preset] = ConfEncoder.instance(v => Conf.Str(v.toString)) + implicit def reader: ConfDecoder[Preset] = + ReaderUtil.oneOf(DEFAULT, INTELLIJ_2020_3) + implicit def writer: ConfEncoder[Preset] = + ConfEncoder.instance(v => Conf.Str(v.toString)) } final case class OrganizeImportsConfig( blankLines: BlankLines = BlankLines.Auto, coalesceToWildcardImportThreshold: Option[Int] = None, expandRelative: Boolean = false, groupExplicitlyImportedImplicitsSeparately: Boolean = false, groupedImports: GroupedImports = GroupedImports.Explode, groups: Seq[String] = Seq( "*", "re:(javax?|scala)\\." ), importSelectorsOrder: ImportSelectorsOrder = ImportSelectorsOrder.Ascii, importsOrder: ImportsOrder = ImportsOrder.Ascii, preset: Preset = Preset.DEFAULT, removeUnused: Boolean = true ) object OrganizeImportsConfig { val default: OrganizeImportsConfig = OrganizeImportsConfig() - implicit val surface: Surface[OrganizeImportsConfig] = deriveSurface - implicit val encoder: ConfEncoder[OrganizeImportsConfig] = deriveEncoder - implicit val decoder: ConfDecoder[OrganizeImportsConfig] = deriveDecoder(default) + implicit val surface: Surface[OrganizeImportsConfig] = + deriveSurface + implicit val encoder: ConfEncoder[OrganizeImportsConfig] = + deriveEncoder + implicit val decoder: ConfDecoder[OrganizeImportsConfig] = + deriveDecoder(default) val presets: Map[Preset, OrganizeImportsConfig] = Map( Preset.DEFAULT -> OrganizeImportsConfig(), Preset.INTELLIJ_2020_3 -> OrganizeImportsConfig( coalesceToWildcardImportThreshold = Some(5), groupedImports = GroupedImports.Merge ) ) } diff --combined scalafix-rules/src/main/scala/scalafix/internal/rule/diagnostics.scala index 00000000,58d2b5ee..bf7c6e6e mode 000000,100644..100644 --- /dev/null --- a/rules/src/main/scala/fix/diagnostics.scala ++ b/scalafix-rules/src/main/scala/scalafix/internal/rule/diagnostics.scala @@@ -1,0 -1,42 +1,45 @@@ -package fix +package scalafix.internal.rule import scala.meta.Importee import scala.meta.Name import scala.meta.Term +import scala.meta.XtensionSyntax + import scalafix.lint.Diagnostic import scalafix.lint.LintSeverity case class ImporterSymbolNotFound(ref: Term.Name) extends Diagnostic { override def position: meta.Position = ref.pos override def message: String = s"Could not determine whether '${ref.syntax}' is fully-qualified because the symbol" + " information is missing. We will continue processing assuming that it is fully-qualified." + " Please check whether the corresponding .semanticdb file is properly generated." override def severity: LintSeverity = LintSeverity.Warning } -case class TooManyAliases(name: Name, renames: Seq[Importee.Rename]) extends Diagnostic { +case class TooManyAliases(name: Name, renames: Seq[Importee.Rename]) + extends Diagnostic { assert(renames.length > 1) override def position: meta.Position = name.pos override def message: String = { val aliases = renames .map { case Importee.Rename(_, Name(alias)) => alias } .sorted .map("'" + _ + "'") val aliasList = aliases match { case head :: last :: Nil => s"$head and $last" case init :+ last => init.mkString("", ", ", s", and $last") } s"When `OrganizeImports.groupedImports` is set to `Merge`, renaming a name to multiple" + s" aliases within the same source file is not supported. In this case, '${name.value}' is" + s" renamed to $aliasList." } override def severity: LintSeverity = LintSeverity.Error } diff --combined scalafix-tests/input/src/main/scala-2/test/organizeImports/ExpandRelativePackageObject.scala index 00000000,fa8019b0..b133e16c mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-2/fix/ExpandRelativePackageObject.scala ++ b/scalafix-tests/input/src/main/scala-2/test/organizeImports/ExpandRelativePackageObject.scala @@@ -1,0 -1,10 +1,10 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.expandRelative = true */ -package fix +package test.organizeImports import PackageObject.a object ExpandRelativePackageObject diff --combined scalafix-tests/input/src/main/scala-2/test/organizeImports/ExplicitlyImportedImplicits.scala index 00000000,18b1c804..774d2427 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-2/fix/ExplicitlyImportedImplicits.scala ++ b/scalafix-tests/input/src/main/scala-2/test/organizeImports/ExplicitlyImportedImplicits.scala @@@ -1,0 -1,18 +1,18 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupExplicitlyImportedImplicitsSeparately = true */ -package fix +package test.organizeImports import scala.concurrent.ExecutionContext -import fix.Implicits.b._ +import test.organizeImports.Implicits.b._ import ExecutionContext.Implicits.global -import fix.Implicits.a.{nonImplicit, intImplicit, stringImplicit} +import test.organizeImports.Implicits.a.{nonImplicit, intImplicit, stringImplicit} object ExplicitlyImportedImplicits { def f1()(implicit i: Int) = ??? def f2()(implicit s: String) = ??? f1() f2() } diff --combined scalafix-tests/input/src/main/scala-2/test/organizeImports/PresetDefault.scala index 00000000,dba899e8..f473347c mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-2/fix/PresetDefault.scala ++ b/scalafix-tests/input/src/main/scala-2/test/organizeImports/PresetDefault.scala @@@ -1,0 -1,21 +1,22 @@@ /* rules = [OrganizeImports] OrganizeImports { preset = DEFAULT groupedImports = Merge + removeUnused = false } */ -package fix +package test.organizeImports import scala.collection.mutable import scala.util.Try import java.math.BigDecimal import java.math.BigInteger import java.util.Collections.binarySearch import java.util.Collections.emptyList import javax.management.MXBean -import fix.PresetDefault.a +import test.organizeImports.PresetDefault.a object PresetDefault { val a: Any = ??? } diff --combined scalafix-tests/input/src/main/scala-2/test/organizeImports/PresetIntelliJ_2020_3.scala index 00000000,ee66e39a..1415bc93 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-2/fix/PresetIntelliJ_2020_3.scala ++ b/scalafix-tests/input/src/main/scala-2/test/organizeImports/PresetIntelliJ_2020_3.scala @@@ -1,0 -1,21 +1,22 @@@ /* rules = [OrganizeImports] OrganizeImports { preset = INTELLIJ_2020_3 groupedImports = Explode + removeUnused = false } */ -package fix +package test.organizeImports import scala.collection.mutable import scala.util.Try import java.math.BigDecimal import java.math.BigInteger import java.util.Collections.binarySearch import java.util.Collections.emptyList import javax.management.MXBean -import fix.PresetIntelliJ_2020_3.a +import test.organizeImports.PresetIntelliJ_2020_3.a object PresetIntelliJ_2020_3 { val a: Any = ??? } diff --combined scalafix-tests/input/src/main/scala-2/test/organizeImports/RemoveUnused.scala index 00000000,47ffd9d6..43040f9f mode 000000,100644..100644 --- /dev/null --- a/inputUnusedImports/src/main/scala-2/fix/RemoveUnused.scala ++ b/scalafix-tests/input/src/main/scala-2/test/organizeImports/RemoveUnused.scala @@@ -1,0 -1,19 +1,19 @@@ /* rules = [OrganizeImports] OrganizeImports { groups = ["re:javax?\\.", "scala.", "*"] removeUnused = true } */ -package fix +package test.organizeImports -import fix.UnusedImports.a.{v1, v2} -import fix.UnusedImports.b.v3 -import fix.UnusedImports.c.{v5 => w1, v6 => w2} -import fix.UnusedImports.d.{v7 => unused, _} +import test.organizeImports.UnusedImports.a.{v1, v2} +import test.organizeImports.UnusedImports.b.v3 +import test.organizeImports.UnusedImports.c.{v5 => w1, v6 => w2} +import test.organizeImports.UnusedImports.d.{v7 => unused, _} object RemoveUnused { val x1 = v1 val x2 = w2 val x3 = v8 } diff --combined scalafix-tests/input/src/main/scala-2/test/organizeImports/RemoveUnusedDisabled.scala index 00000000,34d08b63..d839dd34 mode 000000,100644..100644 --- /dev/null --- a/inputUnusedImports/src/main/scala-2/fix/RemoveUnusedDisabled.scala ++ b/scalafix-tests/input/src/main/scala-2/test/organizeImports/RemoveUnusedDisabled.scala @@@ -1,0 -1,21 +1,21 @@@ /* rules = [OrganizeImports] OrganizeImports { groups = ["re:javax?\\.", "scala.", "*"] removeUnused = false } */ -package fix +package test.organizeImports -import fix.UnusedImports.a.{v1, v2} -import fix.UnusedImports.b.v3 -import fix.UnusedImports.c.{v5 => w1, v6 => w2} -import fix.UnusedImports.d.{v7 => unused, _} +import test.organizeImports.UnusedImports.a.{v1, v2} +import test.organizeImports.UnusedImports.b.v3 +import test.organizeImports.UnusedImports.c.{v5 => w1, v6 => w2} +import test.organizeImports.UnusedImports.d.{v7 => unused, _} object RemoveUnusedDisabled { - import fix.UnusedImports.e.v9 + import test.organizeImports.UnusedImports.e.v9 val x1 = v1 val x2 = w2 val x3 = v8 } diff --combined scalafix-tests/input/src/main/scala-2/test/organizeImports/RemoveUnusedLocal.scala index 00000000,85db5211..336d0cbb mode 000000,100644..100644 --- /dev/null --- a/inputUnusedImports/src/main/scala-2/fix/RemoveUnusedLocal.scala ++ b/scalafix-tests/input/src/main/scala-2/test/organizeImports/RemoveUnusedLocal.scala @@@ -1,0 -1,20 +1,20 @@@ /* rules = [OrganizeImports] OrganizeImports { groups = ["re:javax?\\.", "scala.", "*"] removeUnused = true } */ -package fix +package test.organizeImports object RemoveUnusedLocal { import UnusedImports._ import a.{v1, v2} import b.v3 import c.{v5 => w1, v6 => w2} import d.{v7 => unused, _} val x1 = v1 val x2 = w2 val x3 = v8 } diff --combined scalafix-tests/input/src/main/scala-2/test/organizeImports/RemoveUnusedMixed.scala index 00000000,6a848740..030911ed mode 000000,100644..100644 --- /dev/null --- a/inputUnusedImports/src/main/scala-2/fix/RemoveUnusedMixed.scala ++ b/scalafix-tests/input/src/main/scala-2/test/organizeImports/RemoveUnusedMixed.scala @@@ -1,0 -1,20 +1,20 @@@ /* rules = [OrganizeImports] OrganizeImports { groups = ["re:javax?\\.", "scala.", "*"] removeUnused = true } */ -package fix +package test.organizeImports -import fix.UnusedImports.a.{v1, v2} -import fix.UnusedImports.b.v3 -import fix.UnusedImports.c.{v5 => w1, v6 => w2} -import fix.UnusedImports.d.{v7 => unused, _} +import test.organizeImports.UnusedImports.a.{v1, v2} +import test.organizeImports.UnusedImports.b.v3 +import test.organizeImports.UnusedImports.c.{v5 => w1, v6 => w2} +import test.organizeImports.UnusedImports.d.{v7 => unused, _} object RemoveUnusedMixed { - import fix.UnusedImports.e.v9 + import test.organizeImports.UnusedImports.e.v9 val x1 = v1 val x2 = w2 val x3 = v8 } diff --combined scalafix-tests/input/src/main/scala-2/test/organizeImports/RemoveUnusedRelative.scala index 00000000,360ebe66..68926796 mode 000000,100644..100644 --- /dev/null --- a/inputUnusedImports/src/main/scala-2/fix/RemoveUnusedRelative.scala ++ b/scalafix-tests/input/src/main/scala-2/test/organizeImports/RemoveUnusedRelative.scala @@@ -1,0 -1,26 +1,26 @@@ /* rules = [OrganizeImports] OrganizeImports { expandRelative = true groupedImports = Explode groups = ["re:javax?\\.", "scala.", "*"] removeUnused = true } */ -package fix +package test.organizeImports -import fix.UnusedImports.a -import fix.UnusedImports.b -import fix.UnusedImports.c -import fix.UnusedImports.d +import test.organizeImports.UnusedImports.a +import test.organizeImports.UnusedImports.b +import test.organizeImports.UnusedImports.c +import test.organizeImports.UnusedImports.d import a.{v1, v2} import b.v3 import c.{v5 => w1, v6 => w2} import d.{v7 => unused, _} object RemoveUnusedRelative { val x1 = v1 val x2 = w2 val x3 = v8 } diff --combined scalafix-tests/input/src/main/scala-3/test/organizeImports/CoalesceImporteesGivensAndNames.scala index 00000000,bf6fc672..0d6a6fe0 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-3/fix/CoalesceImporteesGivensAndNames.scala ++ b/scalafix-tests/input/src/main/scala-3/test/organizeImports/CoalesceImporteesGivensAndNames.scala @@@ -1,0 -1,14 +1,14 @@@ /* rules = [OrganizeImports] OrganizeImports { groupedImports = Keep coalesceToWildcardImportThreshold = 2 removeUnused = false } */ -package fix +package test.organizeImports -import fix.Givens._ -import fix.Givens.{A, B => B1, C => _, given D, _} +import test.organizeImports.Givens._ +import test.organizeImports.Givens.{A, B => B1, C => _, given D, _} object CoalesceImporteesGivensAndNames diff --combined scalafix-tests/input/src/main/scala-3/test/organizeImports/CoalesceImporteesNoGivens.scala index 00000000,ae931e84..82e3aa7a mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-3/fix/CoalesceImporteesNoGivens.scala ++ b/scalafix-tests/input/src/main/scala-3/test/organizeImports/CoalesceImporteesNoGivens.scala @@@ -1,0 -1,13 +1,13 @@@ /* rules = [OrganizeImports] OrganizeImports { groupedImports = Keep coalesceToWildcardImportThreshold = 2 removeUnused = false } */ -package fix +package test.organizeImports -import fix.Givens.{A, B, C => C1} +import test.organizeImports.Givens.{A, B, C => C1} object CoalesceImporteesNoGivens diff --combined scalafix-tests/input/src/main/scala-3/test/organizeImports/CoalesceImporteesNoGivensNoNames.scala index 00000000,bc9a9124..e91fedb2 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-3/fix/CoalesceImporteesNoGivensNoNames.scala ++ b/scalafix-tests/input/src/main/scala-3/test/organizeImports/CoalesceImporteesNoGivensNoNames.scala @@@ -1,0 -1,13 +1,13 @@@ /* rules = [OrganizeImports] OrganizeImports { groupedImports = Keep coalesceToWildcardImportThreshold = 2 removeUnused = false } */ -package fix +package test.organizeImports -import fix.Givens.{A => A1, B => _, _} +import test.organizeImports.Givens.{A => A1, B => _, _} object CoalesceImporteesNoGivensNoNames diff --combined scalafix-tests/input/src/main/scala-3/test/organizeImports/CoalesceImporteesNoNames.scala index 00000000,63ecb353..9e374ccf mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-3/fix/CoalesceImporteesNoNames.scala ++ b/scalafix-tests/input/src/main/scala-3/test/organizeImports/CoalesceImporteesNoNames.scala @@@ -1,0 -1,14 +1,14 @@@ /* rules = [OrganizeImports] OrganizeImports { groupedImports = Keep coalesceToWildcardImportThreshold = 2 removeUnused = false } */ -package fix +package test.organizeImports -import fix.Givens._ -import fix.Givens.{A => A1, given B, given C} +import test.organizeImports.Givens._ +import test.organizeImports.Givens.{A => A1, given B, given C} object CoalesceImporteesNoNames diff --combined scalafix-tests/input/src/main/scala-3/test/organizeImports/DeduplicateGivenImportees.scala index 00000000,7a469b94..9005f193 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-3/fix/DeduplicateGivenImportees.scala ++ b/scalafix-tests/input/src/main/scala-3/test/organizeImports/DeduplicateGivenImportees.scala @@@ -1,0 -1,13 +1,13 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix +package test.organizeImports -import fix.Givens._ -import fix.Givens.{given A, given B} -import fix.Givens.given A -import fix.Givens.given C -import fix.Givens.given C +import test.organizeImports.Givens._ +import test.organizeImports.Givens.{given A, given B} +import test.organizeImports.Givens.given A +import test.organizeImports.Givens.given C +import test.organizeImports.Givens.given C object DeduplicateGivenImportees diff --combined scalafix-tests/input/src/main/scala-3/test/organizeImports/ExpandGiven.scala index 00000000,b92ca178..f23f6848 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-3/fix/ExpandGiven.scala ++ b/scalafix-tests/input/src/main/scala-3/test/organizeImports/ExpandGiven.scala @@@ -1,0 -1,12 +1,12 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix +package test.organizeImports -import fix.GivenImports.Beta -import fix.GivenImports.Alpha -import fix.GivenImports.{given Beta, given Alpha} +import test.organizeImports.GivenImports.Beta +import test.organizeImports.GivenImports.Alpha +import test.organizeImports.GivenImports.{given Beta, given Alpha} import scala.util.Either object ExpandGiven diff --combined scalafix-tests/input/src/main/scala-3/test/organizeImports/ExpandUnimportGiven.scala index 00000000,eb31b93f..457db872 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-3/fix/ExpandUnimportGiven.scala ++ b/scalafix-tests/input/src/main/scala-3/test/organizeImports/ExpandUnimportGiven.scala @@@ -1,0 -1,14 +1,14 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix +package test.organizeImports -import fix.GivenImports.Beta -import fix.GivenImports.Alpha -import fix.GivenImports.given Alpha -import fix.GivenImports.{alpha => _} -import fix.GivenImports.{beta => _, given} +import test.organizeImports.GivenImports.Beta +import test.organizeImports.GivenImports.Alpha +import test.organizeImports.GivenImports.given Alpha +import test.organizeImports.GivenImports.{alpha => _} +import test.organizeImports.GivenImports.{beta => _, given} import scala.util.Either object ExpandUnimportGiven diff --combined scalafix-tests/input/src/main/scala-3/test/organizeImports/GroupedGivenImportsMergeUnimports.scala index 00000000,35b1f2b7..f34b7189 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-3/fix/GroupedGivenImportsMergeUnimports.scala ++ b/scalafix-tests/input/src/main/scala-3/test/organizeImports/GroupedGivenImportsMergeUnimports.scala @@@ -1,0 -1,19 +1,19 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Merge */ -package fix +package test.organizeImports -import fix.GivenImports._ -import fix.GivenImports.{alpha => _, given} -import fix.GivenImports.{given Beta} -import fix.GivenImports.{gamma => _, given} -import fix.GivenImports.{given Zeta} +import test.organizeImports.GivenImports._ +import test.organizeImports.GivenImports.{alpha => _, given} +import test.organizeImports.GivenImports.{given Beta} +import test.organizeImports.GivenImports.{gamma => _, given} +import test.organizeImports.GivenImports.{given Zeta} -import fix.GivenImports2.{alpha => _} -import fix.GivenImports2.{beta => _} -import fix.GivenImports2.{given Gamma} -import fix.GivenImports2.{given Zeta} +import test.organizeImports.GivenImports2.{alpha => _} +import test.organizeImports.GivenImports2.{beta => _} +import test.organizeImports.GivenImports2.{given Gamma} +import test.organizeImports.GivenImports2.{given Zeta} object GroupedGivenImportsMergeUnimports diff --combined scalafix-tests/input/src/main/scala-3/test/organizeImports/GroupedImportsAggressiveMergeGivenAll.scala index 00000000,4ab1627a..bb0632fc mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-3/fix/GroupedImportsAggressiveMergeGivenAll.scala ++ b/scalafix-tests/input/src/main/scala-3/test/organizeImports/GroupedImportsAggressiveMergeGivenAll.scala @@@ -1,0 -1,23 +1,23 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = AggressiveMerge */ -package fix +package test.organizeImports -import fix.MergeImports.Wildcard1._ -import fix.MergeImports.Wildcard1.{a => _, _} -import fix.MergeImports.Wildcard1.{b => B} -import fix.MergeImports.Wildcard1.{c => _, _} -import fix.MergeImports.Wildcard1.d +import test.organizeImports.MergeImports.Wildcard1._ +import test.organizeImports.MergeImports.Wildcard1.{a => _, _} +import test.organizeImports.MergeImports.Wildcard1.{b => B} +import test.organizeImports.MergeImports.Wildcard1.{c => _, _} +import test.organizeImports.MergeImports.Wildcard1.d -import fix.GivenImports._ -import fix.GivenImports.{Alpha, Beta, Zeta} -import fix.GivenImports.{given Alpha, given Beta, given Zeta} -import fix.GivenImports.given +import test.organizeImports.GivenImports._ +import test.organizeImports.GivenImports.{Alpha, Beta, Zeta} +import test.organizeImports.GivenImports.{given Alpha, given Beta, given Zeta} +import test.organizeImports.GivenImports.given -import fix.MergeImports.Wildcard2._ -import fix.MergeImports.Wildcard2.{a, b} +import test.organizeImports.MergeImports.Wildcard2._ +import test.organizeImports.MergeImports.Wildcard2.{a, b} object GroupedImportsAggressiveMergeGivenAll diff --combined scalafix-tests/input/src/main/scala-3/test/organizeImports/MergeGiven.scala index 00000000,5d5204c9..a7d628d9 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala-3/fix/MergeGiven.scala ++ b/scalafix-tests/input/src/main/scala-3/test/organizeImports/MergeGiven.scala @@@ -1,0 -1,14 +1,14 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Merge */ -package fix +package test.organizeImports -import fix.GivenImports.Beta -import fix.GivenImports.Alpha -import fix.GivenImports.{given Beta} -import fix.GivenImports.{given Alpha} +import test.organizeImports.GivenImports.Beta +import test.organizeImports.GivenImports.Alpha +import test.organizeImports.GivenImports.{given Beta} +import test.organizeImports.GivenImports.{given Alpha} import scala.util.Either object MergeGiven diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/AlreadyOrganized.scala index 00000000,6488ed44..392a2d28 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/AlreadyOrganized.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/AlreadyOrganized.scala @@@ -1,0 -1,15 +1,15 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Merge */ -package fix +package test.organizeImports import scala.collection.mutable.{ ArrayBuffer, Map, Queue, Set } object AlreadyOrganized diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/BlankLinesManual.scala index 00000000,060d4a17..593975a7 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/BlankLinesManual.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/BlankLinesManual.scala @@@ -1,0 -1,21 +1,21 @@@ /* rules = [OrganizeImports] OrganizeImports { blankLines = Manual groups = [ "re:javax?\\." "scala." "---" "*" ] removeUnused = false } */ -package fix +package test.organizeImports import scala.collection.mutable import java.util.Arrays import sun.misc.Unsafe object BlankLinesManual diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/CoalesceImportees.scala index 00000000,8c1e9f7f..6a35ea97 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/CoalesceImportees.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/CoalesceImportees.scala @@@ -1,0 -1,16 +1,16 @@@ /* rules = [OrganizeImports] OrganizeImports { groupedImports = Keep coalesceToWildcardImportThreshold = 3 removeUnused = false } */ -package fix +package test.organizeImports import scala.collection.immutable.{Seq, Map, Vector} import scala.collection.mutable.{Buffer, Seq, Map, Set} import scala.concurrent.{Await, Channel => Ch, Future, Promise, duration} import scala.util.{Either, Random => _, Try, Success, Failure} object CoalesceImportees diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/CurlyBracedSingleImportee.scala index 00000000,66eb557d..9f8255a6 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/CurlyBracedSingleImportee.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/CurlyBracedSingleImportee.scala @@@ -1,0 -1,10 +1,10 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix +package test.organizeImports import scala.collection.{Map} import scala.collection.{Set => ImmutableSet} object CurlyBracedSingleImportee diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/DeduplicateImportees.scala index 00000000,8b7fde25..4150b056 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/DeduplicateImportees.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/DeduplicateImportees.scala @@@ -1,0 -1,12 +1,12 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix +package test.organizeImports import scala.collection.immutable.Vector import scala.collection.immutable.{Map => Dict} import scala.collection.immutable.{Set => _, Map => Dict, _} import scala.collection.immutable.{Map => Dict, Vector} object DeduplicateImportees diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/ExpandRelative.scala index 00000000,4f0081d7..8b900b7a mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/ExpandRelative.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/ExpandRelative.scala @@@ -1,0 -1,12 +1,12 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.expandRelative = true */ -package fix +package test.organizeImports import scala.util import util.control import control.NonFatal object ExpandRelative diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/ExpandRelativeEmptyPackage.scala index 00000000,1ffe6ba6..cfa3dd50 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/ExpandRelativeRootPackage.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/ExpandRelativeEmptyPackage.scala @@@ -1,0 -1,22 +1,22 @@@ /* rules = [OrganizeImports] OrganizeImports { expandRelative = true groupedImports = Explode removeUnused = false } */ import P._ import Q.x import Q._ object P { object x } object Q { object x object y } -object ExpandRelativeRootPackage +object ExpandRelativeEmptyPackage diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/ExpandRelativeMultiGroups.scala index 00000000,e6e5a1cc..7fa9ce00 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/ExpandRelativeMultiGroups.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/ExpandRelativeMultiGroups.scala @@@ -1,0 -1,14 +1,14 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.expandRelative = true */ -package fix +package test.organizeImports import scala.util import java.time.Clock import util.control import javax.management.JMX import control.NonFatal object ExpandRelativeMultiGroups diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/ExpandRelativeQuotedIdent.scala index 00000000,1ce6c7dc..834cea54 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/ExpandRelativeQuotedIdent.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/ExpandRelativeQuotedIdent.scala @@@ -1,0 -1,13 +1,13 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.expandRelative = true */ -package fix +package test.organizeImports import QuotedIdent.`a.b` import QuotedIdent.`macro` import `a.b`.c import `a.b`.`{ d }` object ExpandRelativeQuotedIdent diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/ExpandRelativeRootPackage.scala index 00000000,241c3e75..0b096c22 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/ExpandRelativeRootPackage.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/ExpandRelativeRootPackage.scala @@@ -1,0 -1,13 +1,13 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.expandRelative = true */ -package fix +package test.organizeImports import _root_.scala.collection.mutable.ArrayBuffer import _root_.scala.util import util.control import control.NonFatal object ExpandRelativeRootPackage diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/ExplodeImportsFormatPreserving.scala index 00000000,8b769d1b..179b9c68 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/ExplodeImportsFormatPreserving.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/ExplodeImportsFormatPreserving.scala @@@ -1,0 -1,12 +1,12 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Explode */ -package fix +package test.organizeImports -import fix.ExplodeImports.FormatPreserving.g1.{ a, b } -import fix.ExplodeImports.FormatPreserving.g2.{ c => C, _ } +import test.organizeImports.ExplodeImports.FormatPreserving.g1.{ a, b } +import test.organizeImports.ExplodeImports.FormatPreserving.g2.{ c => C, _ } object ExplodeImportsFormatPreserving diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GlobalImportsOnly.scala index 00000000,58dc4636..76d13478 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GlobalImportsOnly.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GlobalImportsOnly.scala @@@ -1,0 -1,17 +1,17 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix +package test.organizeImports import scala.collection.mutable import scala.concurrent.duration.Duration import java.time.Clock import java.sql.DriverManager object GlobalImportsOnly // These imports should not be organized import java.time.Duration, java.sql.Connection object Foo diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsAggressiveMergeWildcard.scala index 00000000,6cfa22d8..e31c7082 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupedImportsAggressiveMergeWildcard.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsAggressiveMergeWildcard.scala @@@ -1,0 -1,17 +1,17 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = AggressiveMerge */ -package fix +package test.organizeImports -import fix.MergeImports.Wildcard1._ -import fix.MergeImports.Wildcard1.{a => _, _} -import fix.MergeImports.Wildcard1.{b => B} -import fix.MergeImports.Wildcard1.{c => _, _} -import fix.MergeImports.Wildcard1.d +import test.organizeImports.MergeImports.Wildcard1._ +import test.organizeImports.MergeImports.Wildcard1.{a => _, _} +import test.organizeImports.MergeImports.Wildcard1.{b => B} +import test.organizeImports.MergeImports.Wildcard1.{c => _, _} +import test.organizeImports.MergeImports.Wildcard1.d -import fix.MergeImports.Wildcard2._ -import fix.MergeImports.Wildcard2.{a, b} +import test.organizeImports.MergeImports.Wildcard2._ +import test.organizeImports.MergeImports.Wildcard2.{a, b} object GroupedImportsAggressiveMergeWildcard diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsExplode.scala index 00000000,798752dc..059af75c mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupedImportsExplode.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsExplode.scala @@@ -1,0 -1,9 +1,9 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix +package test.organizeImports import scala.collection.mutable.{ArrayBuffer, Buffer, StringBuilder} object GroupedImportsExplode diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsExplodeMixed.scala index 00000000,9c208061..9d438645 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupedImportsExplodeMixed.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsExplodeMixed.scala @@@ -1,0 -1,10 +1,10 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix +package test.organizeImports import scala.collection.immutable._ import scala.collection.mutable.{Map, Seq => S, Buffer => _, _} object GroupedImportsExplodeMixed diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsExplodeUnimport.scala index 00000000,83dfdb0e..acd497ce mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupedImportsExplodeUnimport.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsExplodeUnimport.scala @@@ -1,0 -1,9 +1,9 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix +package test.organizeImports import scala.collection.{Seq => _, _} object GroupedImportExplodeUnimport diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsKeep.scala index 00000000,dfcbb195..7ba18bd9 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupedImportsKeep.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsKeep.scala @@@ -1,0 -1,11 +1,11 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Keep */ -package fix +package test.organizeImports import scala.collection.mutable.{ArrayBuffer, Buffer} import scala.collection.mutable.StringBuilder object GroupedImportsKeep diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsMerge.scala index 00000000,ebb06c11..21761dfa mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupedImportsMerge.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsMerge.scala @@@ -1,0 -1,12 +1,12 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Merge */ -package fix +package test.organizeImports import scala.collection.mutable.Buffer import scala.collection.mutable.StringBuilder import scala.collection.mutable.ArrayBuffer object GroupedImportsMerge diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsMergeDedup.scala index 00000000,c7fcd5ed..15fe853f mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupedImportsMergeDedup.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsMergeDedup.scala @@@ -1,0 -1,15 +1,15 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Merge */ -package fix +package test.organizeImports -import fix.MergeImports.Dedup.a -import fix.MergeImports.Dedup.a -import fix.MergeImports.Dedup.{b => b1} -import fix.MergeImports.Dedup.{b => b1} -import fix.MergeImports.Dedup.{c => _} -import fix.MergeImports.Dedup.{c => _} +import test.organizeImports.MergeImports.Dedup.a +import test.organizeImports.MergeImports.Dedup.a +import test.organizeImports.MergeImports.Dedup.{b => b1} +import test.organizeImports.MergeImports.Dedup.{b => b1} +import test.organizeImports.MergeImports.Dedup.{c => _} +import test.organizeImports.MergeImports.Dedup.{c => _} object GroupedImportsMergeDedup diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsMergeRenames.scala index 00000000,3718c2a9..3a4c2cc6 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupedImportsMergeRenames.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsMergeRenames.scala @@@ -1,0 -1,19 +1,19 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Merge */ -package fix +package test.organizeImports -import fix.MergeImports.Rename1.{a => A} -import fix.MergeImports.Rename1.{b => B} -import fix.MergeImports.Rename1.c -import fix.MergeImports.Rename1.d +import test.organizeImports.MergeImports.Rename1.{a => A} +import test.organizeImports.MergeImports.Rename1.{b => B} +import test.organizeImports.MergeImports.Rename1.c +import test.organizeImports.MergeImports.Rename1.d -import fix.MergeImports.Rename2.a -import fix.MergeImports.Rename2.{a => A} -import fix.MergeImports.Rename2.b -import fix.MergeImports.Rename2.{b => B} -import fix.MergeImports.Rename2.c +import test.organizeImports.MergeImports.Rename2.a +import test.organizeImports.MergeImports.Rename2.{a => A} +import test.organizeImports.MergeImports.Rename2.b +import test.organizeImports.MergeImports.Rename2.{b => B} +import test.organizeImports.MergeImports.Rename2.c object GroupedImportsMergeRenames diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsMergeUnimports.scala index 00000000,b1275c73..51121366 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupedImportsMergeUnimports.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsMergeUnimports.scala @@@ -1,0 -1,18 +1,18 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Merge */ -package fix +package test.organizeImports -import fix.MergeImports.Unimport1.{a => _, _} -import fix.MergeImports.Unimport1.{b => B} -import fix.MergeImports.Unimport1.{c => _, _} -import fix.MergeImports.Unimport1.d +import test.organizeImports.MergeImports.Unimport1.{a => _, _} +import test.organizeImports.MergeImports.Unimport1.{b => B} +import test.organizeImports.MergeImports.Unimport1.{c => _, _} +import test.organizeImports.MergeImports.Unimport1.d -import fix.MergeImports.Unimport2.{a => _} -import fix.MergeImports.Unimport2.{b => _} -import fix.MergeImports.Unimport2.{c => C} -import fix.MergeImports.Unimport2.d +import test.organizeImports.MergeImports.Unimport2.{a => _} +import test.organizeImports.MergeImports.Unimport2.{b => _} +import test.organizeImports.MergeImports.Unimport2.{c => C} +import test.organizeImports.MergeImports.Unimport2.d object GroupedImportsMergeUnimports diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsMergeWildcard.scala index 00000000,0133646c..b8114850 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupedImportsMergeWildcard.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupedImportsMergeWildcard.scala @@@ -1,0 -1,17 +1,17 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Merge */ -package fix +package test.organizeImports -import fix.MergeImports.Wildcard1._ -import fix.MergeImports.Wildcard1.{a => _, _} -import fix.MergeImports.Wildcard1.{b => B} -import fix.MergeImports.Wildcard1.{c => _, _} -import fix.MergeImports.Wildcard1.d +import test.organizeImports.MergeImports.Wildcard1._ +import test.organizeImports.MergeImports.Wildcard1.{a => _, _} +import test.organizeImports.MergeImports.Wildcard1.{b => B} +import test.organizeImports.MergeImports.Wildcard1.{c => _, _} +import test.organizeImports.MergeImports.Wildcard1.d -import fix.MergeImports.Wildcard2._ -import fix.MergeImports.Wildcard2.{a, b} +import test.organizeImports.MergeImports.Wildcard2._ +import test.organizeImports.MergeImports.Wildcard2.{a, b} object GroupedImportsMergeWildcard diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/Groups.scala index 00000000,ee587bbf..4f0a8097 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/Groups.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/Groups.scala @@@ -1,0 -1,14 +1,14 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groups = ["re:javax?\\.", "*", "scala."] */ -package fix +package test.organizeImports import java.time.Clock import scala.collection.JavaConverters._ import sun.misc.Unsafe import scala.concurrent.ExecutionContext import javax.net.ssl object Groups diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/GroupsLongestMatch.scala index 00000000,d9a6543e..5b7182b6 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/GroupsLongestMatch.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/GroupsLongestMatch.scala @@@ -1,0 -1,16 +1,16 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groups = ["re:javax?\\.", "scala.", "scala.util.", "*"] */ -package fix +package test.organizeImports import java.time.Clock import scala.collection.JavaConverters._ import sun.misc.Unsafe import scala.concurrent.ExecutionContext import javax.net.ssl import scala.util.control.NonFatal import scala.util.Random object GroupsLongestMatch diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/ImportsOrderAsciiPreformatted.scala index 00000000,d4273848..19a62636 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/ImportsOrderAsciiPreformatted.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/ImportsOrderAsciiPreformatted.scala @@@ -1,0 -1,14 +1,14 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Keep */ -package fix +package test.organizeImports import scala.collection.immutable.{ Map, Seq } import scala.collection.immutable.{Vector, IntMap} object ImportsOrderAsciiPreformatted diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/ImportsOrderKeep.scala index 00000000,ca933944..7e08de4d mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/ImportsOrderKeep.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/ImportsOrderKeep.scala @@@ -1,0 -1,20 +1,20 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports { groupedImports = Keep importSelectorsOrder = Keep importsOrder = Keep } */ -package fix +package test.organizeImports import scala.concurrent.ExecutionContext.Implicits._ -import fix.QuotedIdent.`a.b`.`{ d }`.e +import test.organizeImports.QuotedIdent.`a.b`.`{ d }`.e import scala.concurrent.duration -import fix.QuotedIdent._ +import test.organizeImports.QuotedIdent._ import scala.concurrent._ -import fix.QuotedIdent.`a.b`.{c => _, _} +import test.organizeImports.QuotedIdent.`a.b`.{c => _, _} import scala.concurrent.{Promise, Future} object ImportsOrderKeep diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/ImportsOrderSymbolsFirst.scala index 00000000,cf2e42d8..ee3b2db0 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/ImportsOrderSymbolsFirst.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/ImportsOrderSymbolsFirst.scala @@@ -1,0 -1,21 +1,21 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports { groupedImports = Keep importSelectorsOrder = Keep importsOrder = SymbolsFirst } */ -package fix +package test.organizeImports import scala.concurrent.ExecutionContext.Implicits._ import scala.concurrent._ import scala.concurrent.duration import scala.concurrent.{Promise, Future} -import fix.QuotedIdent.`a.b`.`{ d }`.e -import fix.QuotedIdent.`a.b`.{c => _, _} -import fix.QuotedIdent._ +import test.organizeImports.QuotedIdent.`a.b`.`{ d }`.e +import test.organizeImports.QuotedIdent.`a.b`.{c => _, _} +import test.organizeImports.QuotedIdent._ object ImportsOrderSymbolsFirst diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/ImportsOrderSymbolsFirstPreformatted.scala index 00000000,0c1d9a3d..686e3358 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/ImportsOrderSymbolsFirstPreformatted.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/ImportsOrderSymbolsFirstPreformatted.scala @@@ -1,0 -1,17 +1,17 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports { groupedImports = Keep importsOrder = SymbolsFirst } */ -package fix +package test.organizeImports import scala.collection.immutable.{ Map, Seq } import scala.collection.immutable.{Vector, IntMap} object ImportsOrderSymbolsFirstPreformatted diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/Inheritance.scala index 00000000,97cfeafb..b83a18e2 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/Inheritance.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/Inheritance.scala @@@ -1,0 -1,10 +1,10 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.expandRelative = true */ -package fix +package test.organizeImports import SomeObject.field.any object Inheritance diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/MergeImportsFormatPreserving.scala index 00000000,2ebc9863..9be512c1 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/MergeImportsFormatPreserving.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/MergeImportsFormatPreserving.scala @@@ -1,0 -1,13 +1,13 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Merge */ -package fix +package test.organizeImports -import fix.MergeImports.FormatPreserving.g1.{ a, b } -import fix.MergeImports.FormatPreserving.g2._ -import fix.MergeImports.FormatPreserving.g2.{ d => D } +import test.organizeImports.MergeImports.FormatPreserving.g1.{ a, b } +import test.organizeImports.MergeImports.FormatPreserving.g2._ +import test.organizeImports.MergeImports.FormatPreserving.g2.{ d => D } object MergeImportsFormatPreserving diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/NoImports.scala index 00000000,240aeaa9..b966bbbe mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/NoImports.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/NoImports.scala @@@ -1,0 -1,7 +1,7 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix +package test.organizeImports object NoImports diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/OrganizeImportsRootPackage.scala index 00000000,d8cca9bd..d8cca9bd mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/OrganizeImportsRootPackage.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/OrganizeImportsRootPackage.scala @@@ -1,0 -1,12 +1,12 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groups = ["re:javax?\\.", "*", "scala."] */ import java.time.Clock import scala.collection.JavaConverters._ import sun.misc.Unsafe import scala.concurrent.ExecutionContext import javax.net.ssl object OrganizeImportsRootPackage diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/RelativeImports.scala index 00000000,8c11fef6..7e3b0084 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/RelativeImports.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/RelativeImports.scala @@@ -1,0 -1,13 +1,13 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groups = ["scala.", "*"] */ -package fix +package test.organizeImports import scala.util import sun.misc.Unsafe import util.control import control.NonFatal object RelativeImports diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/SortImportSelectorsAscii.scala index 00000000,b6e22d88..59e21b6d mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/SortImportSelectorsAscii.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/SortImportSelectorsAscii.scala @@@ -1,0 -1,10 +1,10 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groupedImports = Keep */ -package fix +package test.organizeImports import scala.{Any, ::, collection, :+, Predef, concurrent} object SortImportSelectorsAscii diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/SortImportSelectorsKeep.scala index 00000000,b2d1546c..ddd5a19f mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/SortImportSelectorsKeep.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/SortImportSelectorsKeep.scala @@@ -1,0 -1,13 +1,13 @@@ /* rules = OrganizeImports OrganizeImports { importSelectorsOrder = Keep groupedImports = Keep removeUnused = false } */ -package fix +package test.organizeImports import scala.{Any, ::, collection, :+, Predef, concurrent} object SortImportSelectorsKeep diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/SortImportSelectorsSymbolsFirst.scala index 00000000,97a04fae..0db2501b mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/SortImportSelectorsSymbolsFirst.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/SortImportSelectorsSymbolsFirst.scala @@@ -1,0 -1,13 +1,13 @@@ /* rules = [OrganizeImports] OrganizeImports { importSelectorsOrder = SymbolsFirst groupedImports = Keep removeUnused = false } */ -package fix +package test.organizeImports import scala.{Any, ::, collection, :+, Predef, concurrent} object SortImportSelectorsSymbolsFirst diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/Suppression.scala index 00000000,6cea83e4..deb9f5d8 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/Suppression.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/Suppression.scala @@@ -1,0 -1,16 +1,16 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groups = ["re:javax?\\.", "*", "scala."] */ -package fix +package test.organizeImports // scalafix:off import java.time.Clock import scala.collection.JavaConverters._ import sun.misc.Unsafe import scala.concurrent.ExecutionContext import javax.net.ssl // scalafix:on object Suppression diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/nested/NestedPackage.scala index 00000000,af646ea9..661c26d1 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/nested/NestedPackage.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/nested/NestedPackage.scala @@@ -1,0 -1,15 +1,15 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false OrganizeImports.groups = ["re:javax?\\.", "*", "scala."] */ -package fix +package test.organizeImports package nested import java.time.Clock import scala.collection.JavaConverters._ import sun.misc.Unsafe import scala.concurrent.ExecutionContext import javax.net.ssl object OrganizeImportsNestedPackage diff --combined scalafix-tests/input/src/main/scala/test/organizeImports/nested/NestedPackageWithBraces.scala index 00000000,e89f75b4..600c7573 mode 000000,100644..100644 --- /dev/null --- a/input/src/main/scala/fix/nested/NestedPackageWithBraces.scala ++ b/scalafix-tests/input/src/main/scala/test/organizeImports/nested/NestedPackageWithBraces.scala @@@ -1,0 -1,15 +1,15 @@@ /* rules = [OrganizeImports] OrganizeImports.removeUnused = false */ -package fix { +package test.organizeImports { package nested { import java.time.Clock import scala.collection.JavaConverters._ import sun.misc.Unsafe import scala.concurrent.ExecutionContext import javax.net.ssl object NestedPackageWithBraces } } diff --combined scalafix-tests/output/src/main/scala-3/test/organizeImports/CoalesceImporteesGivensAndNames.scala index 00000000,a0612f7c..e9530cea mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala-3/fix/CoalesceImporteesGivensAndNames.scala ++ b/scalafix-tests/output/src/main/scala-3/test/organizeImports/CoalesceImporteesGivensAndNames.scala @@@ -1,0 -1,6 +1,6 @@@ -package fix +package test.organizeImports -import fix.Givens._ -import fix.Givens.{B => B1, C => _, _, given} +import test.organizeImports.Givens._ +import test.organizeImports.Givens.{B => B1, C => _, _, given} object CoalesceImporteesGivensAndNames diff --combined scalafix-tests/output/src/main/scala-3/test/organizeImports/CoalesceImporteesNoGivens.scala index 00000000,40393d12..b5bbceec mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala-3/fix/CoalesceImporteesNoGivens.scala ++ b/scalafix-tests/output/src/main/scala-3/test/organizeImports/CoalesceImporteesNoGivens.scala @@@ -1,0 -1,5 +1,5 @@@ -package fix +package test.organizeImports -import fix.Givens.{C => C1, _} +import test.organizeImports.Givens.{C => C1, _} object CoalesceImporteesNoGivens diff --combined scalafix-tests/output/src/main/scala-3/test/organizeImports/CoalesceImporteesNoGivensNoNames.scala index 00000000,eb3e6d24..7d440196 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala-3/fix/CoalesceImporteesNoGivensNoNames.scala ++ b/scalafix-tests/output/src/main/scala-3/test/organizeImports/CoalesceImporteesNoGivensNoNames.scala @@@ -1,0 -1,5 +1,5 @@@ -package fix +package test.organizeImports -import fix.Givens.{A => A1, B => _, _} +import test.organizeImports.Givens.{A => A1, B => _, _} object CoalesceImporteesNoGivensNoNames diff --combined scalafix-tests/output/src/main/scala-3/test/organizeImports/CoalesceImporteesNoNames.scala index 00000000,e9a3b2db..c6a2d294 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala-3/fix/CoalesceImporteesNoNames.scala ++ b/scalafix-tests/output/src/main/scala-3/test/organizeImports/CoalesceImporteesNoNames.scala @@@ -1,0 -1,6 +1,6 @@@ -package fix +package test.organizeImports -import fix.Givens._ -import fix.Givens.{A => A1, given} +import test.organizeImports.Givens._ +import test.organizeImports.Givens.{A => A1, given} object CoalesceImporteesNoNames diff --combined scalafix-tests/output/src/main/scala-3/test/organizeImports/DeduplicateGivenImportees.scala index 00000000,9657f0bd..67b6cb5c mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala-3/fix/DeduplicateGivenImportees.scala ++ b/scalafix-tests/output/src/main/scala-3/test/organizeImports/DeduplicateGivenImportees.scala @@@ -1,0 -1,8 +1,8 @@@ -package fix +package test.organizeImports -import fix.Givens._ -import fix.Givens.given A -import fix.Givens.given B -import fix.Givens.given C +import test.organizeImports.Givens._ +import test.organizeImports.Givens.given A +import test.organizeImports.Givens.given B +import test.organizeImports.Givens.given C object DeduplicateGivenImportees diff --combined scalafix-tests/output/src/main/scala-3/test/organizeImports/ExpandGiven.scala index 00000000,b68c136a..e5e028ac mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala-3/fix/ExpandGiven.scala ++ b/scalafix-tests/output/src/main/scala-3/test/organizeImports/ExpandGiven.scala @@@ -1,0 -1,10 +1,10 @@@ -package fix +package test.organizeImports -import fix.GivenImports.Alpha -import fix.GivenImports.Beta -import fix.GivenImports.given Alpha -import fix.GivenImports.given Beta +import test.organizeImports.GivenImports.Alpha +import test.organizeImports.GivenImports.Beta +import test.organizeImports.GivenImports.given Alpha +import test.organizeImports.GivenImports.given Beta import scala.util.Either object ExpandGiven diff --combined scalafix-tests/output/src/main/scala-3/test/organizeImports/ExpandUnimportGiven.scala index 00000000,1d34dbd2..132be591 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala-3/fix/ExpandUnimportGiven.scala ++ b/scalafix-tests/output/src/main/scala-3/test/organizeImports/ExpandUnimportGiven.scala @@@ -1,0 -1,11 +1,11 @@@ -package fix +package test.organizeImports -import fix.GivenImports.Alpha -import fix.GivenImports.Beta -import fix.GivenImports.given Alpha -import fix.GivenImports.{alpha => _} -import fix.GivenImports.{beta => _, given} +import test.organizeImports.GivenImports.Alpha +import test.organizeImports.GivenImports.Beta +import test.organizeImports.GivenImports.given Alpha +import test.organizeImports.GivenImports.{alpha => _} +import test.organizeImports.GivenImports.{beta => _, given} import scala.util.Either object ExpandUnimportGiven diff --combined scalafix-tests/output/src/main/scala-3/test/organizeImports/GroupedGivenImportsMergeUnimports.scala index 00000000,4ca4060d..4a1a27b2 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala-3/fix/GroupedGivenImportsMergeUnimports.scala ++ b/scalafix-tests/output/src/main/scala-3/test/organizeImports/GroupedGivenImportsMergeUnimports.scala @@@ -1,0 -1,8 +1,8 @@@ -package fix +package test.organizeImports -import fix.GivenImports._ -import fix.GivenImports.{gamma => _, given Beta, given Zeta, given} -import fix.GivenImports2.{alpha => _, beta => _} -import fix.GivenImports2.{given Gamma, given Zeta} +import test.organizeImports.GivenImports._ +import test.organizeImports.GivenImports.{gamma => _, given Beta, given Zeta, given} +import test.organizeImports.GivenImports2.{alpha => _, beta => _} +import test.organizeImports.GivenImports2.{given Gamma, given Zeta} object GroupedGivenImportsMergeUnimports diff --combined scalafix-tests/output/src/main/scala-3/test/organizeImports/GroupedImportsAggressiveMergeGivenAll.scala index 00000000,4a5fdfc1..2c5436cc mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala-3/fix/GroupedImportsAggressiveMergeGivenAll.scala ++ b/scalafix-tests/output/src/main/scala-3/test/organizeImports/GroupedImportsAggressiveMergeGivenAll.scala @@@ -1,0 -1,10 +1,10 @@@ -package fix +package test.organizeImports -import fix.GivenImports._ -import fix.GivenImports.given -import fix.MergeImports.Wildcard1._ -import fix.MergeImports.Wildcard1.{b => B} -import fix.MergeImports.Wildcard2._ +import test.organizeImports.GivenImports._ +import test.organizeImports.GivenImports.given +import test.organizeImports.MergeImports.Wildcard1._ +import test.organizeImports.MergeImports.Wildcard1.{b => B} +import test.organizeImports.MergeImports.Wildcard2._ object GroupedImportsAggressiveMergeGivenAll diff --combined scalafix-tests/output/src/main/scala-3/test/organizeImports/MergeGiven.scala index 00000000,dfef4011..b02b7e82 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala-3/fix/MergeGiven.scala ++ b/scalafix-tests/output/src/main/scala-3/test/organizeImports/MergeGiven.scala @@@ -1,0 -1,8 +1,8 @@@ -package fix +package test.organizeImports -import fix.GivenImports.{Alpha, Beta} -import fix.GivenImports.{given Alpha, given Beta} +import test.organizeImports.GivenImports.{Alpha, Beta} +import test.organizeImports.GivenImports.{given Alpha, given Beta} import scala.util.Either object MergeGiven diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/AlreadyOrganized.scala index 00000000,a40177b9..8c4fbc1e mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/AlreadyOrganized.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/AlreadyOrganized.scala @@@ -1,0 -1,10 +1,10 @@@ -package fix +package test.organizeImports import scala.collection.mutable.{ ArrayBuffer, Map, Queue, Set } object AlreadyOrganized diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/BlankLinesManual.scala index 00000000,ee2a2d17..23496588 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/BlankLinesManual.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/BlankLinesManual.scala @@@ -1,0 -1,8 +1,8 @@@ -package fix +package test.organizeImports import java.util.Arrays import scala.collection.mutable import sun.misc.Unsafe object BlankLinesManual diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/CoalesceImportees.scala index 00000000,4023264f..fd90a9de mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/CoalesceImportees.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/CoalesceImportees.scala @@@ -1,0 -1,8 +1,8 @@@ -package fix +package test.organizeImports import scala.collection.immutable.{Map, Seq, Vector} import scala.collection.mutable._ import scala.concurrent.{Channel => Ch, _} import scala.util.{Random => _, _} object CoalesceImportees diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/CurlyBracedSingleImportee.scala index 00000000,2a696255..4a299624 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/CurlyBracedSingleImportee.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/CurlyBracedSingleImportee.scala @@@ -1,0 -1,6 +1,6 @@@ -package fix +package test.organizeImports import scala.collection.Map import scala.collection.{Set => ImmutableSet} object CurlyBracedSingleImportee diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/DeduplicateImportees.scala index 00000000,858589e5..1264c587 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/DeduplicateImportees.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/DeduplicateImportees.scala @@@ -1,0 -1,7 +1,7 @@@ -package fix +package test.organizeImports import scala.collection.immutable.Vector import scala.collection.immutable.{Map => Dict} import scala.collection.immutable.{Set => _, _} object DeduplicateImportees diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelative.scala index 00000000,55059c5e..25417176 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ExpandRelative.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelative.scala @@@ -1,0 -1,7 +1,7 @@@ -package fix +package test.organizeImports import scala.util import scala.util.control import scala.util.control.NonFatal object ExpandRelative diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelativeEmptyPackage.scala index 00000000,6422996b..9db51822 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/ExpandRelativeRootPackage.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelativeEmptyPackage.scala @@@ -1,0 -1,14 +1,14 @@@ import P._ import Q._ import Q.x object P { object x } object Q { object x object y } -object ExpandRelativeRootPackage +object ExpandRelativeEmptyPackage diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelativeMultiGroups.scala index 00000000,965367df..ab5f229f mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ExpandRelativeMultiGroups.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelativeMultiGroups.scala @@@ -1,0 -1,9 +1,9 @@@ -package fix +package test.organizeImports import java.time.Clock import javax.management.JMX import scala.util import scala.util.control import scala.util.control.NonFatal object ExpandRelativeMultiGroups diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelativePackageObject.scala index 00000000,8d42e6ab..1a5f3013 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ExpandRelativePackageObject.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelativePackageObject.scala @@@ -1,0 -1,5 +1,5 @@@ -package fix +package test.organizeImports -import fix.PackageObject.a +import test.organizeImports.PackageObject.a object ExpandRelativePackageObject diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelativeQuotedIdent.scala index 00000000,633c3f3b..6ae0b6bc mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ExpandRelativeQuotedIdent.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelativeQuotedIdent.scala @@@ -1,0 -1,8 +1,8 @@@ -package fix +package test.organizeImports -import fix.QuotedIdent.`a.b` -import fix.QuotedIdent.`a.b`.`{ d }` -import fix.QuotedIdent.`a.b`.c -import fix.QuotedIdent.`macro` +import test.organizeImports.QuotedIdent.`a.b` +import test.organizeImports.QuotedIdent.`a.b`.`{ d }` +import test.organizeImports.QuotedIdent.`a.b`.c +import test.organizeImports.QuotedIdent.`macro` object ExpandRelativeQuotedIdent diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelativeRootPackage.scala index 00000000,0e0f0e49..c8e61214 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ExpandRelativeRootPackage.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ExpandRelativeRootPackage.scala @@@ -1,0 -1,9 +1,9 @@@ -package fix +package test.organizeImports import _root_.scala.collection.mutable.ArrayBuffer import _root_.scala.util import scala.util.control import scala.util.control.NonFatal object ExpandRelativeRootPackage diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ExplicitlyImportedImplicits.scala index 00000000,25905cb1..5115ab56 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ExplicitlyImportedImplicits.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ExplicitlyImportedImplicits.scala @@@ -1,0 -1,17 +1,17 @@@ -package fix +package test.organizeImports -import fix.Implicits.a.nonImplicit -import fix.Implicits.b._ +import test.organizeImports.Implicits.a.nonImplicit +import test.organizeImports.Implicits.b._ import scala.concurrent.ExecutionContext import ExecutionContext.Implicits.global -import fix.Implicits.a.intImplicit -import fix.Implicits.a.stringImplicit +import test.organizeImports.Implicits.a.intImplicit +import test.organizeImports.Implicits.a.stringImplicit object ExplicitlyImportedImplicits { def f1()(implicit i: Int) = ??? def f2()(implicit s: String) = ??? f1() f2() } diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ExplodeImportsFormatPreserving.scala index 00000000,3b4ca7e9..fef0bb4e mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ExplodeImportsFormatPreserving.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ExplodeImportsFormatPreserving.scala @@@ -1,0 -1,7 +1,7 @@@ -package fix +package test.organizeImports -import fix.ExplodeImports.FormatPreserving.g1.a -import fix.ExplodeImports.FormatPreserving.g1.b -import fix.ExplodeImports.FormatPreserving.g2.{ c => C, _ } +import test.organizeImports.ExplodeImports.FormatPreserving.g1.a +import test.organizeImports.ExplodeImports.FormatPreserving.g1.b +import test.organizeImports.ExplodeImports.FormatPreserving.g2.{ c => C, _ } object ExplodeImportsFormatPreserving diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GlobalImportsOnly.scala index 00000000,1928171e..b89d37ab mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GlobalImportsOnly.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GlobalImportsOnly.scala @@@ -1,0 -1,13 +1,13 @@@ -package fix +package test.organizeImports import java.sql.DriverManager import java.time.Clock import scala.collection.mutable import scala.concurrent.duration.Duration object GlobalImportsOnly // These imports should not be organized import java.time.Duration, java.sql.Connection object Foo diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsAggressiveMergeWildcard.scala index 00000000,914e7e2e..e184fab9 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupedImportsAggressiveMergeWildcard.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsAggressiveMergeWildcard.scala @@@ -1,0 -1,7 +1,7 @@@ -package fix +package test.organizeImports -import fix.MergeImports.Wildcard1._ -import fix.MergeImports.Wildcard1.{b => B} -import fix.MergeImports.Wildcard2._ +import test.organizeImports.MergeImports.Wildcard1._ +import test.organizeImports.MergeImports.Wildcard1.{b => B} +import test.organizeImports.MergeImports.Wildcard2._ object GroupedImportsAggressiveMergeWildcard diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsExplode.scala index 00000000,c71c9474..b7f8052c mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupedImportsExplode.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsExplode.scala @@@ -1,0 -1,7 +1,7 @@@ -package fix +package test.organizeImports import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.Buffer import scala.collection.mutable.StringBuilder object GroupedImportsExplode diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsExplodeMixed.scala index 00000000,67074e0b..6b851dd2 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupedImportsExplodeMixed.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsExplodeMixed.scala @@@ -1,0 -1,7 +1,7 @@@ -package fix +package test.organizeImports import scala.collection.immutable._ import scala.collection.mutable.Map import scala.collection.mutable.{Buffer => _, Seq => S, _} object GroupedImportsExplodeMixed diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsExplodeUnimport.scala index 00000000,5611e8ae..c48b6304 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupedImportsExplodeUnimport.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsExplodeUnimport.scala @@@ -1,0 -1,5 +1,5 @@@ -package fix +package test.organizeImports import scala.collection.{Seq => _, _} object GroupedImportExplodeUnimport diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsKeep.scala index 00000000,ca37b56b..cacbb69e mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupedImportsKeep.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsKeep.scala @@@ -1,0 -1,6 +1,6 @@@ -package fix +package test.organizeImports import scala.collection.mutable.StringBuilder import scala.collection.mutable.{ArrayBuffer, Buffer} object GroupedImportsKeep diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsMerge.scala index 00000000,f7cac59c..102e99f9 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupedImportsMerge.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsMerge.scala @@@ -1,0 -1,5 +1,5 @@@ -package fix +package test.organizeImports import scala.collection.mutable.{ArrayBuffer, Buffer, StringBuilder} object GroupedImportsMerge diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsMergeDedup.scala index 00000000,118c4601..ce414cdc mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupedImportsMergeDedup.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsMergeDedup.scala @@@ -1,0 -1,5 +1,5 @@@ -package fix +package test.organizeImports -import fix.MergeImports.Dedup.{a, b => b1, c => _} +import test.organizeImports.MergeImports.Dedup.{a, b => b1, c => _} object GroupedImportsMergeDedup diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsMergeRenames.scala index 00000000,e40a3b2a..05058591 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupedImportsMergeRenames.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsMergeRenames.scala @@@ -1,0 -1,7 +1,7 @@@ -package fix +package test.organizeImports -import fix.MergeImports.Rename1.{a => A, b => B, c, d} -import fix.MergeImports.Rename2.{a => A, b => B, c} -import fix.MergeImports.Rename2.{a, b} +import test.organizeImports.MergeImports.Rename1.{a => A, b => B, c, d} +import test.organizeImports.MergeImports.Rename2.{a => A, b => B, c} +import test.organizeImports.MergeImports.Rename2.{a, b} object GroupedImportsMergeRenames diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsMergeUnimports.scala index 00000000,06d5c67a..a8c7b14b mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupedImportsMergeUnimports.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsMergeUnimports.scala @@@ -1,0 -1,6 +1,6 @@@ -package fix +package test.organizeImports -import fix.MergeImports.Unimport1.{b => B, c => _, d, _} -import fix.MergeImports.Unimport2.{a => _, b => _, c => C, d} +import test.organizeImports.MergeImports.Unimport1.{b => B, c => _, d, _} +import test.organizeImports.MergeImports.Unimport2.{a => _, b => _, c => C, d} object GroupedImportsMergeUnimports diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsMergeWildcard.scala index 00000000,6399a8b6..9b502ea1 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupedImportsMergeWildcard.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupedImportsMergeWildcard.scala @@@ -1,0 -1,7 +1,7 @@@ -package fix +package test.organizeImports -import fix.MergeImports.Wildcard1.{b => B} -import fix.MergeImports.Wildcard1.{d, _} -import fix.MergeImports.Wildcard2.{a, b, _} +import test.organizeImports.MergeImports.Wildcard1.{b => B} +import test.organizeImports.MergeImports.Wildcard1.{d, _} +import test.organizeImports.MergeImports.Wildcard2.{a, b, _} object GroupedImportsMergeWildcard diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/Groups.scala index 00000000,5c48e694..cd706d64 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/Groups.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/Groups.scala @@@ -1,0 -1,11 +1,11 @@@ -package fix +package test.organizeImports import java.time.Clock import javax.net.ssl import sun.misc.Unsafe import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext object Groups diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/GroupsLongestMatch.scala index 00000000,8f45a5f8..1ca80683 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/GroupsLongestMatch.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/GroupsLongestMatch.scala @@@ -1,0 -1,14 +1,14 @@@ -package fix +package test.organizeImports import java.time.Clock import javax.net.ssl import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext import scala.util.Random import scala.util.control.NonFatal import sun.misc.Unsafe object GroupsLongestMatch diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ImportsOrderAsciiPreformatted.scala index 00000000,b9e621ee..d056bac1 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ImportsOrderAsciiPreformatted.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ImportsOrderAsciiPreformatted.scala @@@ -1,0 -1,9 +1,9 @@@ -package fix +package test.organizeImports import scala.collection.immutable.{IntMap, Vector} import scala.collection.immutable.{ Map, Seq } object ImportsOrderAsciiPreformatted diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ImportsOrderKeep.scala index 00000000,6001a1c6..e742e4d3 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ImportsOrderKeep.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ImportsOrderKeep.scala @@@ -1,0 -1,12 +1,12 @@@ -package fix +package test.organizeImports -import fix.QuotedIdent.`a.b`.`{ d }`.e -import fix.QuotedIdent._ -import fix.QuotedIdent.`a.b`.{c => _, _} +import test.organizeImports.QuotedIdent.`a.b`.`{ d }`.e +import test.organizeImports.QuotedIdent._ +import test.organizeImports.QuotedIdent.`a.b`.{c => _, _} import scala.concurrent.ExecutionContext.Implicits._ import scala.concurrent.duration import scala.concurrent._ import scala.concurrent.{Promise, Future} object ImportsOrderKeep diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ImportsOrderSymbolsFirst.scala index 00000000,d43c2b35..5bd3317c mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ImportsOrderSymbolsFirst.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ImportsOrderSymbolsFirst.scala @@@ -1,0 -1,12 +1,12 @@@ -package fix +package test.organizeImports -import fix.QuotedIdent._ -import fix.QuotedIdent.`a.b`.{c => _, _} -import fix.QuotedIdent.`a.b`.`{ d }`.e +import test.organizeImports.QuotedIdent._ +import test.organizeImports.QuotedIdent.`a.b`.{c => _, _} +import test.organizeImports.QuotedIdent.`a.b`.`{ d }`.e import scala.concurrent._ import scala.concurrent.{Promise, Future} import scala.concurrent.ExecutionContext.Implicits._ import scala.concurrent.duration object ImportsOrderSymbolsFirst diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/ImportsOrderSymbolsFirstPreformatted.scala index 00000000,331b57bd..416b9294 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/ImportsOrderSymbolsFirstPreformatted.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/ImportsOrderSymbolsFirstPreformatted.scala @@@ -1,0 -1,9 +1,9 @@@ -package fix +package test.organizeImports import scala.collection.immutable.{IntMap, Vector} import scala.collection.immutable.{ Map, Seq } object ImportsOrderSymbolsFirstPreformatted diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/Inheritance.scala index 00000000,c569c7ec..df855c63 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/Inheritance.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/Inheritance.scala @@@ -1,0 -1,5 +1,5 @@@ -package fix +package test.organizeImports -import fix.SomeObject.field.any +import test.organizeImports.SomeObject.field.any object Inheritance diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/MergeImportsFormatPreserving.scala index 00000000,072a5a3c..dee1ea2a mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/MergeImportsFormatPreserving.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/MergeImportsFormatPreserving.scala @@@ -1,0 -1,7 +1,7 @@@ -package fix +package test.organizeImports -import fix.MergeImports.FormatPreserving.g1.{ a, b } -import fix.MergeImports.FormatPreserving.g2._ -import fix.MergeImports.FormatPreserving.g2.{ d => D } +import test.organizeImports.MergeImports.FormatPreserving.g1.{ a, b } +import test.organizeImports.MergeImports.FormatPreserving.g2._ +import test.organizeImports.MergeImports.FormatPreserving.g2.{ d => D } object MergeImportsFormatPreserving diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/NoImports.scala index 00000000,00000000..d22b896f new file mode 100644 --- /dev/null --- /dev/null ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/NoImports.scala @@@ -1,0 -1,0 +1,3 @@@ +package test.organizeImports + +object NoImports diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/OrganizeImportsRootPackage.scala index 00000000,926b68df..926b68df mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/OrganizeImportsRootPackage.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/OrganizeImportsRootPackage.scala @@@ -1,0 -1,9 +1,9 @@@ import java.time.Clock import javax.net.ssl import sun.misc.Unsafe import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext object OrganizeImportsRootPackage diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/PresetDefault.scala index 00000000,327045c5..9cb2ccb5 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/PresetDefault.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/PresetDefault.scala @@@ -1,0 -1,13 +1,13 @@@ -package fix +package test.organizeImports -import fix.PresetDefault.a +import test.organizeImports.PresetDefault.a import java.math.{BigDecimal, BigInteger} import java.util.Collections.{binarySearch, emptyList} import javax.management.MXBean import scala.collection.mutable import scala.util.Try object PresetDefault { val a: Any = ??? } diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/PresetIntelliJ_2020_3.scala index 00000000,1b45dfd8..4ff7dcff mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/PresetIntelliJ_2020_3.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/PresetIntelliJ_2020_3.scala @@@ -1,0 -1,15 +1,15 @@@ -package fix +package test.organizeImports -import fix.PresetIntelliJ_2020_3.a +import test.organizeImports.PresetIntelliJ_2020_3.a import java.math.BigDecimal import java.math.BigInteger import java.util.Collections.binarySearch import java.util.Collections.emptyList import javax.management.MXBean import scala.collection.mutable import scala.util.Try object PresetIntelliJ_2020_3 { val a: Any = ??? } diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/RelativeImports.scala index 00000000,03ffa935..bd8bca1f mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/RelativeImports.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/RelativeImports.scala @@@ -1,0 -1,10 +1,10 @@@ -package fix +package test.organizeImports import scala.util import sun.misc.Unsafe import util.control import control.NonFatal object RelativeImports diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/RemoveUnused.scala index 00000000,bf35dcf3..4ed70725 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/RemoveUnused.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/RemoveUnused.scala @@@ -1,0 -1,11 +1,11 @@@ -package fix +package test.organizeImports -import fix.UnusedImports.a.v1 -import fix.UnusedImports.c.{v6 => w2} -import fix.UnusedImports.d.{v7 => _, _} +import test.organizeImports.UnusedImports.a.v1 +import test.organizeImports.UnusedImports.c.{v6 => w2} +import test.organizeImports.UnusedImports.d.{v7 => _, _} object RemoveUnused { val x1 = v1 val x2 = w2 val x3 = v8 } diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/RemoveUnusedDisabled.scala index 00000000,ba16113a..79fc47a2 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/RemoveUnusedDisabled.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/RemoveUnusedDisabled.scala @@@ -1,0 -1,16 +1,16 @@@ -package fix +package test.organizeImports -import fix.UnusedImports.a.v1 -import fix.UnusedImports.a.v2 -import fix.UnusedImports.b.v3 -import fix.UnusedImports.c.{v5 => w1} -import fix.UnusedImports.c.{v6 => w2} -import fix.UnusedImports.d.{v7 => unused, _} +import test.organizeImports.UnusedImports.a.v1 +import test.organizeImports.UnusedImports.a.v2 +import test.organizeImports.UnusedImports.b.v3 +import test.organizeImports.UnusedImports.c.{v5 => w1} +import test.organizeImports.UnusedImports.c.{v6 => w2} +import test.organizeImports.UnusedImports.d.{v7 => unused, _} object RemoveUnusedDisabled { - import fix.UnusedImports.e.v9 + import test.organizeImports.UnusedImports.e.v9 val x1 = v1 val x2 = w2 val x3 = v8 } diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/RemoveUnusedLocal.scala index 00000000,d867a711..8dac4161 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/RemoveUnusedLocal.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/RemoveUnusedLocal.scala @@@ -1,0 -1,12 +1,12 @@@ -package fix +package test.organizeImports object RemoveUnusedLocal { import UnusedImports._ import a.v1 import c.{v6 => w2} import d.{v7 => _, _} val x1 = v1 val x2 = w2 val x3 = v8 } diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/RemoveUnusedMixed.scala index 00000000,db6da7fa..e7e339a9 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/RemoveUnusedMixed.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/RemoveUnusedMixed.scala @@@ -1,0 -1,11 +1,11 @@@ -package fix +package test.organizeImports -import fix.UnusedImports.a.v1 -import fix.UnusedImports.c.{v6 => w2} -import fix.UnusedImports.d.{v7 => _, _} +import test.organizeImports.UnusedImports.a.v1 +import test.organizeImports.UnusedImports.c.{v6 => w2} +import test.organizeImports.UnusedImports.d.{v7 => _, _} object RemoveUnusedMixed { val x1 = v1 val x2 = w2 val x3 = v8 } diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/RemoveUnusedRelative.scala index 00000000,d365a468..3f873f0d mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/RemoveUnusedRelative.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/RemoveUnusedRelative.scala @@@ -1,0 -1,15 +1,15 @@@ -package fix +package test.organizeImports -import fix.UnusedImports.a -import fix.UnusedImports.a.v1 -import fix.UnusedImports.b -import fix.UnusedImports.c -import fix.UnusedImports.c.{v6 => w2} -import fix.UnusedImports.d -import fix.UnusedImports.d.{v7 => _, _} +import test.organizeImports.UnusedImports.a +import test.organizeImports.UnusedImports.a.v1 +import test.organizeImports.UnusedImports.b +import test.organizeImports.UnusedImports.c +import test.organizeImports.UnusedImports.c.{v6 => w2} +import test.organizeImports.UnusedImports.d +import test.organizeImports.UnusedImports.d.{v7 => _, _} object RemoveUnusedRelative { val x1 = v1 val x2 = w2 val x3 = v8 } diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/SortImportSelectorsAscii.scala index 00000000,4f71b51d..c2c90a60 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/SortImportSelectorsAscii.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/SortImportSelectorsAscii.scala @@@ -1,0 -1,5 +1,5 @@@ -package fix +package test.organizeImports import scala.{:+, ::, Any, Predef, collection, concurrent} object SortImportSelectorsAscii diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/SortImportSelectorsKeep.scala index 00000000,f26f9446..a2b6a642 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/SortImportSelectorsKeep.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/SortImportSelectorsKeep.scala @@@ -1,0 -1,5 +1,5 @@@ -package fix +package test.organizeImports import scala.{Any, ::, collection, :+, Predef, concurrent} object SortImportSelectorsKeep diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/SortImportSelectorsSymbolsFirst.scala index 00000000,cced0588..980b72e7 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/SortImportSelectorsSymbolsFirst.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/SortImportSelectorsSymbolsFirst.scala @@@ -1,0 -1,5 +1,5 @@@ -package fix +package test.organizeImports import scala.{:+, ::, collection, concurrent, Any, Predef} object SortImportSelectorsSymbolsFirst diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/Suppression.scala index 00000000,3116253d..42baa723 mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/Suppression.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/Suppression.scala @@@ -1,0 -1,11 +1,11 @@@ -package fix +package test.organizeImports // scalafix:off import java.time.Clock import scala.collection.JavaConverters._ import sun.misc.Unsafe import scala.concurrent.ExecutionContext import javax.net.ssl // scalafix:on object Suppression diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/nested/NestedPackage.scala index 00000000,fde60523..aedfa20e mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/nested/NestedPackage.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/nested/NestedPackage.scala @@@ -1,0 -1,12 +1,12 @@@ -package fix +package test.organizeImports package nested import java.time.Clock import javax.net.ssl import sun.misc.Unsafe import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext object OrganizeImportsNestedPackage diff --combined scalafix-tests/output/src/main/scala/test/organizeImports/nested/NestedPackageWithBraces.scala index 00000000,550e36f5..ddc5cd4d mode 000000,100644..100644 --- /dev/null --- a/output/src/main/scala/fix/nested/NestedPackageWithBraces.scala ++ b/scalafix-tests/output/src/main/scala/test/organizeImports/nested/NestedPackageWithBraces.scala @@@ -1,0 -1,12 +1,12 @@@ -package fix { +package test.organizeImports { package nested { import sun.misc.Unsafe import java.time.Clock import javax.net.ssl import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext object NestedPackageWithBraces } } diff --combined scalafix-tests/shared/src/main/scala-3/test/organizeImports/GivenImports.scala index 00000000,e10942d6..9a417ded mode 000000,100644..100644 --- /dev/null --- a/shared/src/main/scala-3/fix/GivenImports.scala ++ b/scalafix-tests/shared/src/main/scala-3/test/organizeImports/GivenImports.scala @@@ -1,0 -1,25 +1,25 @@@ -package fix +package test.organizeImports object GivenImports { trait Alpha trait Beta trait Gamma trait Delta trait Zeta given alpha: Alpha = ??? given beta: Beta = ??? given gamma: Gamma = ??? given delta: Delta = ??? given zeta: Zeta = ??? } object GivenImports2 { import GivenImports.* given alpha: Alpha = ??? given beta: Beta = ??? given gamma: Gamma = ??? given delta: Delta = ??? given zeta: Zeta = ??? } diff --combined scalafix-tests/shared/src/main/scala-3/test/organizeImports/Givens.scala index 00000000,65778653..69e136ed mode 000000,100644..100644 --- /dev/null --- a/shared/src/main/scala-3/fix/Givens.scala ++ b/scalafix-tests/shared/src/main/scala-3/test/organizeImports/Givens.scala @@@ -1,0 -1,15 +1,15 @@@ -package fix +package test.organizeImports object Givens { trait A trait B trait C trait D trait E given a: A = ??? given b: B = ??? given c: C = ??? given d: D = ??? given e: E = ??? } diff --combined scalafix-tests/shared/src/main/scala/test/organizeImports/ExplodeImports.scala index 00000000,834ad5f9..4a7e585d mode 000000,100644..100644 --- /dev/null --- a/shared/src/main/scala/fix/ExplodeImports.scala ++ b/scalafix-tests/shared/src/main/scala/test/organizeImports/ExplodeImports.scala @@@ -1,0 -1,60 +1,60 @@@ -package fix +package test.organizeImports object ExplodeImports { object Wildcard1 { object a object b object c object d } object Wildcard2 { object a object b } object Unimport1 { object a object b object c object d } object Unimport2 { object a object b object c object d } object Rename1 { object a object b object c object d } object Rename2 { object a object b object c } object Dedup { object a object b object c } object FormatPreserving { object g1 { object a object b } object g2 { object c object d } } } diff --combined scalafix-tests/shared/src/main/scala/test/organizeImports/Implicits.scala index 00000000,fd2903f9..2eed0d4f mode 000000,100644..100644 --- /dev/null --- a/shared/src/main/scala/fix/Implicits.scala ++ b/scalafix-tests/shared/src/main/scala/test/organizeImports/Implicits.scala @@@ -1,0 -1,14 +1,14 @@@ -package fix +package test.organizeImports object Implicits { object a { def nonImplicit: Unit = ??? implicit def intImplicit: Int = ??? implicit def stringImplicit: String = ??? } object b { implicit def intImplicit: Int = ??? implicit def stringImplicit: String = ??? } } diff --combined scalafix-tests/shared/src/main/scala/test/organizeImports/Inheritance.scala index 00000000,1a42554d..9ff845ca mode 000000,100644..100644 --- /dev/null --- a/shared/src/main/scala/fix/Inheritance.scala ++ b/scalafix-tests/shared/src/main/scala/test/organizeImports/Inheritance.scala @@@ -1,0 -1,11 +1,11 @@@ -package fix +package test.organizeImports class SomeClass { val any: Any = ??? } trait SomeTrait { val field = new SomeClass } object SomeObject extends SomeTrait diff --combined scalafix-tests/shared/src/main/scala/test/organizeImports/MergeImports.scala index 00000000,16d26fa5..ede6105b mode 000000,100644..100644 --- /dev/null --- a/shared/src/main/scala/fix/MergeImports.scala ++ b/scalafix-tests/shared/src/main/scala/test/organizeImports/MergeImports.scala @@@ -1,0 -1,60 +1,60 @@@ -package fix +package test.organizeImports object MergeImports { object Wildcard1 { object a object b object c object d } object Wildcard2 { object a object b } object Unimport1 { object a object b object c object d } object Unimport2 { object a object b object c object d } object Rename1 { object a object b object c object d } object Rename2 { object a object b object c } object Dedup { object a object b object c } object FormatPreserving { object g1 { object a object b } object g2 { object c object d } } } diff --combined scalafix-tests/shared/src/main/scala/test/organizeImports/QuotedIdent.scala index 00000000,121d61f9..4bfd2b57 mode 000000,100644..100644 --- /dev/null --- a/shared/src/main/scala/fix/QuotedIdent.scala ++ b/scalafix-tests/shared/src/main/scala/test/organizeImports/QuotedIdent.scala @@@ -1,0 -1,12 +1,12 @@@ -package fix +package test.organizeImports object QuotedIdent { object `a.b` { object c object `{ d }` { object e } } object `macro` } diff --combined scalafix-tests/shared/src/main/scala/test/organizeImports/UnusedImports.scala index 00000000,017b07dd..ac50470b mode 000000,100644..100644 --- /dev/null --- a/shared/src/main/scala/fix/UnusedImports.scala ++ b/scalafix-tests/shared/src/main/scala/test/organizeImports/UnusedImports.scala @@@ -1,0 -1,27 +1,27 @@@ -package fix +package test.organizeImports object UnusedImports { object a { object v1 object v2 } object b { object v3 object v4 } object c { object v5 object v6 } object d { object v7 object v8 } object e { object v9 } } diff --combined scalafix-tests/shared/src/main/scala/test/organizeImports/package.scala index 00000000,207f0701..c4858a72 mode 000000,100644..100644 --- /dev/null --- a/shared/src/main/scala/fix/package.scala ++ b/scalafix-tests/shared/src/main/scala/test/organizeImports/package.scala @@@ -1,0 -1,5 +1,5 @@@ -package object fix { +package test.organizeImports { object PackageObject { object a } } diff --combined website/i18n/en.json index 9f08d5ed,00000000..77bee14a mode 100644,000000..100644 --- a/website/i18n/en.json --- /dev/null ++ b/website/i18n/en.json @@@ -1,105 -1,0 +1,118 @@@ { "_comment": "This file is auto-generated by write-translations.js", "localized-strings": { "next": "Next", "previous": "Previous", "tagline": "Refactoring and linting tool for Scala", "docs": { "developers/api": { "title": "API Overview", "sidebar_label": "Overview" }, "developers/before-you-begin": { "title": "Before you write code" }, "developers/contributing": { "title": "Contributing Guide", "sidebar_label": "Guide" }, + "developers/cross-publish-custom-rules": { + "title": "Cross publish custom rules" + }, "developers/local-rules": { "title": "Local rules" }, "developers/patch": { "title": "Patch" }, "developers/semantic-tree": { "title": "SemanticTree" }, "developers/semantic-type": { "title": "SemanticType" }, "developers/setup": { "title": "Setup" }, "developers/symbol-information": { "title": "SymbolInformation" }, "developers/symbol-matcher": { "title": "SymbolMatcher" }, "developers/tutorial": { "title": "Tutorial" }, + "rules/community-rules": { + "title": "Community rules", + "sidebar_label": "Community rules" + }, "rules/DisableSyntax": { "title": "DisableSyntax" }, "rules/ExplicitResultTypes": { "title": "ExplicitResultTypes" }, "rules/external-rules": { "title": "Using external rules", "sidebar_label": "Using external rules" }, "rules/LeakingImplicitClassVal": { "title": "LeakingImplicitClassVal" }, "rules/NoAutoTupling": { "title": "NoAutoTupling" }, "rules/NoValInForComprehension": { "title": "NoValInForComprehension" }, + "rules/OrganizeImports": { + "title": "OrganizeImports" + }, "rules/overview": { "title": "Built-in Rules", "sidebar_label": "Built-in rules" }, "rules/ProcedureSyntax": { "title": "ProcedureSyntax" }, + "rules/RedundantSyntax": { + "title": "RedundantSyntax" + }, "rules/RemoveUnused": { "title": "RemoveUnused" }, "users/configuration": { "title": "Configuration" }, "users/installation": { "title": "Installation" }, "users/related-projects": { "title": "Related projects" }, "users/suppression": { "title": "Suppressing rules" } }, "links": { "User guide": "User guide", "Developer guide": "Developer guide", "Browse sources": "Browse sources", "GitHub": "GitHub" }, "categories": { "Usage": "Usage", "Rules": "Rules", "Misc": "Misc", "Implementing rules": "Implementing rules", "API Reference": "API Reference", "Contributing": "Contributing" } }, "pages-strings": { "Help Translate|recruit community translators for your project": "Help Translate", "Edit this Doc|recruitment message asking to edit the doc source": "Edit", "Translate this Doc|recruitment message asking to translate the docs": "Translate" } } diff --combined website/sidebars.json index 5eb350b8,00000000..90d84b4a mode 100644,000000..100644 --- a/website/sidebars.json --- /dev/null ++ b/website/sidebars.json @@@ -1,37 -1,0 +1,38 @@@ { "users": { "Usage": ["users/installation", "users/configuration", "users/suppression"], "Rules": [ "rules/overview", "rules/DisableSyntax", "rules/ExplicitResultTypes", "rules/LeakingImplicitClassVal", "rules/NoAutoTupling", "rules/NoValInForComprehension", + "rules/OrganizeImports", "rules/ProcedureSyntax", "rules/RedundantSyntax", "rules/RemoveUnused", "rules/external-rules", "rules/community-rules" ], "Misc": ["users/related-projects"] }, "developers": { "Implementing rules": [ "developers/setup", "developers/before-you-begin", "developers/tutorial", "developers/local-rules", "developers/cross-publish-custom-rules" ], "API Reference": [ "developers/api", "developers/patch", "developers/symbol-matcher", "developers/symbol-information", "developers/semantic-type", "developers/semantic-tree" ], "Contributing": ["developers/contributing"] } }