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