All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.ceylon.langtools.tools.javac.code.Symbol Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/*
 * Copyright (c) 1999, 2011, 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.redhat.ceylon.langtools.tools.javac.code;

import static com.redhat.ceylon.langtools.tools.javac.code.Flags.*;
import static com.redhat.ceylon.langtools.tools.javac.code.Kinds.*;
import static com.redhat.ceylon.langtools.tools.javac.code.TypeTags.*;

import java.util.Set;
import java.util.concurrent.Callable;

import com.redhat.ceylon.javax.lang.model.element.Element;
import com.redhat.ceylon.javax.lang.model.element.ElementKind;
import com.redhat.ceylon.javax.lang.model.element.ElementVisitor;
import com.redhat.ceylon.javax.lang.model.element.ExecutableElement;
import com.redhat.ceylon.javax.lang.model.element.Modifier;
import com.redhat.ceylon.javax.lang.model.element.NestingKind;
import com.redhat.ceylon.javax.lang.model.element.PackageElement;
import com.redhat.ceylon.javax.lang.model.element.TypeElement;
import com.redhat.ceylon.javax.lang.model.element.TypeParameterElement;
import com.redhat.ceylon.javax.lang.model.element.VariableElement;

import com.redhat.ceylon.javax.lang.model.element.*;
import com.redhat.ceylon.javax.tools.JavaFileObject;
import com.redhat.ceylon.langtools.tools.javac.code.Type.*;
import com.redhat.ceylon.langtools.tools.javac.comp.Attr;
import com.redhat.ceylon.langtools.tools.javac.comp.AttrContext;
import com.redhat.ceylon.langtools.tools.javac.comp.Env;
import com.redhat.ceylon.langtools.tools.javac.jvm.*;
import com.redhat.ceylon.langtools.tools.javac.model.*;
import com.redhat.ceylon.langtools.tools.javac.tree.JCTree;
import com.redhat.ceylon.langtools.tools.javac.util.*;
import com.redhat.ceylon.langtools.tools.javac.util.List;
import com.redhat.ceylon.langtools.tools.javac.util.Name;

/** Root class for Java symbols. It contains subclasses
 *  for specific sorts of symbols, such as variables, methods and operators,
 *  types, packages. Each subclass is represented as a static inner class
 *  inside Symbol.
 *
 *  

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. */ public abstract class Symbol implements Element { // public Throwable debug = new Throwable(); /** The kind of this symbol. * @see Kinds */ public int kind; /** The flags of this symbol. */ public long flags_field; /** An accessor method for the flags of this symbol. * Flags of class symbols should be accessed through the accessor * method to make sure that the class symbol is loaded. */ public long flags() { return flags_field; } /** The attributes of this symbol. */ public List attributes_field; /** An accessor method for the attributes of this symbol. * Attributes of class symbols should be accessed through the accessor * method to make sure that the class symbol is loaded. */ public List getAnnotationMirrors() { return Assert.checkNonNull(attributes_field); } /** Fetch a particular annotation from a symbol. */ public Attribute.Compound attribute(Symbol anno) { for (Attribute.Compound a : getAnnotationMirrors()) if (a.type.tsym == anno) return a; return null; } /** The name of this symbol in Utf8 representation. */ public Name name; /** The type of this symbol. */ public Type type; /** The owner of this symbol. */ public Symbol owner; /** The completer of this symbol. */ public Completer completer; /** A cache for the type erasure of this symbol. */ public Type erasure_field; /** Construct a symbol with given kind, flags, name, type and owner. */ public Symbol(int kind, long flags, Name name, Type type, Symbol owner) { this.kind = kind; this.flags_field = flags; this.type = type; this.owner = owner; this.completer = null; this.erasure_field = null; this.attributes_field = List.nil(); this.name = name; } /** Clone this symbol with new owner. * Legal only for fields and methods. */ public Symbol clone(Symbol newOwner) { throw new AssertionError(); } public R accept(Symbol.Visitor v, P p) { return v.visitSymbol(this, p); } /** The Java source which this symbol represents. * A description of this symbol; overrides Object. */ public String toString() { return name.toString(); } /** A Java source description of the location of this symbol; used for * error reporting. * * @return null if the symbol is a package or a toplevel class defined in * the default package; otherwise, the owner symbol is returned */ public Symbol location() { if (owner.name == null || (owner.name.isEmpty() && owner.kind != PCK && owner.kind != TYP)) { return null; } return owner; } public Symbol location(Type site, Types types) { if (owner.name == null || owner.name.isEmpty()) { return location(); } if (owner.type.tag == CLASS) { Type ownertype = types.asOuterSuper(site, owner); if (ownertype != null) return ownertype.tsym; } return owner; } // Backported by Ceylon from JDK8 public Symbol baseSymbol() { return this; } /** The symbol's erased type. */ public Type erasure(Types types) { if (erasure_field == null) erasure_field = types.erasure(type); return erasure_field; } /** The external type of a symbol. This is the symbol's erased type * except for constructors of inner classes which get the enclosing * instance class added as first argument. */ public Type externalType(Types types) { Type t = erasure(types); if (name == name.table.names.init && owner.hasOuterInstance()) { Type outerThisType = types.erasure(owner.type.getEnclosingType()); return new MethodType(t.getParameterTypes().prepend(outerThisType), t.getReturnType(), t.getThrownTypes(), t.tsym); } else { return t; } } public boolean isStatic() { return (flags() & STATIC) != 0 || (owner.flags() & INTERFACE) != 0 && kind != MTH; } public boolean isInterface() { return (flags() & INTERFACE) != 0; } /** Recognize if this symbol was marked @PolymorphicSignature in the source. */ public boolean isPolymorphicSignatureGeneric() { return (flags() & (POLYMORPHIC_SIGNATURE | HYPOTHETICAL)) == POLYMORPHIC_SIGNATURE; } /** Recognize if this symbol was split from a @PolymorphicSignature symbol in the source. */ public boolean isPolymorphicSignatureInstance() { return (flags() & (POLYMORPHIC_SIGNATURE | HYPOTHETICAL)) == (POLYMORPHIC_SIGNATURE | HYPOTHETICAL); } /** Is this symbol declared (directly or indirectly) local * to a method or variable initializer? * Also includes fields of inner classes which are in * turn local to a method or variable initializer. */ public boolean isLocal() { return (owner.kind & (VAR | MTH)) != 0 || (owner.kind == TYP && owner.isLocal()); } /** Has this symbol an empty name? This includes anonymous * inner classses. */ public boolean isAnonymous() { return name.isEmpty(); } /** Is this symbol a constructor? */ public boolean isConstructor() { return name == name.table.names.init; } /** The fully qualified name of this symbol. * This is the same as the symbol's name except for class symbols, * which are handled separately. */ public Name getQualifiedName() { return name; } /** The fully qualified name of this symbol after converting to flat * representation. This is the same as the symbol's name except for * class symbols, which are handled separately. */ public Name flatName() { return getQualifiedName(); } /** If this is a class or package, its members, otherwise null. */ public Scope members() { return null; } /** A class is an inner class if it it has an enclosing instance class. */ public boolean isInner() { return type.getEnclosingType().tag == CLASS; } /** An inner class has an outer instance if it is not an interface * it has an enclosing instance class which might be referenced from the class. * Nested classes can see instance members of their enclosing class. * Their constructors carry an additional this$n parameter, inserted * implicitly by the compiler. * * @see #isInner */ public boolean hasOuterInstance() { return type.getEnclosingType().tag == CLASS && (flags() & (INTERFACE | NOOUTERTHIS)) == 0; } /** * Returns true if this class is a member class whose direct enclosing class is not accessible, * but whose enclosing type may exist and be accessible. This is for example the case for anonymous * classes defined in this() or super() calls. Java uses NOOUTERTHIS to disable it entirely, but in * Ceylon we use CEYLON_NOOUTERTHIS to allow access to the enclosing class's container, if any. */ public boolean skipOuterClass(){ // Note: do not use flags() as that triggers complete(), which is not ready to be called // yet when we need to call this method. We make sure that the flags are set anyways, since this // is only relevant for source symbols, not compiled symbols. return (flags_field & CEYLON_NOOUTERTHIS) != 0; } /** The closest enclosing class of this symbol's declaration. */ public ClassSymbol enclClass() { Symbol c = this; while (c != null && ((c.kind & TYP) == 0 || c.type.tag != CLASS)) { c = c.owner; } return (ClassSymbol)c; } /** The outermost class which indirectly owns this symbol. */ public ClassSymbol outermostClass() { Symbol sym = this; Symbol prev = null; while (sym.kind != PCK) { prev = sym; sym = sym.owner; } return (ClassSymbol) prev; } /** The package which indirectly owns this symbol. */ public PackageSymbol packge() { Symbol sym = this; while (sym.kind != PCK) { sym = sym.owner; } return (PackageSymbol) sym; } /** Is this symbol a subclass of `base'? Only defined for ClassSymbols. */ public boolean isSubClass(Symbol base, Types types) { throw new AssertionError("isSubClass " + this); } /** Fully check membership: hierarchy, protection, and hiding. * Does not exclude methods not inherited due to overriding. */ public boolean isMemberOf(TypeSymbol clazz, Types types) { return owner == clazz || clazz.isSubClass(owner, types) && isInheritedIn(clazz, types) && !hiddenIn((ClassSymbol)clazz, types); } /** Is this symbol the same as or enclosed by the given class? */ public boolean isEnclosedBy(ClassSymbol clazz) { for (Symbol sym = this; sym.kind != PCK; sym = sym.owner) if (sym == clazz) return true; return false; } /** Check for hiding. Note that this doesn't handle multiple * (interface) inheritance. */ private boolean hiddenIn(ClassSymbol clazz, Types types) { if (kind == MTH && (flags() & STATIC) == 0) return false; while (true) { if (owner == clazz) return false; Scope.Entry e = clazz.members().lookup(name); while (e.scope != null) { if (e.sym == this) return false; if (e.sym.kind == kind && (kind != MTH || (e.sym.flags() & STATIC) != 0 && types.isSubSignature(e.sym.type, type))) return true; e = e.next(); } Type superType = types.supertype(clazz.type); if (superType.tag != TypeTags.CLASS) return false; clazz = (ClassSymbol)superType.tsym; } } /** Is this symbol inherited into a given class? * PRE: If symbol's owner is a interface, * it is already assumed that the interface is a superinterface * of given class. * @param clazz The class for which we want to establish membership. * This must be a subclass of the member's owner. */ public boolean isInheritedIn(Symbol clazz, Types types) { switch ((int)(flags_field & Flags.AccessFlags)) { default: // error recovery case PUBLIC: return true; case PRIVATE: return this.owner == clazz; case PROTECTED: // we model interfaces as extending Object return (clazz.flags() & INTERFACE) == 0; case 0: PackageSymbol thisPackage = this.packge(); for (Symbol sup = clazz; sup != null && sup != this.owner; sup = types.supertype(sup.type).tsym) { while (sup.type.tag == TYPEVAR) sup = sup.type.getUpperBound().tsym; if (sup.type.isErroneous()) return true; // error recovery if ((sup.flags() & COMPOUND) != 0) continue; if (sup.packge() != thisPackage) return false; } return (clazz.flags() & INTERFACE) == 0; } } /** The (variable or method) symbol seen as a member of given * class type`site' (this might change the symbol's type). * This is used exclusively for producing diagnostics. */ public Symbol asMemberOf(Type site, Types types) { throw new AssertionError(); } /** Does this method symbol override `other' symbol, when both are seen as * members of class `origin'? It is assumed that _other is a member * of origin. * * It is assumed that both symbols have the same name. The static * modifier is ignored for this test. * * See JLS 8.4.6.1 (without transitivity) and 8.4.6.4 */ public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean checkResult) { return false; } /** Complete the elaboration of this symbol's definition. */ public void complete() throws CompletionFailure { if (completer != null) { Completer c = completer; completer = null; c.complete(this); } } /** True if the symbol represents an entity that exists. */ public boolean exists() { return true; } public Type asType() { return type; } public Symbol getEnclosingElement() { return owner; } public ElementKind getKind() { return ElementKind.OTHER; // most unkind } public Set getModifiers() { return Flags.asModifierSet(flags()); } public Name getSimpleName() { return name; } /** * @deprecated this method should never be used by javac internally. */ @Deprecated public A getAnnotation(Class annoType) { return JavacElements.getAnnotation(this, annoType); } // TODO: getEnclosedElements should return a javac List, fix in FilteredMemberList public java.util.List getEnclosedElements() { return List.nil(); } public List getTypeParameters() { ListBuffer l = ListBuffer.lb(); for (Type t : type.getTypeArguments()) { l.append(t.tsym); } return l.toList(); } public static class DelegatedSymbol extends Symbol { protected Symbol other; public DelegatedSymbol(Symbol other) { super(other.kind, other.flags_field, other.name, other.type, other.owner); this.other = other; } public String toString() { return other.toString(); } public Symbol location() { return other.location(); } public Symbol location(Type site, Types types) { return other.location(site, types); } // Backported by Ceylon from JDK8 public Symbol baseSymbol() { return other; } public Type erasure(Types types) { return other.erasure(types); } public Type externalType(Types types) { return other.externalType(types); } public boolean isLocal() { return other.isLocal(); } public boolean isConstructor() { return other.isConstructor(); } public Name getQualifiedName() { return other.getQualifiedName(); } public Name flatName() { return other.flatName(); } public Scope members() { return other.members(); } public boolean isInner() { return other.isInner(); } public boolean hasOuterInstance() { return other.hasOuterInstance(); } public ClassSymbol enclClass() { return other.enclClass(); } public ClassSymbol outermostClass() { return other.outermostClass(); } public PackageSymbol packge() { return other.packge(); } public boolean isSubClass(Symbol base, Types types) { return other.isSubClass(base, types); } public boolean isMemberOf(TypeSymbol clazz, Types types) { return other.isMemberOf(clazz, types); } public boolean isEnclosedBy(ClassSymbol clazz) { return other.isEnclosedBy(clazz); } public boolean isInheritedIn(Symbol clazz, Types types) { return other.isInheritedIn(clazz, types); } public Symbol asMemberOf(Type site, Types types) { return other.asMemberOf(site, types); } public void complete() throws CompletionFailure { other.complete(); } public R accept(ElementVisitor v, P p) { return other.accept(v, p); } public R accept(Symbol.Visitor v, P p) { return v.visitSymbol(other, p); } } /** A class for type symbols. Type variables are represented by instances * of this class, classes and packages by instances of subclasses. */ public static class TypeSymbol extends Symbol implements TypeParameterElement { // Implements TypeParameterElement because type parameters don't // have their own TypeSymbol subclass. // TODO: type parameters should have their own TypeSymbol subclass public TypeSymbol(long flags, Name name, Type type, Symbol owner) { super(TYP, flags, name, type, owner); } /** form a fully qualified name from a name and an owner */ static public Name formFullName(Name name, Symbol owner) { if (owner == null) return name; if (((owner.kind != ERR)) && ((owner.kind & (VAR | MTH)) != 0 || (owner.kind == TYP && owner.type.tag == TYPEVAR) )) return name; Name prefix = owner.getQualifiedName(); if (prefix == null || prefix == prefix.table.names.empty) return name; else return prefix.append('.', name); } /** form a fully qualified name from a name and an owner, after * converting to flat representation */ static public Name formFlatName(Name name, Symbol owner) { if (owner == null || (owner.kind & (VAR | MTH)) != 0 || (owner.kind == TYP && owner.type.tag == TYPEVAR) ) return name; char sep = owner.kind == TYP ? '$' : '.'; Name prefix = owner.flatName(); if (prefix == null || prefix == prefix.table.names.empty) return name; else return prefix.append(sep, name); } /** * A total ordering between type symbols that refines the * class inheritance graph. * * Typevariables always precede other kinds of symbols. */ public final boolean precedes(TypeSymbol that, Types types) { if (this == that) return false; if (this.type.tag == that.type.tag) { if (this.type.tag == CLASS) { return types.rank(that.type) < types.rank(this.type) || types.rank(that.type) == types.rank(this.type) && that.getQualifiedName().compareTo(this.getQualifiedName()) < 0; } else if (this.type.tag == TYPEVAR) { return types.isSubtype(this.type, that.type); } } return this.type.tag == TYPEVAR; } // For type params; overridden in subclasses. public ElementKind getKind() { return ElementKind.TYPE_PARAMETER; } public java.util.List getEnclosedElements() { List list = List.nil(); if (kind == TYP && type.tag == TYPEVAR) { return list; } for (Scope.Entry e = members().elems; e != null; e = e.sibling) { if (e.sym != null && (e.sym.flags() & SYNTHETIC) == 0 && e.sym.owner == this) list = list.prepend(e.sym); } return list; } // For type params. // Perhaps not needed if getEnclosingElement can be spec'ed // to do the same thing. // TODO: getGenericElement() might not be needed public Symbol getGenericElement() { return owner; } public R accept(ElementVisitor v, P p) { Assert.check(type.tag == TYPEVAR); // else override will be invoked return v.visitTypeParameter(this, p); } public R accept(Symbol.Visitor v, P p) { return v.visitTypeSymbol(this, p); } public List getBounds() { TypeVar t = (TypeVar)type; Type bound = t.getUpperBound(); if (!bound.isCompound()) return List.of(bound); ClassType ct = (ClassType)bound; if (!ct.tsym.erasure_field.isInterface()) { return ct.interfaces_field.prepend(ct.supertype_field); } else { // No superclass was given in bounds. // In this case, supertype is Object, erasure is first interface. return ct.interfaces_field; } } } /** A class for package symbols */ public static class PackageSymbol extends TypeSymbol implements PackageElement { public Scope members_field; public Name fullname; public ClassSymbol package_info; // see bug 6443073 public PackageSymbol(Name name, Type type, Symbol owner) { super(0, name, type, owner); this.kind = PCK; this.members_field = null; this.fullname = formFullName(name, owner); } public PackageSymbol(Name name, Symbol owner) { this(name, null, owner); this.type = new PackageType(this); } public String toString() { return fullname.toString(); } public Name getQualifiedName() { return fullname; } public boolean isUnnamed() { return name.isEmpty() && owner != null; } public Scope members() { if (completer != null) complete(); return members_field; } public long flags() { if (completer != null) complete(); return flags_field; } public List 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; } return Assert.checkNonNull(attributes_field); } /** A package "exists" if a type or package that exists has * been seen within it. */ public boolean exists() { return (flags_field & EXISTS) != 0; } public ElementKind getKind() { return ElementKind.PACKAGE; } public Symbol getEnclosingElement() { return null; } public R accept(ElementVisitor v, P p) { return v.visitPackage(this, p); } public R accept(Symbol.Visitor v, P p) { return v.visitPackageSymbol(this, p); } } /** A class for class symbols */ public static class ClassSymbol extends TypeSymbol implements TypeElement { /** a scope for all class members; variables, methods and inner classes * type parameters are not part of this scope */ public Scope members_field; /** the fully qualified name of the class, i.e. pck.outer.inner. * null for anonymous classes */ public Name fullname; /** the fully qualified name of the class after converting to flat * representation, i.e. pck.outer$inner, * set externally for local and anonymous classes */ public Name flatname; /** the sourcefile where the class came from */ public JavaFileObject sourcefile; /** the classfile from where to load this class * this will have extension .class or .java */ public JavaFileObject classfile; /** the constant pool of the class */ public Pool pool; public ClassSymbol(long flags, Name name, Type type, Symbol owner) { super(flags, name, type, owner); this.members_field = null; this.fullname = formFullName(name, owner); this.flatname = formFlatName(name, owner); this.sourcefile = null; this.classfile = null; this.pool = null; } public ClassSymbol(long flags, Name name, Symbol owner) { this( flags, name, new ClassType(Type.noType, null, null), owner); this.type.tsym = this; } /** The Java source which this symbol represents. */ public String toString() { return className(); } public long flags() { if (completer != null) complete(); return flags_field; } public Scope members() { if (completer != null) complete(); return members_field; } public List getAnnotationMirrors() { if (completer != null) complete(); return Assert.checkNonNull(attributes_field); } public Type erasure(Types types) { if (erasure_field == null) erasure_field = new ClassType(types.erasure(type.getEnclosingType()), List.nil(), this); return erasure_field; } public String className() { if (name.isEmpty()) return Log.getLocalizedString("anonymous.class", flatname); else return fullname.toString(); } public Name getQualifiedName() { return fullname; } public Name flatName() { return flatname; } public boolean isSubClass(Symbol base, Types types) { if (this == base) { return true; } else if ((base.flags() & INTERFACE) != 0) { for (Type t = type; t.tag == CLASS; t = types.supertype(t)) for (List is = types.interfaces(t); is.nonEmpty(); is = is.tail) if (is.head.tsym.isSubClass(base, types)) return true; } else { for (Type t = type; t.tag == CLASS; t = types.supertype(t)) if (t.tsym == base) return true; } return false; } /** Complete the elaboration of this symbol's definition. */ public void complete() throws CompletionFailure { try { super.complete(); } catch (CompletionFailure ex) { // quiet error recovery flags_field |= (PUBLIC|STATIC); this.type = new ErrorType(this, Type.noType); throw ex; } } public List getInterfaces() { complete(); if (type instanceof ClassType) { ClassType t = (ClassType)type; if (t.interfaces_field == null) // FIXME: shouldn't be null t.interfaces_field = List.nil(); if (t.all_interfaces_field != null) return Type.getModelTypes(t.all_interfaces_field); return t.interfaces_field; } else { return List.nil(); } } public Type getSuperclass() { complete(); if (type instanceof ClassType) { ClassType t = (ClassType)type; if (t.supertype_field == null) // FIXME: shouldn't be null t.supertype_field = Type.noType; // An interface has no superclass; its supertype is Object. return t.isInterface() ? Type.noType : t.supertype_field.getModelType(); } else { return Type.noType; } } public ElementKind getKind() { long flags = flags(); if ((flags & ANNOTATION) != 0) return ElementKind.ANNOTATION_TYPE; else if ((flags & INTERFACE) != 0) return ElementKind.INTERFACE; else if ((flags & ENUM) != 0) return ElementKind.ENUM; else return ElementKind.CLASS; } public NestingKind getNestingKind() { complete(); if (owner.kind == PCK) return NestingKind.TOP_LEVEL; else if (name.isEmpty()) return NestingKind.ANONYMOUS; else if (owner.kind == MTH) return NestingKind.LOCAL; else return NestingKind.MEMBER; } /** * @deprecated this method should never be used by javac internally. */ @Override @Deprecated public A getAnnotation(Class annoType) { return JavacElements.getAnnotation(this, annoType); } public R accept(ElementVisitor v, P p) { return v.visitType(this, p); } public R accept(Symbol.Visitor v, P p) { return v.visitClassSymbol(this, p); } } /** A class for variable symbols */ public static class VarSymbol extends Symbol implements VariableElement { /** The variable's declaration position. */ public int pos = Position.NOPOS; /** The variable's address. Used for different purposes during * flow analysis, translation and code generation. * Flow analysis: * If this is a blank final or local variable, its sequence number. * Translation: * If this is a private field, its access number. * Code generation: * If this is a local variable, its logical slot number. */ public int adr = -1; /** Construct a variable symbol, given its flags, name, type and owner. */ public VarSymbol(long flags, Name name, Type type, Symbol owner) { super(VAR, flags, name, type, owner); } /** Clone this symbol with new owner. */ public VarSymbol clone(Symbol newOwner) { VarSymbol v = new VarSymbol(flags_field, name, type, newOwner) { // Backported by Ceylon from JDK8 @Override public Symbol baseSymbol() { return VarSymbol.this; } }; v.pos = pos; v.adr = adr; v.data = data; // System.out.println("clone " + v + " in " + newOwner);//DEBUG return v; } public String toString() { return name.toString(); } public Symbol asMemberOf(Type site, Types types) { return new VarSymbol(flags_field, name, types.memberType(site, this), owner); } public ElementKind getKind() { long flags = flags(); if ((flags & PARAMETER) != 0) { if (isExceptionParameter()) return ElementKind.EXCEPTION_PARAMETER; else return ElementKind.PARAMETER; } else if ((flags & ENUM) != 0) { return ElementKind.ENUM_CONSTANT; } else if (owner.kind == TYP || owner.kind == ERR) { return ElementKind.FIELD; } else if (isResourceVariable()) { return ElementKind.RESOURCE_VARIABLE; } else { return ElementKind.LOCAL_VARIABLE; } } public R accept(ElementVisitor v, P p) { return v.visitVariable(this, p); } public Object getConstantValue() { // Mirror API return Constants.decode(getConstValue(), type); } public void setLazyConstValue(final Env env, final Attr attr, final JCTree.JCExpression initializer) { setData(new Callable() { public Object call() { return attr.attribLazyConstantValue(env, initializer, type); } }); } /** * The variable's constant value, if this is a constant. * Before the constant value is evaluated, it points to an * initalizer environment. If this is not a constant, it can * be used for other stuff. */ private Object data; public boolean isExceptionParameter() { return data == ElementKind.EXCEPTION_PARAMETER; } public boolean isResourceVariable() { return data == ElementKind.RESOURCE_VARIABLE; } public Object getConstValue() { // TODO: Consider if getConstValue and getConstantValue can be collapsed if (data == ElementKind.EXCEPTION_PARAMETER || data == ElementKind.RESOURCE_VARIABLE) { return null; } else if (data instanceof Callable) { // In this case, this is a final variable, with an as // yet unevaluated initializer. Callable eval = (Callable)data; data = null; // to make sure we don't evaluate this twice. try { data = eval.call(); } catch (Exception ex) { throw new AssertionError(ex); } } return data; } public void setData(Object data) { Assert.check(!(data instanceof Env), this); this.data = data; } public R accept(Symbol.Visitor v, P p) { return v.visitVarSymbol(this, p); } } /** A class for method symbols. */ public static class MethodSymbol extends Symbol implements ExecutableElement { /** The code of the method. */ public Code code = null; /** The parameters of the method. */ public List params = null; /** The names of the parameters */ public List savedParameterNames; /** For an attribute field accessor, its default value if any. * The value is null if none appeared in the method * declaration. */ public Attribute defaultValue = null; /** Construct a method symbol, given its flags, name, type and owner. */ public MethodSymbol(long flags, Name name, Type type, Symbol owner) { super(MTH, flags, name, type, owner); if (owner.type.tag == TYPEVAR) Assert.error(owner + "." + name); } /** Clone this symbol with new owner. */ public MethodSymbol clone(Symbol newOwner) { MethodSymbol m = new MethodSymbol(flags_field, name, type, newOwner) { // Backported by Ceylon from JDK8 @Override public Symbol baseSymbol() { return MethodSymbol.this; } }; m.code = code; return m; } /** The Java source which this symbol represents. */ public String toString() { if ((flags() & BLOCK) != 0) { return owner.name.toString(); } else { String s = (name == name.table.names.init) ? owner.name.toString() : name.toString(); if (type != null) { if (type.tag == FORALL) s = "<" + ((ForAll)type).getTypeArguments() + ">" + s; s += "(" + type.argtypes((flags() & VARARGS) != 0) + ")"; } return s; } } // Backported by Ceylon from JDK8 public boolean isDynamic() { return false; } /** find a symbol that this (proxy method) symbol implements. * @param c The class whose members are searched for * implementations */ public Symbol implemented(TypeSymbol c, Types types) { Symbol impl = null; for (List is = types.interfaces(c.type); impl == null && is.nonEmpty(); is = is.tail) { TypeSymbol i = is.head.tsym; impl = implementedIn(i, types); if (impl == null) impl = implemented(i, types); } return impl; } public Symbol implementedIn(TypeSymbol c, Types types) { Symbol impl = null; for (Scope.Entry e = c.members().lookup(name); impl == null && e.scope != null; e = e.next()) { if (this.overrides(e.sym, (TypeSymbol)owner, types, true)/* && // Ceylon (Stef): I disabled this because it failed to notice that " T[] toArray(T[] ret)" would be implementing // " T[] Collection.toArray(T[] ret)", and because this.overrides has the last parameter set to "true", which means // the return type is already checked and agrees with covariance and type parameter substitution, which types.isSameType // does not do // FIXME: I suspect the following requires a // subst() for a parametric return type. types.isSameType(type.getReturnType(), types.memberType(owner.type, e.sym).getReturnType())*/) { impl = e.sym; } } return impl; } /** Will the erasure of this method be considered by the VM to * override the erasure of the other when seen from class `origin'? */ public boolean binaryOverrides(Symbol _other, TypeSymbol origin, Types types) { if (isConstructor() || _other.kind != MTH) return false; if (this == _other) return true; MethodSymbol other = (MethodSymbol)_other; // check for a direct implementation if (other.isOverridableIn((TypeSymbol)owner) && types.asSuper(owner.type, other.owner) != null && types.isSameType(erasure(types), other.erasure(types))) return true; // check for an inherited implementation return (flags() & ABSTRACT) == 0 && other.isOverridableIn(origin) && this.isMemberOf(origin, types) && types.isSameType(erasure(types), other.erasure(types)); } /** The implementation of this (abstract) symbol in class origin, * from the VM's point of view, null if method does not have an * implementation in class. * @param origin The class of which the implementation is a member. */ public MethodSymbol binaryImplementation(ClassSymbol origin, Types types) { for (TypeSymbol c = origin; c != null; c = types.supertype(c.type).tsym) { for (Scope.Entry e = c.members().lookup(name); e.scope != null; e = e.next()) { if (e.sym.kind == MTH && ((MethodSymbol)e.sym).binaryOverrides(this, origin, types)) return (MethodSymbol)e.sym; } } return null; } /** Does this symbol override `other' symbol, when both are seen as * members of class `origin'? It is assumed that _other is a member * of origin. * * It is assumed that both symbols have the same name. The static * modifier is ignored for this test. * * See JLS 8.4.6.1 (without transitivity) and 8.4.6.4 */ public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean checkResult) { if (isConstructor() || _other.kind != MTH) return false; if (this == _other) return true; MethodSymbol other = (MethodSymbol)_other; // check for a direct implementation if (other.isOverridableIn((TypeSymbol)owner) && types.asSuper(owner.type, other.owner) != null) { Type mt = types.memberType(owner.type, this); Type ot = types.memberType(owner.type, other); if (types.isSubSignature(mt, ot)) { if (!checkResult || (flags() & CEYLON_METHOD_OVERRIDE_CHECKED) != 0) return true; if (types.returnTypeSubstitutable(mt, ot)) return true; } } // check for an inherited implementation if ((flags() & ABSTRACT) != 0 || (other.flags() & ABSTRACT) == 0 || !other.isOverridableIn(origin) || !this.isMemberOf(origin, types)) return false; // assert types.asSuper(origin.type, other.owner) != null; Type mt = types.memberType(origin.type, this); Type ot = types.memberType(origin.type, other); return types.isSubSignature(mt, ot) && (!checkResult || types.resultSubtype(mt, ot, Warner.noWarnings)); } private boolean isOverridableIn(TypeSymbol origin) { // JLS 8.4.6.1 switch ((int)(flags_field & Flags.AccessFlags)) { case Flags.PRIVATE: return false; case Flags.PUBLIC: return true; case Flags.PROTECTED: return (origin.flags() & INTERFACE) == 0; case 0: // for package private: can only override in the same // package return this.packge() == origin.packge() && (origin.flags() & INTERFACE) == 0; default: return false; } } /** The implementation of this (abstract) symbol in class origin; * null if none exists. Synthetic methods are not considered * as possible implementations. */ public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult) { return implementation(origin, types, checkResult, implementation_filter); } // where private static final Filter implementation_filter = new Filter() { public boolean accepts(Symbol s) { return s.kind == Kinds.MTH && (s.flags() & SYNTHETIC) == 0; } }; public MethodSymbol implementation(TypeSymbol origin, Types types, boolean checkResult, Filter implFilter) { MethodSymbol res = types.implementation(this, origin, checkResult, implFilter); if (res != null) return res; // if origin is derived from a raw type, we might have missed // an implementation because we do not know enough about instantiations. // in this case continue with the supertype as origin. if (types.isDerivedRaw(origin.type)) return implementation(types.supertype(origin.type).tsym, types, checkResult); else return null; } public List params() { owner.complete(); if (params == null) { // If ClassReader.saveParameterNames has been set true, then // savedParameterNames will be set to a list of names that // matches the types in type.getParameterTypes(). If any names // were not found in the class file, those names in the list will // be set to the empty name. // If ClassReader.saveParameterNames has been set false, then // savedParameterNames will be null. List paramNames = savedParameterNames; savedParameterNames = null; // discard the provided names if the list of names is the wrong size. if (paramNames == null || paramNames.size() != type.getParameterTypes().size()) paramNames = List.nil(); ListBuffer buf = new ListBuffer(); List remaining = paramNames; // assert: remaining and paramNames are both empty or both // have same cardinality as type.getParameterTypes() int i = 0; for (Type t : type.getParameterTypes()) { Name paramName; if (remaining.isEmpty()) { // no names for any parameters available paramName = createArgName(i, paramNames); } else { paramName = remaining.head; remaining = remaining.tail; if (paramName.isEmpty()) { // no name for this specific parameter paramName = createArgName(i, paramNames); } } buf.append(new VarSymbol(PARAMETER, paramName, t, this)); i++; } params = buf.toList(); } return params; } // Create a name for the argument at position 'index' that is not in // the exclude list. In normal use, either no names will have been // provided, in which case the exclude list is empty, or all the names // will have been provided, in which case this method will not be called. private Name createArgName(int index, List exclude) { String prefix = "arg"; while (true) { Name argName = name.table.fromString(prefix + index); if (!exclude.contains(argName)) return argName; prefix += "$"; } } public Symbol asMemberOf(Type site, Types types) { return new MethodSymbol(flags_field, name, types.memberType(site, this), owner); } public ElementKind getKind() { if (name == name.table.names.init) return ElementKind.CONSTRUCTOR; else if (name == name.table.names.clinit) return ElementKind.STATIC_INIT; else return ElementKind.METHOD; } public Attribute getDefaultValue() { return defaultValue; } public List getParameters() { return params(); } public boolean isVarArgs() { return (flags() & VARARGS) != 0; } public R accept(ElementVisitor v, P p) { return v.visitExecutable(this, p); } public R accept(Symbol.Visitor v, P p) { return v.visitMethodSymbol(this, p); } public Type getReturnType() { return asType().getReturnType(); } public List getThrownTypes() { return asType().getThrownTypes(); } } // Backported by Ceylon from JDK8 /** A class for invokedynamic method calls. */ public static class DynamicMethodSymbol extends MethodSymbol { public Object[] staticArgs; public Symbol bsm; public int bsmKind; public DynamicMethodSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) { super(0, name, type, owner); this.bsm = bsm; this.bsmKind = bsmKind; this.staticArgs = staticArgs; } @Override public boolean isDynamic() { return true; } } /** A class for predefined operators. */ public static class OperatorSymbol extends MethodSymbol { public int opcode; public OperatorSymbol(Name name, Type type, int opcode, Symbol owner) { super(PUBLIC | STATIC, name, type, owner); this.opcode = opcode; } public R accept(Symbol.Visitor v, P p) { return v.visitOperatorSymbol(this, p); } } /** Symbol completer interface. */ public static interface Completer { void complete(Symbol sym) throws CompletionFailure; } public static class CompletionFailure extends RuntimeException { private static final long serialVersionUID = 0; public Symbol sym; /** A diagnostic object describing the failure */ public JCDiagnostic diag; /** A localized string describing the failure. * @deprecated Use {@code getDetail()} or {@code getMessage()} */ @Deprecated public String errmsg; public CompletionFailure(Symbol sym, String errmsg) { this.sym = sym; this.errmsg = errmsg; // this.printStackTrace();//DEBUG } public CompletionFailure(Symbol sym, JCDiagnostic diag) { this.sym = sym; this.diag = diag; // this.printStackTrace();//DEBUG } public JCDiagnostic getDiagnostic() { return diag; } @Override public String getMessage() { if (diag != null) return diag.getMessage(null); else return errmsg; } public Object getDetailValue() { return (diag != null ? diag : errmsg); } @Override public CompletionFailure initCause(Throwable cause) { super.initCause(cause); return this; } } /** * A visitor for symbols. A visitor is used to implement operations * (or relations) on symbols. Most common operations on types are * binary relations and this interface is designed for binary * relations, that is, operations on the form * Symbol × P → R. * * * @param the return type of the operation implemented by this * visitor; use Void if no return type is needed. * @param

the type of the second argument (the first being the * symbol itself) of the operation implemented by this visitor; use * Void if a second argument is not needed. */ public interface Visitor { R visitClassSymbol(ClassSymbol s, P arg); R visitMethodSymbol(MethodSymbol s, P arg); R visitPackageSymbol(PackageSymbol s, P arg); R visitOperatorSymbol(OperatorSymbol s, P arg); R visitVarSymbol(VarSymbol s, P arg); R visitTypeSymbol(TypeSymbol s, P arg); R visitSymbol(Symbol s, P arg); } }