All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jsweet.transpiler.StaticInitilializerAnalyzer Maven / Gradle / Ivy

The newest version!
/* 
 * JSweet transpiler - http://www.jsweet.org
 * Copyright (C) 2015 CINCHEO SAS 
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *  
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.jsweet.transpiler;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;

import org.apache.log4j.Logger;
import org.jsweet.JSweetConfig;
import org.jsweet.transpiler.util.DirectedGraph;
import org.jsweet.transpiler.util.ReferenceGrabber;
import org.jsweet.transpiler.util.Util;

import com.sun.source.tree.BlockTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ImportTree;
import com.sun.source.tree.PackageTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.Trees;

/**
 * This AST scanner creates a class dependency graph for each package, based on
 * static field initializers.
 * 
 * @author Renaud Pawlak
 * @author Louis Grignon
 */
public class StaticInitilializerAnalyzer extends TreePathScanner {

	private JSweetContext context;
	private CompilationUnitTree currentCompilationUnit;
	private int pass = 1;
	private static final Logger logger = Logger.getLogger(StaticInitilializerAnalyzer.class);
	/**
	 * A map containing the static initializers dependencies for each package when
	 * using modules (empty otherwise).
	 */
	public Map> staticInitializersDependencies = new HashMap<>();

	/**
	 * A map containing the static initializers dependencies when not using modules
	 * (empty otherwise).
	 */
	public DirectedGraph globalStaticInitializersDependencies = new DirectedGraph<>();

	/**
	 * Maps the types to the compilation units in which they are declared.
	 */
	public Map typesToCompilationUnits = new HashMap<>();

	/**
	 * Creates the analyzer.
	 */
	public StaticInitilializerAnalyzer(JSweetContext context) {
		this.context = context;
		this.context.referenceAnalyzer = this;
	}

	private DirectedGraph getGraph() {
	    return globalStaticInitializersDependencies;
	}
	
	public boolean isDependent(CompilationUnitTree cuSource, TypeElement target) {
	    CompilationUnitTree cuTarget = typesToCompilationUnits.get(target);
        if (cuSource != null && cuTarget != null) {
            return globalStaticInitializersDependencies.hasEdge(cuTarget, cuSource);
        }
        return false;
    }

	Set currentTopLevelImportedTypes = new HashSet<>();

	@Override
	public Void visitCompilationUnit(CompilationUnitTree compilationUnit, Trees trees) {

		currentCompilationUnit = compilationUnit;
		if (pass == 1) {
			getGraph().add(compilationUnit);
		} else {
			if (context.util.getPackageFullNameForCompilationUnit(compilationUnit)
					.startsWith(JSweetConfig.LIBS_PACKAGE + ".")) {

				// skip definitions
				return null;
			}
			currentTopLevelImportedTypes.clear();
			for (ImportTree importTree : compilationUnit.getImports()) {

				TypeMirror importedType = getImportedType(compilationUnit, importTree);
				if (importedType != null) {
					currentTopLevelImportedTypes.add(importedType);
				}
				// TypeElement type = Util.getImportedType(i);
				// if (type != null) {
				// CompilationUnitTree target = typesToCompilationUnits.get(type);
				// if (target != null && getGraph().contains(target)) {
				// logger.debug("adding import dependency: " +
				// currentTopLevel.getSourceFile() + " -> " +
				// target.getSourceFile());
				// getGraph().addEdge(target, currentTopLevel);
				// }
				// }

			}
		}

		super.visitCompilationUnit(compilationUnit, trees);
		currentCompilationUnit = null;

		return null;
	}

	private TypeMirror getImportedType(CompilationUnitTree compilationUnit, ImportTree importTree) {
		Tree importedIdentifier = importTree.getQualifiedIdentifier();
		TypeMirror importedType = Util.getType(importedIdentifier);
		return importedType;
	}

	@Override
	public Void visitClass(ClassTree classTree, Trees trees) {
		if (pass == 1) {
			typesToCompilationUnits.put((TypeElement) Util.getElement(classTree), currentCompilationUnit);
		} else {
			if (classTree.getExtendsClause() != null) {
				CompilationUnitTree target = typesToCompilationUnits.get(Util.getTypeElement(classTree.getExtendsClause()));
				if (target != null && getGraph().contains(target)) {
					logger.debug("adding inheritance dependency: " + currentCompilationUnit.getSourceFile() + " -> "
							+ target.getSourceFile());
					getGraph().addEdge(target, currentCompilationUnit);
				}
			}

			for (Tree member : classTree.getMembers()) {
				if (member instanceof VariableTree) {
					VariableTree field = (VariableTree) member;
					if (field.getModifiers().getFlags().contains(Modifier.STATIC) && field.getInitializer() != null
							&& !context.hasAnnotationType(Util.getElement(field), JSweetConfig.ANNOTATION_STRING_TYPE,
									JSweetConfig.ANNOTATION_ERASED)) {
						acceptReferences(field.getInitializer());
					}
				} else if (member instanceof BlockTree) {
					BlockTree initializer = (BlockTree) member;
					if (initializer.isStatic()) {
						acceptReferences(initializer);
					}
				}
			}
		}
		return super.visitClass(classTree, trees);
	}

	private void acceptReferences(Tree tree) {
		ReferenceGrabber refGrabber = new ReferenceGrabber();
		refGrabber.scan(tree, context.trees);
		for (TypeMirror referencedType : refGrabber.referencedTypes) {
			TypeElement referencedTypeElement = (TypeElement) context.types.asElement(referencedType);
			PackageElement referencedPackageElement = context.util.getParentElement(referencedTypeElement,
					PackageElement.class);
			PackageElement currentPackageElement = (PackageElement) Util.getElement(currentCompilationUnit.getPackage());

			if (!context.useModules || (Objects.equals(currentPackageElement, referencedPackageElement))) {
				CompilationUnitTree target = typesToCompilationUnits.get(referencedTypeElement);
				if (target != null && !currentCompilationUnit.equals(target) && getGraph().contains(target)) {
					logger.debug("adding static initializer dependency: " + currentCompilationUnit.getSourceFile()
							+ " -> " + target.getSourceFile());
					getGraph().addEdge(target, currentCompilationUnit);
				}
			}
		}
	}

	/**
	 * Processes all the given compilation units.
	 */
	public void process(Collection compilationUnits) {
		scan(compilationUnits, context.trees);
		pass++;
		scan(compilationUnits, context.trees);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy