|
Hi,
We are in the process of adding some transform magic to Geb. Basically, in a bunch of places we want to convert every expression into an assertion implicitly. Here's the crux of the implementation: private Statement encloseWithVoidCheckAndAssert(Expression toBeRewritten, Statement original) { return original Statement replacement BooleanExpression booleanExpression = new BooleanExpression(toBeRewritten) Statement withAssertion = new AssertStatement(booleanExpression) if (toBeRewritten in MethodCallExpression) { MethodCallExpression rewrittenMethodCall = toBeRewritten Statement noAssertion = new ExpressionStatement(toBeRewritten) ArgumentListExpression isVoidMethodArguments = new ArgumentListExpression() isVoidMethodArguments.with { addExpression(rewrittenMethodCall.objectExpression) addExpression(rewrittenMethodCall.method) addExpression(toArgumentArray(rewrittenMethodCall.arguments)) } StaticMethodCallExpression isVoidMethod = new StaticMethodCallExpression(new ClassNode(Runtime), "isVoidMethod", isVoidMethodArguments) replacement = new IfStatement(new BooleanExpression(isVoidMethod), noAssertion, withAssertion) } else { replacement = withAssertion } replacement.setSourcePosition(original) replacement } Runtime.isVoidMethod looks like this: class Runtime { public static boolean isVoidMethod(Object target, String method, Object... args) { Class[] argTypes = args.collect { it?.getClass() } as Class[] MetaClass metaClass = InvokerHelper.getMetaClass(target) MetaMethod metaMethod = metaClass.pickMethod(method, argTypes) if (metaMethod == null) { return false } Class returnType = metaMethod.getReturnType() return returnType == void.class || returnType == Void.class } } The code that's being transformed is this: class SomeClass { void voidMethod() { } def run() { waitFor { // transform will visit contents of this closure voidMethod() } } } This works fine for Groovy 1.7. However, when recompiling with 1.8 I get the following compiler exception: groovy.lang.GroovyRuntimeException: NPE while processing GoogleResultsPage.groovy at org.codehaus.groovy.classgen.AsmClassGenerator.visitClass(AsmClassGenerator.java:192) at org.codehaus.groovy.control.CompilationUnit$14.call(CompilationUnit.java:767) at org.codehaus.groovy.control.CompilationUnit$14.call(CompilationUnit.java:784) at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:967) at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:546) at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:524) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:501) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:480) at org.codehaus.groovy.tools.FileSystemCompiler.compile(FileSystemCompiler.java:60) at org.codehaus.groovy.tools.FileSystemCompiler.doCompilation(FileSystemCompiler.java:216) at org.codehaus.groovy.tools.FileSystemCompiler.commandLineCompile(FileSystemCompiler.java:149) at org.codehaus.groovy.tools.FileSystemCompiler.commandLineCompileWithErrorHandling(FileSystemCompiler.java:179) at org.codehaus.groovy.ant.FileSystemCompilerFacade.main(FileSystemCompilerFacade.java:27) Caused by: java.lang.NullPointerException at org.codehaus.groovy.classgen.asm.AssertionWriter.record(AssertionWriter.java:211) at org.codehaus.groovy.classgen.AsmClassGenerator.visitMethodCallExpression(AsmClassGenerator.java:658) at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:75) at org.codehaus.groovy.classgen.AsmClassGenerator.visitBooleanExpression(AsmClassGenerator.java:650) at org.codehaus.groovy.ast.expr.BooleanExpression.visit(BooleanExpression.java:40) at org.codehaus.groovy.classgen.asm.AssertionWriter.writeAssertStatement(AssertionWriter.java:84) at org.codehaus.groovy.classgen.asm.StatementWriter.writeAssert(StatementWriter.java:542) at org.codehaus.groovy.classgen.AsmClassGenerator.visitAssertStatement(AsmClassGenerator.java:469) at org.codehaus.groovy.ast.stmt.AssertStatement.visit(AssertStatement.java:47) at org.codehaus.groovy.classgen.asm.StatementWriter.writeIfElse(StatementWriter.java:292) at org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.writeIfElse(OptimizingStatementWriter.java:277) at org.codehaus.groovy.classgen.AsmClassGenerator.visitIfElse(AsmClassGenerator.java:465) at org.codehaus.groovy.ast.stmt.IfStatement.visit(IfStatement.java:41) at org.codehaus.groovy.classgen.asm.StatementWriter.writeBlockStatement(StatementWriter.java:80) at org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.writeBlockStatement(OptimizingStatementWriter.java:155) at org.codehaus.groovy.classgen.AsmClassGenerator.visitBlockStatement(AsmClassGenerator.java:449) at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:69) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClassCodeContainer(ClassCodeVisitorSupport.java:101) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructorOrMethod(ClassCodeVisitorSupport.java:112) at org.codehaus.groovy.classgen.AsmClassGenerator.visitStdMethod(AsmClassGenerator.java:313) at org.codehaus.groovy.classgen.AsmClassGenerator.visitConstructorOrMethod(AsmClassGenerator.java:270) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:123) at org.codehaus.groovy.classgen.AsmClassGenerator.visitMethod(AsmClassGenerator.java:390) at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1056) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:50) at org.codehaus.groovy.classgen.AsmClassGenerator.visitClass(AsmClassGenerator.java:174) ... 12 more The exception is happening in this method in org.codehaus.groovy.classgen.asm.AssertionWriter: public void record(Expression expression) { if (assertionTracker==null) return; record(assertionTracker.sourceText.getNormalizedColumn(expression.getLineNumber(), expression.getColumnNumber())); } The null value is “assertionTracker.sourceText”. When this method is entered and about to fail, expression looks like this: • expression = {org.codehaus.groovy.ast.expr.ConstantExpression@2136}"ConstantExpression[voidMethod]" • value = {java.lang.String@2144}"voidMethod" • constantName = null • type = {org.codehaus.groovy.ast.ClassNode@2145}"java.lang.String" • annotations = {java.util.Collections$EmptyList@2146} size = 0 • synthetic = false • declaringClass = null • hasNoRealSourcePositionFlag = false • lineNumber = 17 • columnNumber = 13 • lastLineNumber = 17 • lastColumnNumber = 23 • metaDataMap = {org.codehaus.groovy.util.ListHashMap@2148} size = 0 I'm at a bit of a loss here. Does anyone have any insight on why assertionTracker.sourceText would be null here? Thanks. --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email |
|
Hi,
I faced a similar problem recently: you cannot add assert statements programatically, because they are considered as "power asserts". The problem is that the power assert is itself transformed later, and expects the assertion to correspond to source code. In an AST transform, there's no source code for the assert part, so the power assert processor cannot pick the original source code (text) of the assertion, and it fails with an NPE. I think this is something that needs to be fixed. At least, we can avoid the NPE, but an assert in that case should not be considered as a power assert, and fall back to the old behaviour. Can you file an issue for this? Thanks! Le 15/03/2012 15:04, [hidden email] a écrit : > Hi, > > We are in the process of adding some transform magic to Geb. Basically, in a bunch of places we want to convert every expression into an assertion implicitly. > > Here's the crux of the implementation: > > private Statement encloseWithVoidCheckAndAssert(Expression toBeRewritten, Statement original) { > return original > Statement replacement > > BooleanExpression booleanExpression = new BooleanExpression(toBeRewritten) > Statement withAssertion = new AssertStatement(booleanExpression) > > if (toBeRewritten in MethodCallExpression) { > MethodCallExpression rewrittenMethodCall = toBeRewritten > > Statement noAssertion = new ExpressionStatement(toBeRewritten) > > ArgumentListExpression isVoidMethodArguments = new ArgumentListExpression() > isVoidMethodArguments.with { > addExpression(rewrittenMethodCall.objectExpression) > addExpression(rewrittenMethodCall.method) > addExpression(toArgumentArray(rewrittenMethodCall.arguments)) > } > > StaticMethodCallExpression isVoidMethod = new StaticMethodCallExpression(new ClassNode(Runtime), "isVoidMethod", isVoidMethodArguments) > > replacement = new IfStatement(new BooleanExpression(isVoidMethod), noAssertion, withAssertion) > } else { > replacement = withAssertion > } > > replacement.setSourcePosition(original) > replacement > } > > Runtime.isVoidMethod looks like this: > > class Runtime { > public static boolean isVoidMethod(Object target, String method, Object... args) { > Class[] argTypes = args.collect { it?.getClass() } as Class[] > > MetaClass metaClass = InvokerHelper.getMetaClass(target) > > MetaMethod metaMethod = metaClass.pickMethod(method, argTypes) > if (metaMethod == null) { > return false > } > > Class returnType = metaMethod.getReturnType() > return returnType == void.class || returnType == Void.class > } > } > > > The code that's being transformed is this: > > class SomeClass { > void voidMethod() { > } > > def run() { > waitFor { // transform will visit contents of this closure > voidMethod() > } > } > } > > This works fine for Groovy 1.7. However, when recompiling with 1.8 I get the following compiler exception: > > groovy.lang.GroovyRuntimeException: NPE while processing GoogleResultsPage.groovy > at org.codehaus.groovy.classgen.AsmClassGenerator.visitClass(AsmClassGenerator.java:192) > at org.codehaus.groovy.control.CompilationUnit$14.call(CompilationUnit.java:767) > at org.codehaus.groovy.control.CompilationUnit$14.call(CompilationUnit.java:784) > at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:967) > at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:546) > at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:524) > at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:501) > at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:480) > at org.codehaus.groovy.tools.FileSystemCompiler.compile(FileSystemCompiler.java:60) > at org.codehaus.groovy.tools.FileSystemCompiler.doCompilation(FileSystemCompiler.java:216) > at org.codehaus.groovy.tools.FileSystemCompiler.commandLineCompile(FileSystemCompiler.java:149) > at org.codehaus.groovy.tools.FileSystemCompiler.commandLineCompileWithErrorHandling(FileSystemCompiler.java:179) > at org.codehaus.groovy.ant.FileSystemCompilerFacade.main(FileSystemCompilerFacade.java:27) > Caused by: java.lang.NullPointerException > at org.codehaus.groovy.classgen.asm.AssertionWriter.record(AssertionWriter.java:211) > at org.codehaus.groovy.classgen.AsmClassGenerator.visitMethodCallExpression(AsmClassGenerator.java:658) > at org.codehaus.groovy.ast.expr.MethodCallExpression.visit(MethodCallExpression.java:75) > at org.codehaus.groovy.classgen.AsmClassGenerator.visitBooleanExpression(AsmClassGenerator.java:650) > at org.codehaus.groovy.ast.expr.BooleanExpression.visit(BooleanExpression.java:40) > at org.codehaus.groovy.classgen.asm.AssertionWriter.writeAssertStatement(AssertionWriter.java:84) > at org.codehaus.groovy.classgen.asm.StatementWriter.writeAssert(StatementWriter.java:542) > at org.codehaus.groovy.classgen.AsmClassGenerator.visitAssertStatement(AsmClassGenerator.java:469) > at org.codehaus.groovy.ast.stmt.AssertStatement.visit(AssertStatement.java:47) > at org.codehaus.groovy.classgen.asm.StatementWriter.writeIfElse(StatementWriter.java:292) > at org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.writeIfElse(OptimizingStatementWriter.java:277) > at org.codehaus.groovy.classgen.AsmClassGenerator.visitIfElse(AsmClassGenerator.java:465) > at org.codehaus.groovy.ast.stmt.IfStatement.visit(IfStatement.java:41) > at org.codehaus.groovy.classgen.asm.StatementWriter.writeBlockStatement(StatementWriter.java:80) > at org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.writeBlockStatement(OptimizingStatementWriter.java:155) > at org.codehaus.groovy.classgen.AsmClassGenerator.visitBlockStatement(AsmClassGenerator.java:449) > at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:69) > at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClassCodeContainer(ClassCodeVisitorSupport.java:101) > at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructorOrMethod(ClassCodeVisitorSupport.java:112) > at org.codehaus.groovy.classgen.AsmClassGenerator.visitStdMethod(AsmClassGenerator.java:313) > at org.codehaus.groovy.classgen.AsmClassGenerator.visitConstructorOrMethod(AsmClassGenerator.java:270) > at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:123) > at org.codehaus.groovy.classgen.AsmClassGenerator.visitMethod(AsmClassGenerator.java:390) > at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1056) > at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:50) > at org.codehaus.groovy.classgen.AsmClassGenerator.visitClass(AsmClassGenerator.java:174) > ... 12 more > > The exception is happening in this method in org.codehaus.groovy.classgen.asm.AssertionWriter: > > public void record(Expression expression) { > if (assertionTracker==null) return; > record(assertionTracker.sourceText.getNormalizedColumn(expression.getLineNumber(), expression.getColumnNumber())); > } > > The null value is “assertionTracker.sourceText”. > > When this method is entered and about to fail, expression looks like this: > > • expression = {org.codehaus.groovy.ast.expr.ConstantExpression@2136}"ConstantExpression[voidMethod]" > • value = {java.lang.String@2144}"voidMethod" > • constantName = null > • type = {org.codehaus.groovy.ast.ClassNode@2145}"java.lang.String" > • annotations = {java.util.Collections$EmptyList@2146} size = 0 > • synthetic = false > • declaringClass = null > • hasNoRealSourcePositionFlag = false > • lineNumber = 17 > • columnNumber = 13 > • lastLineNumber = 17 > • lastColumnNumber = 23 > • metaDataMap = {org.codehaus.groovy.util.ListHashMap@2148} size = 0 > > > I'm at a bit of a loss here. Does anyone have any insight on why assertionTracker.sourceText would be null here? > > Thanks. > > > > --------------------------------------------------------------------- > To unsubscribe from this list, please visit: > > http://xircles.codehaus.org/manage_email > > > -- Cédric Champeau SpringSource - A Division Of VMware http://www.springsource.com/ http://twitter.com/CedricChampeau --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email |
|
Hi,
as far as I remember the old behavior can be triggered by providing an assert message expression != ConstantExpression.NULL Cheers, André -- Andre Steingresshttp://about.me/asteingress http://blog.andresteingress.com http://github.com/andresteingress On Thursday, March 15, 2012 at 3:22 PM, Cédric Champeau wrote:
|
|
In reply to this post by Cédric Champeau
On 15/03/2012, at 2:22 PM, Cédric Champeau wrote: > I faced a similar problem recently: you cannot add assert statements programatically, because they are considered as "power asserts". The problem is that the power assert is itself transformed later, and expects the assertion to correspond to source code. In an AST transform, there's no source code for the assert part, so the power assert processor cannot pick the original source code (text) of the assertion, and it fails with an NPE. Ouch. > I think this is something that needs to be fixed. At least, we can avoid the NPE, but an assert in that case should not be considered as a power assert, and fall back to the old behaviour. Can you file an issue for this? http://jira.codehaus.org/browse/GROOVY-5366 So there is no way to add assertions and have them become power asserts and never will be? Is this a technical impossibility? --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email |
|
It is technically possible, GContracts uses power asserts all over the place.
You need to call assertStatement.setSourcePosition() as in https://github.com/andresteingress/gcontracts/blob/1.2/gcontracts-core/src/main/java/org/gcontracts/generation/AssertStatementCreationUtility.java Cheers, André -- Andre Steingresshttp://about.me/asteingress http://blog.andresteingress.com http://github.com/andresteingress On Thursday, March 15, 2012 at 3:49 PM, [hidden email] wrote:
|
|
This has made it work fine for me.
Thanks André! On 15/03/2012, at 2:58 PM, Andre Steingress wrote:
|
|
Luke, could you nail down the exact problem? I just saw you actually called setSourcePosition()...
Cheers, André |
| Powered by Nabble | Edit this page |
