-
-
Notifications
You must be signed in to change notification settings - Fork 404
Method call analysis based testQuick
command
#4731
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ import mill.codesig.JvmModel.* | |
import org.objectweb.asm.{ClassReader, ClassVisitor, MethodVisitor, Opcodes} | ||
|
||
import java.net.URLClassLoader | ||
import scala.util.Try | ||
|
||
case class ExternalSummary( | ||
directMethods: Map[JCls, Map[MethodSig, Boolean]], | ||
|
@@ -47,7 +48,8 @@ object ExternalSummary { | |
|
||
def load(cls: JCls): Unit = methodsPerCls.getOrElse(cls, load0(cls)) | ||
|
||
def load0(cls: JCls): Unit = { | ||
// Some macros implementations will fail the ClassReader, we can skip them | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What kind of error do those macro implementations produce? We should try and be specific about what errors we catch here, to avoid silencing unexpected errors that may indicate real issues There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you run // Source code is decompiled from a .class file using FernFlower decompiler.
package mill.define;
import java.io.Serializable;
import mill.define.internal.CrossMacros;
import mill.define.internal.CrossMacros.;
import scala.runtime.ModuleSerializationProxy;
public final class Cross$Factory$ implements Serializable {
public static final Cross$Factory$ MODULE$ = new Cross$Factory$();
public Cross$Factory$() {
}
private Object writeReplace() {
return new ModuleSerializationProxy(Cross$Factory$.class);
}
public CrossMacros inline$CrossMacros$i1(final internal x$0) {
return .MODULE$;
}
} The retrieved call from asm yield something like this: As you can see I don't know why the code is like this, I will try to reproduce this and look around for clues |
||
def load0(cls: JCls): Unit = Try { | ||
val visitor = new MyClassVisitor() | ||
val resourcePath = | ||
os.resource(upstreamClassloader) / os.SubPath(cls.name.replace('.', '/') + ".class") | ||
|
@@ -61,7 +63,7 @@ object ExternalSummary { | |
methodsPerCls(cls) = visitor.methods | ||
ancestorsPerCls(cls) = visitor.ancestors | ||
ancestorsPerCls(cls).foreach(load) | ||
} | ||
}.getOrElse(()) | ||
|
||
(allDirectAncestors ++ allMethodCallParamClasses) | ||
.filter(!localSummary.contains(_)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -124,7 +124,16 @@ object Task extends TaskBase { | |
inline def Command[T](inline t: Result[T])(implicit | ||
inline w: W[T], | ||
inline ctx: mill.define.ModuleCtx | ||
): Command[T] = ${ TaskMacros.commandImpl[T]('t)('w, 'ctx, exclusive = '{ false }) } | ||
): Command[T] = ${ TaskMacros.commandImpl[T]('t)('w, 'ctx, exclusive = '{ false }, persistent = '{ false }) } | ||
|
||
|
||
/** | ||
* This version allow [[Command]] to be persistent | ||
*/ | ||
inline def Command[T](inline persistent: Boolean)(inline t: Result[T])(implicit | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a Command with |
||
inline w: W[T], | ||
inline ctx: mill.define.ModuleCtx | ||
): Command[T] = ${ TaskMacros.commandImpl[T]('t)('w, 'ctx, exclusive = '{ false }, persistent = '{ persistent }) } | ||
|
||
/** | ||
* @param exclusive Exclusive commands run serially at the end of an evaluation, | ||
|
@@ -142,7 +151,7 @@ object Task extends TaskBase { | |
inline def apply[T](inline t: Result[T])(implicit | ||
inline w: W[T], | ||
inline ctx: mill.define.ModuleCtx | ||
): Command[T] = ${ TaskMacros.commandImpl[T]('t)('w, 'ctx, '{ this.exclusive }) } | ||
): Command[T] = ${ TaskMacros.commandImpl[T]('t)('w, 'ctx, '{ this.exclusive }, '{ false }) } | ||
} | ||
|
||
/** | ||
|
@@ -396,7 +405,8 @@ class Command[+T]( | |
val ctx0: mill.define.ModuleCtx, | ||
val writer: W[?], | ||
val isPrivate: Option[Boolean], | ||
val exclusive: Boolean | ||
val exclusive: Boolean, | ||
override val persistent: Boolean | ||
) extends NamedTask[T] { | ||
|
||
override def asCommand: Some[Command[T]] = Some(this) | ||
|
@@ -543,12 +553,13 @@ private object TaskMacros { | |
)(t: Expr[Result[T]])( | ||
w: Expr[W[T]], | ||
ctx: Expr[mill.define.ModuleCtx], | ||
exclusive: Expr[Boolean] | ||
exclusive: Expr[Boolean], | ||
persistent: Expr[Boolean] | ||
): Expr[Command[T]] = { | ||
appImpl[Command, T]( | ||
(in, ev) => | ||
'{ | ||
new Command[T]($in, $ev, $ctx, $w, ${ taskIsPrivate() }, exclusive = $exclusive) | ||
new Command[T]($in, $ev, $ctx, $w, ${ taskIsPrivate() }, exclusive = $exclusive, persistent = $persistent) | ||
}, | ||
t | ||
) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
//// SNIPPET:BUILD1 | ||
package build | ||
import mill._, javalib._ | ||
import os._ | ||
|
||
object foo extends JavaModule { | ||
object test extends JavaTests { | ||
def testFramework = "com.novocode.junit.JUnitFramework" // Use JUnit 4 framework interface | ||
def mvnDeps = Seq( | ||
mvn"junit:junit:4.13.2", // JUnit 4 itself | ||
mvn"com.novocode:junit-interface:0.11" // sbt-compatible JUnit interface | ||
) | ||
} | ||
// Ultilities for replacing text in files | ||
def replaceBar(args: String*) = Task.Command { | ||
val relativePath = os.RelPath("../../../foo/src/Bar.java") | ||
val filePath = Task.dest() / relativePath | ||
os.write.over(filePath, os.read(filePath).replace( | ||
"""return String.format("Hi, %s!", name);""", | ||
"""return String.format("Ciao, %s!", name);""" | ||
)) | ||
} | ||
Comment on lines
+15
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's move these into the |
||
|
||
def replaceFooTest2(args: String*) = Task.Command { | ||
val relativePath = os.RelPath("../../../foo/test/src/FooTest2.java") | ||
val filePath = Task.dest() / relativePath | ||
os.write.over(filePath, os.read(filePath).replace( | ||
"""assertEquals("Hi, " + name + "!", greeted);""", | ||
"""assertEquals("Ciao, " + name + "!", greeted);""", | ||
)) | ||
} | ||
} | ||
//// SNIPPET:END |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package foo; | ||
|
||
public class Bar { | ||
public static String greet(String name) { | ||
return String.format("Hello, %s!", name); | ||
} | ||
|
||
public static String greet2(String name) { | ||
return String.format("Hi, %s!", name); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these two
mandatoryLog
s necessary? It seems we only usetransitiveCallGraphHashes
andspanningInvalidationTree
, at least as far as I can tellThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no ideal either, I put them here to mimic the original code, which log everything like this