-Ywarn-unused-import触发播放路由文件

时间:2016-05-24 12:04:06

标签: scala playframework sbt scalac

我希望能够使用-Xfatal-warnings-Ywarn-unused-import,问题是编译器在包含我的应用程序的播放路径的文件上触发错误:

[error] /path/to/app/conf/routes: Unused import
[error] /path/to/app/conf/routes: Unused import
[error] /path/to/app/conf/routes:1: Unused import
[error] GET        /document/:id        my.app.controllers.MyController.getById(id: Int)

其他路线也一样。

是否有可能告诉scalac忽略文件?

Scala版本为2.11.8

3 个答案:

答案 0 :(得分:4)

一个可怕的解决方案"可能是在生成路由之后但在编译任务运行之前删除那些未使用的导入。这是一个草图:

lazy val optimizeRoutesImports = taskKey[Unit]("Remove unused imports from generated routes sources.")

optimizeRoutesImports := {

  def removeUnusedImports(targetFiles: (File) => PathFinder, linesToRemove: Set[String], linesToReplace: Map[String, String]) = {
    val files = targetFiles(crossTarget.value).get
    files foreach { file =>
      val lines = sbt.IO.readLines(file)
      val updatedLines = lines map { line =>
        linesToReplace.getOrElse(line, line)
      } filterNot { line =>
        linesToRemove.contains(line.trim)
      }
      sbt.IO.writeLines(file, updatedLines, append = false)
    }
  }

  removeUnusedImports(
    _ / "routes" / "main" / "controllers" / "ReverseRoutes.scala",
    Set("import ReverseRouteContext.empty"),
    Map(
      "import play.api.mvc.{ QueryStringBindable, PathBindable, Call, JavascriptLiteral }" ->
        "import play.api.mvc.{ QueryStringBindable, PathBindable, Call }",
      "import play.core.routing.{ HandlerDef, ReverseRouteContext, queryString, dynamicString }" ->
        "import play.core.routing.{ ReverseRouteContext, queryString, dynamicString }"
    )
  )

  removeUnusedImports(
    _ / "routes" / "main" / "controllers" / "javascript" / "JavaScriptReverseRoutes.scala",
    Set(
      "import play.core.routing.{ HandlerDef, ReverseRouteContext, queryString, dynamicString }",
      "import ReverseRouteContext.empty"
    ),
    Map(
      "import play.api.mvc.{ QueryStringBindable, PathBindable, Call, JavascriptLiteral }" ->
        "import play.api.mvc.{ QueryStringBindable, PathBindable }"
    )
  )

  removeUnusedImports(
    _ / "routes" / "main" / "router" / "Routes.scala",
    Set("import play.core.j._"),
    Map())
}

然后,您将要理清任务依赖关系:

// Our optimize routes imports task depends on the routes task.
optimizeRoutesImports := (optimizeRoutesImports dependsOn (play.sbt.routes.RoutesKeys.routes in Compile)).value

// And compilation depends on the unused routes having been removed.
compile := ((compile in Compile) dependsOn optimizeRoutesImports).value

在启用TwirlKeys.templateImports之前,您还可能需要将-Ywarn-unused-import设置为保守列表。这样的东西,取决于您的视图中使用的类型:

TwirlKeys.templateImports := Seq("play.api.mvc._", "play.api.i18n.Messages", "controllers.routes")

我还必须从Twirl模板(YMMV)中删除未使用的TemplateMagic导入:

  removeUnusedImports(
    _ / "twirl" ** "*.template.scala",
    Set("import play.twirl.api.TemplateMagic._"),
    Map())

如果这样做,请确保正确设置任务依赖性。

这对我有用。 Scala 2.11.8,Play 2.5.10,-Xfatal-warnings-Ywarn-unused-import都已启用。它很可怕,但它确实有效。

答案 1 :(得分:3)

我刚刚在Scala 2.12和Play 2.6(您现在可能正在使用)中遇到了相同的问题。

一个名为Silencer的Scala编译器插件对其进行了整理: https://github.com/ghik/silencer

将以下依赖项添加到build.sbt中:

val silencerVersion = "1.2.1"

libraryDependencies ++= Seq(
    compilerPlugin("com.github.ghik" %% "silencer-plugin" % silencerVersion),
    "com.github.ghik" %% "silencer-lib" % silencerVersion % Provided
)

然后添加(同样在build.sbt中):

scalacOptions += "-P:silencer:globalFilters=Unused import"

globalFilters=之后的文本是正则表达式匹配项的列表,用于编译器警告静默警告,可以用逗号分隔。您可能需要根据自己的情况调整正则表达式,但我发现上面的示例很好用。

这确实意味着它会消除所有“未使用的导入”警告,但是,如果您习惯于自动格式化代码(Intellij中的{ctrl+alt+L),包括整理未使用的导入,则它不应该”不会造成问题。

答案 2 :(得分:0)

这是另一个选择(可能不如danielnixon)

我在build.sbt中添加了以下内容:

import CustomGenerator._

import play.sbt.routes.RoutesKeys
RoutesKeys.routesImport := Seq.empty
routesGenerator := ModifiedInjectedRoutesGenerator

然后将其添加到project/CustomGenerator.scala(始终是最高级别project/):

object CustomGenerator {
  object ModifiedInjectedRoutesGenerator extends play.routes.compiler.RoutesGenerator {
    import play.routes.compiler._
    import play.routes.compiler.RoutesCompiler.RoutesCompilerTask

    def generate(task: RoutesCompilerTask, namespace: Option[String], rules: List[Rule]): Seq[(String, String)] = {
      play.routes.compiler.InjectedRoutesGenerator.generate(task, namespace, rules) map { case(key, value) =>
        var v = value
        if(key.endsWith("/ReverseRoutes.scala")) {
          v = v.replace("import ReverseRouteContext.empty", "implicit val empty = ReverseRouteContext(Map())")
          v = v.replace("import play.core.routing.{ HandlerDef, ReverseRouteContext, queryString, dynamicString }", "import play.core.routing.{ ReverseRouteContext, queryString }")
          v = v.replace("import play.api.mvc.{ QueryStringBindable, PathBindable, Call, JavascriptLiteral }", "import play.api.mvc.{ QueryStringBindable, Call }")
        }
        if(key.endsWith("migrations/ReverseRoutes.scala")) {
          v = v.replace("import play.api.mvc.{ QueryStringBindable, Call }", "import play.api.mvc.{ Call }")
          v = v.replace("import play.core.routing.{ ReverseRouteContext, queryString }", "import play.core.routing.{ ReverseRouteContext }")
        }
        if(key.endsWith("/JavaScriptReverseRoutes.scala")) {
          v = v.replace("import ReverseRouteContext.empty", "")
          v = v.replace("import play.api.mvc.{ QueryStringBindable, PathBindable, Call, JavascriptLiteral }", "import play.api.mvc.{ QueryStringBindable, JavascriptLiteral }")
          v = v.replace("import play.core.routing.{ HandlerDef, ReverseRouteContext, queryString, dynamicString }", "")
        }
        if(key.endsWith("migrations/javascript/JavaScriptReverseRoutes.scala")) {
          v = v.replace("import play.api.mvc.{ QueryStringBindable, JavascriptLiteral }", "")
        }
        if(key.endsWith("/Routes.scala")) {
          v = v.replace("import play.core.routing.HandlerInvokerFactory._", "")
          v = v.replace("import play.core.j._", "")
          v = v.replace("import ReverseRouteContext.empty", "implicit val empty = ReverseRouteContext(Map())")
        }
        (key, v)
      }
    }

    def id: String = "injected+"
  }
}

Play sbt插件生成路由代码(可以在target/scala-2.11/routes下看到)。此代码段删除或内联所有未使用的导入。您可能需要根据自己的路线进行调整。