Skip to content

Commit e72a2e2

Browse files
authored
Merge pull request #812 from olafurpg/perf
Performance improvements
2 parents efa85ee + cf2fa8f commit e72a2e2

File tree

14 files changed

+95
-52
lines changed

14 files changed

+95
-52
lines changed

scalafix-cli/src/main/scala/scalafix/internal/v1/MainOps.scala

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import scala.collection.mutable.ListBuffer
2323
import scala.meta.Tree
2424
import scala.meta.inputs.Input
2525
import scala.meta.internal.semanticdb.TextDocument
26+
import scala.meta.internal.tokenizers.PlatformTokenizerCache
2627
import scala.meta.io.AbsolutePath
2728
import scala.meta.parsers.ParseException
2829
import scala.util.control.NoStackTrace
@@ -229,8 +230,10 @@ object MainOps {
229230
}
230231

231232
def handleFile(args: ValidatedArgs, file: AbsolutePath): ExitStatus = {
232-
try unsafeHandleFile(args, file)
233-
catch {
233+
try {
234+
PlatformTokenizerCache.megaCache.clear()
235+
unsafeHandleFile(args, file)
236+
} catch {
234237
case e: ParseException =>
235238
args.config.reporter.error(e.shortMessage, e.pos)
236239
ExitStatus.ParseError
@@ -251,10 +254,15 @@ object MainOps {
251254

252255
def run(args: ValidatedArgs): ExitStatus = {
253256
val files = this.files(args)
257+
var i = 0
258+
val N = files.length
259+
val width = N.toString.length
254260
var exit = ExitStatus.Ok
255261
files.foreach { file =>
256262
if (args.args.verbose) {
257-
args.config.reporter.info(s"Processing $file")
263+
val message = s"Processing (%${width}s/%s) %s".format(i, N, file)
264+
args.config.reporter.info(message)
265+
i += 1
258266
}
259267
val next = handleFile(args, file)
260268
exit = ExitStatus.merge(exit, next)

scalafix-core/src/main/scala/scalafix/internal/config/Optimization.scala

Lines changed: 0 additions & 17 deletions
This file was deleted.

scalafix-core/src/main/scala/scalafix/internal/config/ScalafixConfig.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ case class ScalafixConfig(
1010
debug: DebugConfig = DebugConfig(),
1111
groupImportsByPrefix: Boolean = true,
1212
fatalWarnings: Boolean = true,
13-
optimization: Optimization = Optimization.default,
1413
reporter: ScalafixReporter = ScalafixReporter.default,
1514
patches: ConfigRulePatches = ConfigRulePatches.default,
1615
dialect: Dialect = ScalafixConfig.DefaultDialect,

scalafix-core/src/main/scala/scalafix/internal/diff/DiffDisable.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ object DiffDisable {
1515
sealed trait DiffDisable {
1616
def isDisabled(position: Position): Boolean
1717
def isDisabled(file: Input): Boolean
18+
def isEmpty: Boolean
1819
}
1920

20-
private object EmptyDiff extends DiffDisable {
21+
object EmptyDiff extends DiffDisable {
22+
override def isEmpty: Boolean = true
2123
def isDisabled(position: Position): Boolean = false
2224
def isDisabled(file: Input): Boolean = false
2325
}
2426

25-
private class FullDiffDisable(diffs: List[GitDiff]) extends DiffDisable {
27+
class FullDiffDisable(diffs: List[GitDiff]) extends DiffDisable {
28+
override def isEmpty: Boolean = diffs.isEmpty
2629
private val newFiles: Set[String] = diffs.collect {
2730
case NewFile(path) => path.toAbsolutePath.toString
2831
}.toSet

scalafix-core/src/main/scala/scalafix/internal/patch/EscapeHatch.scala

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import scala.meta.tokens.Token
1010
import scala.meta.tokens.Token.Comment
1111
import scalafix.v0._
1212
import scalafix.internal.config.FilterMatcher
13-
import scalafix.internal.config.ScalafixConfig
14-
import scalafix.internal.diff.DiffDisable
1513
import scalafix.internal.patch.EscapeHatch._
1614
import scalafix.lint.RuleDiagnostic
1715
import scalafix.patch.AtomicPatch
@@ -32,13 +30,33 @@ class EscapeHatch private (
3230
anchoredEscapes: AnchoredEscapes,
3331
annotatedEscapes: AnnotatedEscapes) {
3432

33+
def rawFilter(
34+
patchesByName: Map[RuleName, Patch],
35+
ctx: RuleCtx): (Patch, List[RuleDiagnostic]) = {
36+
var patchBuilder = Patch.empty
37+
val diagnostics = List.newBuilder[RuleDiagnostic]
38+
patchesByName.foreach {
39+
case (rule, rulePatch) =>
40+
Patch.foreach(rulePatch) {
41+
case LintPatch(message) =>
42+
diagnostics += message.toDiagnostic(rule, ctx.config)
43+
case rewritePatch =>
44+
patchBuilder += rewritePatch
45+
}
46+
}
47+
(patchBuilder, diagnostics.result())
48+
}
49+
3550
def filter(
3651
patchesByName: Map[RuleName, Patch],
3752
ctx: RuleCtx,
38-
index: SemanticdbIndex,
39-
diff: DiffDisable,
40-
config: ScalafixConfig
53+
index: SemanticdbIndex
4154
): (Patch, List[RuleDiagnostic]) = {
55+
if (!FastPatch.hasSuppression(ctx.input.text) && ctx.diffDisable.isEmpty) {
56+
return rawFilter(patchesByName, ctx)
57+
}
58+
val diff = ctx.diffDisable
59+
val config = ctx.config
4260
val usedEscapes = mutable.Set.empty[EscapeFilter]
4361
val lintMessages = List.newBuilder[RuleDiagnostic]
4462

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package scalafix.internal.patch
2+
3+
import scalafix.patch.Patch
4+
import scalafix.rule.RuleName
5+
import scalafix.v0
6+
7+
object FastPatch {
8+
9+
def hasSuppression(text: String): Boolean = {
10+
text.indexOf("scalafix:") >= 0 ||
11+
text.indexOf("SuppressWarnings") >= 0
12+
}
13+
14+
def shortCircuit(
15+
patchesByName: Map[RuleName, Patch],
16+
ctx: v0.RuleCtx): Boolean = {
17+
if (ctx.diffDisable.isEmpty &&
18+
patchesByName.values.forall(_.isEmpty)) {
19+
!hasSuppression(ctx.input.text)
20+
} else {
21+
false
22+
}
23+
}
24+
}

scalafix-core/src/main/scala/scalafix/internal/v0/DeprecatedRuleCtx.scala renamed to scalafix-core/src/main/scala/scalafix/internal/v0/LegacyRuleCtx.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import scalafix.util.TokenList
1212
import scalafix.v0.RuleCtx
1313
import scalafix.v1.Doc
1414

15-
class DeprecatedRuleCtx(doc: Doc) extends RuleCtx with DeprecatedPatchOps {
15+
class LegacyRuleCtx(doc: Doc) extends RuleCtx with DeprecatedPatchOps {
1616
override def tree: Tree = doc.tree
1717
override def input: Input = doc.input
1818
override def tokens: Tokens = doc.tokens

scalafix-core/src/main/scala/scalafix/internal/v0/LegacySemanticRule.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class LegacySemanticRule(name: RuleName, fn: v0.SemanticdbIndex => v0.Rule)
2121
}
2222
}
2323
override def fix(implicit sdoc: SemanticDoc): Patch = {
24-
val ctx = new DeprecatedRuleCtx(sdoc.internal.doc)
24+
val ctx = new LegacyRuleCtx(sdoc.internal.doc)
2525
val rule = fn(new DocSemanticdbIndex(sdoc)).init(this.conf).get
2626
rule.fix(ctx) + LegacyRule.lints(ctx, rule)
2727
}

scalafix-core/src/main/scala/scalafix/internal/v0/LegacySyntacticRule.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class LegacySyntacticRule(rule: v0.Rule) extends SyntacticRule(rule.name) {
1818
}
1919
}
2020
override def fix(implicit doc: Doc): Patch = {
21-
val ctx = new DeprecatedRuleCtx(doc)
21+
val ctx = new LegacyRuleCtx(doc)
2222
configuredRule.fix(ctx) + LegacyRule.lints(ctx, configuredRule)
2323
}
2424
}

scalafix-core/src/main/scala/scalafix/patch/Patch.scala

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ import scalafix.patch.TreePatch.ReplaceSymbol
1616
import org.scalameta.logger
1717
import scala.meta.Token
1818
import scala.meta.tokens.Tokens
19+
import scalafix.internal.patch.FastPatch
1920
import scalafix.internal.config.ScalafixMetaconfigReaders
2021
import scalafix.internal.util.SuppressOps
2122
import scalafix.internal.util.SymbolOps.Root
22-
import scalafix.internal.v0.DeprecatedRuleCtx
23+
import scalafix.internal.v0.LegacyRuleCtx
2324
import scalafix.internal.v0.DocSemanticdbIndex
2425
import scalafix.lint.RuleDiagnostic
2526
import scalafix.patch.TreePatch.AddGlobalImport
@@ -204,18 +205,11 @@ object Patch {
204205
index: Option[SemanticdbIndex],
205206
suppress: Boolean = false
206207
): (String, List[RuleDiagnostic]) = {
207-
if (ctx.config.optimization.skipSuppressionWhenPossible &&
208-
patchesByName.values.forall(_.isEmpty)) {
208+
if (FastPatch.shortCircuit(patchesByName, ctx)) {
209209
(ctx.input.text, Nil)
210210
} else {
211211
val idx = index.getOrElse(SemanticdbIndex.empty)
212-
val (patch, lints) = ctx.escapeHatch.filter(
213-
patchesByName,
214-
ctx,
215-
idx,
216-
ctx.diffDisable,
217-
ctx.config
218-
)
212+
val (patch, lints) = ctx.escapeHatch.filter(patchesByName, ctx, idx)
219213
val finalPatch =
220214
if (suppress) {
221215
patch + SuppressOps.addComments(ctx.tokens, lints.map(_.position))
@@ -232,7 +226,7 @@ object Patch {
232226
doc: Doc,
233227
suppress: Boolean
234228
): (String, List[RuleDiagnostic]) = {
235-
apply(patchesByName, new DeprecatedRuleCtx(doc), None, suppress)
229+
apply(patchesByName, new LegacyRuleCtx(doc), None, suppress)
236230
}
237231

238232
private[scalafix] def semantic(
@@ -242,7 +236,7 @@ object Patch {
242236
): (String, List[RuleDiagnostic]) = {
243237
apply(
244238
patchesByName,
245-
new DeprecatedRuleCtx(doc.internal.doc),
239+
new LegacyRuleCtx(doc.internal.doc),
246240
Some(new DocSemanticdbIndex(doc)),
247241
suppress)
248242
}
@@ -311,7 +305,7 @@ object Patch {
311305
patch.isEmpty || hasLintMessage && onlyLint
312306
}
313307

314-
private def foreach(patch: Patch)(f: Patch => Unit): Unit = {
308+
private[scalafix] def foreach(patch: Patch)(f: Patch => Unit): Unit = {
315309
def loop(patch: Patch): Unit = patch match {
316310
case Concat(a, b) =>
317311
loop(a)

scalafix-testkit/src/main/scala/scalafix/testkit/DiffAssertions.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@ object DiffAssertions {
2323
else
2424
difflib.DiffUtils
2525
.generateUnifiedDiff(
26-
"original",
27-
"revised",
26+
"expected",
27+
"obtained",
2828
original.asJava,
2929
diff,
3030
1
3131
)
3232
.asScala
33-
.drop(3)
3433
.mkString("\n")
3534
}
3635
}

scalafix-tests/input/src/main/scala/test/escapeHatch/AnnotationUnused.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ rules = [
33
"class:scalafix.test.NoDummy"
44
"class:scalafix.test.NoNull"
55
]
6-
optimization.skipSuppressionWhenPossible = false
76
*/
87
package test.escapeHatch
98

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
banana.rule.SemanticRuleV1
22
banana.rule.SyntacticRuleV1
3+
scalafix.tests.cli.NoOpRule
34
scalafix.tests.cli.DeprecatedName

scalafix-tests/unit/src/test/scala/scalafix/tests/cli/CliSyntacticSuite.scala

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,23 +304,38 @@ class CliSyntacticSuite extends BaseCliSuite {
304304
)
305305

306306
check(
307-
name = "--settings.optimization.skipSuppressionWhenPossible",
307+
name = "skip parser when it's not needed",
308308
originalLayout = """
309309
|/src/shared/a.scala
310310
|object a {
311311
|""".stripMargin,
312312
args = Array(
313313
"-r",
314-
"class:scalafix.tests.cli.NoOpRule",
315-
"--settings.optimization.skipSuppressionWhenPossible",
316-
"true"
314+
"NoOpRule"
317315
),
318316
expectedLayout = """
319317
|/src/shared/a.scala
320318
|object a {
321319
|""".stripMargin,
322320
expectedExit = ExitStatus.Ok
323321
)
322+
323+
check(
324+
name = "don't skip parser when there is a suppression",
325+
originalLayout = """
326+
|/src/shared/a.scala
327+
|object a { // scalafix:
328+
|""".stripMargin,
329+
args = Array(
330+
"-r",
331+
"NoOpRule"
332+
),
333+
expectedLayout = """
334+
|/src/shared/a.scala
335+
|object a { // scalafix:
336+
|""".stripMargin,
337+
expectedExit = ExitStatus.ParseError
338+
)
324339
}
325340

326341
class NoOpRule extends SyntacticRule("NoOpRule") {

0 commit comments

Comments
 (0)