blob: 0f67ea16331d4975c9f45f92ad278fd592d108d3 [file] [log] [blame]
/*
* Copyright 2010 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.jjs.SourceInfo;
import com.google.gwt.dev.jjs.SourceOrigin;
import java.io.Serializable;
import java.util.List;
/**
* A Java constructor method.
*/
public class JConstructor extends JMethod {
private static class ExternalSerializedForm implements Serializable {
private final JClassType enclosingType;
private final String signature;
public ExternalSerializedForm(JConstructor ctor) {
enclosingType = ctor.getEnclosingType();
signature = ctor.getSignature();
}
private Object readResolve() {
JConstructor result = new JConstructor(SourceOrigin.UNKNOWN, enclosingType);
result.signature = signature;
return result;
}
}
/**
* Caches whether or not this constructor does any work. Once true, we never
* have to recheck, but we keep rechecking as long as it's false.
*/
private boolean isEmpty = false;
public JConstructor(SourceInfo info, JClassType enclosingType) {
super(info, enclosingType.getShortName(), enclosingType, JPrimitiveType.VOID, false, false,
true, false);
}
@Override
public boolean canBePolymorphic() {
return false;
}
@Override
public JMethodBody getBody() {
return (JMethodBody) super.getBody();
}
@Override
public JClassType getEnclosingType() {
return (JClassType) super.getEnclosingType();
}
public JNonNullType getNewType() {
return getEnclosingType().getNonNull();
}
/**
* Returns <code>true</code> if this constructor does no real work.
*
* NOTE: this method does NOT account for any clinits that would be triggered
* if this constructor is the target of a new instance operation from an
* external class.
*
* TODO(scottb): make this method less expensive by computing in an external
* visitor.
*/
public boolean isEmpty() {
if (isEmpty) {
return true;
}
JMethodBody body = getBody();
List<JStatement> statements = body.getStatements();
if (statements.isEmpty()) {
return (isEmpty = true);
}
if (statements.size() > 1) {
return false;
}
// Only one statement. Check to see if it's an empty super() or this() call.
JStatement stmt = statements.get(0);
if (stmt instanceof JExpressionStatement) {
JExpressionStatement exprStmt = (JExpressionStatement) stmt;
JExpression expr = exprStmt.getExpr();
if (expr instanceof JMethodCall && !(expr instanceof JNewInstance)) {
JMethodCall call = (JMethodCall) expr;
JMethod target = call.getTarget();
if (target instanceof JConstructor) {
return isEmpty = ((JConstructor) target).isEmpty();
}
}
}
return false;
}
@Override
public boolean needsVtable() {
return false;
}
@Override
public void traverse(JVisitor visitor, Context ctx) {
String before = traceBefore(visitor);
if (visitor.visit(this, ctx)) {
visitChildren(visitor);
}
visitor.endVisit(this, ctx);
traceAfter(visitor, before);
}
@Override
protected Object writeReplace() {
if (isExternal()) {
return new ExternalSerializedForm(this);
} else {
return this;
}
}
}