-
Notifications
You must be signed in to change notification settings - Fork 477
Fix anonymous inner classes #1027
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
Fix anonymous inner classes #1027
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1027 +/- ##
=========================================
Coverage 74.01% 74.01%
Complexity 3434 3434
=========================================
Files 382 382
Lines 10614 10614
Branches 1297 1297
=========================================
Hits 7856 7856
Misses 2294 2294
Partials 464 464
Continue to review full report at Codecov.
|
|
While trying to satisfy Codecov, I spent a tremendous amount of trial and error to find out what actually triggers the failure, as I had a bit of a problem to write a small but failing test. So it "only" fails if either
or
|
c84876b to
f3e84e5
Compare
|
If anyone is in need for a work-around that does not involve changing the code under test but is a proper generic solution, here is a custom Groovy AST transformation that does what this PR is doing after Spock did its transformations: @GroovyASTTransformation
public class AnonymousClassTransform implements ASTTransformation {
@Override
public void visit(ASTNode[] nodes, SourceUnit source) {
((ModuleNode) nodes[0])
.getClasses()
.stream()
.filter(clazz -> clazz.getEnclosingMethod() != null)
.forEach(clazz -> {
MethodNode enclosingMethod = clazz.getEnclosingMethod();
String enclosingMethodName = enclosingMethod.getName();
enclosingMethod
.getDeclaringClass()
.getMethods()
.stream()
.filter(method -> method
.getAnnotations()
.stream()
.anyMatch(annotation -> {
ClassNode annotationClass = annotation.getClassNode();
Expression nameAttribute = annotation.getMember("name");
return (annotationClass != null)
&& (nameAttribute != null)
&& "org.spockframework.runtime.model.FeatureMetadata".equals(annotationClass.getName())
&& enclosingMethodName.equals(nameAttribute.getText());
}))
.findAny()
.ifPresent(clazz::setEnclosingMethod);
});
}
} |
f3e84e5 to
1d135ed
Compare
I have a test like
which runs fine with Java 8, but with Java 11 I get
Where
CommandTest$1is thenew BaseCommand() { }.If I instead do
it works fine.
I found out this has to do with the enclosing method.
If I run with Java 8 and do
testee.getClass().getEnclosingMethodInfo(),I get
#testee.getClass().simpleName should have #aliases #expectedAliasesas enclosing method,but calling
testee.getClass().getEnclosingMethod()throws anInternalError("Enclosing method not found"),as in the transformed spec the enclosing method was changed due to AST rewriting,
but the inner class was not rewritten to have a valid method as enclosing method.
It seems in Java 11 the validation in
java.lang.ClassLoader.defineClass1(...)was extendedto there already validate the enclosing method name for syntactical correctness.
I still get the
InternalErrorwhen using the@Unrollannotation and name the methodfoo,but at least then
defineClass1(...)is happy.I added a breakpoint in
org.spockframework.compiler.SpecRewriter#transplantMethodafter
newAstwas created that does evaluateoldAst.declaringClass.innerClasses.findAll { it.enclosingMethod == oldAst }*.enclosingMethod = newAstand suddenly the test succeeds properly and also
testee.enclosingMethodcan be properly resolved.So the changes in this PR do exactly this, they find inner classes that have the
old rewritten feature method as enclosing method and set the new rewritten feature
method as enclosing method instead.
This change is