Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add scalafix-interfaces with Java APIs for reflective invocation #783

Merged
merged 3 commits into from
Aug 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ inThisBuild(

noPublish

lazy val interfaces = project
.in(file("scalafix-interfaces"))
.settings(
javaHome.in(Compile) := {
// force javac to fork by setting javaHome to get error messages during compilation,
// see https://github.com/sbt/zinc/issues/520
Some(file(sys.props("java.home")).getParentFile)
},
moduleName := "scalafix-interfaces",
crossVersion := CrossVersion.disabled,
crossScalaVersions := List(scala212),
autoScalaLibrary := false
)

lazy val core = project
.in(file("scalafix-core"))
.settings(
Expand Down Expand Up @@ -51,7 +65,7 @@ lazy val cli = project
"org.apache.commons" % "commons-text" % "1.2"
)
)
.dependsOn(reflect)
.dependsOn(reflect, interfaces)

lazy val testsShared = project
.in(file("scalafix-tests/shared"))
Expand Down Expand Up @@ -120,9 +134,10 @@ lazy val unit = project
javaOptions := Nil,
buildInfoPackage := "scalafix.tests",
buildInfoObject := "BuildInfo",
libraryDependencies ++= coursierDeps ++ testsDeps,
libraryDependencies ++= testsDeps,
libraryDependencies ++= List(
jgit,
semanticdbPluginLibrary,
scalatest
),
compileInputs.in(Compile, compile) := {
Expand Down
2 changes: 2 additions & 0 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ object Dependencies {
def googleDiff = "com.googlecode.java-diff-utils" % "diffutils" % "1.3.0"

def metacp = "org.scalameta" %% "metacp" % scalametaV
def semanticdbPluginLibrary = "org.scalameta" % "semanticdb-scalac-core" % scalametaV cross CrossVersion.full
def scalameta = "org.scalameta" %% "contrib" % scalametaV
def symtab = "org.scalameta" %% "symtab" % scalametaV
def scalatest = "org.scalatest" %% "scalatest" % "3.2.0-SNAP10"
def scalacheck = "org.scalacheck" %% "scalacheck" % "1.14.0"

def testsDeps = List(
// integration property tests
"com.geirsson" %% "coursier-small" % "1.0.0-M4",
"org.renucci" %% "scala-xml-quote" % "0.1.4",
"org.typelevel" %% "catalysts-platform" % "0.0.5",
"org.typelevel" %% "cats-core" % "0.9.0",
Expand Down
5 changes: 2 additions & 3 deletions project/ScalafixBuild.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,15 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys {
lazy val noPublish = Seq(
mimaReportBinaryIssues := {},
mimaPreviousArtifacts := Set.empty,
publishArtifact := false,
publish := {},
publishLocal := {}
skip in publish := true
)
lazy val supportedScalaVersions = List(scala211, scala212)
lazy val isFullCrossVersion = Seq(
crossVersion := CrossVersion.full
)
lazy val warnUnusedImports = "-Ywarn-unused-import"
lazy val compilerOptions = Seq(
"-target:jvm-1.8",
warnUnusedImports,
"-deprecation",
"-encoding",
Expand Down
2 changes: 1 addition & 1 deletion scalafix-cli/src/main/scala/scalafix/cli/ExitStatus.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import scala.collection.mutable

sealed abstract case class ExitStatus(code: Int, name: String) {
def isOk: Boolean = code == ExitStatus.Ok.code
def is(exit: ExitStatus): Boolean = (code & exit.code) != 0
override def toString: String = s"$name=$code"
}

Expand All @@ -26,7 +27,6 @@ object ExitStatus {
val Ok,
UnexpectedError,
ParseError,
ScalafixError,
CommandLineError,
MissingSemanticdbError,
StaleSemanticdbError,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package scalafix.internal.interfaces

import scala.meta.inputs.Position
import scalafix.interfaces.ScalafixDiagnostic
import scalafix.interfaces.ScalafixMainCallback
import scalafix.internal.config
import scalafix.internal.config.ScalafixReporter
import scalafix.internal.util.LintSyntax
import scalafix.lint.LintDiagnostic
import scalafix.lint.LintID
import scalafix.lint.LintSeverity

object MainCallbackImpl {

def default: ScalafixMainCallback = fromScala(config.ScalafixReporter.default)

def fromScala(underlying: config.ScalafixReporter): ScalafixMainCallback =
new ScalafixMainCallback {
override def reportDiagnostic(d: ScalafixDiagnostic): Unit = {
val diagnostic = ScalafixDiagnosticImpl.fromJava(d)
if (diagnostic.id == LintID.empty) {
underlying.report(
diagnostic.message,
diagnostic.position,
diagnostic.severity)
} else {
underlying.lint(diagnostic)
}
}
}

def fromJava(underlying: ScalafixMainCallback): ScalafixReporter =
new ScalafixReporter {
override def lint(d: LintDiagnostic): Unit = {
val diagnostic = ScalafixDiagnosticImpl.fromScala(d)
underlying.reportDiagnostic(diagnostic)
}
def report(msg: String, pos: Position, sev: LintSeverity): Unit = {
val diagnostic = ScalafixDiagnosticImpl.fromScala(
new LintSyntax.EagerLintDiagnostic(msg, pos, sev, "", LintID.empty)
)
underlying.reportDiagnostic(diagnostic)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package scalafix.internal.interfaces

import java.util.Optional
import scala.meta.inputs.Position
import scalafix.interfaces.ScalafixInput
import scalafix.interfaces.ScalafixPosition
import scalafix.internal.util.PositionSyntax._

object PositionImpl {
def optionalFromScala(pos: Position): Optional[ScalafixPosition] =
if (pos == Position.None) Optional.empty()
else Optional.of(fromScala(pos))
def fromScala(pos: Position): ScalafixPosition =
new ScalafixPosition {
override def formatMessage(severity: String, message: String): String =
pos.formatMessage(severity, message)
override def startOffset(): Int = pos.start
override def startLine(): Int = pos.startLine
override def startColumn(): Int = pos.startColumn
override def endOffset(): Int = pos.end
override def endLine(): Int = pos.endLine
override def endColumn(): Int = pos.endColumn
override def input(): ScalafixInput =
ScalafixInputImpl.fromScala(pos.input)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package scalafix.internal.interfaces
import java.util.Optional
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline between 1 and 2 plz.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-opened scalameta/scalafmt#1069 This started happening more frequently now because intellij-scala uses Scalafmt after refactorings.

import scala.meta.inputs.Input
import scala.meta.inputs.Position
import scalafix.interfaces.ScalafixDiagnostic
import scalafix.interfaces.ScalafixLintID
import scalafix.interfaces.ScalafixPosition
import scalafix.interfaces.ScalafixSeverity
import scalafix.lint.LintDiagnostic
import scalafix.lint.LintID
import scalafix.lint.LintSeverity

object ScalafixDiagnosticImpl {
def fromScala(diagnostic: LintDiagnostic): ScalafixDiagnostic =
new ScalafixDiagnostic {
override def severity(): ScalafixSeverity = diagnostic.severity match {
case LintSeverity.Info => ScalafixSeverity.INFO
case LintSeverity.Warning => ScalafixSeverity.WARNING
case LintSeverity.Error => ScalafixSeverity.ERROR
}
override def message(): String = diagnostic.message
override def explanation(): String = diagnostic.explanation
override def position(): Optional[ScalafixPosition] =
PositionImpl.optionalFromScala(diagnostic.position)
override def lintID(): Optional[ScalafixLintID] =
if (diagnostic.id == LintID.empty) {
Optional.empty()
} else {
Optional.of(new ScalafixLintID {
override def ruleName(): String = diagnostic.id.rule
override def categoryID(): String = diagnostic.id.categoryID
})
}
}

def fromJava(diagnostic: ScalafixDiagnostic): LintDiagnostic =
new LintDiagnostic {
override def message: String = diagnostic.message()
override def position: Position = {
if (diagnostic.position().isPresent) {
val spos = diagnostic.position().get
val input = Input.VirtualFile(
spos.input().filename(),
spos.input().text().toString
)
Position.Range(input, spos.startOffset(), spos.endOffset())
} else {
Position.None
}
}
override def severity: LintSeverity = diagnostic.severity() match {
case ScalafixSeverity.INFO => LintSeverity.Info
case ScalafixSeverity.WARNING => LintSeverity.Warning
case ScalafixSeverity.ERROR => LintSeverity.Error
}
override def explanation: String = diagnostic.explanation()
override def id: LintID = {
if (diagnostic.lintID().isPresent) {
val lintID = diagnostic.lintID().get
LintID(lintID.ruleName(), lintID.categoryID())
} else {
LintID.empty
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package scalafix.internal.interfaces
import scalafix.cli.ExitStatus
import scalafix.interfaces.ScalafixError

object ScalafixErrorImpl {
private lazy val statusToError: Map[ExitStatus, ScalafixError] = {
val ok :: from = ExitStatus.all
assert(ok.isOk)
val to = ScalafixError.values().toList
assert(from.length == to.length, s"$from != $to")
val map = from.zip(to).toMap
map.foreach {
case (key, value) =>
assert(
key.name.toLowerCase() == value.toString.toLowerCase,
s"$key != $value"
)
}
map
}

def fromScala(exit: ExitStatus): Array[ScalafixError] = {
val buf = Array.newBuilder[ScalafixError]
ExitStatus.all.foreach { code =>
if (exit.is(code))
buf += statusToError(code)
}
buf.result()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package scalafix.internal.interfaces

import scalafix.Versions
import scalafix.interfaces.Scalafix
import scalafix.interfaces.ScalafixError
import scalafix.interfaces.ScalafixMainArgs
import scalafix.internal.v1.MainOps

final class ScalafixImpl extends Scalafix {

override def toString: String =
s"""Scalafix v${scalafixVersion()}"""

override def runMain(args: ScalafixMainArgs): Array[ScalafixError] = {
val exit =
MainOps.run(Array(), args.asInstanceOf[ScalafixMainArgsImpl].args)
ScalafixErrorImpl.fromScala(exit)
}

override def newMainArgs(): ScalafixMainArgs =
ScalafixMainArgsImpl()

override def mainHelp(screenWidth: Int): String = {
MainOps.helpMessage(screenWidth)
}

override def scalafixVersion(): String =
Versions.version
override def scalametaVersion(): String =
Versions.scalameta
override def supportedScalaVersions(): Array[String] =
Versions.supportedScalaVersions.toArray
override def scala211(): String =
Versions.scala211
override def scala212(): String =
Versions.scala212
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package scalafix.internal.interfaces

import java.nio.CharBuffer
import java.nio.file.Path
import java.util.Optional
import scala.meta.inputs.Input
import scala.{meta => m}
import scalafix.interfaces.ScalafixInput

object ScalafixInputImpl {
def fromScala(input: m.Input): ScalafixInput =
new ScalafixInput {
override def text(): CharSequence = input match {
case Input.VirtualFile(_, value) => value
case _ => CharBuffer.wrap(input.chars)
}
override def filename(): String = input.syntax
override def path(): Optional[Path] = input match {
case Input.File(path, _) => Optional.of(path.toNIO)
case _ => Optional.empty()
}
}
}
Loading