@@ -20,6 +20,7 @@ import mill.util.Jvm
20
20
21
21
import os .Path
22
22
import scala .util .Try
23
+ import scala .annotation .unused
23
24
24
25
/**
25
26
* Core configuration required to compile a single Java compilation target
@@ -108,6 +109,7 @@ trait JavaModule
108
109
def testQuick (args : String * ): Command [(String , Seq [TestResult ])] = Task .Command (persistent = true ) {
109
110
val quicktestFailedClassesLog = Task .dest / " quickTestFailedClasses.json"
110
111
val transitiveCallGraphHashes0 = Task .dest / " transitiveCallGraphHashes0.json"
112
+ val invalidatedClassNamesLog = Task .dest / " invalidatedClassNames.json"
111
113
112
114
val classFiles : Seq [os.Path ] = callGraphAnalysisClasspath()
113
115
.flatMap(os.walk(_).filter(_.ext == " class" ))
@@ -120,7 +122,7 @@ trait JavaModule
120
122
ignoreCall = (callSiteOpt, calledSig) => callGraphAnalysisIgnoreCalls(callSiteOpt, calledSig)
121
123
)
122
124
val testClasses = testForkGrouping()
123
- val (quickTestClassLists, invalidClassNames ) = if (! os.exists(transitiveCallGraphHashes0)) {
125
+ val (quickTestClassLists, invalidatedClassNames ) = if (! os.exists(transitiveCallGraphHashes0)) {
124
126
// cannot calcuate invalid classes, so test all classes
125
127
testClasses -> Set .empty[String ]
126
128
} else {
@@ -133,15 +135,15 @@ trait JavaModule
133
135
}.getOrElse(Seq .empty[String ]).toSet
134
136
}
135
137
136
- val invalidClassNames = callAnalysis.calculateInvalidClassName {
138
+ val invalidatedClassNames = callAnalysis.calculateInvalidatedClassNames {
137
139
Some (upickle.default.read[Map [String , Int ]](os.read.stream(transitiveCallGraphHashes0)))
138
140
}
139
141
140
- val testingClasses = invalidClassNames ++ failedTestClasses
142
+ val testingClasses = invalidatedClassNames ++ failedTestClasses
141
143
142
144
testClasses
143
145
.map(_.filter(testingClasses.contains))
144
- .filter(_.nonEmpty) -> invalidClassNames
146
+ .filter(_.nonEmpty) -> invalidatedClassNames
145
147
}
146
148
147
149
// Clean up the directory for test runners
@@ -171,7 +173,7 @@ trait JavaModule
171
173
172
174
val results = testModuleUtil.runTests()
173
175
174
- val badTestClasses = results match {
176
+ val badTestClasses = ( results match {
175
177
case Result .Failure (_) =>
176
178
// Consider all quick testing classes as failed
177
179
quickTestClassLists.flatten
@@ -180,11 +182,11 @@ trait JavaModule
180
182
results
181
183
.filter(testResult => Set (" Error" , " Failure" ).contains(testResult.status))
182
184
.map(_.fullyQualifiedName)
183
- }
185
+ }).distinct
184
186
185
- os.write.over(quicktestFailedClassesLog, upickle.default.write(badTestClasses.distinct ))
187
+ os.write.over(quicktestFailedClassesLog, upickle.default.write(badTestClasses))
186
188
os.write.over(transitiveCallGraphHashes0, upickle.default.write(callAnalysis.transitiveCallGraphHashes0))
187
- os.write.over(Task .dest / " invalidClasses.json " , upickle.default.write(invalidClassNames ))
189
+ os.write.over(invalidatedClassNamesLog , upickle.default.write(invalidatedClassNames ))
188
190
189
191
results match {
190
192
case Result .Failure (errMsg) => Result .Failure (errMsg)
@@ -1486,47 +1488,9 @@ trait JavaModule
1486
1488
1487
1489
@ internal
1488
1490
protected def callGraphAnalysisIgnoreCalls (
1489
- callSiteOpt : Option [mill.codesig.JvmModel .MethodDef ],
1490
- calledSig : mill.codesig.JvmModel .MethodSig
1491
- ): Boolean = {
1492
- // We can ignore all calls to methods that look like Targets when traversing
1493
- // the call graph. We can do this because we assume `def` Targets are pure,
1494
- // and so any changes in their behavior will be picked up by the runtime build
1495
- // graph evaluator without needing to be accounted for in the post-compile
1496
- // bytecode callgraph analysis.
1497
- def isSimpleTarget (desc : mill.codesig.JvmModel .Desc ) =
1498
- (desc.ret.pretty == classOf [mill.define.Target [? ]].getName ||
1499
- desc.ret.pretty == classOf [mill.define.Worker [? ]].getName) &&
1500
- desc.args.isEmpty
1501
-
1502
- // We avoid ignoring method calls that are simple trait forwarders, because
1503
- // we need the trait forwarders calls to be counted in order to wire up the
1504
- // method definition that a Target is associated with during evaluation
1505
- // (e.g. `myModuleObject.myTarget`) with its implementation that may be defined
1506
- // somewhere else (e.g. `trait MyModuleTrait{ def myTarget }`). Only that one
1507
- // step is necessary, after that the runtime build graph invalidation logic can
1508
- // take over
1509
- def isForwarderCallsiteOrLambda =
1510
- callSiteOpt.nonEmpty && {
1511
- val callSiteSig = callSiteOpt.get.sig
1512
-
1513
- (callSiteSig.name == (calledSig.name + " $" ) &&
1514
- callSiteSig.static &&
1515
- callSiteSig.desc.args.size == 1 )
1516
- || (
1517
- // In Scala 3, lambdas are implemented by private instance methods,
1518
- // not static methods, so they fall through the crack of "isSimpleTarget".
1519
- // Here make the assumption that a zero-arg lambda called from a simpleTarget,
1520
- // should in fact be tracked. e.g. see `integration.invalidation[codesig-hello]`,
1521
- // where the body of the `def foo` target is a zero-arg lambda i.e. the argument
1522
- // of `Cacher.cachedTarget`.
1523
- // To be more precise I think ideally we should capture more information in the signature
1524
- isSimpleTarget(callSiteSig.desc) && calledSig.name.contains(" $anonfun" )
1525
- )
1526
- }
1527
-
1528
- isSimpleTarget(calledSig.desc) && ! isForwarderCallsiteOrLambda
1529
- }
1491
+ @ unused callSiteOpt : Option [mill.codesig.JvmModel .MethodDef ],
1492
+ @ unused calledSig : mill.codesig.JvmModel .MethodSig
1493
+ ): Boolean = false
1530
1494
1531
1495
@ internal
1532
1496
protected def callGraphAnalysisClasspath : Task [Seq [os.Path ]] = Task .Anon {
0 commit comments