blob: 6af0dc4b51b5abbec6f5794ce574f3976758ce69 [file] [log] [blame]
/*
* Copyright 2014 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.impl;
import com.google.gwt.dev.MinimalRebuildCache;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JArrayType;
import com.google.gwt.dev.jjs.ast.JCastOperation;
import com.google.gwt.dev.jjs.ast.JClassLiteral;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JFieldRef;
import com.google.gwt.dev.jjs.ast.JInstanceOf;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodCall;
import com.google.gwt.dev.jjs.ast.JNewInstance;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JType;
import com.google.gwt.dev.jjs.ast.JValueLiteral;
import com.google.gwt.dev.jjs.ast.JVariable;
import com.google.gwt.dev.jjs.ast.JVisitor;
import com.google.gwt.dev.jjs.ast.js.JsniFieldRef;
import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
import java.util.List;
/**
* Records Type->Type references.
*/
public class TypeReferencesRecorder extends JVisitor {
public static void exec(JProgram program, MinimalRebuildCache minimalRebuildCache,
boolean onlyUpdate) {
new TypeReferencesRecorder(minimalRebuildCache, onlyUpdate).execImpl(program);
}
private String fromTypeName;
private final MinimalRebuildCache minimalRebuildCache;
private final boolean onlyUpdate;
public TypeReferencesRecorder(MinimalRebuildCache minimalRebuildCache, boolean onlyUpdate) {
this.onlyUpdate = onlyUpdate;
this.minimalRebuildCache = minimalRebuildCache;
}
@Override
public void endVisit(JCastOperation x, Context ctx) {
// Gather (Foo) casts.
maybeRecordTypeRef(x.getCastType());
super.endVisit(x, ctx);
}
@Override
public void endVisit(JClassLiteral x, Context ctx) {
// Gather Foo.class literal references.
maybeRecordTypeRef(x.getRefType());
super.endVisit(x, ctx);
}
@Override
public void endVisit(JFieldRef x, Context ctx) {
// Gather Foo.someField static references.
processJFieldRef(x);
super.endVisit(x, ctx);
}
@Override
public void endVisit(JInstanceOf x, Context ctx) {
// Gather instanceof Foo references.
maybeRecordTypeRef(x.getTestType());
super.endVisit(x, ctx);
}
@Override
public void endVisit(JMethod x, Context ctx) {
// Gather return types of method definitions.
maybeRecordTypeRef(x.getType());
super.endVisit(x, ctx);
}
@Override
public void endVisit(JMethodCall x, Context ctx) {
// Gather Foo.doSomething() static method calls.
processMethodCall(x);
super.endVisit(x, ctx);
}
@Override
public void endVisit(JNewInstance x, Context ctx) {
// Gather the type when new objects are created.
JClassType enclosingType = x.getTarget().getEnclosingType();
maybeRecordTypeRef(enclosingType);
super.endVisit(x, ctx);
}
@Override
public void endVisit(JsniFieldRef x, Context ctx) {
// Gather Foo.someField static references.
processJFieldRef(x);
super.endVisit(x, ctx);
}
@Override
public void endVisit(JsniMethodRef x, Context ctx) {
// Gather Foo.doSomething() static method calls.
// System.out.println("JsniMethodRef " + x);
processMethodCall(x);
super.endVisit(x, ctx);
}
@Override
public void endVisit(JValueLiteral x, Context ctx) {
// Gather types whose constructor function is effectively called in value literal definitions.
maybeRecordTypeRef(x.getType());
super.endVisit(x, ctx);
}
@Override
public void endVisit(JVariable x, Context ctx) {
// Gather declared types of local variables, class fields and method parameters.
maybeRecordTypeRef(x.getType());
super.endVisit(x, ctx);
}
@Override
public boolean visit(JDeclaredType x, Context ctx) {
fromTypeName = x.getName();
if (!onlyUpdate) {
minimalRebuildCache.removeReferencesFrom(fromTypeName);
}
// Gather superclass and implemented interface types.
maybeRecordTypeRef(x.getSuperClass());
maybeRecordTypeRefs(x.getImplements());
return super.visit(x, ctx);
}
private void execImpl(JProgram program) {
accept(program);
}
private void maybeRecordTypeRef(JType referencedType) {
if (referencedType instanceof JArrayType) {
JArrayType toArrayType = (JArrayType) referencedType;
maybeRecordTypeRef(toArrayType.getLeafType());
}
if (!(referencedType instanceof JDeclaredType)) {
return;
}
JDeclaredType toType = (JDeclaredType) referencedType;
maybeRecordTypeRef(fromTypeName, toType.getName());
}
private void maybeRecordTypeRef(String fromTypeName, String toTypeName) {
minimalRebuildCache.addTypeReference(fromTypeName, toTypeName);
}
private void maybeRecordTypeRefs(List<? extends JDeclaredType> toTypes) {
for (JDeclaredType toType : toTypes) {
maybeRecordTypeRef(toType);
}
}
private void processJFieldRef(JFieldRef x) {
if (x.getTarget() instanceof JField) {
JField field = (JField) x.getTarget();
if (field.isStatic()) {
maybeRecordTypeRef(field.getEnclosingType());
}
}
}
private void processMethodCall(JMethodCall x) {
if (x.getTarget().isStatic() || x.getTarget().isConstructor()) {
maybeRecordTypeRef(x.getTarget().getEnclosingType());
}
}
}