| /* |
| * 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()); |
| } |
| } |