blob: b2ec0d04330162921e9386183d5c5c8aea525bdf [file] [log] [blame]
/*
* 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());
}
}