Skip to content

Commit

Permalink
Squashed commits: scalafix-reflect3 cross compiled for scala3
Browse files Browse the repository at this point in the history
Original commit messages follow:
configured build for reflect3, isolated RuleCompiler in scala2 and scala3 versions, scala3 has an empty impl, fixed some compilation errors in other classes

convert quasiquotes in RuleInstrumentation with scalameta Trees

removed wrong line forgotten during development

improved term apply quasiquotes q...

wip Rulecompiler with dotty

removed unused lambdarule object in ruleInstrumentation

ruleInstrumentation: fix Init tree for Rewrite with Nil instead of _

Co-authored-by: Tomasz Godzik <tgodzik@users.noreply.github.com>

first draft of reflect3 ruleCompiler, applied scalafixAll and scalafmt

manually removed/organized imports

made reporter private

better error handling messages

refactored RuleCompiler companion obj into own file for reusability

fixed usage of RuleCompilerClasspath

fix scalaversion in build.sbt and import dottyAbstractFile alias

added settings and ctx to rule compiler, changed error handling, removed custom exception, fixed class import for ruleCompilerClasspath

explicit using params, fixed imports manually

added scala3-library in reflect3

This is the commit message scalacenter#2 rebased and squashed afterwards:

fix RuleCompiler initialization by propertly setting classpath and outputDir

This is the commit message scalacenter#2:

build sbt reflect

This is the commit message scalacenter#3:

rule compiler remove position for confError, and notOk/apply fixes
  • Loading branch information
rvacaru committed Aug 12, 2022
1 parent ab4ea61 commit b32bb67
Show file tree
Hide file tree
Showing 13 changed files with 178 additions and 64 deletions.
18 changes: 13 additions & 5 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,21 @@ lazy val reflect = projectMatrix
.settings(
moduleName := "scalafix-reflect",
isFullCrossVersion,
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-compiler" % scalaVersion.value,
"org.scala-lang" % "scala-reflect" % scalaVersion.value
)
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)
.jvmPlatform(buildScalaVersions :+ scala3)
.dependsOn(core)

lazy val cli = projectMatrix
Expand Down
1 change: 1 addition & 0 deletions project/ScalafixBuild.scala
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ object ScalafixBuild extends AutoPlugin with GhpagesKeys {
"unit2_12Target3/test" ::
"core3/compile" ::
"rules3/compile" ::
"reflect3/compile" ::
s
},
commands += Command.command("ci-213") { s =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
package scalafix.internal.reflect
import java.io.File
import java.nio.file.Paths

import scala.reflect.internal.util.AbstractFileClassLoader
import scala.reflect.internal.util.BatchSourceFile
import scala.tools.nsc.Global
Expand All @@ -10,8 +7,6 @@ import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.io.VirtualDirectory
import scala.tools.nsc.reporters.StoreReporter

import scala.meta.io.AbsolutePath

import metaconfig.ConfError
import metaconfig.Configured
import metaconfig.Input
Expand Down Expand Up @@ -58,30 +53,3 @@ class RuleCompiler(
.getOrElse(Configured.Ok(classLoader))
}
}
object RuleCompiler {

def defaultClasspath: String = {
defaultClasspathPaths.mkString(File.pathSeparator)
}

def defaultClasspathPaths: List[AbsolutePath] = {
val classLoader = ClasspathOps.thisClassLoader
val paths = classLoader.getURLs.iterator.map { u =>
if (u.getProtocol.startsWith("bootstrap")) {
import java.nio.file._
val stream = u.openStream
val tmp = Files.createTempFile("bootstrap-" + u.getPath, ".jar")
try {
Files.copy(stream, tmp, StandardCopyOption.REPLACE_EXISTING)
} finally {
stream.close()
}
AbsolutePath(tmp)
} else {
AbsolutePath(Paths.get(u.toURI))
}
}
paths.toList
}

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

import dotty.tools.dotc.Compiler
import dotty.tools.dotc.Run
import dotty.tools.dotc.core.Contexts.FreshContext
import dotty.tools.dotc.util.SourceFile
import dotty.tools.dotc.reporting.StoreReporter
import dotty.tools.dotc.interactive.InteractiveDriver
import dotty.tools.io.AbstractFile as DottyAbstractFile
import dotty.tools.io.VirtualDirectory as DottyVirtualDirectory

import scala.reflect.io.VirtualDirectory
import scala.reflect.io.AbstractFile
import scala.reflect.internal.util.AbstractFileClassLoader

import metaconfig.Configured
import metaconfig.Input
import metaconfig.ConfError
import metaconfig.Position

class RuleCompiler(
classpath: String,
target: AbstractFile = new VirtualDirectory("(memory)", None)
) {
private val settings = "-unchecked" :: "-deprecation" :: "-classpath" :: classpath :: Nil
private val driver = new InteractiveDriver(settings)
private val reporter: StoreReporter = new StoreReporter()
private var ctx: FreshContext = driver.currentCtx.fresh
private val dottyVirtualDirectory = new DottyVirtualDirectory(target.name, None)

ctx = ctx
.setReporter(reporter)
.setSetting(ctx.settings.outputDir, dottyVirtualDirectory)

private val compiler: Compiler = new Compiler()
private val classLoader: AbstractFileClassLoader =
new AbstractFileClassLoader(target, this.getClass.getClassLoader)

def compile(input: Input): Configured[ClassLoader] = {
reporter.removeBufferedMessages(using ctx)
val run: Run = compiler.newRun(using ctx)
run.compileSources(
List(
new SourceFile(
DottyAbstractFile.getFile(input.path),
input.chars
)
)
)

val errors = reporter.allErrors.map(error =>
ConfError
.message(error.getMessage)
)
if (!errors.isEmpty)
errors :+ ConfError.message(
"Error compiling rule(s) from source using Scala 3 compiler; " +
"to use the Scala 2.x compiler instead, use the corresponding " +
"scalafix-cli artifact or force scalafixScalaBinaryVersion " +
"to 2.x in your build tool"
)

ConfError
.apply(errors)
.map(_.notOk)
.getOrElse(Configured.Ok(classLoader))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package scalafix.internal.reflect

import java.io.File
import java.nio.file.Paths

import scala.meta.io.AbsolutePath

object RuleCompilerClasspath {

def defaultClasspath: String = {
defaultClasspathPaths.mkString(File.pathSeparator)
}

def defaultClasspathPaths: List[AbsolutePath] = {
val classLoader = ClasspathOps.thisClassLoader
val paths = classLoader.getURLs.iterator.map { u =>
if (u.getProtocol.startsWith("bootstrap")) {
import java.nio.file._
val stream = u.openStream
val tmp = Files.createTempFile("bootstrap-" + u.getPath, ".jar")
try {
Files.copy(stream, tmp, StandardCopyOption.REPLACE_EXISTING)
} finally {
stream.close()
}
AbsolutePath(tmp)
} else {
AbsolutePath(Paths.get(u.toURI))
}
}
paths.toList
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,63 @@ object RuleInstrumentation {
def unapply(templ: Template): Boolean = templ match {

// v0
case Template(_, init"Rewrite" :: _, _, _) => true
case Template(_, init"Rule($_)" :: _, _, _) => true
case Template(_, init"SemanticRewrite($_)" :: _, _, _) => true
case Template(_, init"SemanticRule($_, $_)" :: _, _, _) => true
case Template(_, Init(Type.Name("Rewrite"), _, Nil) :: _, _, _) => true
case Template(
_,
Init(Type.Name("Rule"), _, List(List(_))) :: _,
_,
_
) =>
true
case Template(
_,
Init(Type.Name("SemanticRewrite"), _, List(List(_))) :: _,
_,
_
) =>
true
case Template(
_,
Init(Type.Name("SemanticRule"), _, List(List(_, _))) :: _,
_,
_
) =>
true

// v1
case Template(_, init"SemanticRule($_)" :: _, _, _) => true
case Template(_, init"v1.SemanticRule($_)" :: _, _, _) => true
case Template(_, init"SyntacticRule($_)" :: _, _, _) => true
case Template(_, init"v1.SyntacticRule($_)" :: _, _, _) => true
case Template(
_,
Init(Type.Name("SemanticRule"), _, List(List(_))) :: _,
_,
_
) =>
true
case Template(
_,
Init(Type.Name("v1.SemanticRule"), _, List(List(_))) :: _,
_,
_
) =>
true
case Template(
_,
Init(Type.Name("SyntacticRule"), _, List(List(_))) :: _,
_,
_
) =>
true
case Template(
_,
Init(Type.Name("v1.SyntacticRule"), _, List(List(_))) :: _,
_,
_
) =>
true

case _ => false
}
}
object LambdaRule {
def unapply(arg: Term): Boolean = arg match {
case q"Rule.syntactic($_)" => true
case q"Rule.semantic($_)" => true
case q"Rule.syntactic($_)" => true
case q"Rule.semantic($_)" => true
case _ => false
}
}

(dialects.Scala213, code).parse[Source] match {
case parsers.Parsed.Error(pos, msg, details) =>
ConfError.parseError(pos.toMetaconfig, msg).notOk
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ScalafixToolbox {
new function.Function[String, RuleCompiler] {
override def apply(classpath: String) =
new RuleCompiler(
classpath + File.pathSeparator + RuleCompiler.defaultClasspath
classpath + File.pathSeparator + RuleCompilerClasspath.defaultClasspath
)
}

Expand Down Expand Up @@ -54,6 +54,6 @@ class ScalafixToolbox {
(
compiler.compile(code) |@|
RuleInstrumentation.getRuleFqn(code.toMeta)
).map(CompiledRules.tupled.apply)
).map((CompiledRules.apply _).tupled)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package scalafix.internal.v0
import scala.{meta => m}

import scala.meta._
import scala.meta.internal.inputs.XtensionInputSyntaxStructure
import scala.meta.internal.io._
import scala.meta.internal.symtab.SymbolTable
import scala.meta.internal.{semanticdb => s}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ object RuleDecoder {
// Patch.replaceSymbols(from, to)
case UriRuleString("replace", replace @ SlashSeparated(from, to)) =>
val constant = parseReplaceSymbol(from, to)
.map(Patch.internal.ReplaceSymbol.tupled)
.map((Patch.internal.ReplaceSymbol.apply _).tupled)
.map(p => scalafix.v1.SemanticRule.constant(replace, p.atomic))
constant :: Nil
// Classload rule from classloader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package scalafix.testkit

import scala.meta._

import scalafix.internal.reflect.RuleCompiler
import scalafix.internal.reflect.RuleCompilerClasspath
import scalafix.internal.testkit.EndOfLineAssertExtractor
import scalafix.internal.testkit.MultiLineAssertExtractor

object SemanticRuleSuite {
def defaultClasspath(classDirectory: AbsolutePath): Classpath = Classpath(
classDirectory ::
RuleCompiler.defaultClasspathPaths.filter(path =>
RuleCompilerClasspath.defaultClasspathPaths.filter(path =>
path.toNIO.getFileName.toString.contains("scala-library")
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import scalafix.interfaces.ScalafixException
import scalafix.interfaces.ScalafixMainCallback
import scalafix.interfaces.ScalafixMainMode
import scalafix.internal.reflect.ClasspathOps
import scalafix.internal.reflect.RuleCompiler
import scalafix.internal.reflect.RuleCompilerClasspath
import scalafix.test.StringFS
import scalafix.testkit.DiffAssertions
import scalafix.tests.util.ScalaVersions
Expand All @@ -34,7 +34,7 @@ import scalafix.{interfaces => i}
class ScalafixImplSuite extends AnyFunSuite with DiffAssertions {

def scalaLibrary: AbsolutePath =
RuleCompiler.defaultClasspathPaths
RuleCompilerClasspath.defaultClasspathPaths
.find(_.toNIO.getFileName.toString.contains("scala-library"))
.getOrElse {
throw new IllegalStateException("Unable to detect scala-library.jar")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package scalafix.tests.core
import scala.meta.io.AbsolutePath
import scala.meta.io.Classpath

import scalafix.internal.reflect.RuleCompiler
import scalafix.internal.reflect.RuleCompilerClasspath

object Classpaths {
def scalaLibrary: Classpath = Classpath(
RuleCompiler.defaultClasspathPaths.filter { path =>
RuleCompilerClasspath.defaultClasspathPaths.filter { path =>
path.isFile ||
path.toNIO.getFileName.toString.contains("scala-library")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import metaconfig.Conf
import org.scalatest.BeforeAndAfterAll
import org.scalatest.funsuite.AnyFunSuite
import scalafix.internal.reflect.RuleCompiler
import scalafix.internal.reflect.RuleCompilerClasspath
import scalafix.internal.tests.utils.SkipWindows
import scalafix.tests.util.ScalaVersions
import scalafix.v1.RuleDecoder
Expand Down Expand Up @@ -68,7 +69,7 @@ class ToolClasspathSuite extends AnyFunSuite with BeforeAndAfterAll {
""".stripMargin
val tmp = Files.createTempDirectory("scalafix")
val compiler = new RuleCompiler(
RuleCompiler.defaultClasspath,
RuleCompilerClasspath.defaultClasspath,
new PlainDirectory(new Directory(tmp.toFile))
)
compiler.compile(metaconfig.Input.VirtualFile("CustomRule.scala", rewrite))
Expand Down

0 comments on commit b32bb67

Please sign in to comment.