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

de.is24.deadcode4j.analyzer.SuperClassAnalyzer Maven / Gradle / Ivy

There is a newer version: 2.1.0
Show newest version
package de.is24.deadcode4j.analyzer;

import com.google.common.collect.Sets;
import de.is24.deadcode4j.AnalysisContext;
import de.is24.deadcode4j.analyzer.javassist.ClassPathFilter;
import de.is24.guava.NonNullFunction;
import javassist.CtClass;

import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Lists.newArrayList;
import static de.is24.javassist.CtClasses.getSuperclassOf;
import static de.is24.javassist.CtClasses.isJavaLangObject;

/**
 * Serves as a base class with which to mark classes as being in use if they are a direct subclass of one of the
 * specified classes.
 *
 * @since 1.4
 */
public abstract class SuperClassAnalyzer extends ByteCodeAnalyzer {

    private final String dependerId;
    private final NonNullFunction> supplySuperClassesFoundInClassPath;

    private SuperClassAnalyzer(@Nonnull String dependerId, @Nonnull Set classNames) {
        checkArgument(!classNames.isEmpty(), "classNames cannot by empty!");
        this.dependerId = dependerId;
        supplySuperClassesFoundInClassPath = new ClassPathFilter(classNames);
    }

    /**
     * Creates a new SuperClassAnalyzer.
     *
     * @param dependerId a description of the depending entity with which to
     *                   call {@link de.is24.deadcode4j.AnalysisContext#addDependencies(String, Iterable)}
     * @param classNames a list of fully qualified class names indicating that the extending class is still in use
     * @since 1.4
     */
    protected SuperClassAnalyzer(@Nonnull String dependerId, @Nonnull String... classNames) {
        this(dependerId, Sets.newHashSet(classNames));
    }

    /**
     * Creates a new SuperClassAnalyzer.
     *
     * @param dependerId a description of the depending entity with which to
     *                   call {@link de.is24.deadcode4j.AnalysisContext#addDependencies(String, Iterable)}
     * @param classNames a list of fully qualified class names indicating that the extending class is still in use
     * @since 1.4
     */
    public SuperClassAnalyzer(String dependerId, Iterable classNames) {
        this(dependerId, Sets.newHashSet(classNames));
    }

    @Override
    protected final void analyzeClass(@Nonnull AnalysisContext analysisContext, @Nonnull CtClass clazz) {
        Set knownSuperClasses = getSuperClassesFoundInClassPath(analysisContext);
        if (knownSuperClasses.isEmpty()) {
            return;
        }

        String clazzName = clazz.getName();
        analysisContext.addAnalyzedClass(clazzName);

        if (!Collections.disjoint(knownSuperClasses, getClassHierarchy(clazz))) {
            analysisContext.addDependencies(this.dependerId, clazzName);
        }
    }

    @Nonnull
    private List getClassHierarchy(@Nonnull final CtClass clazz) {
        List classes = newArrayList();
        CtClass loopClass = clazz;
        do {
            classes.add(loopClass.getClassFile2().getSuperclass());
            loopClass = getSuperclassOf(loopClass);
        } while (loopClass != null && !isJavaLangObject(loopClass));
        return classes;
    }

    @Nonnull
    protected final Set getSuperClassesFoundInClassPath(@Nonnull AnalysisContext analysisContext) {
        return analysisContext.getOrCreateCacheEntry(getClass(), supplySuperClassesFoundInClassPath);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy