Merge
This commit is contained in:
commit
c6007b2aa2
@ -744,6 +744,7 @@ public class ClassWriter {
|
||||
out.writeByte(p.type_index);
|
||||
break;
|
||||
case CLASS_LITERAL:
|
||||
case CLASS_LITERAL_GENERIC_OR_ARRAY:
|
||||
out.writeShort(p.offset);
|
||||
break;
|
||||
// method parameter: not specified
|
||||
|
@ -123,11 +123,14 @@ public class ExtendedAnnotation {
|
||||
// Class extends and implements clauses
|
||||
case CLASS_EXTENDS:
|
||||
case CLASS_EXTENDS_GENERIC_OR_ARRAY:
|
||||
position.type_index = cr.readUnsignedByte();
|
||||
int in = cr.readUnsignedShort();
|
||||
if (in == 0xFFFF)
|
||||
in = -1;
|
||||
position.type_index = in;
|
||||
break;
|
||||
// throws
|
||||
case THROWS:
|
||||
position.type_index = cr.readUnsignedByte();
|
||||
position.type_index = cr.readUnsignedShort();
|
||||
break;
|
||||
case CLASS_LITERAL:
|
||||
case CLASS_LITERAL_GENERIC_OR_ARRAY:
|
||||
@ -213,11 +216,11 @@ public class ExtendedAnnotation {
|
||||
// Class extends and implements clauses
|
||||
case CLASS_EXTENDS:
|
||||
case CLASS_EXTENDS_GENERIC_OR_ARRAY:
|
||||
n += 1; // type_index
|
||||
n += 2; // type_index
|
||||
break;
|
||||
// throws
|
||||
case THROWS:
|
||||
n += 1; // type_index
|
||||
n += 2; // type_index
|
||||
break;
|
||||
case CLASS_LITERAL:
|
||||
case CLASS_LITERAL_GENERIC_OR_ARRAY:
|
||||
@ -264,18 +267,18 @@ public class ExtendedAnnotation {
|
||||
public int offset = -1;
|
||||
|
||||
// For locals.
|
||||
public int[] lvarOffset = new int[] { -1 };
|
||||
public int[] lvarLength = new int[] { -1 };
|
||||
public int[] lvarIndex = new int[] { -1 };
|
||||
public int[] lvarOffset = null;
|
||||
public int[] lvarLength = null;
|
||||
public int[] lvarIndex = null;
|
||||
|
||||
// For type parameter bound
|
||||
public int bound_index = -1;
|
||||
public int bound_index = Integer.MIN_VALUE;
|
||||
|
||||
// For type parameter and method parameter
|
||||
public int parameter_index = -1;
|
||||
public int parameter_index = Integer.MIN_VALUE;
|
||||
|
||||
// For class extends, implements, and throws classes
|
||||
public int type_index = -2;
|
||||
public int type_index = Integer.MIN_VALUE;
|
||||
|
||||
// For wildcards
|
||||
public Position wildcard_position = null;
|
||||
|
@ -113,6 +113,7 @@ public class Flags {
|
||||
public static final int ENUM = 1<<14;
|
||||
|
||||
public static final int StandardFlags = 0x0fff;
|
||||
public static final int ModifierFlags = StandardFlags & ~INTERFACE;
|
||||
|
||||
// Because the following access flags are overloaded with other
|
||||
// bit positions, we translate them when reading and writing class
|
||||
|
@ -657,6 +657,11 @@ public abstract class Symbol implements Element {
|
||||
|
||||
public List<Attribute.Compound> getAnnotationMirrors() {
|
||||
if (completer != null) complete();
|
||||
if (package_info != null && package_info.completer != null) {
|
||||
package_info.complete();
|
||||
if (attributes_field.isEmpty())
|
||||
attributes_field = package_info.attributes_field;
|
||||
}
|
||||
assert attributes_field != null;
|
||||
return attributes_field;
|
||||
}
|
||||
|
@ -49,18 +49,18 @@ public class TypeAnnotationPosition {
|
||||
public int offset = -1;
|
||||
|
||||
// For locals. arrays same length
|
||||
public int[] lvarOffset = new int[] { -1 };
|
||||
public int[] lvarLength = new int[] { -1 };
|
||||
public int[] lvarIndex = new int[] { -1 };
|
||||
public int[] lvarOffset = null;
|
||||
public int[] lvarLength = null;
|
||||
public int[] lvarIndex = null;
|
||||
|
||||
// For type parameter bound
|
||||
public int bound_index = -1;
|
||||
public int bound_index = Integer.MIN_VALUE;
|
||||
|
||||
// For type parameter and method parameter
|
||||
public int parameter_index = -1;
|
||||
public int parameter_index = Integer.MIN_VALUE;
|
||||
|
||||
// For class extends, implements, and throws classes
|
||||
public int type_index = -2;
|
||||
public int type_index = Integer.MIN_VALUE;
|
||||
|
||||
// For wildcards
|
||||
public TypeAnnotationPosition wildcard_position = null;
|
||||
@ -139,6 +139,7 @@ public class TypeAnnotationPosition {
|
||||
sb.append(type_index);
|
||||
break;
|
||||
case CLASS_LITERAL:
|
||||
case CLASS_LITERAL_GENERIC_OR_ARRAY:
|
||||
sb.append(", offset = ");
|
||||
sb.append(offset);
|
||||
break;
|
||||
|
@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.javac.code;
|
||||
|
||||
import javax.lang.model.element.ElementKind;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.TreeInfo;
|
||||
import com.sun.tools.javac.tree.TreeScanner;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
|
||||
/**
|
||||
* Contains operations specific to processing type annotations
|
||||
*/
|
||||
public class TypeAnnotations {
|
||||
private static final Context.Key<TypeAnnotations> key
|
||||
= new Context.Key<TypeAnnotations>();
|
||||
|
||||
public static TypeAnnotations instance(Context context) {
|
||||
TypeAnnotations instance = context.get(key);
|
||||
if (instance == null)
|
||||
instance = new TypeAnnotations(context);
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected TypeAnnotations(Context context) {
|
||||
context.put(key, this);
|
||||
}
|
||||
|
||||
public void taFillAndLift(JCClassDecl tree, boolean visitBodies) {
|
||||
new TypeAnnotationPositions().scan(tree);
|
||||
new TypeAnnotationLift().scan(tree);
|
||||
}
|
||||
|
||||
private static class TypeAnnotationPositions extends TreeScanner {
|
||||
|
||||
private ListBuffer<JCTree> frames = ListBuffer.lb();
|
||||
private void push(JCTree t) { frames = frames.prepend(t); }
|
||||
private JCTree pop() { return frames.next(); }
|
||||
private JCTree peek2() { return frames.toList().tail.head; }
|
||||
|
||||
@Override
|
||||
public void scan(JCTree tree) {
|
||||
push(tree);
|
||||
super.scan(tree);
|
||||
pop();
|
||||
}
|
||||
|
||||
private boolean inClass = false;
|
||||
|
||||
@Override
|
||||
public void visitClassDef(JCClassDecl tree) {
|
||||
if (!inClass) {
|
||||
// Do not recurse into nested and inner classes since
|
||||
// TransTypes.visitClassDef makes an invocation for each class
|
||||
// separately.
|
||||
inClass = true;
|
||||
try {
|
||||
super.visitClassDef(tree);
|
||||
} finally {
|
||||
inClass = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TypeAnnotationPosition resolveFrame(JCTree tree, JCTree frame,
|
||||
List<JCTree> path, TypeAnnotationPosition p) {
|
||||
switch (frame.getKind()) {
|
||||
case TYPE_CAST:
|
||||
p.type = TargetType.TYPECAST;
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
|
||||
case INSTANCE_OF:
|
||||
p.type = TargetType.INSTANCEOF;
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
|
||||
case NEW_CLASS:
|
||||
p.type = TargetType.NEW;
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
|
||||
case NEW_ARRAY:
|
||||
p.type = TargetType.NEW;
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
|
||||
case CLASS:
|
||||
p.pos = frame.pos;
|
||||
if (((JCClassDecl)frame).extending == tree) {
|
||||
p.type = TargetType.CLASS_EXTENDS;
|
||||
p.type_index = -1;
|
||||
} else if (((JCClassDecl)frame).implementing.contains(tree)) {
|
||||
p.type = TargetType.CLASS_EXTENDS;
|
||||
p.type_index = ((JCClassDecl)frame).implementing.indexOf(tree);
|
||||
} else if (((JCClassDecl)frame).typarams.contains(tree)) {
|
||||
p.type = TargetType.CLASS_TYPE_PARAMETER;
|
||||
p.parameter_index = ((JCClassDecl)frame).typarams.indexOf(tree);
|
||||
} else
|
||||
throw new AssertionError();
|
||||
return p;
|
||||
|
||||
case METHOD: {
|
||||
JCMethodDecl frameMethod = (JCMethodDecl)frame;
|
||||
p.pos = frame.pos;
|
||||
if (frameMethod.receiverAnnotations.contains(tree))
|
||||
p.type = TargetType.METHOD_RECEIVER;
|
||||
else if (frameMethod.thrown.contains(tree)) {
|
||||
p.type = TargetType.THROWS;
|
||||
p.type_index = frameMethod.thrown.indexOf(tree);
|
||||
} else if (((JCMethodDecl)frame).restype == tree) {
|
||||
p.type = TargetType.METHOD_RETURN_GENERIC_OR_ARRAY;
|
||||
} else if (frameMethod.typarams.contains(tree)) {
|
||||
p.type = TargetType.METHOD_TYPE_PARAMETER;
|
||||
p.parameter_index = frameMethod.typarams.indexOf(tree);
|
||||
} else
|
||||
throw new AssertionError();
|
||||
return p;
|
||||
}
|
||||
case MEMBER_SELECT: {
|
||||
JCFieldAccess fieldFrame = (JCFieldAccess)frame;
|
||||
if ("class".contentEquals(fieldFrame.name)) {
|
||||
p.type = TargetType.CLASS_LITERAL;
|
||||
p.pos = TreeInfo.innermostType(fieldFrame.selected).pos;
|
||||
} else
|
||||
throw new AssertionError();
|
||||
return p;
|
||||
}
|
||||
case PARAMETERIZED_TYPE: {
|
||||
TypeAnnotationPosition nextP;
|
||||
if (((JCTypeApply)frame).clazz == tree)
|
||||
nextP = p; // generic: RAW; noop
|
||||
else if (((JCTypeApply)frame).arguments.contains(tree))
|
||||
p.location = p.location.prepend(
|
||||
((JCTypeApply)frame).arguments.indexOf(tree));
|
||||
else
|
||||
throw new AssertionError();
|
||||
|
||||
List<JCTree> newPath = path.tail;
|
||||
return resolveFrame(newPath.head, newPath.tail.head, newPath, p);
|
||||
}
|
||||
|
||||
case ARRAY_TYPE: {
|
||||
p.location = p.location.prepend(0);
|
||||
List<JCTree> newPath = path.tail;
|
||||
return resolveFrame(newPath.head, newPath.tail.head, newPath, p);
|
||||
}
|
||||
|
||||
case TYPE_PARAMETER:
|
||||
if (path.tail.tail.head.getTag() == JCTree.CLASSDEF) {
|
||||
JCClassDecl clazz = (JCClassDecl)path.tail.tail.head;
|
||||
p.type = TargetType.CLASS_TYPE_PARAMETER_BOUND;
|
||||
p.parameter_index = clazz.typarams.indexOf(path.tail.head);
|
||||
p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
|
||||
} else if (path.tail.tail.head.getTag() == JCTree.METHODDEF) {
|
||||
JCMethodDecl method = (JCMethodDecl)path.tail.tail.head;
|
||||
p.type = TargetType.METHOD_TYPE_PARAMETER_BOUND;
|
||||
p.parameter_index = method.typarams.indexOf(path.tail.head);
|
||||
p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
|
||||
} else
|
||||
throw new AssertionError();
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
|
||||
case VARIABLE:
|
||||
VarSymbol v = ((JCVariableDecl)frame).sym;
|
||||
p.pos = frame.pos;
|
||||
switch (v.getKind()) {
|
||||
case LOCAL_VARIABLE:
|
||||
p.type = TargetType.LOCAL_VARIABLE; break;
|
||||
case FIELD:
|
||||
p.type = TargetType.FIELD_GENERIC_OR_ARRAY; break;
|
||||
case PARAMETER:
|
||||
p.type = TargetType.METHOD_PARAMETER_GENERIC_OR_ARRAY;
|
||||
p.parameter_index = methodParamIndex(path, frame);
|
||||
break;
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
return p;
|
||||
|
||||
case ANNOTATED_TYPE: {
|
||||
List<JCTree> newPath = path.tail;
|
||||
return resolveFrame(newPath.head, newPath.tail.head,
|
||||
newPath, p);
|
||||
}
|
||||
|
||||
case METHOD_INVOCATION: {
|
||||
JCMethodInvocation invocation = (JCMethodInvocation)frame;
|
||||
if (!invocation.typeargs.contains(tree))
|
||||
throw new AssertionError("{" + tree + "} is not an argument in the invocation: " + invocation);
|
||||
p.type = TargetType.METHOD_TYPE_ARGUMENT;
|
||||
p.pos = invocation.pos;
|
||||
p.type_index = invocation.typeargs.indexOf(tree);
|
||||
return p;
|
||||
}
|
||||
|
||||
case EXTENDS_WILDCARD:
|
||||
case SUPER_WILDCARD: {
|
||||
p.type = TargetType.WILDCARD_BOUND;
|
||||
List<JCTree> newPath = path.tail;
|
||||
|
||||
TypeAnnotationPosition wildcard =
|
||||
resolveFrame(newPath.head, newPath.tail.head, newPath,
|
||||
new TypeAnnotationPosition());
|
||||
if (!wildcard.location.isEmpty())
|
||||
wildcard.type = wildcard.type.getGenericComplement();
|
||||
p.wildcard_position = wildcard;
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private void setTypeAnnotationPos(List<JCTypeAnnotation> annotations, TypeAnnotationPosition position) {
|
||||
for (JCTypeAnnotation anno : annotations) {
|
||||
anno.annotation_position = position;
|
||||
anno.attribute_field.position = position;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNewArray(JCNewArray tree) {
|
||||
findPosition(tree, tree, tree.annotations);
|
||||
int dimAnnosCount = tree.dimAnnotations.size();
|
||||
|
||||
// handle annotations associated with dimentions
|
||||
for (int i = 0; i < dimAnnosCount; ++i) {
|
||||
TypeAnnotationPosition p = new TypeAnnotationPosition();
|
||||
p.type = TargetType.NEW_GENERIC_OR_ARRAY;
|
||||
p.pos = tree.pos;
|
||||
p.location = p.location.append(i);
|
||||
setTypeAnnotationPos(tree.dimAnnotations.get(i), p);
|
||||
}
|
||||
|
||||
// handle "free" annotations
|
||||
int i = dimAnnosCount == 0 ? 0 : dimAnnosCount - 1;
|
||||
JCExpression elemType = tree.elemtype;
|
||||
while (elemType != null) {
|
||||
if (elemType.getTag() == JCTree.ANNOTATED_TYPE) {
|
||||
JCAnnotatedType at = (JCAnnotatedType)elemType;
|
||||
TypeAnnotationPosition p = new TypeAnnotationPosition();
|
||||
p.type = TargetType.NEW_GENERIC_OR_ARRAY;
|
||||
p.pos = tree.pos;
|
||||
p.location = p.location.append(i);
|
||||
setTypeAnnotationPos(at.annotations, p);
|
||||
elemType = at.underlyingType;
|
||||
} else if (elemType.getTag() == JCTree.TYPEARRAY) {
|
||||
++i;
|
||||
elemType = ((JCArrayTypeTree)elemType).elemtype;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
// find annotations locations of initializer elements
|
||||
scan(tree.elems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnnotatedType(JCAnnotatedType tree) {
|
||||
findPosition(tree, peek2(), tree.annotations);
|
||||
super.visitAnnotatedType(tree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodDef(JCMethodDecl tree) {
|
||||
TypeAnnotationPosition p = new TypeAnnotationPosition();
|
||||
p.type = TargetType.METHOD_RECEIVER;
|
||||
setTypeAnnotationPos(tree.receiverAnnotations, p);
|
||||
super.visitMethodDef(tree);
|
||||
}
|
||||
@Override
|
||||
public void visitTypeParameter(JCTypeParameter tree) {
|
||||
findPosition(tree, peek2(), tree.annotations);
|
||||
super.visitTypeParameter(tree);
|
||||
}
|
||||
|
||||
void findPosition(JCTree tree, JCTree frame, List<JCTypeAnnotation> annotations) {
|
||||
if (!annotations.isEmpty()) {
|
||||
TypeAnnotationPosition p =
|
||||
resolveFrame(tree, frame, frames.toList(),
|
||||
new TypeAnnotationPosition());
|
||||
if (!p.location.isEmpty())
|
||||
p.type = p.type.getGenericComplement();
|
||||
setTypeAnnotationPos(annotations, p);
|
||||
}
|
||||
}
|
||||
|
||||
private int methodParamIndex(List<JCTree> path, JCTree param) {
|
||||
List<JCTree> curr = path;
|
||||
if (curr.head != param)
|
||||
curr = path.tail;
|
||||
JCMethodDecl method = (JCMethodDecl)curr.tail.head;
|
||||
return method.params.indexOf(param);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TypeAnnotationLift extends TreeScanner {
|
||||
List<Attribute.TypeCompound> recordedTypeAnnotations = List.nil();
|
||||
|
||||
boolean isInner = false;
|
||||
@Override
|
||||
public void visitClassDef(JCClassDecl tree) {
|
||||
if (isInner) {
|
||||
// tree is an inner class tree. stop now.
|
||||
// TransTypes.visitClassDef makes an invocation for each class
|
||||
// separately.
|
||||
return;
|
||||
}
|
||||
isInner = true;
|
||||
List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
|
||||
recordedTypeAnnotations = List.nil();
|
||||
try {
|
||||
super.visitClassDef(tree);
|
||||
} finally {
|
||||
tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
|
||||
recordedTypeAnnotations = prevTAs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodDef(JCMethodDecl tree) {
|
||||
List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
|
||||
recordedTypeAnnotations = List.nil();
|
||||
try {
|
||||
super.visitMethodDef(tree);
|
||||
} finally {
|
||||
tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
|
||||
recordedTypeAnnotations = prevTAs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarDef(JCVariableDecl tree) {
|
||||
List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
|
||||
recordedTypeAnnotations = List.nil();
|
||||
ElementKind kind = tree.sym.getKind();
|
||||
if (kind == ElementKind.LOCAL_VARIABLE && tree.mods.annotations.nonEmpty()) {
|
||||
// need to lift the annotations
|
||||
TypeAnnotationPosition position = new TypeAnnotationPosition();
|
||||
position.pos = tree.pos;
|
||||
position.type = TargetType.LOCAL_VARIABLE;
|
||||
for (Attribute.Compound attribute : tree.sym.attributes_field) {
|
||||
Attribute.TypeCompound tc =
|
||||
new Attribute.TypeCompound(attribute.type, attribute.values, position);
|
||||
recordedTypeAnnotations = recordedTypeAnnotations.append(tc);
|
||||
}
|
||||
}
|
||||
try {
|
||||
super.visitVarDef(tree);
|
||||
} finally {
|
||||
if (kind.isField() || kind == ElementKind.LOCAL_VARIABLE)
|
||||
tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
|
||||
recordedTypeAnnotations = kind.isField() ? prevTAs : prevTAs.appendList(recordedTypeAnnotations);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitApply(JCMethodInvocation tree) {
|
||||
scan(tree.meth);
|
||||
scan(tree.typeargs);
|
||||
scan(tree.args);
|
||||
}
|
||||
|
||||
public void visitAnnotation(JCAnnotation tree) {
|
||||
if (tree instanceof JCTypeAnnotation)
|
||||
recordedTypeAnnotations = recordedTypeAnnotations.append(((JCTypeAnnotation)tree).attribute_field);
|
||||
super.visitAnnotation(tree);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -2047,7 +2047,7 @@ public class Check {
|
||||
Symbol m = TreeInfo.symbol(assign.lhs);
|
||||
if (m == null || m.type.isErroneous()) continue;
|
||||
if (!members.remove(m))
|
||||
log.error(arg.pos(), "duplicate.annotation.member.value",
|
||||
log.error(assign.lhs.pos(), "duplicate.annotation.member.value",
|
||||
m.name, a.type);
|
||||
if (assign.rhs.getTag() == ANNOTATION)
|
||||
validateAnnotation((JCAnnotation)assign.rhs);
|
||||
|
@ -100,6 +100,7 @@ public class Enter extends JCTree.Visitor {
|
||||
MemberEnter memberEnter;
|
||||
Types types;
|
||||
Lint lint;
|
||||
Names names;
|
||||
JavaFileManager fileManager;
|
||||
|
||||
private final Todo todo;
|
||||
@ -123,6 +124,7 @@ public class Enter extends JCTree.Visitor {
|
||||
types = Types.instance(context);
|
||||
annotate = Annotate.instance(context);
|
||||
lint = Lint.instance(context);
|
||||
names = Names.instance(context);
|
||||
|
||||
predefClassDef = make.ClassDef(
|
||||
make.Modifiers(PUBLIC),
|
||||
@ -308,6 +310,17 @@ public class Enter extends JCTree.Visitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Symbol q = tree.packge; q != null && q.kind == PCK; q = q.owner)
|
||||
q.flags_field |= EXISTS;
|
||||
|
||||
Name name = names.package_info;
|
||||
ClassSymbol c = reader.enterClass(name, tree.packge);
|
||||
c.flatname = names.fromString(tree.packge + "." + name);
|
||||
c.sourcefile = tree.sourcefile;
|
||||
c.completer = null;
|
||||
c.members_field = new Scope(c);
|
||||
tree.packge.package_info = c;
|
||||
}
|
||||
classEnter(tree.defs, env);
|
||||
if (addEnv) {
|
||||
|
@ -1994,19 +1994,14 @@ public class Lower extends TreeTranslator {
|
||||
tree.packageAnnotations),
|
||||
name, List.<JCTypeParameter>nil(),
|
||||
null, List.<JCExpression>nil(), List.<JCTree>nil());
|
||||
ClassSymbol c = reader.enterClass(name, tree.packge);
|
||||
c.flatname = names.fromString(tree.packge + "." + name);
|
||||
c.sourcefile = tree.sourcefile;
|
||||
c.completer = null;
|
||||
c.members_field = new Scope(c);
|
||||
c.flags_field = flags;
|
||||
ClassSymbol c = tree.packge.package_info;
|
||||
c.flags_field |= flags;
|
||||
c.attributes_field = tree.packge.attributes_field;
|
||||
ClassType ctype = (ClassType) c.type;
|
||||
ctype.supertype_field = syms.objectType;
|
||||
ctype.interfaces_field = List.nil();
|
||||
packageAnnotationsClass.sym = c;
|
||||
|
||||
|
||||
translated.append(packageAnnotationsClass);
|
||||
}
|
||||
}
|
||||
|
@ -1065,11 +1065,6 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
|
||||
super.visitNewArray(tree);
|
||||
}
|
||||
@Override
|
||||
public void visitApply(JCMethodInvocation tree) {
|
||||
super.visitApply(tree);
|
||||
scan(tree.typeargs);
|
||||
}
|
||||
@Override
|
||||
public void visitMethodDef(JCMethodDecl tree) {
|
||||
annotate(tree, tree.receiverAnnotations);
|
||||
super.visitMethodDef(tree);
|
||||
|
@ -61,8 +61,6 @@ public class TransTypes extends TreeTranslator {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private boolean debugJSR308;
|
||||
|
||||
private Names names;
|
||||
private Log log;
|
||||
private Symtab syms;
|
||||
@ -71,6 +69,7 @@ public class TransTypes extends TreeTranslator {
|
||||
private boolean allowEnums;
|
||||
private Types types;
|
||||
private final Resolve resolve;
|
||||
private final TypeAnnotations typeAnnotations;
|
||||
|
||||
/**
|
||||
* Flag to indicate whether or not to generate bridge methods.
|
||||
@ -92,7 +91,7 @@ public class TransTypes extends TreeTranslator {
|
||||
types = Types.instance(context);
|
||||
make = TreeMaker.instance(context);
|
||||
resolve = Resolve.instance(context);
|
||||
debugJSR308 = Options.instance(context).get("TA:trans") != null;
|
||||
typeAnnotations = TypeAnnotations.instance(context);
|
||||
}
|
||||
|
||||
/** A hashtable mapping bridge methods to the methods they override after
|
||||
@ -440,8 +439,7 @@ public class TransTypes extends TreeTranslator {
|
||||
}
|
||||
|
||||
public void visitClassDef(JCClassDecl tree) {
|
||||
new TypeAnnotationPositions().scan(tree);
|
||||
new TypeAnnotationLift().scan(tree);
|
||||
typeAnnotations.taFillAndLift(tree, true);
|
||||
translateClass(tree.sym);
|
||||
result = tree;
|
||||
}
|
||||
@ -801,359 +799,4 @@ public class TransTypes extends TreeTranslator {
|
||||
pt = null;
|
||||
return translate(cdef, null);
|
||||
}
|
||||
|
||||
private class TypeAnnotationPositions extends TreeScanner {
|
||||
|
||||
private ListBuffer<JCTree> frames = ListBuffer.lb();
|
||||
private void push(JCTree t) { frames = frames.prepend(t); }
|
||||
private JCTree pop() { return frames.next(); }
|
||||
private JCTree peek() { return frames.first(); }
|
||||
private JCTree peek2() { return frames.toList().tail.head; }
|
||||
|
||||
@Override
|
||||
public void scan(JCTree tree) {
|
||||
push(tree);
|
||||
super.scan(tree);
|
||||
pop();
|
||||
}
|
||||
|
||||
private boolean inClass = false;
|
||||
|
||||
@Override
|
||||
public void visitClassDef(JCClassDecl tree) {
|
||||
if (!inClass) {
|
||||
// Do not recurse into nested and inner classes since
|
||||
// TransTypes.visitClassDef makes an invocation for each class
|
||||
// separately.
|
||||
inClass = true;
|
||||
try {
|
||||
super.visitClassDef(tree);
|
||||
} finally {
|
||||
inClass = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TypeAnnotationPosition resolveFrame(JCTree tree, JCTree frame,
|
||||
List<JCTree> path, TypeAnnotationPosition p) {
|
||||
switch (frame.getKind()) {
|
||||
case TYPE_CAST:
|
||||
p.type = TargetType.TYPECAST;
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
|
||||
case INSTANCE_OF:
|
||||
p.type = TargetType.INSTANCEOF;
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
|
||||
case NEW_CLASS:
|
||||
p.type = TargetType.NEW;
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
|
||||
case NEW_ARRAY:
|
||||
p.type = TargetType.NEW;
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
|
||||
case CLASS:
|
||||
p.pos = frame.pos;
|
||||
if (((JCClassDecl)frame).extending == tree) {
|
||||
p.type = TargetType.CLASS_EXTENDS;
|
||||
p.type_index = -1;
|
||||
} else if (((JCClassDecl)frame).implementing.contains(tree)) {
|
||||
p.type = TargetType.CLASS_EXTENDS;
|
||||
p.type_index = ((JCClassDecl)frame).implementing.indexOf(tree);
|
||||
} else if (((JCClassDecl)frame).typarams.contains(tree)) {
|
||||
p.type = TargetType.CLASS_TYPE_PARAMETER;
|
||||
p.parameter_index = ((JCClassDecl)frame).typarams.indexOf(tree);
|
||||
} else
|
||||
throw new AssertionError();
|
||||
return p;
|
||||
|
||||
case METHOD: {
|
||||
JCMethodDecl frameMethod = (JCMethodDecl)frame;
|
||||
p.pos = frame.pos;
|
||||
if (frameMethod.receiverAnnotations.contains(tree))
|
||||
p.type = TargetType.METHOD_RECEIVER;
|
||||
else if (frameMethod.thrown.contains(tree)) {
|
||||
p.type = TargetType.THROWS;
|
||||
p.type_index = frameMethod.thrown.indexOf(tree);
|
||||
} else if (((JCMethodDecl)frame).restype == tree) {
|
||||
p.type = TargetType.METHOD_RETURN_GENERIC_OR_ARRAY;
|
||||
} else if (frameMethod.typarams.contains(tree)) {
|
||||
p.type = TargetType.METHOD_TYPE_PARAMETER;
|
||||
p.parameter_index = frameMethod.typarams.indexOf(tree);
|
||||
} else
|
||||
throw new AssertionError();
|
||||
return p;
|
||||
}
|
||||
case MEMBER_SELECT: {
|
||||
JCFieldAccess fieldFrame = (JCFieldAccess)frame;
|
||||
if (fieldFrame.name == names._class) {
|
||||
p.type = TargetType.CLASS_LITERAL;
|
||||
if (fieldFrame.selected instanceof JCAnnotatedType) {
|
||||
p.pos = TreeInfo.typeIn(fieldFrame).pos;
|
||||
} else if (fieldFrame.selected instanceof JCArrayTypeTree) {
|
||||
p.pos = fieldFrame.selected.pos;
|
||||
}
|
||||
} else
|
||||
throw new AssertionError();
|
||||
return p;
|
||||
}
|
||||
case PARAMETERIZED_TYPE: {
|
||||
TypeAnnotationPosition nextP;
|
||||
if (((JCTypeApply)frame).clazz == tree)
|
||||
nextP = p; // generic: RAW; noop
|
||||
else if (((JCTypeApply)frame).arguments.contains(tree))
|
||||
p.location = p.location.prepend(
|
||||
((JCTypeApply)frame).arguments.indexOf(tree));
|
||||
else
|
||||
throw new AssertionError();
|
||||
|
||||
List<JCTree> newPath = path.tail;
|
||||
return resolveFrame(newPath.head, newPath.tail.head, newPath, p);
|
||||
}
|
||||
|
||||
case ARRAY_TYPE: {
|
||||
p.location = p.location.prepend(0);
|
||||
List<JCTree> newPath = path.tail;
|
||||
return resolveFrame(newPath.head, newPath.tail.head, newPath, p);
|
||||
}
|
||||
|
||||
case TYPE_PARAMETER:
|
||||
if (path.tail.tail.head.getTag() == JCTree.CLASSDEF) {
|
||||
JCClassDecl clazz = (JCClassDecl)path.tail.tail.head;
|
||||
p.type = TargetType.CLASS_TYPE_PARAMETER_BOUND;
|
||||
p.parameter_index = clazz.typarams.indexOf(path.tail.head);
|
||||
p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
|
||||
} else if (path.tail.tail.head.getTag() == JCTree.METHODDEF) {
|
||||
JCMethodDecl method = (JCMethodDecl)path.tail.tail.head;
|
||||
p.type = TargetType.METHOD_TYPE_PARAMETER_BOUND;
|
||||
p.parameter_index = method.typarams.indexOf(path.tail.head);
|
||||
p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
|
||||
} else
|
||||
throw new AssertionError();
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
|
||||
case VARIABLE:
|
||||
VarSymbol v = ((JCVariableDecl)frame).sym;
|
||||
p.pos = frame.pos;
|
||||
switch (v.getKind()) {
|
||||
case LOCAL_VARIABLE:
|
||||
p.type = TargetType.LOCAL_VARIABLE; break;
|
||||
case FIELD:
|
||||
p.type = TargetType.FIELD_GENERIC_OR_ARRAY; break;
|
||||
case PARAMETER:
|
||||
p.type = TargetType.METHOD_PARAMETER_GENERIC_OR_ARRAY;
|
||||
p.parameter_index = methodParamIndex(path, frame);
|
||||
break;
|
||||
default: throw new AssertionError();
|
||||
}
|
||||
return p;
|
||||
|
||||
case ANNOTATED_TYPE: {
|
||||
List<JCTree> newPath = path.tail;
|
||||
return resolveFrame(newPath.head, newPath.tail.head,
|
||||
newPath, p);
|
||||
}
|
||||
|
||||
case METHOD_INVOCATION: {
|
||||
JCMethodInvocation invocation = (JCMethodInvocation)frame;
|
||||
if (!invocation.typeargs.contains(tree))
|
||||
throw new AssertionError("{" + tree + "} is not an argument in the invocation: " + invocation);
|
||||
p.type = TargetType.METHOD_TYPE_ARGUMENT;
|
||||
p.pos = invocation.pos;
|
||||
p.type_index = invocation.typeargs.indexOf(tree);
|
||||
return p;
|
||||
}
|
||||
|
||||
case EXTENDS_WILDCARD:
|
||||
case SUPER_WILDCARD: {
|
||||
p.type = TargetType.WILDCARD_BOUND;
|
||||
List<JCTree> newPath = path.tail;
|
||||
|
||||
TypeAnnotationPosition wildcard =
|
||||
resolveFrame(newPath.head, newPath.tail.head, newPath,
|
||||
new TypeAnnotationPosition());
|
||||
if (!wildcard.location.isEmpty())
|
||||
wildcard.type = wildcard.type.getGenericComplement();
|
||||
p.wildcard_position = wildcard;
|
||||
p.pos = frame.pos;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitApply(JCMethodInvocation tree) {
|
||||
scan(tree.meth);
|
||||
scan(tree.typeargs);
|
||||
scan(tree.args);
|
||||
}
|
||||
|
||||
private void setTypeAnnotationPos(List<JCTypeAnnotation> annotations, TypeAnnotationPosition position) {
|
||||
for (JCTypeAnnotation anno : annotations) {
|
||||
anno.annotation_position = position;
|
||||
anno.attribute_field.position = position;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNewArray(JCNewArray tree) {
|
||||
findPosition(tree, tree, tree.annotations);
|
||||
int dimAnnosCount = tree.dimAnnotations.size();
|
||||
|
||||
// handle annotations associated with dimentions
|
||||
for (int i = 0; i < dimAnnosCount; ++i) {
|
||||
TypeAnnotationPosition p = new TypeAnnotationPosition();
|
||||
p.type = TargetType.NEW_GENERIC_OR_ARRAY;
|
||||
p.pos = tree.pos;
|
||||
p.location = p.location.append(i);
|
||||
setTypeAnnotationPos(tree.dimAnnotations.get(i), p);
|
||||
}
|
||||
|
||||
// handle "free" annotations
|
||||
int i = dimAnnosCount == 0 ? 0 : dimAnnosCount - 1;
|
||||
JCExpression elemType = tree.elemtype;
|
||||
while (elemType != null) {
|
||||
if (elemType.getTag() == JCTree.ANNOTATED_TYPE) {
|
||||
JCAnnotatedType at = (JCAnnotatedType)elemType;
|
||||
TypeAnnotationPosition p = new TypeAnnotationPosition();
|
||||
p.type = TargetType.NEW_GENERIC_OR_ARRAY;
|
||||
p.pos = tree.pos;
|
||||
p.location = p.location.append(i);
|
||||
setTypeAnnotationPos(at.annotations, p);
|
||||
elemType = at.underlyingType;
|
||||
} else if (elemType.getTag() == JCTree.TYPEARRAY) {
|
||||
++i;
|
||||
elemType = ((JCArrayTypeTree)elemType).elemtype;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
// find annotations locations of initializer elements
|
||||
scan(tree.elems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnnotatedType(JCAnnotatedType tree) {
|
||||
findPosition(tree, peek2(), tree.annotations);
|
||||
super.visitAnnotatedType(tree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodDef(JCMethodDecl tree) {
|
||||
TypeAnnotationPosition p = new TypeAnnotationPosition();
|
||||
p.type = TargetType.METHOD_RECEIVER;
|
||||
setTypeAnnotationPos(tree.receiverAnnotations, p);
|
||||
super.visitMethodDef(tree);
|
||||
}
|
||||
@Override
|
||||
public void visitTypeParameter(JCTypeParameter tree) {
|
||||
findPosition(tree, peek2(), tree.annotations);
|
||||
super.visitTypeParameter(tree);
|
||||
}
|
||||
|
||||
void findPosition(JCTree tree, JCTree frame, List<JCTypeAnnotation> annotations) {
|
||||
if (!annotations.isEmpty()) {
|
||||
TypeAnnotationPosition p =
|
||||
resolveFrame(tree, frame, frames.toList(),
|
||||
new TypeAnnotationPosition());
|
||||
if (!p.location.isEmpty())
|
||||
p.type = p.type.getGenericComplement();
|
||||
setTypeAnnotationPos(annotations, p);
|
||||
if (debugJSR308) {
|
||||
System.out.println("trans: " + tree);
|
||||
System.out.println(" target: " + p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int methodParamIndex(List<JCTree> path, JCTree param) {
|
||||
List<JCTree> curr = path;
|
||||
if (curr.head != param)
|
||||
curr = path.tail;
|
||||
JCMethodDecl method = (JCMethodDecl)curr.tail.head;
|
||||
return method.params.indexOf(param);
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeAnnotationLift extends TreeScanner {
|
||||
List<Attribute.TypeCompound> recordedTypeAnnotations = List.nil();
|
||||
|
||||
boolean isInner = false;
|
||||
@Override
|
||||
public void visitClassDef(JCClassDecl tree) {
|
||||
if (isInner) {
|
||||
// tree is an inner class tree. stop now.
|
||||
// TransTypes.visitClassDef makes an invocation for each class
|
||||
// seperately.
|
||||
return;
|
||||
}
|
||||
isInner = true;
|
||||
List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
|
||||
recordedTypeAnnotations = List.nil();
|
||||
try {
|
||||
super.visitClassDef(tree);
|
||||
} finally {
|
||||
tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
|
||||
recordedTypeAnnotations = prevTAs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodDef(JCMethodDecl tree) {
|
||||
List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
|
||||
recordedTypeAnnotations = List.nil();
|
||||
try {
|
||||
super.visitMethodDef(tree);
|
||||
} finally {
|
||||
tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
|
||||
recordedTypeAnnotations = prevTAs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarDef(JCVariableDecl tree) {
|
||||
List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
|
||||
recordedTypeAnnotations = List.nil();
|
||||
ElementKind kind = tree.sym.getKind();
|
||||
if (kind == ElementKind.LOCAL_VARIABLE && tree.mods.annotations.nonEmpty()) {
|
||||
// need to lift the annotations
|
||||
TypeAnnotationPosition position = new TypeAnnotationPosition();
|
||||
position.pos = tree.pos;
|
||||
position.type = TargetType.LOCAL_VARIABLE;
|
||||
for (Attribute.Compound attribute : tree.sym.attributes_field) {
|
||||
Attribute.TypeCompound tc =
|
||||
new Attribute.TypeCompound(attribute.type, attribute.values, position);
|
||||
recordedTypeAnnotations = recordedTypeAnnotations.append(tc);
|
||||
}
|
||||
}
|
||||
try {
|
||||
super.visitVarDef(tree);
|
||||
} finally {
|
||||
if (kind.isField() || kind == ElementKind.LOCAL_VARIABLE)
|
||||
tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
|
||||
recordedTypeAnnotations = kind.isField() ? prevTAs : prevTAs.appendList(recordedTypeAnnotations);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitApply(JCMethodInvocation tree) {
|
||||
scan(tree.meth);
|
||||
scan(tree.typeargs);
|
||||
scan(tree.args);
|
||||
}
|
||||
|
||||
public void visitAnnotation(JCAnnotation tree) {
|
||||
if (tree instanceof JCTypeAnnotation)
|
||||
recordedTypeAnnotations = recordedTypeAnnotations.append(((JCTypeAnnotation)tree).attribute_field);
|
||||
super.visitAnnotation(tree);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1425,11 +1425,11 @@ public class ClassReader implements Completer {
|
||||
// Class extends and implements clauses
|
||||
case CLASS_EXTENDS:
|
||||
case CLASS_EXTENDS_GENERIC_OR_ARRAY:
|
||||
position.type_index = nextByte();
|
||||
position.type_index = nextChar();
|
||||
break;
|
||||
// throws
|
||||
case THROWS:
|
||||
position.type_index = nextByte();
|
||||
position.type_index = nextChar();
|
||||
break;
|
||||
case CLASS_LITERAL:
|
||||
case CLASS_LITERAL_GENERIC_OR_ARRAY:
|
||||
|
@ -965,11 +965,11 @@ public class ClassWriter extends ClassFile {
|
||||
// Class extends and implements clauses
|
||||
case CLASS_EXTENDS:
|
||||
case CLASS_EXTENDS_GENERIC_OR_ARRAY:
|
||||
databuf.appendByte(p.type_index);
|
||||
databuf.appendChar(p.type_index);
|
||||
break;
|
||||
// throws
|
||||
case THROWS:
|
||||
databuf.appendByte(p.type_index);
|
||||
databuf.appendChar(p.type_index);
|
||||
break;
|
||||
case CLASS_LITERAL:
|
||||
case CLASS_LITERAL_GENERIC_OR_ARRAY:
|
||||
|
@ -1926,9 +1926,9 @@ public class Code {
|
||||
for (Attribute.TypeCompound ta : lv.sym.typeAnnotations) {
|
||||
TypeAnnotationPosition p = ta.position;
|
||||
while (p != null) {
|
||||
p.lvarOffset[0] = (int)lv.start_pc;
|
||||
p.lvarLength[0] = (int)lv.length;
|
||||
p.lvarIndex[0] = (int)lv.reg;
|
||||
p.lvarOffset = new int[] { (int)lv.start_pc };
|
||||
p.lvarLength = new int[] { (int)lv.length };
|
||||
p.lvarIndex = new int[] { (int)lv.reg };
|
||||
p.isValidOffset = true;
|
||||
p = p.wildcard_position;
|
||||
}
|
||||
|
@ -1714,7 +1714,7 @@ public class Gen extends JCTree.Visitor {
|
||||
for (Attribute.TypeCompound ta : meth.typeAnnotations) {
|
||||
if (ta.position.pos == treePos) {
|
||||
ta.position.offset = code.cp;
|
||||
ta.position.lvarOffset[0] = code.cp;
|
||||
ta.position.lvarOffset = new int[] { code.cp };
|
||||
ta.position.isValidOffset = true;
|
||||
}
|
||||
}
|
||||
@ -1726,7 +1726,7 @@ public class Gen extends JCTree.Visitor {
|
||||
for (Attribute.TypeCompound ta : meth.owner.typeAnnotations) {
|
||||
if (ta.position.pos == treePos) {
|
||||
ta.position.offset = code.cp;
|
||||
ta.position.lvarOffset[0] = code.cp;
|
||||
ta.position.lvarOffset = new int[] { code.cp };
|
||||
ta.position.isValidOffset = true;
|
||||
}
|
||||
}
|
||||
@ -1738,7 +1738,7 @@ public class Gen extends JCTree.Visitor {
|
||||
for (Attribute.TypeCompound ta : s.typeAnnotations) {
|
||||
if (ta.position.pos == treePos) {
|
||||
ta.position.offset = code.cp;
|
||||
ta.position.lvarOffset[0] = code.cp;
|
||||
ta.position.lvarOffset = new int[] { code.cp };
|
||||
ta.position.isValidOffset = true;
|
||||
}
|
||||
}
|
||||
@ -2158,6 +2158,11 @@ public class Gen extends JCTree.Visitor {
|
||||
code.emitop2(ldc2, makeRef(tree.pos(), tree.selected.type));
|
||||
result = items.makeStackItem(pt);
|
||||
return;
|
||||
} else if (tree.name == names.TYPE) {
|
||||
// Set the annotation positions for primitive class literals
|
||||
// (e.g. int.class) which have been converted to TYPE field
|
||||
// access on the corresponding boxed type (e.g. Integer.TYPE).
|
||||
setTypeAnnotationPositions(tree.pos);
|
||||
}
|
||||
|
||||
Symbol ssym = TreeInfo.symbol(tree.selected);
|
||||
|
@ -761,23 +761,28 @@ public class JavacParser implements Parser {
|
||||
JCExpression[] odStack = newOdStack();
|
||||
List<Token[]> savedOp = opStackSupply.elems;
|
||||
Token[] opStack = newOpStack();
|
||||
List<int[]> savedPos = posStackSupply.elems;
|
||||
int[] posStack = newPosStack();
|
||||
// optimization, was odStack = new Tree[...]; opStack = new Tree[...];
|
||||
int top = 0;
|
||||
odStack[0] = t;
|
||||
int startPos = S.pos();
|
||||
Token topOp = ERROR;
|
||||
int topOpPos = Position.NOPOS;
|
||||
while (prec(S.token()) >= minprec) {
|
||||
posStack[top] = topOpPos;
|
||||
opStack[top] = topOp;
|
||||
top++;
|
||||
topOp = S.token();
|
||||
int pos = S.pos();
|
||||
topOpPos = S.pos();
|
||||
S.nextToken();
|
||||
odStack[top] = topOp == INSTANCEOF ? parseType() : term3();
|
||||
odStack[top] = (topOp == INSTANCEOF) ? parseType() : term3();
|
||||
while (top > 0 && prec(topOp) >= prec(S.token())) {
|
||||
odStack[top-1] = makeOp(pos, topOp, odStack[top-1],
|
||||
odStack[top-1] = makeOp(topOpPos, topOp, odStack[top-1],
|
||||
odStack[top]);
|
||||
top--;
|
||||
topOp = opStack[top];
|
||||
topOpPos = posStack[top];
|
||||
}
|
||||
}
|
||||
assert top == 0;
|
||||
@ -792,6 +797,7 @@ public class JavacParser implements Parser {
|
||||
|
||||
odStackSupply.elems = savedOd; // optimization
|
||||
opStackSupply.elems = savedOp; // optimization
|
||||
posStackSupply.elems = savedPos; // optimization
|
||||
return t;
|
||||
}
|
||||
//where
|
||||
@ -845,6 +851,7 @@ public class JavacParser implements Parser {
|
||||
*/
|
||||
ListBuffer<JCExpression[]> odStackSupply = new ListBuffer<JCExpression[]>();
|
||||
ListBuffer<Token[]> opStackSupply = new ListBuffer<Token[]>();
|
||||
ListBuffer<int[]> posStackSupply = new ListBuffer<int[]>();
|
||||
|
||||
private JCExpression[] newOdStack() {
|
||||
if (odStackSupply.elems == odStackSupply.last)
|
||||
@ -862,6 +869,14 @@ public class JavacParser implements Parser {
|
||||
return opStack;
|
||||
}
|
||||
|
||||
private int[] newPosStack() {
|
||||
if (posStackSupply.elems == posStackSupply.last)
|
||||
posStackSupply.append(new int[infixPrecedenceLevels + 1]);
|
||||
int[] posStack = posStackSupply.elems.head;
|
||||
posStackSupply.elems = posStackSupply.elems.tail;
|
||||
return posStack;
|
||||
}
|
||||
|
||||
/** Expression3 = PrefixOp Expression3
|
||||
* | "(" Expr | TypeNoParams ")" Expression3
|
||||
* | Primary {Selector} {PostfixOp}
|
||||
@ -939,7 +954,7 @@ public class JavacParser implements Parser {
|
||||
args.append(typeArgument());
|
||||
}
|
||||
accept(GT);
|
||||
t = F.at(pos1).TypeApply(t, args.toList());
|
||||
t = toP(F.at(pos1).TypeApply(t, args.toList()));
|
||||
checkGenerics();
|
||||
while (S.token() == DOT) {
|
||||
S.nextToken();
|
||||
@ -950,7 +965,8 @@ public class JavacParser implements Parser {
|
||||
t = bracketsOpt(toP(t));
|
||||
} else if ((mode & EXPR) != 0) {
|
||||
mode = EXPR;
|
||||
t = F.at(pos1).Binary(op, t, term2Rest(t1, TreeInfo.shiftPrec));
|
||||
JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
|
||||
t = F.at(pos1).Binary(op, t, e);
|
||||
t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
|
||||
} else {
|
||||
accept(GT);
|
||||
@ -998,7 +1014,8 @@ public class JavacParser implements Parser {
|
||||
case SUPER:
|
||||
if ((mode & EXPR) != 0) {
|
||||
mode = EXPR;
|
||||
t = to(superSuffix(typeArgs, F.at(pos).Ident(names._super)));
|
||||
t = to(F.at(pos).Ident(names._super));
|
||||
t = superSuffix(typeArgs, t);
|
||||
typeArgs = null;
|
||||
} else return illegal();
|
||||
break;
|
||||
@ -1380,13 +1397,15 @@ public class JavacParser implements Parser {
|
||||
S.nextToken();
|
||||
JCExpression result;
|
||||
if (S.token() == EXTENDS) {
|
||||
TypeBoundKind t = to(F.at(S.pos()).TypeBoundKind(BoundKind.EXTENDS));
|
||||
TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.EXTENDS));
|
||||
S.nextToken();
|
||||
result = F.at(pos).Wildcard(t, parseType());
|
||||
JCExpression bound = parseType();
|
||||
result = F.at(pos).Wildcard(t, bound);
|
||||
} else if (S.token() == SUPER) {
|
||||
TypeBoundKind t = to(F.at(S.pos()).TypeBoundKind(BoundKind.SUPER));
|
||||
TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.SUPER));
|
||||
S.nextToken();
|
||||
result = F.at(pos).Wildcard(t, parseType());
|
||||
JCExpression bound = parseType();
|
||||
result = F.at(pos).Wildcard(t, bound);
|
||||
} else if (S.token() == IDENTIFIER) {
|
||||
//error recovery
|
||||
reportSyntaxError(S.prevEndPos(), "expected3",
|
||||
@ -1396,7 +1415,7 @@ public class JavacParser implements Parser {
|
||||
JCIdent id = toP(F.at(S.pos()).Ident(ident()));
|
||||
result = F.at(pos).Erroneous(List.<JCTree>of(wc, id));
|
||||
} else {
|
||||
TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
|
||||
TypeBoundKind t = toP(F.at(pos).TypeBoundKind(BoundKind.UNBOUND));
|
||||
result = toP(F.at(pos).Wildcard(t, null));
|
||||
}
|
||||
if (!annotations.isEmpty())
|
||||
@ -2117,14 +2136,21 @@ public class JavacParser implements Parser {
|
||||
return modifiersOpt(null);
|
||||
}
|
||||
JCModifiers modifiersOpt(JCModifiers partial) {
|
||||
long flags = (partial == null) ? 0 : partial.flags;
|
||||
long flags;
|
||||
ListBuffer<JCAnnotation> annotations = new ListBuffer<JCAnnotation>();
|
||||
int pos;
|
||||
if (partial == null) {
|
||||
flags = 0;
|
||||
pos = S.pos();
|
||||
} else {
|
||||
flags = partial.flags;
|
||||
annotations.appendList(partial.annotations);
|
||||
pos = partial.pos;
|
||||
}
|
||||
if (S.deprecatedFlag()) {
|
||||
flags |= Flags.DEPRECATED;
|
||||
S.resetDeprecatedFlag();
|
||||
}
|
||||
ListBuffer<JCAnnotation> annotations = new ListBuffer<JCAnnotation>();
|
||||
if (partial != null) annotations.appendList(partial.annotations);
|
||||
int pos = S.pos();
|
||||
int lastPos = Position.NOPOS;
|
||||
loop:
|
||||
while (true) {
|
||||
@ -2150,12 +2176,12 @@ public class JavacParser implements Parser {
|
||||
if (flag == Flags.ANNOTATION) {
|
||||
checkAnnotations();
|
||||
if (S.token() != INTERFACE) {
|
||||
JCAnnotation ann = annotation(lastPos, AnnotationKind.DEFAULT_ANNO);
|
||||
// if first modifier is an annotation, set pos to annotation's.
|
||||
if (flags == 0 && annotations.isEmpty())
|
||||
pos = ann.pos;
|
||||
annotations.append(ann);
|
||||
lastPos = ann.pos;
|
||||
JCAnnotation ann = annotation(lastPos, AnnotationKind.DEFAULT_ANNO);
|
||||
// if first modifier is an annotation, set pos to annotation's.
|
||||
if (flags == 0 && annotations.isEmpty())
|
||||
pos = ann.pos;
|
||||
annotations.append(ann);
|
||||
lastPos = ann.pos;
|
||||
flag = 0;
|
||||
}
|
||||
}
|
||||
@ -2169,7 +2195,7 @@ public class JavacParser implements Parser {
|
||||
|
||||
/* A modifiers tree with no modifier tokens or annotations
|
||||
* has no text position. */
|
||||
if (flags == 0 && annotations.isEmpty())
|
||||
if ((flags & Flags.ModifierFlags) == 0 && annotations.isEmpty())
|
||||
pos = Position.NOPOS;
|
||||
|
||||
JCModifiers mods = F.at(pos).Modifiers(flags, annotations.toList());
|
||||
@ -2226,7 +2252,8 @@ public class JavacParser implements Parser {
|
||||
if (t1.getTag() == JCTree.IDENT && S.token() == EQ) {
|
||||
int pos = S.pos();
|
||||
accept(EQ);
|
||||
return toP(F.at(pos).Assign(t1, annotationValue()));
|
||||
JCExpression v = annotationValue();
|
||||
return toP(F.at(pos).Assign(t1, v));
|
||||
} else {
|
||||
return t1;
|
||||
}
|
||||
@ -2543,10 +2570,9 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
|
||||
List<JCTree> defs = enumBody(name);
|
||||
JCModifiers newMods =
|
||||
F.at(mods.pos).Modifiers(mods.flags|Flags.ENUM, mods.annotations);
|
||||
mods.flags |= Flags.ENUM;
|
||||
JCClassDecl result = toP(F.at(pos).
|
||||
ClassDef(newMods, name, List.<JCTypeParameter>nil(),
|
||||
ClassDef(mods, name, List.<JCTypeParameter>nil(),
|
||||
null, implementing, defs));
|
||||
attach(result, dc);
|
||||
return result;
|
||||
@ -2695,16 +2721,8 @@ public class JavacParser implements Parser {
|
||||
} else {
|
||||
pos = S.pos();
|
||||
List<JCTypeParameter> typarams = typeParametersOpt();
|
||||
// Hack alert: if there are type arguments but no Modifiers, the start
|
||||
// position will be lost unless we set the Modifiers position. There
|
||||
// should be an AST node for type parameters (BugId 5005090).
|
||||
if (typarams.length() > 0 && mods.pos == Position.NOPOS) {
|
||||
mods.pos = pos;
|
||||
}
|
||||
|
||||
List<JCAnnotation> annosAfterParams = annotationsOpt(AnnotationKind.DEFAULT_ANNO);
|
||||
|
||||
Token token = S.token();
|
||||
Name name = S.name();
|
||||
pos = S.pos();
|
||||
JCExpression type;
|
||||
@ -2715,7 +2733,11 @@ public class JavacParser implements Parser {
|
||||
type = to(F.at(pos).TypeIdent(TypeTags.VOID));
|
||||
S.nextToken();
|
||||
} else {
|
||||
mods.annotations = mods.annotations.appendList(annosAfterParams);
|
||||
if (annosAfterParams.nonEmpty()) {
|
||||
mods.annotations = mods.annotations.appendList(annosAfterParams);
|
||||
if (mods.pos == Position.NOPOS)
|
||||
mods.pos = mods.annotations.head.pos;
|
||||
}
|
||||
// method returns types are un-annotated types
|
||||
type = unannotatedType();
|
||||
}
|
||||
@ -2813,6 +2835,7 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JCMethodDecl result =
|
||||
toP(F.at(pos).MethodDef(mods, name, type, typarams,
|
||||
params, receiverAnnotations, thrown,
|
||||
|
@ -67,6 +67,7 @@ import com.sun.tools.javac.tree.*;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import com.sun.tools.javac.util.Abort;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Convert;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
import com.sun.tools.javac.util.Log;
|
||||
@ -893,14 +894,20 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
errorStatus = true;
|
||||
break runAround;
|
||||
} else {
|
||||
ListBuffer<ClassSymbol> classes = enterNewClassFiles(currentContext);
|
||||
List<ClassSymbol> newClasses = enterNewClassFiles(currentContext);
|
||||
compiler.enterTrees(roots);
|
||||
|
||||
// annotationsPresentInSource =
|
||||
// collector.findAnnotations(parsedFiles);
|
||||
classes.appendList(getTopLevelClasses(parsedFiles));
|
||||
topLevelClasses = classes.toList();
|
||||
packageInfoFiles = getPackageInfoFiles(parsedFiles);
|
||||
ListBuffer<ClassSymbol> tlc = new ListBuffer<ClassSymbol>();
|
||||
tlc.appendList(getTopLevelClasses(parsedFiles));
|
||||
tlc.appendList(getTopLevelClassesFromClasses(newClasses));
|
||||
topLevelClasses = tlc.toList();
|
||||
|
||||
ListBuffer<PackageSymbol> pif = new ListBuffer<PackageSymbol>();
|
||||
pif.appendList(getPackageInfoFiles(parsedFiles));
|
||||
pif.appendList(getPackageInfoFilesFromClasses(newClasses));
|
||||
packageInfoFiles = pif.toList();
|
||||
|
||||
annotationsPresent = new LinkedHashSet<TypeElement>();
|
||||
for (ClassSymbol classSym : topLevelClasses)
|
||||
@ -1026,20 +1033,30 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
}
|
||||
}
|
||||
|
||||
private ListBuffer<ClassSymbol> enterNewClassFiles(Context currentContext) {
|
||||
private List<ClassSymbol> enterNewClassFiles(Context currentContext) {
|
||||
ClassReader reader = ClassReader.instance(currentContext);
|
||||
Names names = Names.instance(currentContext);
|
||||
ListBuffer<ClassSymbol> list = new ListBuffer<ClassSymbol>();
|
||||
List<ClassSymbol> list = List.nil();
|
||||
|
||||
for (Map.Entry<String,JavaFileObject> entry : filer.getGeneratedClasses().entrySet()) {
|
||||
Name name = names.fromString(entry.getKey());
|
||||
JavaFileObject file = entry.getValue();
|
||||
if (file.getKind() != JavaFileObject.Kind.CLASS)
|
||||
throw new AssertionError(file);
|
||||
ClassSymbol cs = reader.enterClass(name, file);
|
||||
list.append(cs);
|
||||
ClassSymbol cs;
|
||||
if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) {
|
||||
Name packageName = Convert.packagePart(name);
|
||||
PackageSymbol p = reader.enterPackage(packageName);
|
||||
if (p.package_info == null)
|
||||
p.package_info = reader.enterClass(Convert.shortName(name), p);
|
||||
cs = p.package_info;
|
||||
if (cs.classfile == null)
|
||||
cs.classfile = file;
|
||||
} else
|
||||
cs = reader.enterClass(name, file);
|
||||
list = list.prepend(cs);
|
||||
}
|
||||
return list;
|
||||
return list.reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1066,18 +1083,44 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
return classes.reverse();
|
||||
}
|
||||
|
||||
private List<ClassSymbol> getTopLevelClassesFromClasses(List<? extends ClassSymbol> syms) {
|
||||
List<ClassSymbol> classes = List.nil();
|
||||
for (ClassSymbol sym : syms) {
|
||||
if (!isPkgInfo(sym)) {
|
||||
classes = classes.prepend(sym);
|
||||
}
|
||||
}
|
||||
return classes.reverse();
|
||||
}
|
||||
|
||||
private List<PackageSymbol> getPackageInfoFiles(List<? extends JCCompilationUnit> units) {
|
||||
List<PackageSymbol> packages = List.nil();
|
||||
for (JCCompilationUnit unit : units) {
|
||||
boolean isPkgInfo = unit.sourcefile.isNameCompatible("package-info",
|
||||
JavaFileObject.Kind.SOURCE);
|
||||
if (isPkgInfo) {
|
||||
if (isPkgInfo(unit.sourcefile, JavaFileObject.Kind.SOURCE)) {
|
||||
packages = packages.prepend(unit.packge);
|
||||
}
|
||||
}
|
||||
return packages.reverse();
|
||||
}
|
||||
|
||||
private List<PackageSymbol> getPackageInfoFilesFromClasses(List<? extends ClassSymbol> syms) {
|
||||
List<PackageSymbol> packages = List.nil();
|
||||
for (ClassSymbol sym : syms) {
|
||||
if (isPkgInfo(sym)) {
|
||||
packages = packages.prepend((PackageSymbol) sym.owner);
|
||||
}
|
||||
}
|
||||
return packages.reverse();
|
||||
}
|
||||
|
||||
private boolean isPkgInfo(JavaFileObject fo, JavaFileObject.Kind kind) {
|
||||
return fo.isNameCompatible("package-info", kind);
|
||||
}
|
||||
|
||||
private boolean isPkgInfo(ClassSymbol sym) {
|
||||
return isPkgInfo(sym.classfile, JavaFileObject.Kind.CLASS) && (sym.packge().package_info == sym);
|
||||
}
|
||||
|
||||
private Context contextForNextRound(Context context, boolean shareNames)
|
||||
throws IOException
|
||||
{
|
||||
@ -1252,10 +1295,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
|
||||
node.sym = null;
|
||||
super.visitIdent(node);
|
||||
}
|
||||
public void visitApply(JCMethodInvocation node) {
|
||||
scan(node.typeargs);
|
||||
super.visitApply(node);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -307,8 +307,18 @@ public class TreeInfo {
|
||||
case(JCTree.POSTINC):
|
||||
case(JCTree.POSTDEC):
|
||||
return getStartPos(((JCUnary) tree).arg);
|
||||
case(JCTree.ANNOTATED_TYPE):
|
||||
return getStartPos(((JCAnnotatedType) tree).underlyingType);
|
||||
case(JCTree.ANNOTATED_TYPE): {
|
||||
JCAnnotatedType node = (JCAnnotatedType) tree;
|
||||
if (node.annotations.nonEmpty())
|
||||
return getStartPos(node.annotations.head);
|
||||
return getStartPos(node.underlyingType);
|
||||
}
|
||||
case(JCTree.NEWCLASS): {
|
||||
JCNewClass node = (JCNewClass)tree;
|
||||
if (node.encl != null)
|
||||
return getStartPos(node.encl);
|
||||
break;
|
||||
}
|
||||
case(JCTree.VARDEF): {
|
||||
JCVariableDecl node = (JCVariableDecl)tree;
|
||||
if (node.mods.pos != Position.NOPOS) {
|
||||
@ -406,6 +416,8 @@ public class TreeInfo {
|
||||
return getEndPos(((JCUnary) tree).arg, endPositions);
|
||||
case(JCTree.WHILELOOP):
|
||||
return getEndPos(((JCWhileLoop) tree).body, endPositions);
|
||||
case(JCTree.ANNOTATED_TYPE):
|
||||
return getEndPos(((JCAnnotatedType) tree).underlyingType, endPositions);
|
||||
case(JCTree.ERRONEOUS): {
|
||||
JCErroneous node = (JCErroneous)tree;
|
||||
if (node.errs != null && node.errs.nonEmpty())
|
||||
|
@ -480,7 +480,7 @@ public class TreeMaker implements JCTree.Factory {
|
||||
|
||||
public JCModifiers Modifiers(long flags, List<JCAnnotation> annotations) {
|
||||
JCModifiers tree = new JCModifiers(flags, annotations);
|
||||
boolean noFlags = (flags & Flags.StandardFlags) == 0;
|
||||
boolean noFlags = (flags & Flags.ModifierFlags) == 0;
|
||||
tree.pos = (noFlags && annotations.isEmpty()) ? Position.NOPOS : pos;
|
||||
return tree;
|
||||
}
|
||||
|
@ -193,6 +193,7 @@ public class TreeScanner extends Visitor {
|
||||
}
|
||||
|
||||
public void visitApply(JCMethodInvocation tree) {
|
||||
scan(tree.typeargs);
|
||||
scan(tree.meth);
|
||||
scan(tree.args);
|
||||
}
|
||||
@ -200,6 +201,7 @@ public class TreeScanner extends Visitor {
|
||||
public void visitNewClass(JCNewClass tree) {
|
||||
scan(tree.encl);
|
||||
scan(tree.clazz);
|
||||
scan(tree.typeargs);
|
||||
scan(tree.args);
|
||||
scan(tree.def);
|
||||
}
|
||||
|
@ -162,6 +162,7 @@ public class AnnotationWriter extends BasicWriter {
|
||||
print(pos.type_index);
|
||||
break;
|
||||
case CLASS_LITERAL:
|
||||
case CLASS_LITERAL_GENERIC_OR_ARRAY:
|
||||
if (showOffsets) {
|
||||
print(", offset=");
|
||||
print(pos.offset);
|
||||
|
76
langtools/test/tools/javac/T6654037.java
Normal file
76
langtools/test/tools/javac/T6654037.java
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2008-2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6654037
|
||||
* @summary JCTree.pos may be incorrect for BinaryTrees
|
||||
*/
|
||||
|
||||
import com.sun.source.tree.BinaryTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.tools.javac.api.JavacTaskImpl;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
public class T6654037 {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final String bootPath = System.getProperty("sun.boot.class.path"); //NOI18N
|
||||
final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
|
||||
assert tool != null;
|
||||
|
||||
String code = "package test; public class Test {private void test() {Object o = null; boolean b = o != null && o instanceof String;} private Test() {}}";
|
||||
|
||||
JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, null, null, Arrays.asList("-bootclasspath", bootPath, "-Xjcov"), null, Arrays.asList(new MyFileObject(code)));
|
||||
CompilationUnitTree cut = ct.parse().iterator().next();
|
||||
ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
|
||||
MethodTree method = (MethodTree) clazz.getMembers().get(0);
|
||||
VariableTree condSt = (VariableTree) method.getBody().getStatements().get(1);
|
||||
BinaryTree cond = (BinaryTree) condSt.getInitializer();
|
||||
JCTree condJC = (JCTree) cond;
|
||||
|
||||
if (condJC.pos != 93)
|
||||
throw new IllegalStateException("Unexpected position=" + condJC.pos);
|
||||
}
|
||||
|
||||
static class MyFileObject extends SimpleJavaFileObject {
|
||||
private String text;
|
||||
public MyFileObject(String text) {
|
||||
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
|
||||
this.text = text;
|
||||
}
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +1,31 @@
|
||||
Neg01.java:18:15: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg01.java:18:37: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg01<X>, Neg01<java.lang.String>)
|
||||
Neg01.java:19:25: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg01.java:19:15: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg01.java:19:47: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg01.java:20:23: compiler.err.cant.resolve.location.args: kindname.constructor, Neg01, , java.lang.String, kindname.class, Neg01<java.lang.Number>
|
||||
Neg01.java:21:23: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg01.java:21:15: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg01.java:21:45: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg01<X>, Neg01<? super java.lang.String>)
|
||||
Neg01.java:23:15: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg01.java:23:37: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg01<X>, Neg01<java.lang.String>)
|
||||
Neg01.java:24:25: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg01.java:24:15: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg01.java:24:47: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg01.java:25:23: compiler.err.cant.resolve.location.args: kindname.constructor, Neg01, , java.lang.String, kindname.class, Neg01<java.lang.Number>
|
||||
Neg01.java:25:38: compiler.err.cant.resolve.location.args: kindname.constructor, Neg01, , , kindname.class, Neg01<java.lang.Number>
|
||||
Neg01.java:26:23: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg01.java:26:15: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg01.java:26:45: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg01<X>, Neg01<? super java.lang.String>)
|
||||
Neg01.java:28:15: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg01.java:28:37: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg01<X>, Neg01<java.lang.String>)
|
||||
Neg01.java:29:25: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg01.java:29:15: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg01.java:29:48: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg01.java:30:24: compiler.err.cant.resolve.location.args: kindname.constructor, Neg01, , java.lang.String,java.lang.String, kindname.class, Neg01<java.lang.Number>
|
||||
Neg01.java:31:9: compiler.err.cant.resolve.location: kindname.class, Foo, , , kindname.class, Neg01<X>
|
||||
Neg01.java:31:35: compiler.err.cant.resolve.location.args: kindname.constructor, Neg01, , java.lang.String,java.lang.String, kindname.class, Neg01<java.lang.Number>
|
||||
Neg01.java:33:15: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg01.java:33:38: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg01<X>, Neg01<java.lang.String>)
|
||||
Neg01.java:34:25: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg01.java:34:15: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg01.java:34:48: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg01.java:35:24: compiler.err.cant.resolve.location.args: kindname.constructor, Neg01, , java.lang.String,java.lang.String, kindname.class, Neg01<java.lang.Number>
|
||||
Neg01.java:35:43: compiler.err.cant.resolve.location.args: kindname.constructor, Neg01, , , kindname.class, Neg01<java.lang.Number>
|
||||
Neg01.java:36:23: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg01.java:36:15: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg01.java:36:46: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg01<X>, Neg01<? super java.lang.String>)
|
||||
30 errors
|
||||
|
@ -1,61 +1,61 @@
|
||||
Neg02.java:19:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg02.java:19:33: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<java.lang.String>)
|
||||
Neg02.java:20:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:20:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:20:43: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg02.java:21:21: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:22:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:22:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:22:41: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<? super java.lang.String>)
|
||||
Neg02.java:24:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg02.java:24:33: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<java.lang.String>)
|
||||
Neg02.java:25:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:25:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:25:43: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg02.java:26:21: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:26:34: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:27:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:27:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:27:41: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<? super java.lang.String>)
|
||||
Neg02.java:29:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg02.java:29:33: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<java.lang.String>)
|
||||
Neg02.java:30:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:30:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:30:44: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg02.java:31:22: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:32:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:32:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:32:42: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<? super java.lang.String>)
|
||||
Neg02.java:34:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg02.java:34:34: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<java.lang.String>)
|
||||
Neg02.java:35:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:35:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:35:44: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg02.java:36:22: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:36:39: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:37:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:37:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:37:42: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<? super java.lang.String>)
|
||||
Neg02.java:41:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg02.java:41:39: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<java.lang.String>)
|
||||
Neg02.java:42:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:42:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:42:49: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg02.java:43:21: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:44:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:44:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:44:47: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<? super java.lang.String>)
|
||||
Neg02.java:46:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg02.java:46:39: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<java.lang.String>)
|
||||
Neg02.java:47:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:47:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:47:49: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg02.java:48:21: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:48:40: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:49:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:49:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:49:47: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<? super java.lang.String>)
|
||||
Neg02.java:51:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg02.java:51:39: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<java.lang.String>)
|
||||
Neg02.java:52:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:52:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:52:50: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg02.java:53:22: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:54:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:54:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:54:48: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<? super java.lang.String>)
|
||||
Neg02.java:56:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg02.java:56:40: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<java.lang.String>)
|
||||
Neg02.java:57:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:57:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg02.java:57:50: compiler.err.cant.apply.diamond: X, (compiler.misc.no.unique.maximal.instance.exists: X, java.lang.String,java.lang.Number)
|
||||
Neg02.java:58:22: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:58:45: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Neg02.Foo<java.lang.Number>
|
||||
Neg02.java:59:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:59:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg02.java:59:48: compiler.err.cant.apply.diamond: X, (compiler.misc.no.conforming.instance.exists: X, Neg02.Foo<X>, Neg02.Foo<? super java.lang.String>)
|
||||
60 errors
|
||||
|
@ -1,91 +1,91 @@
|
||||
Neg03.java:19:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:19:33: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:20:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:20:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:20:43: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:21:21: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:22:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:22:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:22:41: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:24:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:24:33: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:25:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:25:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:25:43: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:26:21: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:26:34: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:27:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:27:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:27:41: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:29:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:29:33: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:30:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:30:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:30:44: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:31:22: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:32:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:32:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:32:42: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:34:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:34:34: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:35:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:35:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:35:44: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:36:22: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:36:39: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:37:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:37:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:37:42: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:41:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:41:42: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:42:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:42:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:42:52: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:43:21: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:44:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:44:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:44:50: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:46:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:46:42: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:47:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:47:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:47:52: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:48:21: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:48:43: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:49:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:49:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:49:50: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:51:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:51:42: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:52:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:52:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:52:53: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:53:22: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:54:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:54:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:54:51: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:56:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:56:43: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:57:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:57:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:57:53: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:58:22: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:58:48: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:59:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:59:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:59:51: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:63:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:63:28: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:64:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:64:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:64:38: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:65:23: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:66:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:66:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:66:36: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:68:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:68:28: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:69:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:69:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:69:38: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:70:23: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:70:36: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:71:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:71:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:71:36: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:73:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:73:28: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:74:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:74:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:74:39: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:75:24: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:76:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:76:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:76:37: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
Neg03.java:78:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg03.java:78:29: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<java.lang.String>)
|
||||
Neg03.java:79:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:79:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg03.java:79:39: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg03.java:80:24: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:80:41: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Neg03<U>.Foo<java.lang.Number>
|
||||
Neg03.java:81:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:81:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg03.java:81:37: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Neg03<U>.Foo<V>, Neg03<U>.Foo<? super java.lang.String>)
|
||||
90 errors
|
||||
|
@ -1,31 +1,31 @@
|
||||
Neg04.java:18:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg04.java:18:33: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Foo<V>, Foo<java.lang.String>)
|
||||
Neg04.java:19:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg04.java:19:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg04.java:19:43: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg04.java:20:21: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Foo<java.lang.Number>
|
||||
Neg04.java:21:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg04.java:21:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg04.java:21:41: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Foo<V>, Foo<? super java.lang.String>)
|
||||
Neg04.java:23:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg04.java:23:33: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Foo<V>, Foo<java.lang.String>)
|
||||
Neg04.java:24:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg04.java:24:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg04.java:24:43: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg04.java:25:21: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String, kindname.class, Foo<java.lang.Number>
|
||||
Neg04.java:25:34: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Foo<java.lang.Number>
|
||||
Neg04.java:26:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg04.java:26:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg04.java:26:41: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Foo<V>, Foo<? super java.lang.String>)
|
||||
Neg04.java:28:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg04.java:28:33: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Foo<V>, Foo<java.lang.String>)
|
||||
Neg04.java:29:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg04.java:29:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg04.java:29:44: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg04.java:30:22: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Foo<java.lang.Number>
|
||||
Neg04.java:31:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg04.java:31:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg04.java:31:42: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Foo<V>, Foo<? super java.lang.String>)
|
||||
Neg04.java:33:13: compiler.err.not.within.bounds: java.lang.String
|
||||
Neg04.java:33:34: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Foo<V>, Foo<java.lang.String>)
|
||||
Neg04.java:34:23: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg04.java:34:13: compiler.err.not.within.bounds: ? extends java.lang.String
|
||||
Neg04.java:34:44: compiler.err.cant.apply.diamond: V, (compiler.misc.no.unique.maximal.instance.exists: V, java.lang.String,java.lang.Number)
|
||||
Neg04.java:35:22: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , java.lang.String,java.lang.String, kindname.class, Foo<java.lang.Number>
|
||||
Neg04.java:35:39: compiler.err.cant.resolve.location.args: kindname.constructor, Foo, , , kindname.class, Foo<java.lang.Number>
|
||||
Neg04.java:36:21: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg04.java:36:13: compiler.err.not.within.bounds: ? super java.lang.String
|
||||
Neg04.java:36:42: compiler.err.cant.apply.diamond: V, (compiler.misc.no.conforming.instance.exists: V, Foo<V>, Foo<? super java.lang.String>)
|
||||
30 errors
|
||||
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6499119
|
||||
* @summary Created package-info class file modeled improperly
|
||||
* @compile ClassProcessor.java package-info.java
|
||||
* @compile/process -cp . -processor ClassProcessor -Akind=java java.lang.Object
|
||||
* @compile/process -cp . -processor ClassProcessor -Akind=class java.lang.Object
|
||||
*/
|
||||
|
||||
@SupportedOptions({ "gen", "expect" })
|
||||
@SupportedAnnotationTypes({"*"})
|
||||
public class ClassProcessor extends AbstractProcessor {
|
||||
int round = 1;
|
||||
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latest();
|
||||
}
|
||||
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (round == 1) {
|
||||
System.out.println("-- Round 1 --");
|
||||
createPackageFile();
|
||||
} else if (round == 2) {
|
||||
boolean found_foo_A = false;
|
||||
System.out.println("-- Round 2 --");
|
||||
for(Element e: roundEnv.getRootElements()) {
|
||||
System.out.println("ElementKind: " + e.getKind());
|
||||
System.out.println("Modifiers: " + e.getModifiers());
|
||||
System.out.println("Annotations: " + e.getAnnotationMirrors());
|
||||
if (e.getAnnotationMirrors().toString().equals("@foo.A")) {
|
||||
found_foo_A = true;
|
||||
checkEqual("ElementKind", e.getKind().toString(), "PACKAGE");
|
||||
checkEqual("Modifiers", e.getModifiers().toString(), "[]");
|
||||
}
|
||||
}
|
||||
if (!found_foo_A)
|
||||
error("did not find @foo.A");
|
||||
}
|
||||
round++;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void createPackageFile() {
|
||||
Filer filer = processingEnv.getFiler();
|
||||
|
||||
String kind = processingEnv.getOptions().get("kind");
|
||||
|
||||
File pkgInfo;
|
||||
if (kind.equals("java"))
|
||||
pkgInfo = new File(System.getProperty("test.src"), "package-info.java");
|
||||
else
|
||||
pkgInfo = new File(System.getProperty("test.classes"), "foo/package-info.class");
|
||||
|
||||
byte[] bytes = new byte[(int) pkgInfo.length()];
|
||||
DataInputStream in = null;
|
||||
try {
|
||||
in = new DataInputStream(new FileInputStream(pkgInfo));
|
||||
in.readFully(bytes);
|
||||
} catch (IOException ioe) {
|
||||
error("Couldn't read package info file: " + ioe);
|
||||
} finally {
|
||||
if(in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
error("InputStream closing failed: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream out = null;
|
||||
try {
|
||||
if (kind.equals("java"))
|
||||
out = filer.createSourceFile("foo.package-info").openOutputStream();
|
||||
else
|
||||
out = filer.createClassFile("foo.package-info").openOutputStream();
|
||||
out.write(bytes, 0, bytes.length);
|
||||
} catch (IOException ioe) {
|
||||
error("Couldn't create package info file: " + ioe);
|
||||
} finally {
|
||||
if(out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
error("OutputStream closing failed: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEqual(String label, String actual, String expect) {
|
||||
if (!actual.equals(expect)) {
|
||||
error("Unexpected value for " + label + "; actual=" + actual + ", expected=" + expect);
|
||||
}
|
||||
}
|
||||
|
||||
private void error(String msg) {
|
||||
Messager messager = processingEnv.getMessager();
|
||||
messager.printMessage(Kind.ERROR, msg);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
@A package foo;
|
||||
|
||||
@interface A {}
|
||||
|
462
langtools/test/tools/javac/processing/T6920317.java
Normal file
462
langtools/test/tools/javac/processing/T6920317.java
Normal file
@ -0,0 +1,462 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6920317
|
||||
* @summary package-info.java file has to be specified on the javac cmdline, else it will not be avail
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.util.*;
|
||||
import javax.tools.*;
|
||||
|
||||
/**
|
||||
* The test exercises different ways of providing annotations for a package.
|
||||
* Each way provides an annotation with a unique argument. For each test
|
||||
* case, the test verifies that the annotation with the correct argument is
|
||||
* found by the compiler.
|
||||
*/
|
||||
public class T6920317 {
|
||||
public static void main(String... args) throws Exception {
|
||||
new T6920317().run(args);
|
||||
}
|
||||
|
||||
// Used to describe properties of files to be put on command line, source path, class path
|
||||
enum Kind {
|
||||
/** File is not used. */
|
||||
NONE,
|
||||
/** File is used. */
|
||||
OLD,
|
||||
/** Only applies to files on classpath/sourcepath, when there is another file on the
|
||||
* other path of type OLD, in which case, this file must be newer than the other one. */
|
||||
NEW,
|
||||
/** Only applies to files on classpath/sourcepath, when there is no file in any other
|
||||
* location, in which case, this file will be generated by the annotation processor. */
|
||||
GEN
|
||||
}
|
||||
|
||||
void run(String... args) throws Exception {
|
||||
// if no args given, all test cases are run
|
||||
// if args given, they indicate the test cases to be run
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
tests.add(Integer.valueOf(args[i]));
|
||||
}
|
||||
|
||||
setup();
|
||||
|
||||
// Run tests for all combinations of files on command line, source path and class path.
|
||||
// Invalid combinations are skipped in the test method
|
||||
for (Kind cmdLine: EnumSet.of(Kind.NONE, Kind.OLD)) {
|
||||
for (Kind srcPath: Kind.values()) {
|
||||
for (Kind clsPath: Kind.values()) {
|
||||
try {
|
||||
test(cmdLine, srcPath, clsPath);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
error("Exception " + e);
|
||||
// uncomment to stop on first failed test case
|
||||
// throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors > 0)
|
||||
throw new Exception(errors + " errors occurred");
|
||||
}
|
||||
|
||||
/** One time setup for files and directories to be used in the various test cases. */
|
||||
void setup() throws Exception {
|
||||
// Annotation used in test cases to annotate package. This file is
|
||||
// given on the command line in test cases.
|
||||
test_java = writeFile("Test.java", "package p; @interface Test { String value(); }");
|
||||
// Compile the annotation for use later in setup
|
||||
File tmpClasses = new File("tmp.classes");
|
||||
compile(tmpClasses, new String[] { }, test_java);
|
||||
|
||||
// package-info file to use on the command line when requied
|
||||
cl_pkgInfo_java = writeFile("cl/p/package-info.java", "@Test(\"CL\") package p;");
|
||||
|
||||
// source path containing package-info
|
||||
sp_old = new File("src.old");
|
||||
writeFile("src.old/p/package-info.java", "@Test(\"SP_OLD\") package p;");
|
||||
|
||||
// class path containing package-info
|
||||
cp_old = new File("classes.old");
|
||||
compile(cp_old, new String[] { "-classpath", tmpClasses.getPath() },
|
||||
writeFile("tmp.old/p/package-info.java", "@Test(\"CP_OLD\") package p;"));
|
||||
|
||||
// source path containing package-info which is newer than the one in cp-old
|
||||
sp_new = new File("src.new");
|
||||
File old_class = new File(cp_old, "p/package-info.class");
|
||||
writeFile("src.new/p/package-info.java", "@Test(\"SP_NEW\") package p;", old_class);
|
||||
|
||||
// class path containing package-info which is newer than the one in sp-old
|
||||
cp_new = new File("classes.new");
|
||||
File old_java = new File(sp_old, "p/package-info.java");
|
||||
compile(cp_new, new String[] { "-classpath", tmpClasses.getPath() },
|
||||
writeFile("tmp.new/p/package-info.java", "@Test(\"CP_NEW\") package p;", old_java));
|
||||
|
||||
// directory containing package-info.java to be "generated" later by annotation processor
|
||||
sp_gen = new File("src.gen");
|
||||
writeFile("src.gen/p/package-info.java", "@Test(\"SP_GEN\") package p;");
|
||||
|
||||
// directory containing package-info.class to be "generated" later by annotation processor
|
||||
cp_gen = new File("classes.gen");
|
||||
compile(cp_gen, new String[] { "-classpath", tmpClasses.getPath() },
|
||||
writeFile("tmp.gen/p/package-info.java", "@Test(\"CP_GEN\") package p;"));
|
||||
}
|
||||
|
||||
void test(Kind cl, Kind sp, Kind cp) throws Exception {
|
||||
if (skip(cl, sp, cp))
|
||||
return;
|
||||
|
||||
++count;
|
||||
// if test cases specified, skip this test case if not selected
|
||||
if (tests.size() > 0 && !tests.contains(count))
|
||||
return;
|
||||
|
||||
System.err.println("Test " + count + " cl:" + cl + " sp:" + sp + " cp:" + cp);
|
||||
|
||||
// test specific tmp directory
|
||||
File test_tmp = new File("tmp.test" + count);
|
||||
test_tmp.mkdirs();
|
||||
|
||||
// build up list of options and files to be compiled
|
||||
List<String> opts = new ArrayList<String>();
|
||||
List<File> files = new ArrayList<File>();
|
||||
|
||||
// expected value for annotation
|
||||
String expect = null;
|
||||
|
||||
opts.add("-processorpath");
|
||||
opts.add(System.getProperty("test.classes"));
|
||||
opts.add("-processor");
|
||||
opts.add(Processor.class.getName());
|
||||
opts.add("-proc:only");
|
||||
opts.add("-d");
|
||||
opts.add(test_tmp.getPath());
|
||||
//opts.add("-verbose");
|
||||
files.add(test_java);
|
||||
|
||||
/*
|
||||
* Analyze each of cl, cp, sp, building up the options and files to
|
||||
* be compiled, and determining the expected outcome fo the test case.
|
||||
*/
|
||||
|
||||
// command line file: either omitted or given
|
||||
if (cl == Kind.OLD) {
|
||||
files.add(cl_pkgInfo_java);
|
||||
// command line files always supercede files on paths
|
||||
expect = "CL";
|
||||
}
|
||||
|
||||
// source path:
|
||||
switch (sp) {
|
||||
case NONE:
|
||||
break;
|
||||
|
||||
case OLD:
|
||||
opts.add("-sourcepath");
|
||||
opts.add(sp_old.getPath());
|
||||
if (expect == null && cp == Kind.NONE) {
|
||||
assert cl == Kind.NONE && cp == Kind.NONE;
|
||||
expect = "SP_OLD";
|
||||
}
|
||||
break;
|
||||
|
||||
case NEW:
|
||||
opts.add("-sourcepath");
|
||||
opts.add(sp_new.getPath());
|
||||
if (expect == null) {
|
||||
assert cl == Kind.NONE && cp == Kind.OLD;
|
||||
expect = "SP_NEW";
|
||||
}
|
||||
break;
|
||||
|
||||
case GEN:
|
||||
opts.add("-Agen=" + new File(sp_gen, "p/package-info.java"));
|
||||
assert cl == Kind.NONE && cp == Kind.NONE;
|
||||
expect = "SP_GEN";
|
||||
break;
|
||||
}
|
||||
|
||||
// class path:
|
||||
switch (cp) {
|
||||
case NONE:
|
||||
break;
|
||||
|
||||
case OLD:
|
||||
opts.add("-classpath");
|
||||
opts.add(cp_old.getPath());
|
||||
if (expect == null && sp == Kind.NONE) {
|
||||
assert cl == Kind.NONE && sp == Kind.NONE;
|
||||
expect = "CP_OLD";
|
||||
}
|
||||
break;
|
||||
|
||||
case NEW:
|
||||
opts.add("-classpath");
|
||||
opts.add(cp_new.getPath());
|
||||
if (expect == null) {
|
||||
assert cl == Kind.NONE && sp == Kind.OLD;
|
||||
expect = "CP_NEW";
|
||||
}
|
||||
break;
|
||||
|
||||
case GEN:
|
||||
opts.add("-Agen=" + new File(cp_gen, "p/package-info.class"));
|
||||
assert cl == Kind.NONE && sp == Kind.NONE;
|
||||
expect = "CP_GEN";
|
||||
break;
|
||||
}
|
||||
|
||||
// pass expected value to annotation processor
|
||||
assert expect != null;
|
||||
opts.add("-Aexpect=" + expect);
|
||||
|
||||
// compile the files with the options that have been built up
|
||||
compile(opts, files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this combination of parameters does not identify a useful test case.
|
||||
*/
|
||||
boolean skip(Kind cl, Kind sp, Kind cp) {
|
||||
// skip if no package files required
|
||||
if (cl == Kind.NONE && sp == Kind.NONE && cp == Kind.NONE)
|
||||
return true;
|
||||
|
||||
// skip if both sp and sp are OLD, since results may be indeterminate
|
||||
if (sp == Kind.OLD && cp == Kind.OLD)
|
||||
return true;
|
||||
|
||||
// skip if sp or cp is NEW but the other is not OLD
|
||||
if ((sp == Kind.NEW && cp != Kind.OLD) || (cp == Kind.NEW && sp != Kind.OLD))
|
||||
return true;
|
||||
|
||||
// only use GEN if no other package-info files present
|
||||
if (sp == Kind.GEN && !(cl == Kind.NONE && cp == Kind.NONE) ||
|
||||
cp == Kind.GEN && !(cl == Kind.NONE && sp == Kind.NONE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// remaining combinations are valid
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Write a file with a given body. */
|
||||
File writeFile(String path, String body) throws Exception {
|
||||
File f = new File(path);
|
||||
if (f.getParentFile() != null)
|
||||
f.getParentFile().mkdirs();
|
||||
Writer out = new FileWriter(path);
|
||||
try {
|
||||
out.write(body);
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/** Write a file with a given body, ensuring that the file is newer than a reference file. */
|
||||
File writeFile(String path, String body, File ref) throws Exception {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
File f = writeFile(path, body);
|
||||
if (f.lastModified() > ref.lastModified())
|
||||
return f;
|
||||
Thread.sleep(2000);
|
||||
}
|
||||
throw new Exception("cannot create file " + path + " newer than " + ref);
|
||||
}
|
||||
|
||||
/** Compile a file to a given directory, with options provided. */
|
||||
void compile(File dir, String[] opts, File src) throws Exception {
|
||||
dir.mkdirs();
|
||||
List<String> opts2 = new ArrayList<String>();
|
||||
opts2.addAll(Arrays.asList("-d", dir.getPath()));
|
||||
opts2.addAll(Arrays.asList(opts));
|
||||
compile(opts2, Collections.singletonList(src));
|
||||
}
|
||||
|
||||
/** Compile files with options provided. */
|
||||
void compile(List<String> opts, List<File> files) throws Exception {
|
||||
System.err.println("javac: " + opts + " " + files);
|
||||
List<String> args = new ArrayList<String>();
|
||||
args.addAll(opts);
|
||||
for (File f: files)
|
||||
args.add(f.getPath());
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw);
|
||||
pw.flush();
|
||||
if (sw.getBuffer().length() > 0)
|
||||
System.err.println(sw.toString());
|
||||
if (rc != 0)
|
||||
throw new Exception("compilation failed: rc=" + rc);
|
||||
}
|
||||
|
||||
/** Report an error. */
|
||||
void error(String msg) {
|
||||
System.err.println("Error: " + msg);
|
||||
errors++;
|
||||
}
|
||||
|
||||
/** Test case counter. */
|
||||
int count;
|
||||
|
||||
/** Number of errors found. */
|
||||
int errors;
|
||||
|
||||
/** Optional set of test cases to be run; empty implies all test cases. */
|
||||
Set<Integer> tests = new HashSet<Integer>();
|
||||
|
||||
/* Files created by setup. */
|
||||
File test_java;
|
||||
File sp_old;
|
||||
File sp_new;
|
||||
File sp_gen;
|
||||
File cp_old;
|
||||
File cp_new;
|
||||
File cp_gen;
|
||||
File cl_pkgInfo_java;
|
||||
|
||||
/** Annotation processor used to verify the expected value for the
|
||||
package annotations found by javac. */
|
||||
@SupportedOptions({ "gen", "expect" })
|
||||
@SupportedAnnotationTypes({"*"})
|
||||
public static class Processor extends AbstractProcessor {
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latest();
|
||||
}
|
||||
|
||||
public boolean process(Set<? extends TypeElement> annots, RoundEnvironment renv) {
|
||||
round++;
|
||||
System.err.println("Round " + round + " annots:" + annots + " rootElems:" + renv.getRootElements());
|
||||
|
||||
// if this is the first round and the gen option is given, use the filer to create
|
||||
// a copy of the file specified by the gen option.
|
||||
String gen = getOption("gen");
|
||||
if (round == 1 && gen != null) {
|
||||
try {
|
||||
Filer filer = processingEnv.getFiler();
|
||||
JavaFileObject f;
|
||||
if (gen.endsWith(".java"))
|
||||
f = filer.createSourceFile("p.package-info");
|
||||
else
|
||||
f = filer.createClassFile("p.package-info");
|
||||
System.err.println("copy " + gen + " to " + f.getName());
|
||||
write(f, read(new File(gen)));
|
||||
} catch (IOException e) {
|
||||
error("Cannot create package-info file: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// if annotation processing is complete, verify the package annotation
|
||||
// found by the compiler.
|
||||
if (renv.processingOver()) {
|
||||
System.err.println("final round");
|
||||
Elements eu = processingEnv.getElementUtils();
|
||||
TypeElement te = eu.getTypeElement("p.Test");
|
||||
PackageElement pe = eu.getPackageOf(te);
|
||||
System.err.println("final: te:" + te + " pe:" + pe);
|
||||
List<? extends AnnotationMirror> annos = pe.getAnnotationMirrors();
|
||||
System.err.println("final: annos:" + annos);
|
||||
if (annos.size() == 1) {
|
||||
String expect = "@" + te + "(\"" + getOption("expect") + "\")";
|
||||
String actual = annos.get(0).toString();
|
||||
checkEqual("package annotations", actual, expect);
|
||||
} else {
|
||||
error("Wrong number of annotations found: (" + annos.size() + ") " + annos);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Get an option given to the annotation processor. */
|
||||
String getOption(String name) {
|
||||
return processingEnv.getOptions().get(name);
|
||||
}
|
||||
|
||||
/** Read a file. */
|
||||
byte[] read(File file) {
|
||||
byte[] bytes = new byte[(int) file.length()];
|
||||
DataInputStream in = null;
|
||||
try {
|
||||
in = new DataInputStream(new FileInputStream(file));
|
||||
in.readFully(bytes);
|
||||
} catch (IOException e) {
|
||||
error("Error reading file: " + e);
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
error("Error closing file: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/** Write a file. */
|
||||
void write(JavaFileObject file, byte[] bytes) {
|
||||
OutputStream out = null;
|
||||
try {
|
||||
out = file.openOutputStream();
|
||||
out.write(bytes, 0, bytes.length);
|
||||
} catch (IOException e) {
|
||||
error("Error writing file: " + e);
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
error("Error closing file: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Check two strings are equal, and report an error if they are not. */
|
||||
private void checkEqual(String label, String actual, String expect) {
|
||||
if (!actual.equals(expect)) {
|
||||
error("Unexpected value for " + label + "; actual=" + actual + ", expected=" + expect);
|
||||
}
|
||||
}
|
||||
|
||||
/** Report an error to the annotation processing system. */
|
||||
void error(String msg) {
|
||||
Messager messager = processingEnv.getMessager();
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, msg);
|
||||
}
|
||||
|
||||
int round;
|
||||
}
|
||||
}
|
40
langtools/test/tools/javac/tree/T6923080.java
Normal file
40
langtools/test/tools/javac/tree/T6923080.java
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is not a regular test, but is processed by ./TreeScannerTest.java,
|
||||
* which verifies the operation of the javac TreeScanner.
|
||||
* @bug 6923080
|
||||
* @summary TreeScanner.visitNewClass should scan tree.typeargs
|
||||
*/
|
||||
class T6923080 {
|
||||
void test() {
|
||||
C c = new <Integer>C(); // exercises TreeScanner.visitNewClass
|
||||
Object o = c.<Float>m(); // exercises TreeScanner.visitApply
|
||||
}
|
||||
|
||||
static class C {
|
||||
<T> C() { }
|
||||
<T> T m() { return null; }
|
||||
}
|
||||
}
|
387
langtools/test/tools/javac/tree/TreeScannerTest.java
Normal file
387
langtools/test/tools/javac/tree/TreeScannerTest.java
Normal file
@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Utility and test program to check javac's internal TreeScanner class.
|
||||
* The program can be run standalone, or as a jtreg test. For info on
|
||||
* command line args, run program with no args.
|
||||
*
|
||||
* <p>
|
||||
* jtreg: Note that by using the -r switch in the test description below, this test
|
||||
* will process all java files in the langtools/test directory, thus implicitly
|
||||
* covering any new language features that may be tested in this test suite.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6923080
|
||||
* @summary TreeScanner.visitNewClass should scan tree.typeargs
|
||||
* @run main TreeScannerTest -q -r .
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import javax.tools.*;
|
||||
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.util.JavacTask;
|
||||
import com.sun.tools.javac.api.JavacTool;
|
||||
import com.sun.tools.javac.tree.*;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import com.sun.tools.javac.util.List;
|
||||
|
||||
public class TreeScannerTest {
|
||||
/**
|
||||
* Main entry point.
|
||||
* If test.src is set, program runs in jtreg mode, and will throw an Error
|
||||
* if any errors arise, otherwise System.exit will be used. In jtreg mode,
|
||||
* the default base directory for file args is the value of ${test.src}.
|
||||
* In jtreg mode, the -r option can be given to change the default base
|
||||
* directory to the root test directory.
|
||||
*/
|
||||
public static void main(String... args) {
|
||||
String testSrc = System.getProperty("test.src");
|
||||
File baseDir = (testSrc == null) ? null : new File(testSrc);
|
||||
boolean ok = new TreeScannerTest().run(baseDir, args);
|
||||
if (!ok) {
|
||||
if (testSrc != null) // jtreg mode
|
||||
throw new Error("failed");
|
||||
else
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the program. A base directory can be provided for file arguments.
|
||||
* In jtreg mode, the -r option can be given to change the default base
|
||||
* directory to the test root directory. For other options, see usage().
|
||||
* @param baseDir base directory for any file arguments.
|
||||
* @param args command line args
|
||||
* @return true if successful or in gui mode
|
||||
*/
|
||||
boolean run(File baseDir, String... args) {
|
||||
if (args.length == 0) {
|
||||
usage(System.out);
|
||||
return true;
|
||||
}
|
||||
|
||||
ArrayList<File> files = new ArrayList<File>();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
String arg = args[i];
|
||||
if (arg.equals("-q"))
|
||||
quiet = true;
|
||||
else if (arg.equals("-v"))
|
||||
verbose = true;
|
||||
else if (arg.equals("-r")) {
|
||||
File d = baseDir;
|
||||
while (!new File(d, "TEST.ROOT").exists()) {
|
||||
d = d.getParentFile();
|
||||
if (d == null)
|
||||
throw new Error("cannot find TEST.ROOT");
|
||||
}
|
||||
baseDir = d;
|
||||
}
|
||||
else if (arg.startsWith("-"))
|
||||
throw new Error("unknown option: " + arg);
|
||||
else {
|
||||
while (i < args.length)
|
||||
files.add(new File(baseDir, args[i++]));
|
||||
}
|
||||
}
|
||||
|
||||
for (File file: files) {
|
||||
if (file.exists())
|
||||
test(file);
|
||||
else
|
||||
error("File not found: " + file);
|
||||
}
|
||||
|
||||
if (fileCount != 1)
|
||||
System.err.println(fileCount + " files read");
|
||||
if (errors > 0)
|
||||
System.err.println(errors + " errors");
|
||||
|
||||
return (errors == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print command line help.
|
||||
* @param out output stream
|
||||
*/
|
||||
void usage(PrintStream out) {
|
||||
out.println("Usage:");
|
||||
out.println(" java TreeScannerTest options... files...");
|
||||
out.println("");
|
||||
out.println("where options include:");
|
||||
out.println("-q Quiet: don't report on inapplicable files");
|
||||
out.println("-v Verbose: report on files as they are being read");
|
||||
out.println("");
|
||||
out.println("files may be directories or files");
|
||||
out.println("directories will be scanned recursively");
|
||||
out.println("non java files, or java files which cannot be parsed, will be ignored");
|
||||
out.println("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a file. If the file is a directory, it will be recursively scanned
|
||||
* for java files.
|
||||
* @param file the file or directory to test
|
||||
*/
|
||||
void test(File file) {
|
||||
if (file.isDirectory()) {
|
||||
for (File f: file.listFiles()) {
|
||||
test(f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.isFile() && file.getName().endsWith(".java")) {
|
||||
try {
|
||||
if (verbose)
|
||||
System.err.println(file);
|
||||
fileCount++;
|
||||
ScanTester t = new ScanTester();
|
||||
t.test(read(file));
|
||||
} catch (ParseException e) {
|
||||
if (!quiet) {
|
||||
error("Error parsing " + file + "\n" + e.getMessage());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
error("Error reading " + file + ": " + e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!quiet)
|
||||
error("File " + file + " ignored");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file.
|
||||
* @param file the file to be read
|
||||
* @return the tree for the content of the file
|
||||
* @throws IOException if any IO errors occur
|
||||
* @throws TreePosTest.ParseException if any errors occur while parsing the file
|
||||
*/
|
||||
JCCompilationUnit read(File file) throws IOException, ParseException {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
Reporter r = new Reporter(pw);
|
||||
JavacTool tool = JavacTool.create();
|
||||
StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null);
|
||||
Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(file);
|
||||
JavacTask task = tool.getTask(pw, fm, r, Collections.<String>emptyList(), null, files);
|
||||
Iterable<? extends CompilationUnitTree> trees = task.parse();
|
||||
pw.flush();
|
||||
if (r.errors > 0)
|
||||
throw new ParseException(sw.toString());
|
||||
Iterator<? extends CompilationUnitTree> iter = trees.iterator();
|
||||
if (!iter.hasNext())
|
||||
throw new Error("no trees found");
|
||||
JCCompilationUnit t = (JCCompilationUnit) iter.next();
|
||||
if (iter.hasNext())
|
||||
throw new Error("too many trees found");
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an error. When the program is complete, the program will either
|
||||
* exit or throw an Error if any errors have been reported.
|
||||
* @param msg the error message
|
||||
*/
|
||||
void error(String msg) {
|
||||
System.err.println(msg);
|
||||
errors++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an error for a specific tree node.
|
||||
* @param file the source file for the tree
|
||||
* @param t the tree node
|
||||
* @param label an indication of the error
|
||||
*/
|
||||
void error(JavaFileObject file, JCTree t, String msg) {
|
||||
error(file.getName() + ":" + getLine(file, t) + ": " + msg + " " + trim(t, 64));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a trimmed string for a tree node, with normalized white space and limited length.
|
||||
*/
|
||||
String trim(JCTree t, int len) {
|
||||
String s = t.toString().replaceAll("[\r\n]+", " ").replaceAll(" +", " ");
|
||||
return (s.length() < len) ? s : s.substring(0, len);
|
||||
}
|
||||
|
||||
/** Number of files that have been analyzed. */
|
||||
int fileCount;
|
||||
/** Number of errors reported. */
|
||||
int errors;
|
||||
/** Flag: don't report irrelevant files. */
|
||||
boolean quiet;
|
||||
/** Flag: report files as they are processed. */
|
||||
boolean verbose;
|
||||
|
||||
/**
|
||||
* Main class for testing operation of tree scanner.
|
||||
* The set of nodes found by the scanner are compared
|
||||
* against the set of nodes found by reflection.
|
||||
*/
|
||||
private class ScanTester extends TreeScanner {
|
||||
/** Main entry method for the class. */
|
||||
void test(JCCompilationUnit tree) {
|
||||
sourcefile = tree.sourcefile;
|
||||
found = new HashSet<JCTree>();
|
||||
scan(tree);
|
||||
expect = new HashSet<JCTree>();
|
||||
reflectiveScan(tree);
|
||||
if (found.equals(expect))
|
||||
return;
|
||||
|
||||
error("Differences found for " + tree.sourcefile.getName());
|
||||
|
||||
if (found.size() != expect.size())
|
||||
error("Size mismatch; found: " + found.size() + ", expected: " + expect.size());
|
||||
|
||||
Set<JCTree> missing = new HashSet<JCTree>();
|
||||
missing.addAll(expect);
|
||||
missing.removeAll(found);
|
||||
for (JCTree t: missing)
|
||||
error(tree.sourcefile, t, "missing");
|
||||
|
||||
Set<JCTree> excess = new HashSet<JCTree>();
|
||||
excess.addAll(found);
|
||||
excess.removeAll(expect);
|
||||
for (JCTree t: excess)
|
||||
error(tree.sourcefile, t, "unexpected");
|
||||
}
|
||||
|
||||
/** Record all tree nodes found by scanner. */
|
||||
@Override
|
||||
public void scan(JCTree tree) {
|
||||
if (tree == null)
|
||||
return;
|
||||
System.err.println("FOUND: " + tree.getTag() + " " + trim(tree, 64));
|
||||
found.add(tree);
|
||||
super.scan(tree);
|
||||
}
|
||||
|
||||
/** record all tree nodes found by reflection. */
|
||||
public void reflectiveScan(Object o) {
|
||||
if (o == null)
|
||||
return;
|
||||
if (o instanceof JCTree) {
|
||||
JCTree tree = (JCTree) o;
|
||||
System.err.println("EXPECT: " + tree.getTag() + " " + trim(tree, 64));
|
||||
expect.add(tree);
|
||||
for (Field f: getFields(tree)) {
|
||||
try {
|
||||
//System.err.println("FIELD: " + f.getName());
|
||||
reflectiveScan(f.get(tree));
|
||||
} catch (IllegalAccessException e) {
|
||||
error(e.toString());
|
||||
}
|
||||
}
|
||||
} else if (o instanceof List) {
|
||||
List<?> list = (List<?>) o;
|
||||
for (Object item: list)
|
||||
reflectiveScan(item);
|
||||
} else
|
||||
error("unexpected item: " + o);
|
||||
}
|
||||
|
||||
JavaFileObject sourcefile;
|
||||
Set<JCTree> found;
|
||||
Set<JCTree> expect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when errors are found parsing a java file.
|
||||
*/
|
||||
private static class ParseException extends Exception {
|
||||
ParseException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DiagnosticListener to report diagnostics and count any errors that occur.
|
||||
*/
|
||||
private static class Reporter implements DiagnosticListener<JavaFileObject> {
|
||||
Reporter(PrintWriter out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
out.println(diagnostic);
|
||||
switch (diagnostic.getKind()) {
|
||||
case ERROR:
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
int errors;
|
||||
PrintWriter out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of fields for a tree node that may contain child tree nodes.
|
||||
* These are the fields that are subtypes of JCTree or List.
|
||||
* The results are cached, based on the tree's tag.
|
||||
*/
|
||||
Set<Field> getFields(JCTree tree) {
|
||||
Set<Field> fields = map.get(tree.getTag());
|
||||
if (fields == null) {
|
||||
fields = new HashSet<Field>();
|
||||
for (Field f: tree.getClass().getFields()) {
|
||||
Class<?> fc = f.getType();
|
||||
if (JCTree.class.isAssignableFrom(fc) || List.class.isAssignableFrom(fc))
|
||||
fields.add(f);
|
||||
}
|
||||
map.put(tree.getTag(), fields);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
// where
|
||||
Map<Integer, Set<Field>> map = new HashMap<Integer,Set<Field>>();
|
||||
|
||||
/** Get the line number for the primary position for a tree.
|
||||
* The code is intended to be simple, although not necessarily efficient.
|
||||
* However, note that a file manager such as JavacFileManager is likely
|
||||
* to cache the results of file.getCharContent, avoiding the need to read
|
||||
* the bits from disk each time this method is called.
|
||||
*/
|
||||
int getLine(JavaFileObject file, JCTree tree) {
|
||||
try {
|
||||
CharSequence cs = file.getCharContent(true);
|
||||
int line = 1;
|
||||
for (int i = 0; i < tree.pos; i++) {
|
||||
if (cs.charAt(i) == '\n') // jtreg tests always use Unix line endings
|
||||
line++;
|
||||
}
|
||||
return line;
|
||||
} catch (IOException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
44
langtools/test/tools/javac/treeannotests/AnnoTreeTests.java
Normal file
44
langtools/test/tools/javac/treeannotests/AnnoTreeTests.java
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @build DA TA Test TestProcessor
|
||||
* @compile -proc:only -processor TestProcessor AnnoTreeTests.java
|
||||
*/
|
||||
|
||||
@Test(6)
|
||||
class AnnoTreeTests {
|
||||
// primitive types
|
||||
@DA("int") int i1;
|
||||
int i2 = (@TA("int") int) 0;
|
||||
|
||||
// simple array types
|
||||
@DA("int[]") int[] a1;
|
||||
int @TA("int") [] a2;
|
||||
int[] a3 = (@TA("int[]") int[]) a1;
|
||||
int[] a4 = (int @TA("int") []) a1;
|
||||
|
||||
// multi-dimensional array types
|
||||
// (still to come)
|
||||
}
|
37
langtools/test/tools/javac/treeannotests/DA.java
Normal file
37
langtools/test/tools/javac/treeannotests/DA.java
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
/**
|
||||
* Annotation used by TestProcessor to indicate the expected type
|
||||
* of the declaration to which the annotation is attached.
|
||||
* These annotations are expected to be found in the modifiers
|
||||
* field on ClassDef, MethodDef and VarDef nodes.
|
||||
*/
|
||||
@Target({FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
|
||||
@interface DA {
|
||||
String value();
|
||||
}
|
||||
|
36
langtools/test/tools/javac/treeannotests/TA.java
Normal file
36
langtools/test/tools/javac/treeannotests/TA.java
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
/**
|
||||
* Annotation used by TestProcessor to indicate the expected type
|
||||
* to which the annotation is attached.
|
||||
* These annotations are expected to be found in AnnotatedType nodes.
|
||||
*/
|
||||
@Target({TYPE_USE, TYPE_PARAMETER})
|
||||
@interface TA {
|
||||
String value();
|
||||
}
|
||||
|
32
langtools/test/tools/javac/treeannotests/Test.java
Normal file
32
langtools/test/tools/javac/treeannotests/Test.java
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Annotation used by TestProcessor to indicate the expected number of
|
||||
* @DA and @TA annotations in the source tree to which the Test annotation
|
||||
* is attached.
|
||||
*/
|
||||
@interface Test {
|
||||
int value();
|
||||
}
|
||||
|
302
langtools/test/tools/javac/treeannotests/TestProcessor.java
Normal file
302
langtools/test/tools/javac/treeannotests/TestProcessor.java
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.util.*;
|
||||
import javax.tools.*;
|
||||
|
||||
import com.sun.source.util.*;
|
||||
import com.sun.tools.javac.code.BoundKind;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import com.sun.tools.javac.tree.TreeScanner;
|
||||
import com.sun.tools.javac.tree.*;
|
||||
import com.sun.tools.javac.util.List;
|
||||
|
||||
/**
|
||||
* Test processor used to check test programs using the @Test, @DA, and @TA
|
||||
* annotations.
|
||||
*
|
||||
* The processor looks for elements annotated with @Test, and analyzes the
|
||||
* syntax trees for those elements. Within such trees, the processor looks
|
||||
* for the DA annotations on decls and TA annotations on types.
|
||||
* The value of these annotations should be a simple string rendition of
|
||||
* the tree node to which it is attached.
|
||||
* The expected number of annotations is given by the parameter to the
|
||||
* @Test annotation itself.
|
||||
*/
|
||||
@SupportedAnnotationTypes({"Test"})
|
||||
public class TestProcessor extends AbstractProcessor {
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latest();
|
||||
}
|
||||
|
||||
/** Process trees for elements annotated with the @Test(n) annotation. */
|
||||
public boolean process(Set<? extends TypeElement> annos, RoundEnvironment renv) {
|
||||
if (renv.processingOver())
|
||||
return true;
|
||||
|
||||
Elements elements = processingEnv.getElementUtils();
|
||||
Trees trees = Trees.instance(processingEnv);
|
||||
|
||||
TypeElement testAnno = elements.getTypeElement("Test");
|
||||
for (Element elem: renv.getElementsAnnotatedWith(testAnno)) {
|
||||
System.err.println("ELEM: " + elem);
|
||||
int count = getValue(getAnnoMirror(elem, testAnno), Integer.class);
|
||||
System.err.println("count: " + count);
|
||||
TreePath p = trees.getPath(elem);
|
||||
JavaFileObject file = p.getCompilationUnit().getSourceFile();
|
||||
JCTree tree = (JCTree) p.getLeaf();
|
||||
System.err.println("tree: " + tree);
|
||||
new TestScanner(file).check(tree, count);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Get the AnnotationMirror on an element for a given annotation. */
|
||||
AnnotationMirror getAnnoMirror(Element e, TypeElement anno) {
|
||||
Types types = processingEnv.getTypeUtils();
|
||||
for (AnnotationMirror m: e.getAnnotationMirrors()) {
|
||||
if (types.isSameType(m.getAnnotationType(), anno.asType()))
|
||||
return m;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Get the value of the value element of an annotation mirror. */
|
||||
<T> T getValue(AnnotationMirror m, Class<T> type) {
|
||||
for (Map.Entry<? extends ExecutableElement,? extends AnnotationValue> e: m.getElementValues().entrySet()) {
|
||||
ExecutableElement ee = e.getKey();
|
||||
if (ee.getSimpleName().contentEquals("value")) {
|
||||
AnnotationValue av = e.getValue();
|
||||
return type.cast(av.getValue());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Report an error to the annotation processing system. */
|
||||
void error(String msg) {
|
||||
Messager messager = processingEnv.getMessager();
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, msg);
|
||||
}
|
||||
|
||||
/** Report an error to the annotation processing system. */
|
||||
void error(JavaFileObject file, JCTree tree, String msg) {
|
||||
// need better API for reporting tree position errors to the messager
|
||||
Messager messager = processingEnv.getMessager();
|
||||
String text = file.getName() + ":" + getLine(file, tree) + ": " + msg;
|
||||
messager.printMessage(Diagnostic.Kind.ERROR, text);
|
||||
}
|
||||
|
||||
/** Get the line number for the primary position for a tree.
|
||||
* The code is intended to be simple, although not necessarily efficient.
|
||||
* However, note that a file manager such as JavacFileManager is likely
|
||||
* to cache the results of file.getCharContent, avoiding the need to read
|
||||
* the bits from disk each time this method is called.
|
||||
*/
|
||||
int getLine(JavaFileObject file, JCTree tree) {
|
||||
try {
|
||||
CharSequence cs = file.getCharContent(true);
|
||||
int line = 1;
|
||||
for (int i = 0; i < tree.pos; i++) {
|
||||
if (cs.charAt(i) == '\n') // jtreg tests always use Unix line endings
|
||||
line++;
|
||||
}
|
||||
return line;
|
||||
} catch (IOException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** Scan a tree, looking for @DA and @TA annotations, and verifying that such
|
||||
* annotations are attached to the expected tree node matching the string
|
||||
* parameter of the annotation.
|
||||
*/
|
||||
class TestScanner extends TreeScanner {
|
||||
/** Create a scanner for a given file. */
|
||||
TestScanner(JavaFileObject file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/** Check the annotations in a given tree. */
|
||||
void check(JCTree tree, int expectCount) {
|
||||
foundCount = 0;
|
||||
scan(tree);
|
||||
if (foundCount != expectCount)
|
||||
error(file, tree, "Wrong number of annotations found: " + foundCount + ", expected: " + expectCount);
|
||||
}
|
||||
|
||||
/** Check @DA annotations on a class declaration. */
|
||||
@Override
|
||||
public void visitClassDef(JCClassDecl tree) {
|
||||
super.visitClassDef(tree);
|
||||
check(tree.mods.annotations, "DA", tree);
|
||||
}
|
||||
|
||||
/** Check @DA annotations on a method declaration. */
|
||||
@Override
|
||||
public void visitMethodDef(JCMethodDecl tree) {
|
||||
super.visitMethodDef(tree);
|
||||
check(tree.mods.annotations, "DA", tree);
|
||||
}
|
||||
|
||||
/** Check @DA annotations on a field, parameter or local variable declaration. */
|
||||
@Override
|
||||
public void visitVarDef(JCVariableDecl tree) {
|
||||
super.visitVarDef(tree);
|
||||
check(tree.mods.annotations, "DA", tree);
|
||||
}
|
||||
|
||||
/** Check @TA annotations on a type. */
|
||||
public void visitAnnotatedType(JCAnnotatedType tree) {
|
||||
super.visitAnnotatedType(tree);
|
||||
check(tree.annotations, "TA", tree);
|
||||
}
|
||||
|
||||
/** Check to see if a list of annotations contains a named annotation, and
|
||||
* if so, verify the annotation is expected by comparing the value of the
|
||||
* annotation's argument against the string rendition of the reference tree
|
||||
* node.
|
||||
* @param annos the list of annotations to be checked
|
||||
* @param name the name of the annotation to be checked
|
||||
* @param tree the tree against which to compare the annotations's argument
|
||||
*/
|
||||
void check(List<? extends JCAnnotation> annos, String name, JCTree tree) {
|
||||
for (List<? extends JCAnnotation> l = annos; l.nonEmpty(); l = l.tail) {
|
||||
JCAnnotation anno = l.head;
|
||||
if (anno.annotationType.toString().equals(name) && (anno.args.size() == 1)) {
|
||||
String expect = getStringValue(anno.args.head);
|
||||
foundCount++;
|
||||
System.err.println("found: " + name + " " + expect);
|
||||
String found = new TypePrinter().print(tree);
|
||||
if (!found.equals(expect))
|
||||
error(file, anno, "Unexpected result: expected: \"" + expect + "\", found: \"" + found + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the string value of an annotation argument, which is given by the
|
||||
* expression <i>name</i>=<i>value</i>.
|
||||
*/
|
||||
String getStringValue(JCExpression e) {
|
||||
if (e.getTag() == JCTree.ASSIGN) {
|
||||
JCAssign a = (JCAssign) e;
|
||||
JCExpression rhs = a.rhs;
|
||||
if (rhs.getTag() == JCTree.LITERAL) {
|
||||
JCLiteral l = (JCLiteral) rhs;
|
||||
return (String) l.value;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(e.toString());
|
||||
}
|
||||
|
||||
/** The file for the tree. Used to locate errors. */
|
||||
JavaFileObject file;
|
||||
/** The number of annotations that have been found. @see #check */
|
||||
int foundCount;
|
||||
}
|
||||
|
||||
/** Convert a type or decl tree to a reference string used by the @DA and @TA annotations. */
|
||||
class TypePrinter extends Visitor {
|
||||
/** Convert a type or decl tree to a string. */
|
||||
String print(JCTree tree) {
|
||||
if (tree == null)
|
||||
return null;
|
||||
tree.accept(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
String print(List<? extends JCTree> list) {
|
||||
return print(list, ", ");
|
||||
}
|
||||
|
||||
String print(List<? extends JCTree> list, String sep) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (list.nonEmpty()) {
|
||||
sb.append(print(list.head));
|
||||
for (List<? extends JCTree> l = list.tail; l.nonEmpty(); l = l.tail) {
|
||||
sb.append(sep);
|
||||
sb.append(print(l.head));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassDef(JCClassDecl tree) {
|
||||
result = tree.name.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodDef(JCMethodDecl tree) {
|
||||
result = tree.name.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarDef(JCVariableDecl tree) {
|
||||
tree.vartype.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnnotatedType(JCAnnotatedType tree) {
|
||||
tree.underlyingType.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeIdent(JCPrimitiveTypeTree tree) {
|
||||
result = tree.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeArray(JCArrayTypeTree tree) {
|
||||
result = print(tree.elemtype) + "[]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeApply(JCTypeApply tree) {
|
||||
result = print(tree.clazz) + "<" + print(tree.arguments) + ">";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeParameter(JCTypeParameter tree) {
|
||||
if (tree.bounds.isEmpty())
|
||||
result = tree.name.toString();
|
||||
else
|
||||
result = tree.name + " extends " + print(tree.bounds, "&");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitWildcard(JCWildcard tree) {
|
||||
if (tree.kind.kind == BoundKind.UNBOUND)
|
||||
result = tree.kind.toString();
|
||||
else
|
||||
result = tree.kind + " " + print(tree.inner);
|
||||
}
|
||||
|
||||
private String result;
|
||||
}
|
||||
}
|
752
langtools/test/tools/javac/treepostests/TreePosTest.java
Normal file
752
langtools/test/tools/javac/treepostests/TreePosTest.java
Normal file
@ -0,0 +1,752 @@
|
||||
/*
|
||||
* Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.CaretEvent;
|
||||
import javax.swing.event.CaretListener;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.DefaultHighlighter;
|
||||
import javax.swing.text.Highlighter;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.DiagnosticListener;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.util.JavacTask;
|
||||
import com.sun.tools.javac.api.JavacTool;
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
import com.sun.tools.javac.tree.JCTree.JCNewClass;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.tree.TreeInfo;
|
||||
import com.sun.tools.javac.tree.TreeScanner;
|
||||
|
||||
import static com.sun.tools.javac.util.Position.NOPOS;
|
||||
|
||||
/**
|
||||
* Utility and test program to check validity of tree positions for tree nodes.
|
||||
* The program can be run standalone, or as a jtreg test. In standalone mode,
|
||||
* errors can be displayed in a gui viewer. For info on command line args,
|
||||
* run program with no args.
|
||||
*
|
||||
* <p>
|
||||
* jtreg: Note that by using the -r switch in the test description below, this test
|
||||
* will process all java files in the langtools/test directory, thus implicitly
|
||||
* covering any new language features that may be tested in this test suite.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6919889
|
||||
* @summary assorted position errors in compiler syntax trees
|
||||
* @run main TreePosTest -q -r -ef ./tools/javac/typeAnnotations -ef ./tools/javap/typeAnnotations .
|
||||
*/
|
||||
public class TreePosTest {
|
||||
/**
|
||||
* Main entry point.
|
||||
* If test.src is set, program runs in jtreg mode, and will throw an Error
|
||||
* if any errors arise, otherwise System.exit will be used, unless the gui
|
||||
* viewer is being used. In jtreg mode, the default base directory for file
|
||||
* args is the value of ${test.src}. In jtreg mode, the -r option can be
|
||||
* given to change the default base directory to the root test directory.
|
||||
*/
|
||||
public static void main(String... args) {
|
||||
String testSrc = System.getProperty("test.src");
|
||||
File baseDir = (testSrc == null) ? null : new File(testSrc);
|
||||
boolean ok = new TreePosTest().run(baseDir, args);
|
||||
if (!ok) {
|
||||
if (testSrc != null) // jtreg mode
|
||||
throw new Error("failed");
|
||||
else
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the program. A base directory can be provided for file arguments.
|
||||
* In jtreg mode, the -r option can be given to change the default base
|
||||
* directory to the test root directory. For other options, see usage().
|
||||
* @param baseDir base directory for any file arguments.
|
||||
* @param args command line args
|
||||
* @return true if successful or in gui mode
|
||||
*/
|
||||
boolean run(File baseDir, String... args) {
|
||||
if (args.length == 0) {
|
||||
usage(System.out);
|
||||
return true;
|
||||
}
|
||||
|
||||
List<File> files = new ArrayList<File>();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
String arg = args[i];
|
||||
if (arg.equals("-encoding") && i + 1 < args.length)
|
||||
encoding = args[++i];
|
||||
else if (arg.equals("-gui"))
|
||||
gui = true;
|
||||
else if (arg.equals("-q"))
|
||||
quiet = true;
|
||||
else if (arg.equals("-v"))
|
||||
verbose = true;
|
||||
else if (arg.equals("-t") && i + 1 < args.length)
|
||||
tags.add(args[++i]);
|
||||
else if (arg.equals("-ef") && i + 1 < args.length)
|
||||
excludeFiles.add(new File(baseDir, args[++i]));
|
||||
else if (arg.equals("-r")) {
|
||||
if (excludeFiles.size() > 0)
|
||||
throw new Error("-r must be used before -ef");
|
||||
File d = baseDir;
|
||||
while (!new File(d, "TEST.ROOT").exists()) {
|
||||
d = d.getParentFile();
|
||||
if (d == null)
|
||||
throw new Error("cannot find TEST.ROOT");
|
||||
}
|
||||
baseDir = d;
|
||||
}
|
||||
else if (arg.startsWith("-"))
|
||||
throw new Error("unknown option: " + arg);
|
||||
else {
|
||||
while (i < args.length)
|
||||
files.add(new File(baseDir, args[i++]));
|
||||
}
|
||||
}
|
||||
|
||||
for (File file: files) {
|
||||
if (file.exists())
|
||||
test(file);
|
||||
else
|
||||
error("File not found: " + file);
|
||||
}
|
||||
|
||||
if (fileCount != 1)
|
||||
System.err.println(fileCount + " files read");
|
||||
if (errors > 0)
|
||||
System.err.println(errors + " errors");
|
||||
|
||||
return (gui || errors == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print command line help.
|
||||
* @param out output stream
|
||||
*/
|
||||
void usage(PrintStream out) {
|
||||
out.println("Usage:");
|
||||
out.println(" java TreePosTest options... files...");
|
||||
out.println("");
|
||||
out.println("where options include:");
|
||||
out.println("-gui Display returns in a GUI viewer");
|
||||
out.println("-q Quiet: don't report on inapplicable files");
|
||||
out.println("-v Verbose: report on files as they are being read");
|
||||
out.println("-t tag Limit checks to tree nodes with this tag");
|
||||
out.println(" Can be repeated if desired");
|
||||
out.println("-ef file Exclude file or directory");
|
||||
out.println("");
|
||||
out.println("files may be directories or files");
|
||||
out.println("directories will be scanned recursively");
|
||||
out.println("non java files, or java files which cannot be parsed, will be ignored");
|
||||
out.println("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a file. If the file is a directory, it will be recursively scanned
|
||||
* for java files.
|
||||
* @param file the file or directory to test
|
||||
*/
|
||||
void test(File file) {
|
||||
if (excludeFiles.contains(file)) {
|
||||
if (!quiet)
|
||||
error("File " + file + " excluded");
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.isDirectory()) {
|
||||
for (File f: file.listFiles()) {
|
||||
test(f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.isFile() && file.getName().endsWith(".java")) {
|
||||
try {
|
||||
if (verbose)
|
||||
System.err.println(file);
|
||||
fileCount++;
|
||||
PosTester p = new PosTester();
|
||||
p.test(read(file));
|
||||
} catch (ParseException e) {
|
||||
if (!quiet) {
|
||||
error("Error parsing " + file + "\n" + e.getMessage());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
error("Error reading " + file + ": " + e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!quiet)
|
||||
error("File " + file + " ignored");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file.
|
||||
* @param file the file to be read
|
||||
* @return the tree for the content of the file
|
||||
* @throws IOException if any IO errors occur
|
||||
* @throws TreePosTest.ParseException if any errors occur while parsing the file
|
||||
*/
|
||||
JCCompilationUnit read(File file) throws IOException, ParseException {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
Reporter r = new Reporter(pw);
|
||||
JavacTool tool = JavacTool.create();
|
||||
Charset cs = (encoding == null ? null : Charset.forName(encoding));
|
||||
StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null);
|
||||
Iterable<? extends JavaFileObject> files = fm.getJavaFileObjects(file);
|
||||
JavacTask task = tool.getTask(pw, fm, r, Collections.<String>emptyList(), null, files);
|
||||
Iterable<? extends CompilationUnitTree> trees = task.parse();
|
||||
pw.flush();
|
||||
if (r.errors > 0)
|
||||
throw new ParseException(sw.toString());
|
||||
Iterator<? extends CompilationUnitTree> iter = trees.iterator();
|
||||
if (!iter.hasNext())
|
||||
throw new Error("no trees found");
|
||||
JCCompilationUnit t = (JCCompilationUnit) iter.next();
|
||||
if (iter.hasNext())
|
||||
throw new Error("too many trees found");
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an error. When the program is complete, the program will either
|
||||
* exit or throw an Error if any errors have been reported.
|
||||
* @param msg the error message
|
||||
*/
|
||||
void error(String msg) {
|
||||
System.err.println(msg);
|
||||
errors++;
|
||||
}
|
||||
|
||||
/** Number of files that have been analyzed. */
|
||||
int fileCount;
|
||||
/** Number of errors reported. */
|
||||
int errors;
|
||||
/** Flag: don't report irrelevant files. */
|
||||
boolean quiet;
|
||||
/** Flag: report files as they are processed. */
|
||||
boolean verbose;
|
||||
/** Flag: show errors in GUI viewer. */
|
||||
boolean gui;
|
||||
/** Option: encoding for test files. */
|
||||
String encoding;
|
||||
/** The GUI viewer for errors. */
|
||||
Viewer viewer;
|
||||
/** The set of tags for tree nodes to be analyzed; if empty, all tree nodes
|
||||
* are analyzed. */
|
||||
Set<String> tags = new HashSet<String>();
|
||||
/** Set of files and directories to be excluded from analysis. */
|
||||
Set<File> excludeFiles = new HashSet<File>();
|
||||
/** Table of printable names for tree tag values. */
|
||||
TagNames tagNames = new TagNames();
|
||||
|
||||
/**
|
||||
* Main class for testing assertions concerning tree positions for tree nodes.
|
||||
*/
|
||||
private class PosTester extends TreeScanner {
|
||||
void test(JCCompilationUnit tree) {
|
||||
sourcefile = tree.sourcefile;
|
||||
endPosTable = tree.endPositions;
|
||||
encl = new Info();
|
||||
tree.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scan(JCTree tree) {
|
||||
if (tree == null)
|
||||
return;
|
||||
|
||||
Info self = new Info(tree, endPosTable);
|
||||
if (check(self)) {
|
||||
// Modifiers nodes are present throughout the tree even where
|
||||
// there is no corresponding source text.
|
||||
// Redundant semicolons in a class definition can cause empty
|
||||
// initializer blocks with no positions.
|
||||
if ((self.tag == JCTree.MODIFIERS || self.tag == JCTree.BLOCK)
|
||||
&& self.pos == NOPOS) {
|
||||
// If pos is NOPOS, so should be the start and end positions
|
||||
check("start == NOPOS", encl, self, self.start == NOPOS);
|
||||
check("end == NOPOS", encl, self, self.end == NOPOS);
|
||||
} else {
|
||||
// For this node, start , pos, and endpos should be all defined
|
||||
check("start != NOPOS", encl, self, self.start != NOPOS);
|
||||
check("pos != NOPOS", encl, self, self.pos != NOPOS);
|
||||
check("end != NOPOS", encl, self, self.end != NOPOS);
|
||||
// The following should normally be ordered
|
||||
// encl.start <= start <= pos <= end <= encl.end
|
||||
// In addition, the position of the enclosing node should be
|
||||
// within this node.
|
||||
// The primary exceptions are for array type nodes, because of the
|
||||
// need to support legacy syntax:
|
||||
// e.g. int a[]; int[] b[]; int f()[] { return null; }
|
||||
// and because of inconsistent nesting of left and right of
|
||||
// array declarations:
|
||||
// e.g. int[][] a = new int[2][];
|
||||
check("encl.start <= start", encl, self, encl.start <= self.start);
|
||||
check("start <= pos", encl, self, self.start <= self.pos);
|
||||
if (!(self.tag == JCTree.TYPEARRAY
|
||||
&& (encl.tag == JCTree.VARDEF || encl.tag == JCTree.TYPEARRAY))) {
|
||||
check("encl.pos <= start || end <= encl.pos",
|
||||
encl, self, encl.pos <= self.start || self.end <= encl.pos);
|
||||
}
|
||||
check("pos <= end", encl, self, self.pos <= self.end);
|
||||
if (!(self.tag == JCTree.TYPEARRAY && encl.tag == JCTree.TYPEARRAY)) {
|
||||
check("end <= encl.end", encl, self, self.end <= encl.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Info prevEncl = encl;
|
||||
encl = self;
|
||||
tree.accept(this);
|
||||
encl = prevEncl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarDef(JCVariableDecl tree) {
|
||||
// enum member declarations are desugared in the parser and have
|
||||
// ill-defined semantics for tree positions, so for now, we
|
||||
// skip the synthesized bits and just check parts which came from
|
||||
// the original source text
|
||||
if ((tree.mods.flags & Flags.ENUM) != 0) {
|
||||
scan(tree.mods);
|
||||
if (tree.init != null) {
|
||||
if (tree.init.getTag() == JCTree.NEWCLASS) {
|
||||
JCNewClass init = (JCNewClass) tree.init;
|
||||
if (init.args != null && init.args.nonEmpty()) {
|
||||
scan(init.args);
|
||||
}
|
||||
if (init.def != null && init.def.defs != null) {
|
||||
scan(init.def.defs);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
super.visitVarDef(tree);
|
||||
}
|
||||
|
||||
boolean check(Info x) {
|
||||
return tags.size() == 0 || tags.contains(tagNames.get(x.tag));
|
||||
}
|
||||
|
||||
void check(String label, Info encl, Info self, boolean ok) {
|
||||
if (!ok) {
|
||||
if (gui) {
|
||||
if (viewer == null)
|
||||
viewer = new Viewer();
|
||||
viewer.addEntry(sourcefile, label, encl, self);
|
||||
}
|
||||
|
||||
String s = self.tree.toString();
|
||||
String msg = sourcefile.getName() + ": " + label + ": " +
|
||||
"encl:" + encl + " this:" + self + "\n" +
|
||||
s.substring(0, Math.min(80, s.length())).replaceAll("[\r\n]+", " ");
|
||||
error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
JavaFileObject sourcefile;
|
||||
Map<JCTree, Integer> endPosTable;
|
||||
Info encl;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class providing easy access to position and other info for a tree node.
|
||||
*/
|
||||
private class Info {
|
||||
Info() {
|
||||
tree = null;
|
||||
tag = JCTree.ERRONEOUS;
|
||||
start = 0;
|
||||
pos = 0;
|
||||
end = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
Info(JCTree tree, Map<JCTree, Integer> endPosTable) {
|
||||
this.tree = tree;
|
||||
tag = tree.getTag();
|
||||
start = TreeInfo.getStartPos(tree);
|
||||
pos = tree.pos;
|
||||
end = TreeInfo.getEndPos(tree, endPosTable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return tagNames.get(tree.getTag()) + "[start:" + start + ",pos:" + pos + ",end:" + end + "]";
|
||||
}
|
||||
|
||||
final JCTree tree;
|
||||
final int tag;
|
||||
final int start;
|
||||
final int pos;
|
||||
final int end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Names for tree tags.
|
||||
* javac does not provide an API to convert tag values to strings, so this class uses
|
||||
* reflection to determine names of public static final int values in JCTree.
|
||||
*/
|
||||
private static class TagNames {
|
||||
String get(int tag) {
|
||||
if (map == null) {
|
||||
map = new HashMap<Integer, String>();
|
||||
Class c = JCTree.class;
|
||||
for (Field f : c.getDeclaredFields()) {
|
||||
if (f.getType().equals(int.class)) {
|
||||
int mods = f.getModifiers();
|
||||
if (Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
|
||||
try {
|
||||
map.put(f.getInt(null), f.getName());
|
||||
} catch (IllegalAccessException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
String name = map.get(tag);
|
||||
return (name == null) ? "??" : name;
|
||||
}
|
||||
|
||||
private Map<Integer, String> map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when errors are found parsing a java file.
|
||||
*/
|
||||
private static class ParseException extends Exception {
|
||||
ParseException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DiagnosticListener to report diagnostics and count any errors that occur.
|
||||
*/
|
||||
private static class Reporter implements DiagnosticListener<JavaFileObject> {
|
||||
Reporter(PrintWriter out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
out.println(diagnostic);
|
||||
switch (diagnostic.getKind()) {
|
||||
case ERROR:
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
int errors;
|
||||
PrintWriter out;
|
||||
}
|
||||
|
||||
/**
|
||||
* GUI viewer for issues found by TreePosTester. The viewer provides a drop
|
||||
* down list for selecting error conditions, a header area providing details
|
||||
* about an error, and a text area with the ranges of text highlighted as
|
||||
* appropriate.
|
||||
*/
|
||||
private class Viewer extends JFrame {
|
||||
/**
|
||||
* Create a viewer.
|
||||
*/
|
||||
Viewer() {
|
||||
initGUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add another entry to the list of errors.
|
||||
* @param file The file containing the error
|
||||
* @param check The condition that was being tested, and which failed
|
||||
* @param encl the enclosing tree node
|
||||
* @param self the tree node containing the error
|
||||
*/
|
||||
void addEntry(JavaFileObject file, String check, Info encl, Info self) {
|
||||
Entry e = new Entry(file, check, encl, self);
|
||||
DefaultComboBoxModel m = (DefaultComboBoxModel) entries.getModel();
|
||||
m.addElement(e);
|
||||
if (m.getSize() == 1)
|
||||
entries.setSelectedItem(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the GUI window.
|
||||
*/
|
||||
private void initGUI() {
|
||||
JPanel head = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints lc = new GridBagConstraints();
|
||||
GridBagConstraints fc = new GridBagConstraints();
|
||||
fc.anchor = GridBagConstraints.WEST;
|
||||
fc.fill = GridBagConstraints.HORIZONTAL;
|
||||
fc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
|
||||
entries = new JComboBox();
|
||||
entries.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showEntry((Entry) entries.getSelectedItem());
|
||||
}
|
||||
});
|
||||
fc.insets.bottom = 10;
|
||||
head.add(entries, fc);
|
||||
fc.insets.bottom = 0;
|
||||
head.add(new JLabel("check:"), lc);
|
||||
head.add(checkField = createTextField(80), fc);
|
||||
fc.fill = GridBagConstraints.NONE;
|
||||
head.add(setBackground(new JLabel("encl:"), enclColor), lc);
|
||||
head.add(enclPanel = new InfoPanel(), fc);
|
||||
head.add(setBackground(new JLabel("self:"), selfColor), lc);
|
||||
head.add(selfPanel = new InfoPanel(), fc);
|
||||
add(head, BorderLayout.NORTH);
|
||||
|
||||
body = new JTextArea();
|
||||
body.setFont(Font.decode(Font.MONOSPACED));
|
||||
body.addCaretListener(new CaretListener() {
|
||||
public void caretUpdate(CaretEvent e) {
|
||||
int dot = e.getDot();
|
||||
int mark = e.getMark();
|
||||
if (dot == mark)
|
||||
statusText.setText("dot: " + dot);
|
||||
else
|
||||
statusText.setText("dot: " + dot + ", mark:" + mark);
|
||||
}
|
||||
});
|
||||
JScrollPane p = new JScrollPane(body,
|
||||
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
p.setPreferredSize(new Dimension(640, 480));
|
||||
add(p, BorderLayout.CENTER);
|
||||
|
||||
statusText = createTextField(80);
|
||||
add(statusText, BorderLayout.SOUTH);
|
||||
|
||||
pack();
|
||||
setLocationRelativeTo(null); // centered on screen
|
||||
setVisible(true);
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
}
|
||||
|
||||
/** Show an entry that has been selected. */
|
||||
private void showEntry(Entry e) {
|
||||
try {
|
||||
// update simple fields
|
||||
setTitle(e.file.getName());
|
||||
checkField.setText(e.check);
|
||||
enclPanel.setInfo(e.encl);
|
||||
selfPanel.setInfo(e.self);
|
||||
// show file text with highlights
|
||||
body.setText(e.file.getCharContent(true).toString());
|
||||
Highlighter highlighter = body.getHighlighter();
|
||||
highlighter.removeAllHighlights();
|
||||
addHighlight(highlighter, e.encl, enclColor);
|
||||
addHighlight(highlighter, e.self, selfColor);
|
||||
scroll(body, getMinPos(enclPanel.info, selfPanel.info));
|
||||
} catch (IOException ex) {
|
||||
body.setText("Cannot read " + e.file.getName() + ": " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a test field. */
|
||||
private JTextField createTextField(int width) {
|
||||
JTextField f = new JTextField(width);
|
||||
f.setEditable(false);
|
||||
f.setBorder(null);
|
||||
return f;
|
||||
}
|
||||
|
||||
/** Add a highlighted region based on the positions in an Info object. */
|
||||
private void addHighlight(Highlighter h, Info info, Color c) {
|
||||
int start = info.start;
|
||||
int end = info.end;
|
||||
if (start == -1 && end == -1)
|
||||
return;
|
||||
if (start == -1)
|
||||
start = end;
|
||||
if (end == -1)
|
||||
end = start;
|
||||
try {
|
||||
h.addHighlight(info.start, info.end,
|
||||
new DefaultHighlighter.DefaultHighlightPainter(c));
|
||||
if (info.pos != -1) {
|
||||
Color c2 = new Color(c.getRed(), c.getGreen(), c.getBlue(), (int)(.4f * 255)); // 40%
|
||||
h.addHighlight(info.pos, info.pos + 1,
|
||||
new DefaultHighlighter.DefaultHighlightPainter(c2));
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the minimum valid position in a set of info objects. */
|
||||
private int getMinPos(Info... values) {
|
||||
int i = Integer.MAX_VALUE;
|
||||
for (Info info: values) {
|
||||
if (info.start >= 0) i = Math.min(i, info.start);
|
||||
if (info.pos >= 0) i = Math.min(i, info.pos);
|
||||
if (info.end >= 0) i = Math.min(i, info.end);
|
||||
}
|
||||
return (i == Integer.MAX_VALUE) ? 0 : i;
|
||||
}
|
||||
|
||||
/** Set the background on a component. */
|
||||
private JComponent setBackground(JComponent comp, Color c) {
|
||||
comp.setOpaque(true);
|
||||
comp.setBackground(c);
|
||||
return comp;
|
||||
}
|
||||
|
||||
/** Scroll a text area to display a given position near the middle of the visible area. */
|
||||
private void scroll(final JTextArea t, final int pos) {
|
||||
// Using invokeLater appears to give text a chance to sort itself out
|
||||
// before the scroll happens; otherwise scrollRectToVisible doesn't work.
|
||||
// Maybe there's a better way to sync with the text...
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Rectangle r = t.modelToView(pos);
|
||||
JScrollPane p = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, t);
|
||||
r.y = Math.max(0, r.y - p.getHeight() * 2 / 5);
|
||||
r.height += p.getHeight() * 4 / 5;
|
||||
t.scrollRectToVisible(r);
|
||||
} catch (BadLocationException ignore) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private JComboBox entries;
|
||||
private JTextField checkField;
|
||||
private InfoPanel enclPanel;
|
||||
private InfoPanel selfPanel;
|
||||
private JTextArea body;
|
||||
private JTextField statusText;
|
||||
|
||||
private Color selfColor = new Color(0.f, 1.f, 0.f, 0.2f); // 20% green
|
||||
private Color enclColor = new Color(1.f, 0.f, 0.f, 0.2f); // 20% red
|
||||
|
||||
/** Panel to display an Info object. */
|
||||
private class InfoPanel extends JPanel {
|
||||
InfoPanel() {
|
||||
add(tagName = createTextField(20));
|
||||
add(new JLabel("start:"));
|
||||
add(addListener(start = createTextField(6)));
|
||||
add(new JLabel("pos:"));
|
||||
add(addListener(pos = createTextField(6)));
|
||||
add(new JLabel("end:"));
|
||||
add(addListener(end = createTextField(6)));
|
||||
}
|
||||
|
||||
void setInfo(Info info) {
|
||||
this.info = info;
|
||||
tagName.setText(tagNames.get(info.tag));
|
||||
start.setText(String.valueOf(info.start));
|
||||
pos.setText(String.valueOf(info.pos));
|
||||
end.setText(String.valueOf(info.end));
|
||||
}
|
||||
|
||||
JTextField addListener(final JTextField f) {
|
||||
f.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
body.setCaretPosition(Integer.valueOf(f.getText()));
|
||||
body.getCaret().setVisible(true);
|
||||
}
|
||||
});
|
||||
return f;
|
||||
}
|
||||
|
||||
Info info;
|
||||
JTextField tagName;
|
||||
JTextField start;
|
||||
JTextField pos;
|
||||
JTextField end;
|
||||
}
|
||||
|
||||
/** Object to record information about an error to be displayed. */
|
||||
private class Entry {
|
||||
Entry(JavaFileObject file, String check, Info encl, Info self) {
|
||||
this.file = file;
|
||||
this.check = check;
|
||||
this.encl = encl;
|
||||
this.self= self;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return file.getName() + " " + check + " " + getMinPos(encl, self);
|
||||
}
|
||||
|
||||
final JavaFileObject file;
|
||||
final String check;
|
||||
final Info encl;
|
||||
final Info self;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2009-2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.tools.classfile.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6917130
|
||||
* @summary test that optimized away annotations are not emited to classfile
|
||||
*/
|
||||
|
||||
public class DeadCode {
|
||||
public static void main(String[] args) throws Exception {
|
||||
new DeadCode().run();
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
ClassFile cf = getClassFile("DeadCode$Test.class");
|
||||
test(cf);
|
||||
for (Field f : cf.fields) {
|
||||
test(cf, f);
|
||||
}
|
||||
for (Method m: cf.methods) {
|
||||
test(cf, m);
|
||||
}
|
||||
|
||||
countAnnotations();
|
||||
|
||||
if (errors > 0)
|
||||
throw new Exception(errors + " errors found");
|
||||
System.out.println("PASSED");
|
||||
}
|
||||
|
||||
ClassFile getClassFile(String name) throws IOException, ConstantPoolException {
|
||||
URL url = getClass().getResource(name);
|
||||
InputStream in = url.openStream();
|
||||
try {
|
||||
return ClassFile.read(in);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
/************ Helper annotations counting methods ******************/
|
||||
void test(ClassFile cf) {
|
||||
test(cf, Attribute.RuntimeVisibleTypeAnnotations, true);
|
||||
test(cf, Attribute.RuntimeInvisibleTypeAnnotations, false);
|
||||
}
|
||||
|
||||
void test(ClassFile cf, Method m) {
|
||||
test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
|
||||
test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
|
||||
}
|
||||
|
||||
void test(ClassFile cf, Field m) {
|
||||
test(cf, m, Attribute.RuntimeVisibleTypeAnnotations, true);
|
||||
test(cf, m, Attribute.RuntimeInvisibleTypeAnnotations, false);
|
||||
}
|
||||
|
||||
// test the result of Attributes.getIndex according to expectations
|
||||
// encoded in the method's name
|
||||
void test(ClassFile cf, String name, boolean visible) {
|
||||
int index = cf.attributes.getIndex(cf.constant_pool, name);
|
||||
if (index != -1) {
|
||||
Attribute attr = cf.attributes.get(index);
|
||||
assert attr instanceof RuntimeTypeAnnotations_attribute;
|
||||
RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
|
||||
all += tAttr.annotations.length;
|
||||
if (visible)
|
||||
visibles += tAttr.annotations.length;
|
||||
else
|
||||
invisibles += tAttr.annotations.length;
|
||||
}
|
||||
}
|
||||
|
||||
// test the result of Attributes.getIndex according to expectations
|
||||
// encoded in the method's name
|
||||
void test(ClassFile cf, Method m, String name, boolean visible) {
|
||||
int index = m.attributes.getIndex(cf.constant_pool, name);
|
||||
if (index != -1) {
|
||||
Attribute attr = m.attributes.get(index);
|
||||
assert attr instanceof RuntimeTypeAnnotations_attribute;
|
||||
RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
|
||||
all += tAttr.annotations.length;
|
||||
if (visible)
|
||||
visibles += tAttr.annotations.length;
|
||||
else
|
||||
invisibles += tAttr.annotations.length;
|
||||
}
|
||||
}
|
||||
|
||||
// test the result of Attributes.getIndex according to expectations
|
||||
// encoded in the method's name
|
||||
void test(ClassFile cf, Field m, String name, boolean visible) {
|
||||
int index = m.attributes.getIndex(cf.constant_pool, name);
|
||||
if (index != -1) {
|
||||
Attribute attr = m.attributes.get(index);
|
||||
assert attr instanceof RuntimeTypeAnnotations_attribute;
|
||||
RuntimeTypeAnnotations_attribute tAttr = (RuntimeTypeAnnotations_attribute)attr;
|
||||
all += tAttr.annotations.length;
|
||||
if (visible)
|
||||
visibles += tAttr.annotations.length;
|
||||
else
|
||||
invisibles += tAttr.annotations.length;
|
||||
}
|
||||
}
|
||||
|
||||
void countAnnotations() {
|
||||
int expected_all = expected_visibles + expected_invisibles;
|
||||
|
||||
if (expected_all != all) {
|
||||
errors++;
|
||||
System.err.println("expected " + expected_all
|
||||
+ " annotations but found " + all);
|
||||
}
|
||||
|
||||
if (expected_visibles != visibles) {
|
||||
errors++;
|
||||
System.err.println("expected " + expected_visibles
|
||||
+ " visibles annotations but found " + visibles);
|
||||
}
|
||||
|
||||
if (expected_invisibles != invisibles) {
|
||||
errors++;
|
||||
System.err.println("expected " + expected_invisibles
|
||||
+ " invisibles annotations but found " + invisibles);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int errors;
|
||||
int all;
|
||||
int visibles;
|
||||
int invisibles;
|
||||
|
||||
/*********************** Test class *************************/
|
||||
static int expected_invisibles = 1;
|
||||
static int expected_visibles = 0;
|
||||
static class Test {
|
||||
@interface A {}
|
||||
|
||||
void test() {
|
||||
List<? extends @A Object> o = null;
|
||||
o.toString();
|
||||
|
||||
@A String m;
|
||||
if (false) {
|
||||
@A String a;
|
||||
@A String b = "m";
|
||||
b.toString();
|
||||
List<? extends @A Object> c = null;
|
||||
c.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 6843077
|
||||
* @bug 6843077 6919944
|
||||
* @summary check for duplicate annotation values
|
||||
* @author Mahmood Ali
|
||||
* @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
|
||||
|
@ -1,2 +1,2 @@
|
||||
DuplicateAnnotationValue.java:10:45: compiler.err.duplicate.annotation.member.value: value, A
|
||||
DuplicateAnnotationValue.java:10:37: compiler.err.duplicate.annotation.member.value: value, A
|
||||
1 error
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 6843077
|
||||
* @bug 6843077 6919944
|
||||
* @summary check for duplicate annotation values
|
||||
* @author Mahmood Ali
|
||||
* @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
|
||||
|
@ -1,2 +1,2 @@
|
||||
DuplicateAnnotationValue.java:10:34: compiler.err.duplicate.annotation.member.value: value, A
|
||||
DuplicateAnnotationValue.java:10:26: compiler.err.duplicate.annotation.member.value: value, A
|
||||
1 error
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 6843077
|
||||
* @bug 6843077 6919944
|
||||
* @summary check for duplicate annotation values for type parameter
|
||||
* @author Mahmood Ali
|
||||
* @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
|
||||
|
@ -1,2 +1,2 @@
|
||||
DuplicateAnnotationValue.java:10:39: compiler.err.duplicate.annotation.member.value: value, A
|
||||
DuplicateAnnotationValue.java:10:31: compiler.err.duplicate.annotation.member.value: value, A
|
||||
1 error
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 6843077
|
||||
* @bug 6843077 6919944
|
||||
* @summary check for duplicate annotation values
|
||||
* @author Mahmood Ali
|
||||
* @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
|
||||
|
@ -1,2 +1,2 @@
|
||||
DuplicateAnnotationValue.java:10:51: compiler.err.duplicate.annotation.member.value: value, A
|
||||
DuplicateAnnotationValue.java:10:43: compiler.err.duplicate.annotation.member.value: value, A
|
||||
1 error
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 6843077
|
||||
* @bug 6843077 6919944
|
||||
* @summary check for duplicate annotation values for type parameter
|
||||
* @author Mahmood Ali
|
||||
* @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
|
||||
|
@ -1,2 +1,2 @@
|
||||
DuplicateAnnotationValue.java:8:64: compiler.err.duplicate.annotation.member.value: value, A
|
||||
DuplicateAnnotationValue.java:8:56: compiler.err.duplicate.annotation.member.value: value, A
|
||||
1 error
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 6843077
|
||||
* @bug 6843077 6919944
|
||||
* @summary check for duplicate annotation values in receiver
|
||||
* @author Mahmood Ali
|
||||
* @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
|
||||
|
@ -1,2 +1,2 @@
|
||||
DuplicateAnnotationValue.java:9:37: compiler.err.duplicate.annotation.member.value: value, A
|
||||
DuplicateAnnotationValue.java:9:29: compiler.err.duplicate.annotation.member.value: value, A
|
||||
1 error
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 6843077
|
||||
* @bug 6843077 6919944
|
||||
* @summary check for duplicate annotation values for type parameter
|
||||
* @author Mahmood Ali
|
||||
* @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
|
||||
|
@ -1,2 +1,2 @@
|
||||
DuplicateAnnotationValue.java:9:50: compiler.err.duplicate.annotation.member.value: value, A
|
||||
DuplicateAnnotationValue.java:9:42: compiler.err.duplicate.annotation.member.value: value, A
|
||||
1 error
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 6843077
|
||||
* @bug 6843077 6919944
|
||||
* @summary check for duplicate annotation values for type parameter
|
||||
* @author Mahmood Ali
|
||||
* @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
|
||||
|
@ -1,2 +1,2 @@
|
||||
DuplicateAnnotationValue.java:8:54: compiler.err.duplicate.annotation.member.value: value, A
|
||||
DuplicateAnnotationValue.java:8:46: compiler.err.duplicate.annotation.member.value: value, A
|
||||
1 error
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 6843077
|
||||
* @bug 6843077 6919944
|
||||
* @summary check for duplicate annotation values for type parameter
|
||||
* @author Mahmood Ali
|
||||
* @compile/fail/ref=DuplicateAnnotationValue.out -XDrawDiagnostics -source 1.7 DuplicateAnnotationValue.java
|
||||
|
@ -1,2 +1,2 @@
|
||||
DuplicateAnnotationValue.java:9:50: compiler.err.duplicate.annotation.member.value: value, A
|
||||
DuplicateAnnotationValue.java:9:42: compiler.err.duplicate.annotation.member.value: value, A
|
||||
1 error
|
||||
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6918625
|
||||
* @summary javap dumps type information of array class literals
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class ArrayClassLiterals2 {
|
||||
public static void main(String[] args) throws Exception {
|
||||
new ArrayClassLiterals2().run();
|
||||
}
|
||||
|
||||
public void run() throws IOException {
|
||||
File classFile = new File(System.getProperty("test.classes"), "ArrayClassLiterals2$Test.class");
|
||||
|
||||
verify(classFile,
|
||||
"RuntimeInvisibleTypeAnnotations:",
|
||||
"CLASS_LITERAL_GENERIC_OR_ARRAY"
|
||||
);
|
||||
|
||||
if (errors > 0)
|
||||
throw new Error(errors + " found.");
|
||||
}
|
||||
|
||||
String javap(File f) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter out = new PrintWriter(sw);
|
||||
int rc = com.sun.tools.javap.Main.run(new String[] { "-v", f.getPath() }, out);
|
||||
if (rc != 0)
|
||||
throw new Error("javap failed. rc=" + rc);
|
||||
out.close();
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
void verify(File classFile, String... expects) {
|
||||
String output = javap(classFile);
|
||||
for (String expect: expects) {
|
||||
if (output.indexOf(expect)< 0)
|
||||
error(expect + " not found");
|
||||
}
|
||||
}
|
||||
|
||||
void error(String msg) {
|
||||
System.err.println(msg);
|
||||
errors++;
|
||||
}
|
||||
|
||||
int errors;
|
||||
|
||||
|
||||
/*********************** Test class *************************/
|
||||
static class Test {
|
||||
@interface A { }
|
||||
void test() {
|
||||
Object a = @A String @A [] @A [].class;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user