Bug report (original) (raw)

Adam Hawthorne adamh at basis.com
Thu Jan 10 14:42:54 PST 2013


Per Jonathan, here are the relevant fields from the public bug form:

Synopsis: Trees.getScope() fails for TreePath in constructor with super() or this() call

Full OS version: Linux hostname 3.2.0-36-generic #56-Ubuntu SMP Wed Jan 2 21:50:39 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

Development Kit or Runtime version: java version "1.7.0_10" Java(TM) SE Runtime Environment (build 1.7.0_10-b18) Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04, mixed mode)

Description: In developing an annotation processor that's doing additional constraint checking, I noticed in Java 6 that I would receive error messages saying:

:23: error: call to super must be first statement in constructor super(p_commandID); ^

These didn't affect the operation of my annotation processor. Now, we're in the process of upgrading to Java 7, and we discovered both that these error messages are fully formed, containing the entire java file, and that they prevent the annotation processor from completing successfully.

These files compile correctly via javac, and upon further inspection of the files, the calls to super() are indeed the first statement in each of the constructors, so this error message is itself erroneous.

In digging into the Javac source from the source tarball in OpenJDK 7u6, I see that the JavacTrees.getScope() method calls JavacTrees.getAttrContext(TreePath) . getAttrContext() iterates through the JCTree's in the TreePath and uses a switch on the Kind to visit each one.

In the BLOCK case of that switch statement, there is the following code:

                if (method != null)
                    env = memberEnter.getMethodEnv(method, env);
                JCTree body = copier.copy((JCTree)tree, (JCTree)

path.getLeaf()); env = attribStatToTree(body, env, copier.leafCopy); return env;

I believe the problem might be that 'env' is passed to attribStatToTree(), but 'env' contains a reference to the original Tree, while 'body' and 'copier.leafCopy' have a distinct copy of the tree.

Later, deeper in the call stack, Attr.checkFirstConstructorStat() has the following code. The portion of the expression that fails is:

((JCExpressionStatement) body.stats.head).expr == tree

Since 'body' was obtained from 'enclMethod' and 'enclMethod' was obtained from 'env', and since 'env' doesn't refer to the same JCTree as 'tree', the identity comparison fails.

boolean checkFirstConstructorStat(JCMethodInvocation tree, Env env) { JCMethodDecl enclMethod = env.enclMethod; if (enclMethod != null && enclMethod.name == names.init) { JCBlock body = enclMethod.body; if (body.stats.head.getTag() == JCTree.EXEC && ((JCExpressionStatement) body.stats.head).expr == tree) return true; } log.error(tree.pos(),"call.must.be.first.stmt.in.ctor", TreeInfo.name(tree.meth)); return false; }

I'm not at all familiar with the Javac internals, so this is all speculation, but after inspecting, this makes the most sense to me. Hope it helps.

Steps to Reproduce: Using the provided source code, first, build the annotation processor:

javac -classpath .:/path/to/tools.jar bug/*.java

Then run the annotation processor on the test file:

javac -classpath . -processor bug.TreesScopeBug bug/TreesScopeBugTest.java

Expected Result: I would expect to see no output, and for the TreesScopeBugTest.class file to be updated.

Actual Result: I see the error message:

bug/TreesScopeBugTest.java:6: error: call to super must be first statement in constructor super(); ^ 1 error

Source code for an executable test case:

bug/TestAnnotation.java:

package bug;

public @interface TestAnnotation { // empty } bug/TreesScopeBug.java:

package bug;

import java.util.Set;

import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import com.sun.source.tree.BlockTree; import com.sun.source.util.TreePath; import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees;

@SupportedAnnotationTypes("bug.TestAnnotation") @SupportedSourceVersion(SourceVersion.RELEASE_7) public class TreesScopeBug extends AbstractProcessor {

@Override
public boolean process(Set<? extends TypeElement> p_annotations,
                       RoundEnvironment p_roundEnv) {
    final Trees tr = Trees.instance(processingEnv);
    if (! p_annotations.isEmpty()) {
        // Assuming TestAnnotation here
        TypeElement testAnnElem = p_annotations.iterator().next();
        Set<? extends Element> ctorSet =
            p_roundEnv.getElementsAnnotatedWith(testAnnElem);
        // Assuming one elem here.
        Element e = ctorSet.iterator().next();
        TreePath path = tr.getPath(e);
        new TreePathScanner<Void, Void>() {
            @Override
            public Void visitBlock(BlockTree node, Void p) {
                // Bug occurs here, but diagnostics are delayed.
                tr.getScope(getCurrentPath());
                return null;
            }
        }.scan(path, null);
    }
    return true;
}

}

bug/TreeScopeBugTest.java:

package bug;

public class TreesScopeBugTest { @TestAnnotation TreesScopeBugTest() { super(); } }

Workaround:

I think I can workaround by duplicating the operation of 'Scope' in my particular use-case, but I don't believe a generic workaround is available.

On Thu, Jan 10, 2013 at 5:22 PM, Adam Hawthorne <adamh at basis.com> wrote:

Sorry in advance for the OT post.

I've been trying all day to submit a javac/Tree API bug on bugreport.sun.com, and it fails every time. Is there some other place I can/should send this? The bug is in Trees.getScope() . Feel free to reply privately to avoid OT list traffic. Thanks in advance. Adam

-- Adam Hawthorne Software Architect BASIS International Ltd. www.basis.com +1.505.938.6169 Phone +1.505.750.4128 Direct -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20130110/eb3d6eb4/attachment.html



More information about the compiler-dev mailing list