org.evosuite.continuous.project.ProjectGraph Maven / Gradle / Ivy
/**
* Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
* contributors
*
* This file is part of EvoSuite.
*
* EvoSuite is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3.0 of the License, or
* (at your option) any later version.
*
* EvoSuite 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
* Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with EvoSuite. If not, see .
*/
package org.evosuite.continuous.project;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.evosuite.continuous.project.ProjectStaticData.ClassInfo;
import org.evosuite.seeding.CastClassAnalyzer;
import org.evosuite.setup.DependencyAnalysis;
import org.evosuite.setup.InheritanceTree;
import org.evosuite.setup.InheritanceTreeGenerator;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* Class representing the class graph. For each class (CUT and non-testable),
* not only we want to know its hierarchy (parents, interfaces, subclasses, etc)
* but also where in the project it is used by other classes as input.
*
*
*
* For definition of CUT, see {@link ProjectStaticData}
*
*/
public class ProjectGraph {
/*
* Need to guarantee to build the graph once with all needed info, and then the public
* methods just query the map data structures directly (instead of recalculating
* on the fly)
*/
private static final Logger logger = LoggerFactory.getLogger(ProjectGraph.class);
private final InheritanceTree inheritanceTree;
/**
* FIXME
* Map from TODO (key) to TODO (value)
*/
private final Map> castInformation;
private final ProjectStaticData data;
/**
* Main constructor
*
* @param data
*/
public ProjectGraph(ProjectStaticData data) {
this.data = data;
inheritanceTree = InheritanceTreeGenerator.createFromClassList(data.getClassNames());
castInformation = new HashMap>();
if(logger.isDebugEnabled()){
logger.debug("Classes in inheritance tree: " + inheritanceTree.getAllClasses());
}
}
/**
*
* Return the full qualifying names of all classes that are CUTs and that
* are used as input in any of the public methods of cut
(but
* not of any of its parent hierarchy).
*
*
*
* If a method takes as input a reference of a non-SUT class (e.g.,
* java.lang.Object
), but then there is a cast to a CUT (e.g. a
* class X), then X will be added in the returned set.
*
*
*
* If a method takes as input a reference of a SUT class X that is not a CUT
* (e.g., an interface with no code), then X will not be added in the
* returned set, although based on includeSubclasses
we might
* add its subclasses.
*
*
* @param cut
* the class under test (CUT)
* @param includeSubclasses
* If a class X is in the returned set, then normally no subclass
* Y of X would be added in the returned set, unless Y is
* directly used in the CUT as input.
* @return a set of full qualifying names of CUTs
* @throws IllegalArgumentException
* if the input cut
is not a CUT
*/
public Set getCUTsDirectlyUsedAsInput(String cut, boolean includeSubclasses)
throws IllegalArgumentException {
checkCUT(cut);
Set parameterClasses = recursionToSearchDirectInputs(cut,includeSubclasses);
parameterClasses.remove(cut);
removeNonCUT(parameterClasses);
logger.debug("Parameter classes of " + cut + ": " + parameterClasses);
return parameterClasses;
}
protected Set recursionToSearchDirectInputs(String aClass, boolean includeSubclasses){
if (includeSubclasses) {
Set directlyUsed = recursionToSearchDirectInputs(aClass, false); //recursion
Set all = new LinkedHashSet(directlyUsed);
for (String name : directlyUsed) {
all.addAll(getAllCUTsSubclasses(name));
}
return all;
}
Set parameterClasses = getParameterClasses(aClass);
parameterClasses.addAll(getCastClasses(aClass));
return parameterClasses;
}
/**
* Calculate all the CUTs that use the given cut
as input in
* any of their public methods
*
* @param cut
* the class under test (CUT)
* @param includeSuperClasses
* not only using as input the
* cut