/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.visage.tools.code;
import com.sun.tools.mjavac.code.Kinds;
import org.visage.tools.code.VisageClassSymbol;
import com.sun.tools.mjavac.code.Symbol;
import com.sun.tools.mjavac.code.Symbol.VarSymbol;
import com.sun.tools.mjavac.code.Type;
import com.sun.tools.mjavac.util.List;
import com.sun.tools.mjavac.util.Name;
import static com.sun.tools.mjavac.code.Flags.*;
import static org.visage.tools.code.VisageFlags.*;
/**
* Class to hold and access variable information.
*
* @author Robert Field
*/
public class VisageVarSymbol extends VarSymbol {
private VisageTypeRepresentation typeRepresentation;
private Type elementType = null;
private static int IS_DOT_CLASS = 0x0001;
private static int IS_EXTERNALLY_SEEN = 0x0002;
private static int USED_IN_SIZEOF = 0x0004;
private static int USED_OUTSIDE_SIZEOF = 0x0008;
private static int HAS_VAR_INIT = 0x0010;
private int extraFlags;
private int varIndex = -1;
private Type lastSeenType;
private final VisageTypes types;
private List<Symbol> overridingClasses = List.nil();
/****
private boolean isForwardReferenced = false;
private boolean hasForwardReferencesInInit = false;
****/
/** Construct a variable symbol, given its flags, name, type and owner.
*/
public VisageVarSymbol(VisageTypes types, Name.Table names, long flags, Name name, Type type, Symbol owner) {
super(flags, name, type, owner);
this.types = types;
if (name == names._class)
extraFlags |= IS_DOT_CLASS;
}
public boolean hasVarInit() {
return (extraFlags & HAS_VAR_INIT) != 0;
}
public void setHasVarInit() {
extraFlags |= HAS_VAR_INIT;
}
private void syncType() {
if (lastSeenType != type) {
typeRepresentation = types.typeRep(type);
switch (typeRepresentation) {
case TYPE_REPRESENTATION_SEQUENCE:
elementType = types.elementType(type);
break;
case TYPE_REPRESENTATION_OBJECT:
elementType = type;
break;
default:
elementType = null;
break;
}
lastSeenType = type;
}
}
public boolean isMember() {
return owner.kind == Kinds.TYP && (extraFlags & IS_DOT_CLASS) == 0;
}
public boolean isVisageMember() {
return isMember() && types.isVisageClass(owner);
}
public boolean isSequence() {
syncType();
return typeRepresentation.isSequence();
}
public Type getElementType() {
syncType();
return elementType;
}
public VisageTypeRepresentation getTypeRepresentation() {
syncType();
return typeRepresentation;
}
public long instanceVarAccessFlags() {
return flags_field & VisageAllInstanceVarFlags;
}
public boolean hasScriptOnlyAccess() {
long access = instanceVarAccessFlags();
return access == SCRIPT_PRIVATE || access == PRIVATE;
}
public boolean isSpecial() {
return (flags_field & VisageFlags.VARUSE_SPECIAL) != 0;
}
public boolean isSynthetic() {
return (flags_field & SYNTHETIC) != 0;
}
public boolean isBindAccess() {
return (flags_field & VisageFlags.VARUSE_BIND_ACCESS) != 0;
}
public boolean isInitializedInObjectLiteral() {
return (flags_field & VisageFlags.VARUSE_OBJ_LIT_INIT) != 0;
}
public boolean isInMixin() {
return (owner.flags_field & MIXIN) != 0;
}
public boolean isReferenced() {
return (flags_field & VisageFlags.VARUSE_VARREF) != 0;
}
public boolean isInScriptingModeScript() {
return owner instanceof VisageClassSymbol &&
((VisageClassSymbol) owner).isScriptingModeScript();
}
public boolean isDefault() {
return (flags_field & DEFAULT) != 0;
}
private boolean accessorsRequired() {
return (flags_field & (VARUSE_NEED_ACCESSOR | VARUSE_VARREF)) != 0;
}
public boolean useAccessors() {
return
isVisageMember() &&
!isSpecial() &&
( !hasScriptOnlyAccess() ||
isInMixin() ||
accessorsRequired() ||
isInScriptingModeScript() ||
( isBindAccess() &&
isAssignedTo()
)
);
}
public boolean needsEnumeration() {
return useAccessors() ||
useGetters() ||
hasVarInit() ||
isExternallySeen() ||
isInitializedInObjectLiteral();
}
public boolean hasFlags() {
return needsEnumeration();
}
public boolean useGetters() {
return !isSpecial() && (useAccessors() || (flags_field & VARUSE_NON_LITERAL) != 0);
}
public boolean useSetters() {
return
isVisageMember() &&
!isSpecial() &&
( !hasScriptOnlyAccess() ||
isInMixin() ||
isReferenced() ||
( (isAssignedTo() || isInitializedInObjectLiteral()) &&
accessorsRequired()
)
);
}
/** Either has a trigger or a sub-class may have a trigger. */
public boolean useReplaceTrigger() {
return ! hasScriptOnlyAccess() || (flags_field & VARUSE_HAS_REPLACE_TRIGGER) != 0;
}
// Predicate for def (constant) var.
public boolean isDef() {
return (flags_field & IS_DEF) != 0;
}
public boolean isParameter() {
return (flags_field & PARAMETER) != 0;
}
public void setIsExternallySeen() {
extraFlags |= IS_EXTERNALLY_SEEN;
}
public boolean isExternallySeen() {
return (extraFlags & IS_EXTERNALLY_SEEN) != 0;
}
public boolean isUsedInSizeof() {
return (extraFlags & USED_IN_SIZEOF) != 0;
}
public boolean isUsedOutsideSizeof() {
return (extraFlags & USED_OUTSIDE_SIZEOF) != 0;
}
public void clearUsedOutsideSizeof() {
extraFlags &= ~USED_OUTSIDE_SIZEOF;
}
public void setUsedInSizeof() {
extraFlags |= USED_IN_SIZEOF;
}
public void setUsedOutsideSizeof() {
extraFlags |= USED_OUTSIDE_SIZEOF;
}
// Predicate for self-reference in init.
public boolean hasSelfReference() {
return (flags_field & VARUSE_SELF_REFERENCE) != 0;
}
/****
public void setIsForwardReferenced() {
isForwardReferenced = true;
}
public boolean isForwardReferenced() {
return isForwardReferenced;
}
***/
public boolean hasForwardReference() {
return (flags_field & VARUSE_FORWARD_REFERENCE) != 0;
}
public boolean isAssignedTo() {
return (flags_field & VARUSE_ASSIGNED_TO) != 0;
}
public boolean isDefinedBound() {
//TODO: this bit, it would appear, is not see for shreds
return (flags_field & VARUSE_BOUND_INIT) != 0;
}
public boolean isWritableOutsideScript() {
return !isDef() && (flags_field & (PUBLIC | PROTECTED | PACKAGE_ACCESS)) != 0;
}
public boolean isMutatedWithinScript() {
return (flags_field & (VARUSE_ASSIGNED_TO | VARUSE_SELF_REFERENCE | VARUSE_FORWARD_REFERENCE)) != 0L;
}
public boolean canChange() {
return isWritableOutsideScript() || isMutatedWithinScript() || isDefinedBound();
}
public boolean isMutatedLocal() {
return !isMember() && isMutatedWithinScript();
}
public int getVarIndex() {
return varIndex;
}
public void setVarIndex(int varIndex) {
this.varIndex = varIndex;
}
public int getAbsoluteIndex(Type site) {
types.supertypesClosure(site);
return isLocal() || isStatic() ?
getVarIndex() :
getVarIndex() + baseIndex((TypeSymbol)owner, site);
}
//where
private int baseIndex(TypeSymbol tsym, Type site) {
List<Type> closure = types.supertypesClosure(site, false, true);
int baseIdx = 0;
for (Type t : closure) {
if (types.isSameType(t, tsym.type)) break;
baseIdx += ((VisageClassSymbol)t.tsym).getMemberVarCount();
}
return baseIdx;
}
public void addOverridingClass(Symbol s) {
overridingClasses = overridingClasses.append(s);
}
public boolean isOverridenIn(Symbol s) {
return overridingClasses.contains(s);
}
}