/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.dev.jjs.ast; import com.google.gwt.dev.javac.JsInteropUtil; import com.google.gwt.dev.jjs.SourceInfo; import com.google.gwt.dev.jjs.SourceOrigin; import com.google.gwt.dev.util.StringInterner; import java.io.Serializable; /** * Java field definition. */ public class JField extends JVariable implements JMember { /** * Determines whether the variable is final, volatile, or neither. */ public enum Disposition { COMPILE_TIME_CONSTANT, FINAL, NONE, THIS_REF, VOLATILE; public boolean isFinal() { return this == COMPILE_TIME_CONSTANT || this == FINAL || this == THIS_REF; } public boolean isThisRef() { return this == THIS_REF; } private boolean isCompileTimeConstant() { return this == COMPILE_TIME_CONSTANT; } private boolean isVolatile() { return this == VOLATILE; } } private static class ExternalSerializedForm implements Serializable { private final JDeclaredType enclosingType; private final String signature; public ExternalSerializedForm(JField field) { enclosingType = field.getEnclosingType(); signature = field.getSignature(); } private Object readResolve() { String name = StringInterner.get().intern(signature.substring(0, signature.indexOf(':'))); JField result = new JField(SourceOrigin.UNKNOWN, name, enclosingType, JReferenceType.NULL_TYPE, false, Disposition.NONE); result.signature = signature; return result; } } private static class ExternalSerializedNullField implements Serializable { public static final ExternalSerializedNullField INSTANCE = new ExternalSerializedNullField(); private Object readResolve() { return NULL_FIELD; } } public static final JField NULL_FIELD = new JField(SourceOrigin.UNKNOWN, "nullField", JClassType.NULL_CLASS, JReferenceType.NULL_TYPE, false, Disposition.FINAL); private JsMemberType jsMembertype = JsMemberType.NONE; private String jsName; private String jsNamespace; private boolean exported; private boolean isJsOverlay = false; private final JDeclaredType enclosingType; private final boolean isCompileTimeConstant; private final boolean isStatic; private final boolean isThisRef; private boolean isVolatile; private transient String signature; /** * The access modifier; stored as an int to reduce memory / serialization footprint. */ private final int access; public JField(SourceInfo info, String name, JDeclaredType enclosingType, JType type, boolean isStatic, Disposition disposition, AccessModifier access) { super(info, name, type, disposition.isFinal()); this.enclosingType = enclosingType; this.isStatic = isStatic; this.isCompileTimeConstant = disposition.isCompileTimeConstant(); this.isVolatile = disposition.isVolatile(); this.isThisRef = disposition.isThisRef(); this.access = access.ordinal(); // Disposition is not cached because we can be set final later. } public JField(SourceInfo info, String name, JDeclaredType enclosingType, JType type, boolean isStatic, Disposition disposition) { this(info, name, enclosingType, type, isStatic, disposition, AccessModifier.DEFAULT); } @Override public String getQualifiedName() { return getEnclosingType().getName() + "." + getName(); } @Override public JDeclaredType getEnclosingType() { return enclosingType; } public JValueLiteral getLiteralInitializer() { JExpression initializer = getInitializer(); if (initializer instanceof JValueLiteral) { return (JValueLiteral) initializer; } return null; } @Override public JFieldRef makeRef(SourceInfo info) { throw new UnsupportedOperationException(); } @Override public void setJsMemberInfo( JsMemberType jsMembertype, String namespace, String name, boolean exported) { this.jsMembertype = jsMembertype; this.jsName = name != null ? name : jsMembertype.computeName(this); this.jsNamespace = namespace; this.exported = exported; } @Override public void setJsOverlay() { isJsOverlay = true; } @Override public JsMemberType getJsMemberType() { return jsMembertype; } @Override public boolean isJsInteropEntryPoint() { return exported && isStatic() && !isJsNative() && !isJsOverlay(); } @Override public boolean canBeReferencedExternally() { return exported && !isJsNative(); } @Override public boolean canBeImplementedExternally() { return isJsNative(); } @Override public String getJsNamespace() { return jsNamespace == null ? enclosingType.getQualifiedJsName() : jsNamespace; } @Override public String getQualifiedJsName() { String namespace = getJsNamespace(); return JsInteropUtil.isGlobal(namespace) ? jsName : namespace + "." + jsName; } @Override public boolean isAbstract() { return false; } @Override public boolean isJsNative() { return !isJsOverlay() && enclosingType.isJsNative(); } @Override public boolean isJsOverlay() { return isJsOverlay; } @Override public boolean isJsMethodVarargs() { return false; } @Override public String getJsName() { return jsName; } public String getSignature() { if (signature == null) { StringBuilder sb = new StringBuilder(); sb.append(getName()); sb.append(':'); sb.append(getType().getJsniSignatureName()); signature = sb.toString(); } return signature; } public boolean isCompileTimeConstant() { return isCompileTimeConstant; } @Override public boolean isExternal() { return getEnclosingType().isExternal(); } @Override public boolean isPublic() { return access == AccessModifier.PUBLIC.ordinal(); } @Override public boolean isPrivate() { return access == AccessModifier.PRIVATE.ordinal(); } @Override public boolean needsDynamicDispatch() { return !isStatic; } @Override public boolean isStatic() { return isStatic; } @Override public boolean isSynthetic() { return false; } public boolean isThisRef() { return isThisRef; } public boolean isVolatile() { return isVolatile; } @Override public void setFinal() { if (isVolatile()) { throw new IllegalStateException("Volatile fields cannot be set final"); } super.setFinal(); } @Override public void setInitializer(JDeclarationStatement declStmt) { this.declStmt = declStmt; } @Override public void traverse(JVisitor visitor, Context ctx) { if (visitor.visit(this, ctx)) { // Do not visit declStmt, it gets visited within its own code block. } visitor.endVisit(this, ctx); } protected Object writeReplace() { if (isExternal()) { return new ExternalSerializedForm(this); } else if (this == NULL_FIELD) { return ExternalSerializedNullField.INSTANCE; } else { return this; } } boolean replaces(JField originalField) { if (this == originalField) { return true; } return originalField.isExternal() && originalField.getSignature().equals(this.getSignature()) && this.getEnclosingType().replaces(originalField.getEnclosingType()); } }