8136419: Type annotations in initializers and lambda bodies not written to class file

Reviewed-by: jlahoda
This commit is contained in:
Srikanth Adayapalam 2015-11-12 06:13:14 +05:30
parent f7bc90496a
commit 431aa657a6
5 changed files with 223 additions and 15 deletions

View File

@ -180,6 +180,14 @@ public abstract class Symbol extends AnnoConstruct implements Element {
: metadata.getInitTypeAttributes();
}
public void setInitTypeAttributes(List<Attribute.TypeCompound> l) {
initedMetadata().setInitTypeAttributes(l);
}
public void setClassInitTypeAttributes(List<Attribute.TypeCompound> l) {
initedMetadata().setClassInitTypeAttributes(l);
}
public List<Attribute.Compound> getDeclarationAttributes() {
return (metadata == null)
? List.<Attribute.Compound>nil()

View File

@ -32,6 +32,7 @@ import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.Attribute.Array;
import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.code.Type.ArrayType;
import com.sun.tools.javac.code.Type.CapturedType;
@ -388,8 +389,21 @@ public class TypeAnnotations {
sym.getKind() == ElementKind.RESOURCE_VARIABLE ||
sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
// Make sure all type annotations from the symbol are also
// on the owner.
sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes());
// on the owner. If the owner is an initializer block, propagate
// to the type.
final long ownerFlags = sym.owner.flags();
if ((ownerFlags & Flags.BLOCK) != 0) {
// Store init and clinit type annotations with the ClassSymbol
// to allow output in Gen.normalizeDefs.
ClassSymbol cs = (ClassSymbol) sym.owner.owner;
if ((ownerFlags & Flags.STATIC) != 0) {
cs.appendClassInitTypeAttributes(typeAnnotations);
} else {
cs.appendInitTypeAttributes(typeAnnotations);
}
} else {
sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes());
}
}
}

View File

@ -55,12 +55,16 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Kinds.Kind.*;
import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
import javax.lang.model.element.ElementKind;
import javax.lang.model.type.TypeKind;
/**
@ -268,21 +272,34 @@ public class LambdaToMethod extends TreeTranslator {
MethodSymbol sym = localContext.translatedSym;
MethodType lambdaType = (MethodType) sym.type;
{
Symbol owner = localContext.owner;
ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>();
ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>();
{ /* Type annotation management: Based on where the lambda features, type annotations that
are interior to it, may at this point be attached to the enclosing method, or the first
constructor in the class, or in the enclosing class symbol or in the field whose
initializer is the lambda. In any event, gather up the annotations that belong to the
lambda and attach it to the implementation method.
*/
for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) {
if (tc.position.onLambda == tree) {
lambdaTypeAnnos.append(tc);
} else {
ownerTypeAnnos.append(tc);
}
Symbol owner = localContext.owner;
apportionTypeAnnotations(tree,
owner::getRawTypeAttributes,
owner::setTypeAttributes,
sym::setTypeAttributes);
boolean init;
if ((init = (owner.name == names.init)) || owner.name == names.clinit) {
owner = owner.owner;
apportionTypeAnnotations(tree,
init ? owner::getInitTypeAttributes : owner::getClassInitTypeAttributes,
init ? owner::setInitTypeAttributes : owner::setClassInitTypeAttributes,
sym::appendUniqueTypeAttributes);
}
if (lambdaTypeAnnos.nonEmpty()) {
owner.setTypeAttributes(ownerTypeAnnos.toList());
sym.setTypeAttributes(lambdaTypeAnnos.toList());
if (localContext.self != null && localContext.self.getKind() == ElementKind.FIELD) {
owner = localContext.self;
apportionTypeAnnotations(tree,
owner::getRawTypeAttributes,
owner::setTypeAttributes,
sym::appendUniqueTypeAttributes);
}
}
@ -354,6 +371,29 @@ public class LambdaToMethod extends TreeTranslator {
result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
}
// where
// Reassign type annotations from the source that should really belong to the lambda
private void apportionTypeAnnotations(JCLambda tree,
Supplier<List<Attribute.TypeCompound>> source,
Consumer<List<Attribute.TypeCompound>> owner,
Consumer<List<Attribute.TypeCompound>> lambda) {
ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>();
ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>();
for (Attribute.TypeCompound tc : source.get()) {
if (tc.position.onLambda == tree) {
lambdaTypeAnnos.append(tc);
} else {
ownerTypeAnnos.append(tc);
}
}
if (lambdaTypeAnnos.nonEmpty()) {
owner.accept(ownerTypeAnnos.toList());
lambda.accept(lambdaTypeAnnos.toList());
}
}
private JCIdent makeThis(Type type, Symbol owner) {
VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
names._this,

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.annotation.*;
import java.util.ArrayList;
import com.sun.tools.classfile.*;
/*
* @test
* @bug 8136419
* @summary test that type annotations on entities in initializers are emitted to classfile
* @modules jdk.jdeps/com.sun.tools.classfile
*/
public class InstanceInitializer extends ClassfileTestHelper {
public static void main(String[] args) throws Exception {
new InstanceInitializer().run();
}
public void run() throws Exception {
expected_tinvisibles = 4;
expected_tvisibles = 0;
ClassFile cf = getClassFile("InstanceInitializer$Test.class");
test(cf);
for (Field f : cf.fields) {
test(cf, f);
}
for (Method m: cf.methods) {
test(cf, m, true);
}
countAnnotations();
if (errors > 0)
throw new Exception(errors + " errors found");
System.out.println("PASSED");
}
/*********************** Test class *************************/
static class Test {
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface T {}
{
@T String s = null;
Runnable r = () -> new ArrayList<@T String>();
}
@T String s = null;
Runnable r = () -> new ArrayList<@T String>();
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.lang.annotation.*;
import java.util.ArrayList;
import com.sun.tools.classfile.*;
/*
* @test
* @bug 8136419
* @summary test that type annotations on entities in static initializers are emitted to classfile
* @modules jdk.jdeps/com.sun.tools.classfile
*/
public class StaticInitializer extends ClassfileTestHelper {
public static void main(String[] args) throws Exception {
new StaticInitializer().run();
}
public void run() throws Exception {
expected_tinvisibles = 4;
expected_tvisibles = 0;
ClassFile cf = getClassFile("StaticInitializer$Test.class");
test(cf);
for (Field f : cf.fields) {
test(cf, f);
}
for (Method m: cf.methods) {
test(cf, m, true);
}
countAnnotations();
if (errors > 0)
throw new Exception(errors + " errors found");
System.out.println("PASSED");
}
/*********************** Test class *************************/
static class Test {
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface T {}
static {
@T String s = null;
Runnable r = () -> new ArrayList<@T String>();
}
@T static String s = null;
static Runnable r = () -> new ArrayList<@T String>();
}
}