diff --git a/scalafix-core/src/main/scala/scalafix/internal/v1/LazyValue.scala b/scalafix-core/src/main/scala/scalafix/internal/v1/LazyValue.scala index 01a9fed3b..cb7714ae2 100644 --- a/scalafix-core/src/main/scala/scalafix/internal/v1/LazyValue.scala +++ b/scalafix-core/src/main/scala/scalafix/internal/v1/LazyValue.scala @@ -36,4 +36,6 @@ object LazyValue { def later[T](e: () => T): LazyValue[T] = new LazyValue[T](e) def fromUnsafe[T](e: () => T): LazyValue[Option[T]] = new LazyValue[Option[T]](() => Try(e()).toOption) + def from[T](e: () => Try[T]): LazyValue[Option[T]] = + new LazyValue[Option[T]](() => e().toOption) } diff --git a/scalafix-rules/src/main/scala/scala/meta/internal/pc/ScalafixGlobal.scala b/scalafix-rules/src/main/scala/scala/meta/internal/pc/ScalafixGlobal.scala index 1e2b9660b..3e6f2746b 100644 --- a/scalafix-rules/src/main/scala/scala/meta/internal/pc/ScalafixGlobal.scala +++ b/scalafix-rules/src/main/scala/scala/meta/internal/pc/ScalafixGlobal.scala @@ -2,7 +2,6 @@ package scala.meta.internal.pc import java.io.File import java.{util => ju} - import scala.collection.mutable import scala.reflect.internal.{Flags => gf} import scala.reflect.io.VirtualDirectory @@ -11,9 +10,9 @@ import scala.tools.nsc.interactive.Global import scala.tools.nsc.reporters.StoreReporter import scala.util.control.NonFatal import scala.{meta => m} - import scala.meta.internal.semanticdb.scalac.SemanticdbOps import scala.meta.io.AbsolutePath +import scala.util.{Failure, Success, Try} // used to cross-compile import scala.collection.compat._ // scalafix:ok @@ -22,7 +21,7 @@ object ScalafixGlobal { cp: List[AbsolutePath], options: List[String], symbolReplacements: Map[String, String] - ): ScalafixGlobal = { + ): Try[ScalafixGlobal] = { val classpath = cp.mkString(File.pathSeparator) val vd = new VirtualDirectory("(memory)", None) val settings = new Settings @@ -35,9 +34,19 @@ object ScalafixGlobal { } val (isSuccess, unprocessed) = settings.processArguments(options, processAll = true) - require(isSuccess, unprocessed) - require(unprocessed.isEmpty, unprocessed) - new ScalafixGlobal(settings, new StoreReporter(), symbolReplacements) + (isSuccess, unprocessed) match { + case (true, Nil) => + Try( + new ScalafixGlobal(settings, new StoreReporter(), symbolReplacements) + ) + case (isSuccess, unprocessed) => + Failure( + new Exception( + s"newGlobal failed while processing Arguments. " + + s"Status is $isSuccess, unprocessed arguments are $unprocessed" + ) + ) + } } } diff --git a/scalafix-rules/src/main/scala/scalafix/internal/rule/CompilerTypePrinter.scala b/scalafix-rules/src/main/scala/scalafix/internal/rule/CompilerTypePrinter.scala index ed2b5310f..6ce5925b9 100644 --- a/scalafix-rules/src/main/scala/scalafix/internal/rule/CompilerTypePrinter.scala +++ b/scalafix-rules/src/main/scala/scalafix/internal/rule/CompilerTypePrinter.scala @@ -14,14 +14,14 @@ import scalafix.v1 class CompilerTypePrinter(g: ScalafixGlobal, config: ExplicitResultTypesConfig)( implicit ctx: v1.SemanticDocument -) extends TypePrinter { +) { import g._ private lazy val unit = g.newCompilationUnit(ctx.input.text, ctx.input.syntax) private val willBeImported = mutable.Map.empty[Name, ShortName] private val isInsertedClass = mutable.Set.empty[String] - override def toPatch( + def toPatch( pos: m.Position, sym: v1.Symbol, replace: m.Token, diff --git a/scalafix-rules/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala b/scalafix-rules/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala index e99d88d46..59c2bea55 100644 --- a/scalafix-rules/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala +++ b/scalafix-rules/src/main/scala/scalafix/internal/rule/ExplicitResultTypes.scala @@ -55,7 +55,7 @@ final class ExplicitResultTypes( if (config.scalacClasspath.isEmpty) { LazyValue.now(None) } else { - LazyValue.fromUnsafe { () => + LazyValue.from { () => ScalafixGlobal.newCompiler( config.scalacClasspath, config.scalacOptions, @@ -92,35 +92,32 @@ final class ExplicitResultTypes( } } - override def fix(implicit ctx: SemanticDocument): Patch = { + override def fix(implicit ctx: SemanticDocument): Patch = try unsafeFix() catch { - case _: CompilerException => - shutdownCompiler() - global.restart() - try unsafeFix() - catch { - case _: CompilerException if !config.fatalWarnings => - // Ignore compiler crashes unless `fatalWarnings = true`. - Patch.empty - } + case _: CompilerException if !config.fatalWarnings => + Patch.empty } - } + def unsafeFix()(implicit ctx: SemanticDocument): Patch = { - lazy val types = TypePrinter(global.value, config) - ctx.tree.collect { - case t @ Defn.Val(mods, Pat.Var(name) :: Nil, None, body) - if isRuleCandidate(t, name, mods, body) => - fixDefinition(t, body, types) - - case t @ Defn.Var(mods, Pat.Var(name) :: Nil, None, Some(body)) - if isRuleCandidate(t, name, mods, body) => - fixDefinition(t, body, types) - - case t @ Defn.Def(mods, name, _, _, None, body) - if isRuleCandidate(t, name, mods, body) => - fixDefinition(t, body, types) - }.asPatch + global.value match { + case Some(value) => + val types = new CompilerTypePrinter(value, config) + ctx.tree.collect { + case t @ Defn.Val(mods, Pat.Var(name) :: Nil, None, body) + if isRuleCandidate(t, name, mods, body) => + fixDefinition(t, body, types) + + case t @ Defn.Var(mods, Pat.Var(name) :: Nil, None, Some(body)) + if isRuleCandidate(t, name, mods, body) => + fixDefinition(t, body, types) + + case t @ Defn.Def(mods, name, _, _, None, body) + if isRuleCandidate(t, name, mods, body) => + fixDefinition(t, body, types) + }.asPatch + case None => Patch.empty + } } // Don't explicitly annotate vals when the right-hand body is a single call @@ -195,8 +192,13 @@ final class ExplicitResultTypes( } } - def defnType(defn: Defn, replace: Token, space: String, types: TypePrinter)( - implicit ctx: SemanticDocument + def defnType( + defn: Defn, + replace: Token, + space: String, + types: CompilerTypePrinter + )(implicit + ctx: SemanticDocument ): Option[Patch] = for { name <- defnName(defn) @@ -204,7 +206,7 @@ final class ExplicitResultTypes( patch <- types.toPatch(name.pos, defnSymbol, replace, defn, space) } yield patch - def fixDefinition(defn: Defn, body: Term, types: TypePrinter)(implicit + def fixDefinition(defn: Defn, body: Term, types: CompilerTypePrinter)(implicit ctx: SemanticDocument ): Patch = { val lst = ctx.tokenList diff --git a/scalafix-rules/src/main/scala/scalafix/internal/rule/TypePrinter.scala b/scalafix-rules/src/main/scala/scalafix/internal/rule/TypePrinter.scala deleted file mode 100644 index 0feee4616..000000000 --- a/scalafix-rules/src/main/scala/scalafix/internal/rule/TypePrinter.scala +++ /dev/null @@ -1,28 +0,0 @@ -package scalafix.internal.rule - -import scala.{meta => m} - -import scala.meta.internal.pc.ScalafixGlobal - -import scalafix.v1 - -class TypePrinter { - def toPatch( - pos: m.Position, - sym: v1.Symbol, - replace: m.Token, - defn: m.Defn, - space: String - ): Option[v1.Patch] = None -} - -object TypePrinter { - def apply( - global: Option[ScalafixGlobal], - config: ExplicitResultTypesConfig - )(implicit ctx: v1.SemanticDocument): TypePrinter = - global match { - case None => new TypePrinter - case Some(value) => new CompilerTypePrinter(value, config) - } -} diff --git a/scalafix-tests/unit/src/test/scala/scalafix/tests/rule/MavenFuzzSuite.scala b/scalafix-tests/unit/src/test/scala/scalafix/tests/rule/MavenFuzzSuite.scala index 34ded678c..566915f19 100644 --- a/scalafix-tests/unit/src/test/scala/scalafix/tests/rule/MavenFuzzSuite.scala +++ b/scalafix-tests/unit/src/test/scala/scalafix/tests/rule/MavenFuzzSuite.scala @@ -145,11 +145,13 @@ class MavenFuzzSuite extends AnyFunSuite with DiffAssertions { } tmp.toFile().deleteOnExit() - val g = ScalafixGlobal.newCompiler( - classfiles.map(AbsolutePath(_)).toList, - Nil, - Map.empty - ) + val g = ScalafixGlobal + .newCompiler( + classfiles.map(AbsolutePath(_)).toList, + Nil, + Map.empty + ) + .get val paths = getCompilingSources(g, classfiles, sources, tmp) exec("git", "init") exec("git", "add", ".")