feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,683 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.comp;
import java.util.Map;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import static com.sun.tools.javac.code.TypeTag.ARRAY;
import static com.sun.tools.javac.code.TypeTag.CLASS;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
import javax.lang.model.type.ErrorType;
/** Enter annotations on symbols. Annotations accumulate in a queue,
* which is processed at the top level of any set of recursive calls
* requesting it be processed.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Annotate {
protected static final Context.Key<Annotate> annotateKey =
new Context.Key<Annotate>();
public static Annotate instance(Context context) {
Annotate instance = context.get(annotateKey);
if (instance == null)
instance = new Annotate(context);
return instance;
}
final Attr attr;
final TreeMaker make;
final Log log;
final Symtab syms;
final Names names;
final Resolve rs;
final Types types;
final ConstFold cfolder;
final Check chk;
protected Annotate(Context context) {
context.put(annotateKey, this);
attr = Attr.instance(context);
make = TreeMaker.instance(context);
log = Log.instance(context);
syms = Symtab.instance(context);
names = Names.instance(context);
rs = Resolve.instance(context);
types = Types.instance(context);
cfolder = ConstFold.instance(context);
chk = Check.instance(context);
}
/* ********************************************************************
* Queue maintenance
*********************************************************************/
private int enterCount = 0;
ListBuffer<Worker> q = new ListBuffer<Worker>();
ListBuffer<Worker> typesQ = new ListBuffer<Worker>();
ListBuffer<Worker> repeatedQ = new ListBuffer<Worker>();
ListBuffer<Worker> afterRepeatedQ = new ListBuffer<Worker>();
ListBuffer<Worker> validateQ = new ListBuffer<Worker>();
public void earlier(Worker a) {
q.prepend(a);
}
public void normal(Worker a) {
q.append(a);
}
public void typeAnnotation(Worker a) {
typesQ.append(a);
}
public void repeated(Worker a) {
repeatedQ.append(a);
}
public void afterRepeated(Worker a) {
afterRepeatedQ.append(a);
}
public void validate(Worker a) {
validateQ.append(a);
}
/** Called when the Enter phase starts. */
public void enterStart() {
enterCount++;
}
/** Called after the Enter phase completes. */
public void enterDone() {
enterCount--;
flush();
}
/** Variant which allows for a delayed flush of annotations.
* Needed by ClassReader */
public void enterDoneWithoutFlush() {
enterCount--;
}
public void flush() {
if (enterCount != 0) return;
enterCount++;
try {
while (q.nonEmpty()) {
q.next().run();
}
while (typesQ.nonEmpty()) {
typesQ.next().run();
}
while (repeatedQ.nonEmpty()) {
repeatedQ.next().run();
}
while (afterRepeatedQ.nonEmpty()) {
afterRepeatedQ.next().run();
}
while (validateQ.nonEmpty()) {
validateQ.next().run();
}
} finally {
enterCount--;
}
}
/** A client that needs to run during {@link #flush()} registers an worker
* into one of the queues defined in this class. The queues are: {@link #earlier(Worker)},
* {@link #normal(Worker)}, {@link #typeAnnotation(Worker)}, {@link #repeated(Worker)},
* {@link #afterRepeated(Worker)}, {@link #validate(Worker)}.
* The {@link Worker#run()} method will called inside the {@link #flush()}
* call. Queues are empties in the abovementioned order.
*/
public interface Worker {
void run();
String toString();
}
/**
* This context contains all the information needed to synthesize new
* annotations trees by the completer for repeating annotations.
*/
public class AnnotateRepeatedContext<T extends Attribute.Compound> {
public final Env<AttrContext> env;
public final Map<Symbol.TypeSymbol, ListBuffer<T>> annotated;
public final Map<T, JCDiagnostic.DiagnosticPosition> pos;
public final Log log;
public final boolean isTypeCompound;
public AnnotateRepeatedContext(Env<AttrContext> env,
Map<Symbol.TypeSymbol, ListBuffer<T>> annotated,
Map<T, JCDiagnostic.DiagnosticPosition> pos,
Log log,
boolean isTypeCompound) {
Assert.checkNonNull(env);
Assert.checkNonNull(annotated);
Assert.checkNonNull(pos);
Assert.checkNonNull(log);
this.env = env;
this.annotated = annotated;
this.pos = pos;
this.log = log;
this.isTypeCompound = isTypeCompound;
}
/**
* Process a list of repeating annotations returning a new
* Attribute.Compound that is the attribute for the synthesized tree
* for the container.
*
* @param repeatingAnnotations a List of repeating annotations
* @return a new Attribute.Compound that is the container for the repeatingAnnotations
*/
public T processRepeatedAnnotations(List<T> repeatingAnnotations, Symbol sym) {
return Annotate.this.processRepeatedAnnotations(repeatingAnnotations, this, sym);
}
/**
* Queue the Worker a on the repeating annotations queue of the
* Annotate instance this context belongs to.
*
* @param a the Worker to enqueue for repeating annotation annotating
*/
public void annotateRepeated(Worker a) {
Annotate.this.repeated(a);
}
}
/* ********************************************************************
* Compute an attribute from its annotation.
*********************************************************************/
/** Process a single compound annotation, returning its
* Attribute. Used from MemberEnter for attaching the attributes
* to the annotated symbol.
*/
Attribute.Compound enterAnnotation(JCAnnotation a,
Type expected,
Env<AttrContext> env) {
return enterAnnotation(a, expected, env, false);
}
Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a,
Type expected,
Env<AttrContext> env) {
return (Attribute.TypeCompound) enterAnnotation(a, expected, env, true);
}
// boolean typeAnnotation determines whether the method returns
// a Compound (false) or TypeCompound (true).
Attribute.Compound enterAnnotation(JCAnnotation a,
Type expected,
Env<AttrContext> env,
boolean typeAnnotation) {
// The annotation might have had its type attributed (but not checked)
// by attr.attribAnnotationTypes during MemberEnter, in which case we do not
// need to do it again.
Type at = (a.annotationType.type != null ? a.annotationType.type
: attr.attribType(a.annotationType, env));
a.type = chk.checkType(a.annotationType.pos(), at, expected);
if (a.type.isErroneous()) {
// Need to make sure nested (anno)trees does not have null as .type
attr.postAttr(a);
if (typeAnnotation) {
return new Attribute.TypeCompound(a.type, List.<Pair<MethodSymbol,Attribute>>nil(),
new TypeAnnotationPosition());
} else {
return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil());
}
}
if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0) {
log.error(a.annotationType.pos(),
"not.annotation.type", a.type.toString());
// Need to make sure nested (anno)trees does not have null as .type
attr.postAttr(a);
if (typeAnnotation) {
return new Attribute.TypeCompound(a.type, List.<Pair<MethodSymbol,Attribute>>nil(), null);
} else {
return new Attribute.Compound(a.type, List.<Pair<MethodSymbol,Attribute>>nil());
}
}
List<JCExpression> args = a.args;
if (args.length() == 1 && !args.head.hasTag(ASSIGN)) {
// special case: elided "value=" assumed
args.head = make.at(args.head.pos).
Assign(make.Ident(names.value), args.head);
}
ListBuffer<Pair<MethodSymbol,Attribute>> buf =
new ListBuffer<>();
for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) {
JCExpression t = tl.head;
if (!t.hasTag(ASSIGN)) {
log.error(t.pos(), "annotation.value.must.be.name.value");
continue;
}
JCAssign assign = (JCAssign)t;
if (!assign.lhs.hasTag(IDENT)) {
log.error(t.pos(), "annotation.value.must.be.name.value");
continue;
}
JCIdent left = (JCIdent)assign.lhs;
Symbol method = rs.resolveQualifiedMethod(assign.rhs.pos(),
env,
a.type,
left.name,
List.<Type>nil(),
null);
left.sym = method;
left.type = method.type;
if (method.owner != a.type.tsym)
log.error(left.pos(), "no.annotation.member", left.name, a.type);
Type result = method.type.getReturnType();
Attribute value = enterAttributeValue(result, assign.rhs, env);
if (!method.type.isErroneous())
buf.append(new Pair<>((MethodSymbol)method, value));
t.type = result;
}
if (typeAnnotation) {
if (a.attribute == null || !(a.attribute instanceof Attribute.TypeCompound)) {
// Create a new TypeCompound
Attribute.TypeCompound tc = new Attribute.TypeCompound(a.type, buf.toList(), new TypeAnnotationPosition());
a.attribute = tc;
return tc;
} else {
// Use an existing TypeCompound
return a.attribute;
}
} else {
Attribute.Compound ac = new Attribute.Compound(a.type, buf.toList());
a.attribute = ac;
return ac;
}
}
Attribute enterAttributeValue(Type expected,
JCExpression tree,
Env<AttrContext> env) {
//first, try completing the attribution value sym - if a completion
//error is thrown, we should recover gracefully, and display an
//ordinary resolution diagnostic.
try {
expected.tsym.complete();
} catch(CompletionFailure e) {
log.error(tree.pos(), "cant.resolve", Kinds.kindName(e.sym), e.sym);
expected = syms.errType;
}
if (expected.hasTag(ARRAY)) {
if (!tree.hasTag(NEWARRAY)) {
tree = make.at(tree.pos).
NewArray(null, List.<JCExpression>nil(), List.of(tree));
}
JCNewArray na = (JCNewArray)tree;
if (na.elemtype != null) {
log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
}
ListBuffer<Attribute> buf = new ListBuffer<Attribute>();
for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
buf.append(enterAttributeValue(types.elemtype(expected),
l.head,
env));
}
na.type = expected;
return new Attribute.
Array(expected, buf.toArray(new Attribute[buf.length()]));
}
if (tree.hasTag(NEWARRAY)) { //error recovery
if (!expected.isErroneous())
log.error(tree.pos(), "annotation.value.not.allowable.type");
JCNewArray na = (JCNewArray)tree;
if (na.elemtype != null) {
log.error(na.elemtype.pos(), "new.not.allowed.in.annotation");
}
for (List<JCExpression> l = na.elems; l.nonEmpty(); l=l.tail) {
enterAttributeValue(syms.errType,
l.head,
env);
}
return new Attribute.Error(syms.errType);
}
if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) {
if (tree.hasTag(ANNOTATION)) {
return enterAnnotation((JCAnnotation)tree, expected, env);
} else {
log.error(tree.pos(), "annotation.value.must.be.annotation");
expected = syms.errType;
}
}
if (tree.hasTag(ANNOTATION)) { //error recovery
if (!expected.isErroneous())
log.error(tree.pos(), "annotation.not.valid.for.type", expected);
enterAnnotation((JCAnnotation)tree, syms.errType, env);
return new Attribute.Error(((JCAnnotation)tree).annotationType.type);
}
if (expected.isPrimitive() || types.isSameType(expected, syms.stringType)) {
Type result = attr.attribExpr(tree, env, expected);
if (result.isErroneous())
return new Attribute.Error(result.getOriginalType());
if (result.constValue() == null) {
log.error(tree.pos(), "attribute.value.must.be.constant");
return new Attribute.Error(expected);
}
result = cfolder.coerce(result, expected);
return new Attribute.Constant(expected, result.constValue());
}
if (expected.tsym == syms.classType.tsym) {
Type result = attr.attribExpr(tree, env, expected);
if (result.isErroneous()) {
// Does it look like an unresolved class literal?
if (TreeInfo.name(tree) == names._class &&
((JCFieldAccess) tree).selected.type.isErroneous()) {
Name n = (((JCFieldAccess) tree).selected).type.tsym.flatName();
return new Attribute.UnresolvedClass(expected,
types.createErrorType(n,
syms.unknownSymbol, syms.classType));
} else {
return new Attribute.Error(result.getOriginalType());
}
}
// Class literals look like field accesses of a field named class
// at the tree level
if (TreeInfo.name(tree) != names._class) {
log.error(tree.pos(), "annotation.value.must.be.class.literal");
return new Attribute.Error(syms.errType);
}
return new Attribute.Class(types,
(((JCFieldAccess) tree).selected).type);
}
if (expected.hasTag(CLASS) &&
(expected.tsym.flags() & Flags.ENUM) != 0) {
Type result = attr.attribExpr(tree, env, expected);
Symbol sym = TreeInfo.symbol(tree);
if (sym == null ||
TreeInfo.nonstaticSelect(tree) ||
sym.kind != Kinds.VAR ||
(sym.flags() & Flags.ENUM) == 0) {
log.error(tree.pos(), "enum.annotation.must.be.enum.constant");
return new Attribute.Error(result.getOriginalType());
}
VarSymbol enumerator = (VarSymbol) sym;
return new Attribute.Enum(expected, enumerator);
}
//error recovery:
if (!expected.isErroneous())
log.error(tree.pos(), "annotation.value.not.allowable.type");
return new Attribute.Error(attr.attribExpr(tree, env, expected));
}
/* *********************************
* Support for repeating annotations
***********************************/
/* Process repeated annotations. This method returns the
* synthesized container annotation or null IFF all repeating
* annotation are invalid. This method reports errors/warnings.
*/
private <T extends Attribute.Compound> T processRepeatedAnnotations(List<T> annotations,
AnnotateRepeatedContext<T> ctx,
Symbol on) {
T firstOccurrence = annotations.head;
List<Attribute> repeated = List.nil();
Type origAnnoType = null;
Type arrayOfOrigAnnoType = null;
Type targetContainerType = null;
MethodSymbol containerValueSymbol = null;
Assert.check(!annotations.isEmpty() &&
!annotations.tail.isEmpty()); // i.e. size() > 1
int count = 0;
for (List<T> al = annotations;
!al.isEmpty();
al = al.tail)
{
count++;
// There must be more than a single anno in the annotation list
Assert.check(count > 1 || !al.tail.isEmpty());
T currentAnno = al.head;
origAnnoType = currentAnno.type;
if (arrayOfOrigAnnoType == null) {
arrayOfOrigAnnoType = types.makeArrayType(origAnnoType);
}
// Only report errors if this isn't the first occurrence I.E. count > 1
boolean reportError = count > 1;
Type currentContainerType = getContainingType(currentAnno, ctx.pos.get(currentAnno), reportError);
if (currentContainerType == null) {
continue;
}
// Assert that the target Container is == for all repeated
// annos of the same annotation type, the types should
// come from the same Symbol, i.e. be '=='
Assert.check(targetContainerType == null || currentContainerType == targetContainerType);
targetContainerType = currentContainerType;
containerValueSymbol = validateContainer(targetContainerType, origAnnoType, ctx.pos.get(currentAnno));
if (containerValueSymbol == null) { // Check of CA type failed
// errors are already reported
continue;
}
repeated = repeated.prepend(currentAnno);
}
if (!repeated.isEmpty()) {
repeated = repeated.reverse();
TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
Pair<MethodSymbol, Attribute> p =
new Pair<MethodSymbol, Attribute>(containerValueSymbol,
new Attribute.Array(arrayOfOrigAnnoType, repeated));
if (ctx.isTypeCompound) {
/* TODO: the following code would be cleaner:
Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
((Attribute.TypeCompound)annotations.head).position);
JCTypeAnnotation annoTree = m.TypeAnnotation(at);
at = enterTypeAnnotation(annoTree, targetContainerType, ctx.env);
*/
// However, we directly construct the TypeCompound to keep the
// direct relation to the contained TypeCompounds.
Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
((Attribute.TypeCompound)annotations.head).position);
// TODO: annotation applicability checks from below?
at.setSynthesized(true);
@SuppressWarnings("unchecked")
T x = (T) at;
return x;
} else {
Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p));
JCAnnotation annoTree = m.Annotation(c);
if (!chk.annotationApplicable(annoTree, on))
log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType);
if (!chk.validateAnnotationDeferErrors(annoTree))
log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType);
c = enterAnnotation(annoTree, targetContainerType, ctx.env);
c.setSynthesized(true);
@SuppressWarnings("unchecked")
T x = (T) c;
return x;
}
} else {
return null; // errors should have been reported elsewhere
}
}
/** Fetches the actual Type that should be the containing annotation. */
private Type getContainingType(Attribute.Compound currentAnno,
DiagnosticPosition pos,
boolean reportError)
{
Type origAnnoType = currentAnno.type;
TypeSymbol origAnnoDecl = origAnnoType.tsym;
// Fetch the Repeatable annotation from the current
// annotation's declaration, or null if it has none
Attribute.Compound ca = origAnnoDecl.attribute(syms.repeatableType.tsym);
if (ca == null) { // has no Repeatable annotation
if (reportError)
log.error(pos, "duplicate.annotation.missing.container", origAnnoType, syms.repeatableType);
return null;
}
return filterSame(extractContainingType(ca, pos, origAnnoDecl),
origAnnoType);
}
// returns null if t is same as 's', returns 't' otherwise
private Type filterSame(Type t, Type s) {
if (t == null || s == null) {
return t;
}
return types.isSameType(t, s) ? null : t;
}
/** Extract the actual Type to be used for a containing annotation. */
private Type extractContainingType(Attribute.Compound ca,
DiagnosticPosition pos,
TypeSymbol annoDecl)
{
// The next three checks check that the Repeatable annotation
// on the declaration of the annotation type that is repeating is
// valid.
// Repeatable must have at least one element
if (ca.values.isEmpty()) {
log.error(pos, "invalid.repeatable.annotation", annoDecl);
return null;
}
Pair<MethodSymbol,Attribute> p = ca.values.head;
Name name = p.fst.name;
if (name != names.value) { // should contain only one element, named "value"
log.error(pos, "invalid.repeatable.annotation", annoDecl);
return null;
}
if (!(p.snd instanceof Attribute.Class)) { // check that the value of "value" is an Attribute.Class
log.error(pos, "invalid.repeatable.annotation", annoDecl);
return null;
}
return ((Attribute.Class)p.snd).getValue();
}
/* Validate that the suggested targetContainerType Type is a valid
* container type for repeated instances of originalAnnoType
* annotations. Return null and report errors if this is not the
* case, return the MethodSymbol of the value element in
* targetContainerType if it is suitable (this is needed to
* synthesize the container). */
private MethodSymbol validateContainer(Type targetContainerType,
Type originalAnnoType,
DiagnosticPosition pos) {
MethodSymbol containerValueSymbol = null;
boolean fatalError = false;
// Validate that there is a (and only 1) value method
Scope scope = targetContainerType.tsym.members();
int nr_value_elems = 0;
boolean error = false;
for(Symbol elm : scope.getElementsByName(names.value)) {
nr_value_elems++;
if (nr_value_elems == 1 &&
elm.kind == Kinds.MTH) {
containerValueSymbol = (MethodSymbol)elm;
} else {
error = true;
}
}
if (error) {
log.error(pos,
"invalid.repeatable.annotation.multiple.values",
targetContainerType,
nr_value_elems);
return null;
} else if (nr_value_elems == 0) {
log.error(pos,
"invalid.repeatable.annotation.no.value",
targetContainerType);
return null;
}
// validate that the 'value' element is a method
// probably "impossible" to fail this
if (containerValueSymbol.kind != Kinds.MTH) {
log.error(pos,
"invalid.repeatable.annotation.invalid.value",
targetContainerType);
fatalError = true;
}
// validate that the 'value' element has the correct return type
// i.e. array of original anno
Type valueRetType = containerValueSymbol.type.getReturnType();
Type expectedType = types.makeArrayType(originalAnnoType);
if (!(types.isArray(valueRetType) &&
types.isSameType(expectedType, valueRetType))) {
log.error(pos,
"invalid.repeatable.annotation.value.return",
targetContainerType,
valueRetType,
expectedType);
fatalError = true;
}
if (error) {
fatalError = true;
}
// The conditions for a valid containing annotation are made
// in Check.validateRepeatedAnnotaton();
return fatalError ? null : containerValueSymbol;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,130 @@
/*
* Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.comp;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.code.*;
/** Contains information specific to the attribute and enter
* passes, to be used in place of the generic field in environments.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class AttrContext {
/** The scope of local symbols.
*/
Scope scope = null;
/** The number of enclosing `static' modifiers.
*/
int staticLevel = 0;
/** Is this an environment for a this(...) or super(...) call?
*/
boolean isSelfCall = false;
/** Are we evaluating the selector of a `super' or type name?
*/
boolean selectSuper = false;
/** Is the current target of lambda expression or method reference serializable?
*/
boolean isSerializable = false;
/** Are arguments to current function applications boxed into an array for varargs?
*/
Resolve.MethodResolutionPhase pendingResolutionPhase = null;
/** A record of the lint/SuppressWarnings currently in effect
*/
Lint lint;
/** The variable whose initializer is being attributed
* useful for detecting self-references in variable initializers
*/
Symbol enclVar = null;
/** ResultInfo to be used for attributing 'return' statement expressions
* (set by Attr.visitMethod and Attr.visitLambda)
*/
Attr.ResultInfo returnResult = null;
/** Symbol corresponding to the site of a qualified default super call
*/
Type defaultSuperCallSite = null;
/** Tree that when non null, is to be preferentially used in diagnostics.
* Usually Env<AttrContext>.tree is the tree to be referred to in messages,
* but this may not be true during the window a method is looked up in enclosing
* contexts (JDK-8145466)
*/
JCTree preferredTreeForDiagnostics;
/** Duplicate this context, replacing scope field and copying all others.
*/
AttrContext dup(Scope scope) {
AttrContext info = new AttrContext();
info.scope = scope;
info.staticLevel = staticLevel;
info.isSelfCall = isSelfCall;
info.selectSuper = selectSuper;
info.pendingResolutionPhase = pendingResolutionPhase;
info.lint = lint;
info.enclVar = enclVar;
info.returnResult = returnResult;
info.defaultSuperCallSite = defaultSuperCallSite;
info.isSerializable = isSerializable;
info.preferredTreeForDiagnostics = preferredTreeForDiagnostics;
return info;
}
/** Duplicate this context, copying all fields.
*/
AttrContext dup() {
return dup(scope);
}
public Iterable<Symbol> getLocalElements() {
if (scope == null)
return List.nil();
return scope.getElements();
}
boolean lastResolveVarargs() {
return pendingResolutionPhase != null &&
pendingResolutionPhase.isVarargsRequired();
}
@Override
public String toString() {
return "AttrContext[" + scope.toString() + "]";
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.comp;
import com.sun.tools.javac.tree.JCTree;
/** {@code Env<A>} specialized as {@code Env<AttrContext>}
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class AttrContextEnv extends Env<AttrContext> {
/** Create an outermost environment for a given (toplevel)tree,
* with a given info field.
*/
public AttrContextEnv(JCTree tree, AttrContext info) {
super(tree, info);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.comp;
import java.util.HashMap;
import com.sun.tools.javac.util.Context;
/** Partial map to record which compiler phases have been executed
* for each compilation unit. Used for ATTR and FLOW phases.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class CompileStates extends HashMap<Env<AttrContext>, CompileStates.CompileState> {
/** The context key for the compile states. */
protected static final Context.Key<CompileStates> compileStatesKey =
new Context.Key<CompileStates>();
/** Get the CompileStates instance for this context. */
public static CompileStates instance(Context context) {
CompileStates instance = context.get(compileStatesKey);
if (instance == null) {
instance = new CompileStates(context);
}
return instance;
}
/** Ordered list of compiler phases for each compilation unit. */
public enum CompileState {
INIT(0),
PARSE(1),
ENTER(2),
PROCESS(3),
ATTR(4),
FLOW(5),
TRANSTYPES(6),
UNLAMBDA(7),
LOWER(8),
GENERATE(9);
CompileState(int value) {
this.value = value;
}
public boolean isAfter(CompileState other) {
return value > other.value;
}
public static CompileState max(CompileState a, CompileState b) {
return a.value > b.value ? a : b;
}
private final int value;
};
private static final long serialVersionUID = 1812267524140424433L;
protected Context context;
public CompileStates(Context context) {
this.context = context;
context.put(compileStatesKey, this);
}
public boolean isDone(Env<AttrContext> env, CompileState cs) {
CompileState ecs = get(env);
return (ecs != null) && !cs.isAfter(ecs);
}
}

View File

@@ -0,0 +1,357 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.comp;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.jvm.*;
import com.sun.tools.javac.util.*;
import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
import static com.sun.tools.javac.jvm.ByteCodes.*;
/** Helper class for constant folding, used by the attribution phase.
* This class is marked strictfp as mandated by JLS 15.4.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
strictfp class ConstFold {
protected static final Context.Key<ConstFold> constFoldKey =
new Context.Key<ConstFold>();
private Symtab syms;
public static ConstFold instance(Context context) {
ConstFold instance = context.get(constFoldKey);
if (instance == null)
instance = new ConstFold(context);
return instance;
}
private ConstFold(Context context) {
context.put(constFoldKey, this);
syms = Symtab.instance(context);
}
static final Integer minusOne = -1;
static final Integer zero = 0;
static final Integer one = 1;
/** Convert boolean to integer (true = 1, false = 0).
*/
private static Integer b2i(boolean b) {
return b ? one : zero;
}
private static int intValue(Object x) { return ((Number)x).intValue(); }
private static long longValue(Object x) { return ((Number)x).longValue(); }
private static float floatValue(Object x) { return ((Number)x).floatValue(); }
private static double doubleValue(Object x) { return ((Number)x).doubleValue(); }
/** Fold binary or unary operation, returning constant type reflecting the
* operations result. Return null if fold failed due to an
* arithmetic exception.
* @param opcode The operation's opcode instruction (usually a byte code),
* as entered by class Symtab.
* @param argtypes The operation's argument types (a list of length 1 or 2).
* Argument types are assumed to have non-null constValue's.
*/
Type fold(int opcode, List<Type> argtypes) {
int argCount = argtypes.length();
if (argCount == 1)
return fold1(opcode, argtypes.head);
else if (argCount == 2)
return fold2(opcode, argtypes.head, argtypes.tail.head);
else
throw new AssertionError();
}
/** Fold unary operation.
* @param opcode The operation's opcode instruction (usually a byte code),
* as entered by class Symtab.
* opcode's ifeq to ifge are for postprocessing
* xcmp; ifxx pairs of instructions.
* @param operand The operation's operand type.
* Argument types are assumed to have non-null constValue's.
*/
Type fold1(int opcode, Type operand) {
try {
Object od = operand.constValue();
switch (opcode) {
case nop:
return operand;
case ineg: // unary -
return syms.intType.constType(-intValue(od));
case ixor: // ~
return syms.intType.constType(~intValue(od));
case bool_not: // !
return syms.booleanType.constType(b2i(intValue(od) == 0));
case ifeq:
return syms.booleanType.constType(b2i(intValue(od) == 0));
case ifne:
return syms.booleanType.constType(b2i(intValue(od) != 0));
case iflt:
return syms.booleanType.constType(b2i(intValue(od) < 0));
case ifgt:
return syms.booleanType.constType(b2i(intValue(od) > 0));
case ifle:
return syms.booleanType.constType(b2i(intValue(od) <= 0));
case ifge:
return syms.booleanType.constType(b2i(intValue(od) >= 0));
case lneg: // unary -
return syms.longType.constType(new Long(-longValue(od)));
case lxor: // ~
return syms.longType.constType(new Long(~longValue(od)));
case fneg: // unary -
return syms.floatType.constType(new Float(-floatValue(od)));
case dneg: // ~
return syms.doubleType.constType(new Double(-doubleValue(od)));
default:
return null;
}
} catch (ArithmeticException e) {
return null;
}
}
/** Fold binary operation.
* @param opcode The operation's opcode instruction (usually a byte code),
* as entered by class Symtab.
* opcode's ifeq to ifge are for postprocessing
* xcmp; ifxx pairs of instructions.
* @param left The type of the operation's left operand.
* @param right The type of the operation's right operand.
*/
Type fold2(int opcode, Type left, Type right) {
try {
if (opcode > ByteCodes.preMask) {
// we are seeing a composite instruction of the form xcmp; ifxx.
// In this case fold both instructions separately.
Type t1 = fold2(opcode >> ByteCodes.preShift, left, right);
return (t1.constValue() == null) ? t1
: fold1(opcode & ByteCodes.preMask, t1);
} else {
Object l = left.constValue();
Object r = right.constValue();
switch (opcode) {
case iadd:
return syms.intType.constType(intValue(l) + intValue(r));
case isub:
return syms.intType.constType(intValue(l) - intValue(r));
case imul:
return syms.intType.constType(intValue(l) * intValue(r));
case idiv:
return syms.intType.constType(intValue(l) / intValue(r));
case imod:
return syms.intType.constType(intValue(l) % intValue(r));
case iand:
return (left.hasTag(BOOLEAN)
? syms.booleanType : syms.intType)
.constType(intValue(l) & intValue(r));
case bool_and:
return syms.booleanType.constType(b2i((intValue(l) & intValue(r)) != 0));
case ior:
return (left.hasTag(BOOLEAN)
? syms.booleanType : syms.intType)
.constType(intValue(l) | intValue(r));
case bool_or:
return syms.booleanType.constType(b2i((intValue(l) | intValue(r)) != 0));
case ixor:
return (left.hasTag(BOOLEAN)
? syms.booleanType : syms.intType)
.constType(intValue(l) ^ intValue(r));
case ishl: case ishll:
return syms.intType.constType(intValue(l) << intValue(r));
case ishr: case ishrl:
return syms.intType.constType(intValue(l) >> intValue(r));
case iushr: case iushrl:
return syms.intType.constType(intValue(l) >>> intValue(r));
case if_icmpeq:
return syms.booleanType.constType(
b2i(intValue(l) == intValue(r)));
case if_icmpne:
return syms.booleanType.constType(
b2i(intValue(l) != intValue(r)));
case if_icmplt:
return syms.booleanType.constType(
b2i(intValue(l) < intValue(r)));
case if_icmpgt:
return syms.booleanType.constType(
b2i(intValue(l) > intValue(r)));
case if_icmple:
return syms.booleanType.constType(
b2i(intValue(l) <= intValue(r)));
case if_icmpge:
return syms.booleanType.constType(
b2i(intValue(l) >= intValue(r)));
case ladd:
return syms.longType.constType(
new Long(longValue(l) + longValue(r)));
case lsub:
return syms.longType.constType(
new Long(longValue(l) - longValue(r)));
case lmul:
return syms.longType.constType(
new Long(longValue(l) * longValue(r)));
case ldiv:
return syms.longType.constType(
new Long(longValue(l) / longValue(r)));
case lmod:
return syms.longType.constType(
new Long(longValue(l) % longValue(r)));
case land:
return syms.longType.constType(
new Long(longValue(l) & longValue(r)));
case lor:
return syms.longType.constType(
new Long(longValue(l) | longValue(r)));
case lxor:
return syms.longType.constType(
new Long(longValue(l) ^ longValue(r)));
case lshl: case lshll:
return syms.longType.constType(
new Long(longValue(l) << intValue(r)));
case lshr: case lshrl:
return syms.longType.constType(
new Long(longValue(l) >> intValue(r)));
case lushr:
return syms.longType.constType(
new Long(longValue(l) >>> intValue(r)));
case lcmp:
if (longValue(l) < longValue(r))
return syms.intType.constType(minusOne);
else if (longValue(l) > longValue(r))
return syms.intType.constType(one);
else
return syms.intType.constType(zero);
case fadd:
return syms.floatType.constType(
new Float(floatValue(l) + floatValue(r)));
case fsub:
return syms.floatType.constType(
new Float(floatValue(l) - floatValue(r)));
case fmul:
return syms.floatType.constType(
new Float(floatValue(l) * floatValue(r)));
case fdiv:
return syms.floatType.constType(
new Float(floatValue(l) / floatValue(r)));
case fmod:
return syms.floatType.constType(
new Float(floatValue(l) % floatValue(r)));
case fcmpg: case fcmpl:
if (floatValue(l) < floatValue(r))
return syms.intType.constType(minusOne);
else if (floatValue(l) > floatValue(r))
return syms.intType.constType(one);
else if (floatValue(l) == floatValue(r))
return syms.intType.constType(zero);
else if (opcode == fcmpg)
return syms.intType.constType(one);
else
return syms.intType.constType(minusOne);
case dadd:
return syms.doubleType.constType(
new Double(doubleValue(l) + doubleValue(r)));
case dsub:
return syms.doubleType.constType(
new Double(doubleValue(l) - doubleValue(r)));
case dmul:
return syms.doubleType.constType(
new Double(doubleValue(l) * doubleValue(r)));
case ddiv:
return syms.doubleType.constType(
new Double(doubleValue(l) / doubleValue(r)));
case dmod:
return syms.doubleType.constType(
new Double(doubleValue(l) % doubleValue(r)));
case dcmpg: case dcmpl:
if (doubleValue(l) < doubleValue(r))
return syms.intType.constType(minusOne);
else if (doubleValue(l) > doubleValue(r))
return syms.intType.constType(one);
else if (doubleValue(l) == doubleValue(r))
return syms.intType.constType(zero);
else if (opcode == dcmpg)
return syms.intType.constType(one);
else
return syms.intType.constType(minusOne);
case if_acmpeq:
return syms.booleanType.constType(b2i(l.equals(r)));
case if_acmpne:
return syms.booleanType.constType(b2i(!l.equals(r)));
case string_add:
return syms.stringType.constType(
left.stringValue() + right.stringValue());
default:
return null;
}
}
} catch (ArithmeticException e) {
return null;
}
}
/** Coerce constant type to target type.
* @param etype The source type of the coercion,
* which is assumed to be a constant type compatible with
* ttype.
* @param ttype The target type of the coercion.
*/
Type coerce(Type etype, Type ttype) {
// WAS if (etype.baseType() == ttype.baseType())
if (etype.tsym.type == ttype.tsym.type)
return etype;
if (etype.isNumeric()) {
Object n = etype.constValue();
switch (ttype.getTag()) {
case BYTE:
return syms.byteType.constType(0 + (byte)intValue(n));
case CHAR:
return syms.charType.constType(0 + (char)intValue(n));
case SHORT:
return syms.shortType.constType(0 + (short)intValue(n));
case INT:
return syms.intType.constType(intValue(n));
case LONG:
return syms.longType.constType(longValue(n));
case FLOAT:
return syms.floatType.constType(floatValue(n));
case DOUBLE:
return syms.doubleType.constType(doubleValue(n));
}
}
return ttype;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,515 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.comp;
import java.util.*;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileManager;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Scope.*;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.jvm.*;
import com.sun.tools.javac.main.Option.PkgInfo;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.List;
import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Kinds.*;
/** This class enters symbols for all encountered definitions into
* the symbol table. The pass consists of two phases, organized as
* follows:
*
* <p>In the first phase, all class symbols are entered into their
* enclosing scope, descending recursively down the tree for classes
* which are members of other classes. The class symbols are given a
* MemberEnter object as completer.
*
* <p>In the second phase classes are completed using
* MemberEnter.complete(). Completion might occur on demand, but
* any classes that are not completed that way will be eventually
* completed by processing the `uncompleted' queue. Completion
* entails (1) determination of a class's parameters, supertype and
* interfaces, as well as (2) entering all symbols defined in the
* class into its scope, with the exception of class symbols which
* have been entered in phase 1. (2) depends on (1) having been
* completed for a class and all its superclasses and enclosing
* classes. That's why, after doing (1), we put classes in a
* `halfcompleted' queue. Only when we have performed (1) for a class
* and all it's superclasses and enclosing classes, we proceed to
* (2).
*
* <p>Whereas the first phase is organized as a sweep through all
* compiled syntax trees, the second phase is demand. Members of a
* class are entered when the contents of a class are first
* accessed. This is accomplished by installing completer objects in
* class symbols for compiled classes which invoke the member-enter
* phase for the corresponding class tree.
*
* <p>Classes migrate from one phase to the next via queues:
*
* <pre>{@literal
* class enter -> (Enter.uncompleted) --> member enter (1)
* -> (MemberEnter.halfcompleted) --> member enter (2)
* -> (Todo) --> attribute
* (only for toplevel classes)
* }</pre>
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Enter extends JCTree.Visitor {
protected static final Context.Key<Enter> enterKey =
new Context.Key<Enter>();
Log log;
Symtab syms;
Check chk;
TreeMaker make;
ClassReader reader;
Annotate annotate;
MemberEnter memberEnter;
Types types;
Lint lint;
Names names;
JavaFileManager fileManager;
PkgInfo pkginfoOpt;
TypeEnvs typeEnvs;
private final Todo todo;
public static Enter instance(Context context) {
Enter instance = context.get(enterKey);
if (instance == null)
instance = new Enter(context);
return instance;
}
protected Enter(Context context) {
context.put(enterKey, this);
log = Log.instance(context);
reader = ClassReader.instance(context);
make = TreeMaker.instance(context);
syms = Symtab.instance(context);
chk = Check.instance(context);
memberEnter = MemberEnter.instance(context);
types = Types.instance(context);
annotate = Annotate.instance(context);
lint = Lint.instance(context);
names = Names.instance(context);
predefClassDef = make.ClassDef(
make.Modifiers(PUBLIC),
syms.predefClass.name,
List.<JCTypeParameter>nil(),
null,
List.<JCExpression>nil(),
List.<JCTree>nil());
predefClassDef.sym = syms.predefClass;
todo = Todo.instance(context);
fileManager = context.get(JavaFileManager.class);
Options options = Options.instance(context);
pkginfoOpt = PkgInfo.get(options);
typeEnvs = TypeEnvs.instance(context);
}
/** Accessor for typeEnvs
*/
public Env<AttrContext> getEnv(TypeSymbol sym) {
return typeEnvs.get(sym);
}
public Env<AttrContext> getClassEnv(TypeSymbol sym) {
Env<AttrContext> localEnv = getEnv(sym);
Env<AttrContext> lintEnv = localEnv;
while (lintEnv.info.lint == null)
lintEnv = lintEnv.next;
localEnv.info.lint = lintEnv.info.lint.augment(sym);
return localEnv;
}
/** The queue of all classes that might still need to be completed;
* saved and initialized by main().
*/
ListBuffer<ClassSymbol> uncompleted;
/** A dummy class to serve as enclClass for toplevel environments.
*/
private JCClassDecl predefClassDef;
/* ************************************************************************
* environment construction
*************************************************************************/
/** Create a fresh environment for class bodies.
* This will create a fresh scope for local symbols of a class, referred
* to by the environments info.scope field.
* This scope will contain
* - symbols for this and super
* - symbols for any type parameters
* In addition, it serves as an anchor for scopes of methods and initializers
* which are nested in this scope via Scope.dup().
* This scope should not be confused with the members scope of a class.
*
* @param tree The class definition.
* @param env The environment current outside of the class definition.
*/
public Env<AttrContext> classEnv(JCClassDecl tree, Env<AttrContext> env) {
Env<AttrContext> localEnv =
env.dup(tree, env.info.dup(new Scope(tree.sym)));
localEnv.enclClass = tree;
localEnv.outer = env;
localEnv.info.isSelfCall = false;
localEnv.info.lint = null; // leave this to be filled in by Attr,
// when annotations have been processed
return localEnv;
}
/** Create a fresh environment for toplevels.
* @param tree The toplevel tree.
*/
Env<AttrContext> topLevelEnv(JCCompilationUnit tree) {
Env<AttrContext> localEnv = new Env<AttrContext>(tree, new AttrContext());
localEnv.toplevel = tree;
localEnv.enclClass = predefClassDef;
tree.namedImportScope = new ImportScope(tree.packge);
tree.starImportScope = new StarImportScope(tree.packge);
localEnv.info.scope = tree.namedImportScope;
localEnv.info.lint = lint;
return localEnv;
}
public Env<AttrContext> getTopLevelEnv(JCCompilationUnit tree) {
Env<AttrContext> localEnv = new Env<AttrContext>(tree, new AttrContext());
localEnv.toplevel = tree;
localEnv.enclClass = predefClassDef;
localEnv.info.scope = tree.namedImportScope;
localEnv.info.lint = lint;
return localEnv;
}
/** The scope in which a member definition in environment env is to be entered
* This is usually the environment's scope, except for class environments,
* where the local scope is for type variables, and the this and super symbol
* only, and members go into the class member scope.
*/
Scope enterScope(Env<AttrContext> env) {
return (env.tree.hasTag(JCTree.Tag.CLASSDEF))
? ((JCClassDecl) env.tree).sym.members_field
: env.info.scope;
}
/* ************************************************************************
* Visitor methods for phase 1: class enter
*************************************************************************/
/** Visitor argument: the current environment.
*/
protected Env<AttrContext> env;
/** Visitor result: the computed type.
*/
Type result;
/** Visitor method: enter all classes in given tree, catching any
* completion failure exceptions. Return the tree's type.
*
* @param tree The tree to be visited.
* @param env The environment visitor argument.
*/
Type classEnter(JCTree tree, Env<AttrContext> env) {
Env<AttrContext> prevEnv = this.env;
try {
this.env = env;
tree.accept(this);
return result;
} catch (CompletionFailure ex) {
return chk.completionError(tree.pos(), ex);
} finally {
this.env = prevEnv;
}
}
/** Visitor method: enter classes of a list of trees, returning a list of types.
*/
<T extends JCTree> List<Type> classEnter(List<T> trees, Env<AttrContext> env) {
ListBuffer<Type> ts = new ListBuffer<Type>();
for (List<T> l = trees; l.nonEmpty(); l = l.tail) {
Type t = classEnter(l.head, env);
if (t != null)
ts.append(t);
}
return ts.toList();
}
@Override
public void visitTopLevel(JCCompilationUnit tree) {
JavaFileObject prev = log.useSource(tree.sourcefile);
boolean addEnv = false;
boolean isPkgInfo = tree.sourcefile.isNameCompatible("package-info",
JavaFileObject.Kind.SOURCE);
if (tree.pid != null) {
tree.packge = reader.enterPackage(TreeInfo.fullName(tree.pid));
if (tree.packageAnnotations.nonEmpty()
|| pkginfoOpt == PkgInfo.ALWAYS
|| tree.docComments != null) {
if (isPkgInfo) {
addEnv = true;
} else if (tree.packageAnnotations.nonEmpty()){
log.error(tree.packageAnnotations.head.pos(),
"pkg.annotations.sb.in.package-info.java");
}
}
} else {
tree.packge = syms.unnamedPackage;
}
tree.packge.complete(); // Find all classes in package.
Env<AttrContext> topEnv = topLevelEnv(tree);
// Save environment of package-info.java file.
if (isPkgInfo) {
Env<AttrContext> env0 = typeEnvs.get(tree.packge);
if (env0 == null) {
typeEnvs.put(tree.packge, topEnv);
} else {
JCCompilationUnit tree0 = env0.toplevel;
if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) {
log.warning(tree.pid != null ? tree.pid.pos()
: null,
"pkg-info.already.seen",
tree.packge);
if (addEnv || (tree0.packageAnnotations.isEmpty() &&
tree.docComments != null &&
tree.docComments.hasComment(tree))) {
typeEnvs.put(tree.packge, topEnv);
}
}
}
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, topEnv);
if (addEnv) {
todo.append(topEnv);
}
log.useSource(prev);
result = null;
}
@Override
public void visitClassDef(JCClassDecl tree) {
Symbol owner = env.info.scope.owner;
Scope enclScope = enterScope(env);
ClassSymbol c;
if (owner.kind == PCK) {
// We are seeing a toplevel class.
PackageSymbol packge = (PackageSymbol)owner;
for (Symbol q = packge; q != null && q.kind == PCK; q = q.owner)
q.flags_field |= EXISTS;
c = reader.enterClass(tree.name, packge);
packge.members().enterIfAbsent(c);
if ((tree.mods.flags & PUBLIC) != 0 && !classNameMatchesFileName(c, env)) {
log.error(tree.pos(),
"class.public.should.be.in.file", tree.name);
}
} else {
if (!tree.name.isEmpty() &&
!chk.checkUniqueClassName(tree.pos(), tree.name, enclScope)) {
result = null;
return;
}
if (owner.kind == TYP) {
// We are seeing a member class.
c = reader.enterClass(tree.name, (TypeSymbol)owner);
if ((owner.flags_field & INTERFACE) != 0) {
tree.mods.flags |= PUBLIC | STATIC;
}
} else {
// We are seeing a local class.
c = reader.defineClass(tree.name, owner);
c.flatname = chk.localClassName(c);
if (!c.name.isEmpty())
chk.checkTransparentClass(tree.pos(), c, env.info.scope);
}
}
tree.sym = c;
// Enter class into `compiled' table and enclosing scope.
if (chk.compiled.get(c.flatname) != null) {
duplicateClass(tree.pos(), c);
result = types.createErrorType(tree.name, (TypeSymbol)owner, Type.noType);
tree.sym = (ClassSymbol)result.tsym;
return;
}
chk.compiled.put(c.flatname, c);
enclScope.enter(c);
// Set up an environment for class block and store in `typeEnvs'
// table, to be retrieved later in memberEnter and attribution.
Env<AttrContext> localEnv = classEnv(tree, env);
typeEnvs.put(c, localEnv);
// Fill out class fields.
c.completer = memberEnter;
c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree);
c.sourcefile = env.toplevel.sourcefile;
c.members_field = new Scope(c);
ClassType ct = (ClassType)c.type;
if (owner.kind != PCK && (c.flags_field & STATIC) == 0) {
// We are seeing a local or inner class.
// Set outer_field of this class to closest enclosing class
// which contains this class in a non-static context
// (its "enclosing instance class"), provided such a class exists.
Symbol owner1 = owner;
while ((owner1.kind & (VAR | MTH)) != 0 &&
(owner1.flags_field & STATIC) == 0) {
owner1 = owner1.owner;
}
if (owner1.kind == TYP) {
ct.setEnclosingType(owner1.type);
}
}
// Enter type parameters.
ct.typarams_field = classEnter(tree.typarams, localEnv);
// Add non-local class to uncompleted, to make sure it will be
// completed later.
if (!c.isLocal() && uncompleted != null) uncompleted.append(c);
// System.err.println("entering " + c.fullname + " in " + c.owner);//DEBUG
// Recursively enter all member classes.
classEnter(tree.defs, localEnv);
result = c.type;
}
//where
/** Does class have the same name as the file it appears in?
*/
private static boolean classNameMatchesFileName(ClassSymbol c,
Env<AttrContext> env) {
return env.toplevel.sourcefile.isNameCompatible(c.name.toString(),
JavaFileObject.Kind.SOURCE);
}
/** Complain about a duplicate class. */
protected void duplicateClass(DiagnosticPosition pos, ClassSymbol c) {
log.error(pos, "duplicate.class", c.fullname);
}
/** Class enter visitor method for type parameters.
* Enter a symbol for type parameter in local scope, after checking that it
* is unique.
*/
@Override
public void visitTypeParameter(JCTypeParameter tree) {
TypeVar a = (tree.type != null)
? (TypeVar)tree.type
: new TypeVar(tree.name, env.info.scope.owner, syms.botType);
tree.type = a;
if (chk.checkUnique(tree.pos(), a.tsym, env.info.scope)) {
env.info.scope.enter(a.tsym);
}
result = a;
}
/** Default class enter visitor method: do nothing.
*/
@Override
public void visitTree(JCTree tree) {
result = null;
}
/** Main method: enter all classes in a list of toplevel trees.
* @param trees The list of trees to be processed.
*/
public void main(List<JCCompilationUnit> trees) {
complete(trees, null);
}
/** Main method: enter one class from a list of toplevel trees and
* place the rest on uncompleted for later processing.
* @param trees The list of trees to be processed.
* @param c The class symbol to be processed.
*/
public void complete(List<JCCompilationUnit> trees, ClassSymbol c) {
annotate.enterStart();
ListBuffer<ClassSymbol> prevUncompleted = uncompleted;
if (memberEnter.completionEnabled) uncompleted = new ListBuffer<ClassSymbol>();
try {
// enter all classes, and construct uncompleted list
classEnter(trees, null);
// complete all uncompleted classes in memberEnter
if (memberEnter.completionEnabled) {
while (uncompleted.nonEmpty()) {
ClassSymbol clazz = uncompleted.next();
if (c == null || c == clazz || prevUncompleted == null)
clazz.complete();
else
// defer
prevUncompleted.append(clazz);
}
// if there remain any unimported toplevels (these must have
// no classes at all), process their import statements as well.
for (JCCompilationUnit tree : trees) {
if (tree.starImportScope.elems == null) {
JavaFileObject prev = log.useSource(tree.sourcefile);
Env<AttrContext> topEnv = topLevelEnv(tree);
memberEnter.memberEnter(tree, topEnv);
log.useSource(prev);
}
}
}
} finally {
uncompleted = prevUncompleted;
annotate.enterDone();
}
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.comp;
import com.sun.tools.javac.tree.*;
import java.util.Iterator;
import java.util.NoSuchElementException;
/** A class for environments, instances of which are passed as
* arguments to tree visitors. Environments refer to important ancestors
* of the subtree that's currently visited, such as the enclosing method,
* the enclosing class, or the enclosing toplevel node. They also contain
* a generic component, represented as a type parameter, to carry further
* information specific to individual passes.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Env<A> implements Iterable<Env<A>> {
/** The next enclosing environment.
*/
public Env<A> next;
/** The environment enclosing the current class.
*/
public Env<A> outer;
/** The tree with which this environment is associated.
*/
public JCTree tree;
/** The enclosing toplevel tree.
*/
public JCTree.JCCompilationUnit toplevel;
/** The next enclosing class definition.
*/
public JCTree.JCClassDecl enclClass;
/** The next enclosing method definition.
*/
public JCTree.JCMethodDecl enclMethod;
/** A generic field for further information.
*/
public A info;
/** Is this an environment for evaluating a base clause?
*/
public boolean baseClause = false;
/** Create an outermost environment for a given (toplevel)tree,
* with a given info field.
*/
public Env(JCTree tree, A info) {
this.next = null;
this.outer = null;
this.tree = tree;
this.toplevel = null;
this.enclClass = null;
this.enclMethod = null;
this.info = info;
}
/** Duplicate this environment, updating with given tree and info,
* and copying all other fields.
*/
public Env<A> dup(JCTree tree, A info) {
return dupto(new Env<A>(tree, info));
}
/** Duplicate this environment into a given Environment,
* using its tree and info, and copying all other fields.
*/
public Env<A> dupto(Env<A> that) {
that.next = this;
that.outer = this.outer;
that.toplevel = this.toplevel;
that.enclClass = this.enclClass;
that.enclMethod = this.enclMethod;
return that;
}
/** Duplicate this environment, updating with given tree,
* and copying all other fields.
*/
public Env<A> dup(JCTree tree) {
return dup(tree, this.info);
}
/** Return closest enclosing environment which points to a tree with given tag.
*/
public Env<A> enclosing(JCTree.Tag tag) {
Env<A> env1 = this;
while (env1 != null && !env1.tree.hasTag(tag)) env1 = env1.next;
return env1;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Env[").append(info);
// if (enclMethod != null)
// sb.append(",enclMethod=").append(Pretty.toSimpleString(enclMethod));
// if (enclClass != null)
// sb.append(",enclClass=").append(Pretty.toSimpleString(enclClass));
if (outer != null)
sb.append(",outer=").append(outer);
sb.append("]");
return sb.toString();
}
public Iterator<Env<A>> iterator() {
return new Iterator<Env<A>>() {
Env<A> next = Env.this;
public boolean hasNext() {
return next.outer != null;
}
public Env<A> next() {
if (hasNext()) {
Env<A> current = next;
next = current.outer;
return current;
}
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,172 @@
/*
* Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.comp;
import java.util.AbstractQueue;
import com.sun.tools.javac.util.Context;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import javax.tools.JavaFileObject;
/** A queue of all as yet unattributed classes.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Todo extends AbstractQueue<Env<AttrContext>> {
/** The context key for the todo list. */
protected static final Context.Key<Todo> todoKey =
new Context.Key<Todo>();
/** Get the Todo instance for this context. */
public static Todo instance(Context context) {
Todo instance = context.get(todoKey);
if (instance == null)
instance = new Todo(context);
return instance;
}
/** Create a new todo list. */
protected Todo(Context context) {
context.put(todoKey, this);
}
public void append(Env<AttrContext> env) {
add(env);
}
@Override
public Iterator<Env<AttrContext>> iterator() {
return contents.iterator();
}
@Override
public int size() {
return contents.size();
}
public boolean offer(Env<AttrContext> e) {
if (contents.add(e)) {
if (contentsByFile != null)
addByFile(e);
return true;
} else {
return false;
}
}
public Env<AttrContext> poll() {
if (size() == 0)
return null;
Env<AttrContext> env = contents.remove(0);
if (contentsByFile != null)
removeByFile(env);
return env;
}
public Env<AttrContext> peek() {
return (size() == 0 ? null : contents.get(0));
}
public Queue<Queue<Env<AttrContext>>> groupByFile() {
if (contentsByFile == null) {
contentsByFile = new LinkedList<Queue<Env<AttrContext>>>();
for (Env<AttrContext> env: contents) {
addByFile(env);
}
}
return contentsByFile;
}
private void addByFile(Env<AttrContext> env) {
JavaFileObject file = env.toplevel.sourcefile;
if (fileMap == null)
fileMap = new HashMap<JavaFileObject, FileQueue>();
FileQueue fq = fileMap.get(file);
if (fq == null) {
fq = new FileQueue();
fileMap.put(file, fq);
contentsByFile.add(fq);
}
fq.fileContents.add(env);
}
private void removeByFile(Env<AttrContext> env) {
JavaFileObject file = env.toplevel.sourcefile;
FileQueue fq = fileMap.get(file);
if (fq == null)
return;
if (fq.fileContents.remove(env)) {
if (fq.isEmpty()) {
fileMap.remove(file);
contentsByFile.remove(fq);
}
}
}
LinkedList<Env<AttrContext>> contents = new LinkedList<Env<AttrContext>>();
LinkedList<Queue<Env<AttrContext>>> contentsByFile;
Map<JavaFileObject, FileQueue> fileMap;
class FileQueue extends AbstractQueue<Env<AttrContext>> {
@Override
public Iterator<Env<AttrContext>> iterator() {
return fileContents.iterator();
}
@Override
public int size() {
return fileContents.size();
}
public boolean offer(Env<AttrContext> e) {
if (fileContents.offer(e)) {
contents.add(e);
return true;
}
return false;
}
public Env<AttrContext> poll() {
if (fileContents.size() == 0)
return null;
Env<AttrContext> env = fileContents.remove(0);
contents.remove(env);
return env;
}
public Env<AttrContext> peek() {
return (fileContents.size() == 0 ? null : fileContents.get(0));
}
LinkedList<Env<AttrContext>> fileContents = new LinkedList<Env<AttrContext>>();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.comp;
import java.util.Collection;
import java.util.HashMap;
import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.util.Context;
/** This class contains the type environments used by Enter, MemberEnter,
* Attr, DeferredAttr, and Lower.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
class TypeEnvs {
private static final long serialVersionUID = 571524752489954631L;
protected static final Context.Key<TypeEnvs> typeEnvsKey = new Context.Key<>();
public static TypeEnvs instance(Context context) {
TypeEnvs instance = context.get(typeEnvsKey);
if (instance == null)
instance = new TypeEnvs(context);
return instance;
}
private HashMap<TypeSymbol,Env<AttrContext>> map;
protected TypeEnvs(Context context) {
map = new HashMap<>();
context.put(typeEnvsKey, this);
}
Env<AttrContext> get(TypeSymbol sym) { return map.get(sym); }
Env<AttrContext> put(TypeSymbol sym, Env<AttrContext> env) { return map.put(sym, env); }
Env<AttrContext> remove(TypeSymbol sym) { return map.remove(sym); }
Collection<Env<AttrContext>> values() { return map.values(); }
void clear() { map.clear(); }
}