diff --git a/sdg-cli/src/main/java/es/upv/mist/slicing/cli/PHPSlice.java b/sdg-cli/src/main/java/es/upv/mist/slicing/cli/PHPSlice.java index 900648694cc54434fefb9a6ad50fe95ad01b40a8..6a4b7f4cc16f43abd28d09da019462f32c4bf82b 100644 --- a/sdg-cli/src/main/java/es/upv/mist/slicing/cli/PHPSlice.java +++ b/sdg-cli/src/main/java/es/upv/mist/slicing/cli/PHPSlice.java @@ -4,9 +4,6 @@ import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.comments.BlockComment; -import com.github.javaparser.symbolsolver.JavaSymbolSolver; -import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; -import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; import es.upv.mist.slicing.graphs.augmented.ASDG; import es.upv.mist.slicing.graphs.augmented.PSDG; import es.upv.mist.slicing.graphs.cfg.CFG; @@ -16,6 +13,7 @@ import es.upv.mist.slicing.slicing.FileLineSlicingCriterion; import es.upv.mist.slicing.slicing.NodeIdSlicingCriterion; import es.upv.mist.slicing.slicing.Slice; import es.upv.mist.slicing.slicing.SlicingCriterion; +import es.upv.mist.slicing.utils.StaticTypeSolver; import org.apache.commons.cli.*; import java.io.File; @@ -88,9 +86,7 @@ public class PHPSlice { public void slice() throws ParseException, IOException { // Configure JavaParser - CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(); - combinedTypeSolver.add(new ReflectionTypeSolver(true)); - StaticJavaParser.getConfiguration().setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver)); + StaticTypeSolver.addTypeSolverJRE(); StaticJavaParser.getConfiguration().setAttributeComments(false); // Build the SDG diff --git a/sdg-cli/src/main/java/es/upv/mist/slicing/cli/Slicer.java b/sdg-cli/src/main/java/es/upv/mist/slicing/cli/Slicer.java index edbc79c2010af60bdeda2da77c11b861975db4bb..cc34c1c5fd9fba2c82aae5946cda10feb2df8368 100644 --- a/sdg-cli/src/main/java/es/upv/mist/slicing/cli/Slicer.java +++ b/sdg-cli/src/main/java/es/upv/mist/slicing/cli/Slicer.java @@ -5,10 +5,7 @@ import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.comments.BlockComment; import com.github.javaparser.ast.nodeTypes.NodeWithName; -import com.github.javaparser.symbolsolver.JavaSymbolSolver; -import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver; -import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; import es.upv.mist.slicing.graphs.augmented.ASDG; import es.upv.mist.slicing.graphs.augmented.PSDG; import es.upv.mist.slicing.graphs.exceptionsensitive.ESSDG; @@ -16,6 +13,7 @@ import es.upv.mist.slicing.graphs.sdg.SDG; import es.upv.mist.slicing.slicing.FileLineSlicingCriterion; import es.upv.mist.slicing.slicing.Slice; import es.upv.mist.slicing.slicing.SlicingCriterion; +import es.upv.mist.slicing.utils.StaticTypeSolver; import org.apache.commons.cli.*; import java.io.File; @@ -211,11 +209,9 @@ public class Slicer { public void slice() throws ParseException { // Configure JavaParser - CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(); - combinedTypeSolver.add(new ReflectionTypeSolver(true)); + StaticTypeSolver.addTypeSolverJRE(); for (File directory : dirIncludeSet) - combinedTypeSolver.add(new JavaParserTypeSolver(directory)); - StaticJavaParser.getConfiguration().setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver)); + StaticTypeSolver.addTypeSolver(new JavaParserTypeSolver(directory)); StaticJavaParser.getConfiguration().setAttributeComments(false); // Build the SDG diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/ClassGraph.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/ClassGraph.java index 0777a79d102ca3ed772758b0822864b03a64e057..899dfb404ae5afaaf0f0bf48ec41a72da067ceec 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/ClassGraph.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/ClassGraph.java @@ -4,18 +4,18 @@ import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.*; import com.github.javaparser.ast.visitor.VoidVisitorAdapter; +import com.github.javaparser.resolution.declarations.ResolvedClassDeclaration; import es.upv.mist.slicing.arcs.Arc; import es.upv.mist.slicing.utils.ASTUtils; import es.upv.mist.slicing.utils.Utils; -import org.jgrapht.graph.DefaultEdge; import org.jgrapht.graph.DirectedPseudograph; -import org.jgrapht.nio.Attribute; -import org.jgrapht.nio.DefaultAttribute; import org.jgrapht.nio.dot.DOTExporter; import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; -public class ClassGraph extends DirectedPseudograph implements Buildable> { +public class ClassGraph extends DirectedPseudograph implements Buildable> { /** The key of the vertex map needs to be a String because extendedTypes represent extended classes * as ClassOrInterfaceType objects while class declarations define classes as ClassOrInterfaceDeclaration @@ -28,6 +28,29 @@ public class ClassGraph extends DirectedPseudograph vertex = vertexSet().stream() + .filter(v -> v.declaration instanceof ClassOrInterfaceDeclaration) + .filter(v -> v.declaration.asClassOrInterfaceDeclaration().resolve().asClass().equals(declaration)) + .findFirst(); + return vertex.orElseThrow(); + } + + public Set subclassesOf(ResolvedClassDeclaration clazz) { + return subclassesStreamOf(findVertex(clazz)) + .map(ClassOrInterfaceDeclaration.class::cast) + .collect(Collectors.toSet()); + } + + protected Stream subclassesStreamOf(Vertex classVertex) { + return Stream.concat(Stream.of(classVertex), outgoingEdgesOf(classVertex).stream() + .filter(ClassArc.Extends.class::isInstance) + .map(this::getEdgeTarget) + .flatMap(this::subclassesStreamOf)); + } + @Override public void build(NodeList arg) { if (isBuilt()) @@ -121,7 +144,7 @@ public class ClassGraph extends DirectedPseudograph { Vertex source = vertexDeclarationMap.get(p.getNameAsString()); if (source != null && containsVertex(v)) - addEdge(source, v, new ExtendsArc()); + addEdge(source, v, new ClassArc.Extends()); }); dv.getImplementedTypes().forEach(p -> { Vertex source = vertexDeclarationMap.get(p.getNameAsString()); if (source != null && containsVertex(v)) - addEdge(source, v, new ImplementsArc()); + addEdge(source, v, new ClassArc.Implements()); }); } @@ -167,7 +190,7 @@ public class ClassGraph extends DirectedPseudograph declaration; @@ -197,40 +220,13 @@ public class ClassGraph extends DirectedPseudograph getDotAttributes() { - Map map = super.getDotAttributes(); - map.put("style", DefaultAttribute.createAttribute("dashed")); - return map; - } - } - - /** - * An edge of the {@link ClassGraph}. Represents the implements relationship in Java. - * It goes from the interface to the class that implements it. - */ - public static class ImplementsArc extends Arc { - public Map getDotAttributes() { - Map map = super.getDotAttributes(); - map.put("style", DefaultAttribute.createAttribute("dashed")); - return map; - } - } - - /** - * An edge of the {@link ClassGraph}. It represents the membership of a class node. - * It links the class node and its inner data members/function definitions. - */ - public static class MemberArc extends Arc { - public Map getDotAttributes() { - Map map = super.getDotAttributes(); - map.put("style", DefaultAttribute.createAttribute("dashed")); - return map; - } + protected static class ClassArc extends Arc { + /** An arc that connects a class with another one that inherits from it. */ + protected static class Extends extends ClassArc {} + /** An arc that connects an interface to a class that implements it. */ + protected static class Implements extends ClassArc {} + /** An arc that connects a class with a field or method contained in it. */ + protected static class Member extends ClassArc {} } } diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/augmented/ACFGBuilder.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/augmented/ACFGBuilder.java index 9acd217e4d4df59eee7fbc3a5f7f4e024ad4f43b..debd87e1f319c01ed2683bc49f69b7ec4a537e75 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/augmented/ACFGBuilder.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/augmented/ACFGBuilder.java @@ -132,8 +132,10 @@ public class ACFGBuilder extends CFGBuilder { @Override public void visit(ReturnStmt returnStmt, Void arg) { GraphNode node = connectTo(returnStmt); - node.addDefinedVariable(new NameExpr(VARIABLE_NAME_OUTPUT)); - returnStmt.getExpression().ifPresent(n -> n.accept(this, arg)); + returnStmt.getExpression().ifPresent(n -> { + n.accept(this, arg); + node.addDefinedVariable(new NameExpr(VARIABLE_NAME_OUTPUT), n); + }); returnList.add(node); clearHanging(); nonExecHangingNodes.add(node); // NEW vs CFG diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/cfg/CFGBuilder.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/cfg/CFGBuilder.java index 280059df31a4cf3c65f6bee7363d611f748fdf6a..79a14d1a49b6f8073e682dd29f88e985cebf7cbe 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/cfg/CFGBuilder.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/cfg/CFGBuilder.java @@ -331,7 +331,7 @@ public class CFGBuilder extends VoidVisitorAdapter { GraphNode node = connectTo(returnStmt); returnStmt.getExpression().ifPresent(n -> { n.accept(this, arg); - node.addDefinedVariable(new NameExpr(VARIABLE_NAME_OUTPUT)); + node.addDefinedVariable(new NameExpr(VARIABLE_NAME_OUTPUT), n); }); returnList.add(node); clearHanging(); diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/exceptionsensitive/ESCFG.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/exceptionsensitive/ESCFG.java index afd874b6e0007b7e089acab96d59cb5d4fabdfa6..d4bf2600cd8c9d841e0b626d71395b7919519717 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/exceptionsensitive/ESCFG.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/exceptionsensitive/ESCFG.java @@ -240,7 +240,7 @@ public class ESCFG extends ACFG { stmtStack.push(n); GraphNode stmt = connectTo(n); n.getExpression().accept(this, arg); - stmt.addDefinedVariable(new NameExpr(ACTIVE_EXCEPTION_VARIABLE)); + stmt.addDefinedVariable(new NameExpr(ACTIVE_EXCEPTION_VARIABLE), n.getExpression()); populateExceptionSourceMap(new ExceptionSource(stmt, n.getExpression().calculateResolvedType())); clearHanging(); nonExecHangingNodes.add(stmt); @@ -286,7 +286,7 @@ public class ESCFG extends ACFG { for (ResolvedType type : resolved.getSpecifiedExceptions()) { hangingNodes.add(stmtNode); ExceptionReturnNode exceptionReturn = addExceptionReturnNode(call, type); - exceptionReturn.addDefinedVariable(new NameExpr(ACTIVE_EXCEPTION_VARIABLE)); + exceptionReturn.addDefinedVariable(new NameExpr(ACTIVE_EXCEPTION_VARIABLE), null); // TODO: improve initializer populateExceptionSourceMap(new ExceptionSource(exceptionReturn, type)); returnNodes.add(exceptionReturn); connectTo(exceptionReturn); diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java new file mode 100644 index 0000000000000000000000000000000000000000..abb527d0d0276939794d507298e7b5b5d7e3d27c --- /dev/null +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/oo/DynamicTypeResolver.java @@ -0,0 +1,69 @@ +package es.upv.mist.slicing.graphs.oo; + +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.expr.Expression; +import com.github.javaparser.resolution.types.ResolvedType; +import es.upv.mist.slicing.graphs.ClassGraph; +import es.upv.mist.slicing.graphs.cfg.CFG; +import es.upv.mist.slicing.nodes.VariableAction; +import es.upv.mist.slicing.utils.ASTUtils; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** A dynamic type solver that complements Javaparser's {@code resolve()} method. */ +public class DynamicTypeResolver { + protected final CFG cfg; + protected final ClassGraph classGraph; + + public DynamicTypeResolver(CFG cfg, ClassGraph classGraph) { + this.cfg = cfg; + this.classGraph = classGraph; + } + + /** Obtains the set of dynamic types that the variable passed as argument + * may take. The current implementation is intra-procedural! */ + public Set resolve(VariableAction action) { + return resolveIntraProcedural(action); + } + + /** Obtains a list of possible dynamic types for the given action, by + * searching for definitions intraprocedurally. */ + public Set resolveIntraProcedural(VariableAction action) { + return cfg.findLastDefinitionsFrom(action).stream() + .map(VariableAction::asDefinition) + .filter(Objects::nonNull) + .map(def -> { + Expression expr = unwrapExpr(def.getExpression()); + if (expr.isObjectCreationExpr() || expr.isArrayCreationExpr() + || expr.isArrayInitializerExpr()) + return Set.of(expr.calculateResolvedType()); + else + return findAllSubtypes(def.getExpression().calculateResolvedType()); + }) + .reduce(new HashSet<>(), (a, b) -> { a.addAll(b); return a; }); + } + + /** Unwraps an enclosed expression, and other constructs that are type-transparent. */ + protected Expression unwrapExpr(Expression expr) { + if (expr.isCastExpr()) + if (ASTUtils.isDownCast(expr.asCastExpr())) + return expr; + else + return unwrapExpr(expr.asCastExpr().getExpression()); + if (expr.isEnclosedExpr()) + return unwrapExpr(expr.asEnclosedExpr().getInner()); + return expr; + } + + /** Extracts from the call graph all the subtypes of the given argument. + * The input is included as part of the output. */ + protected Set findAllSubtypes(ResolvedType t) { + return classGraph.subclassesOf(t.asReferenceType().getTypeDeclaration().orElseThrow().asClass()).stream() + .map(ClassOrInterfaceDeclaration::resolve) + .map(ASTUtils::resolvedTypeDeclarationToResolvedType) + .collect(Collectors.toSet()); + } +} diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java index 7436c91ea96675974a4a4823ffcb0fc5cf69feaa..4b6414822db47a2d6ba32d1130b223a862ebeede 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/graphs/sdg/InterproceduralUsageFinder.java @@ -41,7 +41,7 @@ public class InterproceduralUsageFinder extends InterproceduralActionFinder movables.add(new VariableAction.Movable(new VariableAction.Declaration(name, graphNode), actualIn)), - (n, name) -> movables.add(new VariableAction.Movable(new VariableAction.Definition(name, graphNode), actualIn)), + (n, name, expression) -> movables.add(new VariableAction.Movable(new VariableAction.Definition(name, graphNode, expression), actualIn)), (n, name) -> movables.add(new VariableAction.Movable(new VariableAction.Usage(name, graphNode), actualIn)) ), VariableVisitor.Action.USE); graphNode.addActionsForCall(movables, edge.getCall(), true); diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/GraphNode.java b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/GraphNode.java index 6b010bf3cbd814f2ab52490c823b934e210b2943..f56a2bfb663eb90a272faaf22b8ced9e0e7b62e5 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/GraphNode.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/GraphNode.java @@ -1,6 +1,7 @@ package es.upv.mist.slicing.nodes; import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.resolution.Resolvable; import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration; @@ -131,8 +132,8 @@ public class GraphNode implements Comparable> { } /** Create and append a definition of a variable to the list of actions of this node. */ - public void addDefinedVariable(NameExpr variable) { - VariableAction.Definition def = new VariableAction.Definition(variable, this); + public void addDefinedVariable(NameExpr variable, Expression expression) { + VariableAction.Definition def = new VariableAction.Definition(variable, this, expression); variableActions.add(def); } diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java index 9d471687ff85ea351e6e8eb2d59fcc4f174f9bd1..0b6bf849e5454f8ee6348708774d0afb52b7d777 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableAction.java @@ -1,5 +1,6 @@ package es.upv.mist.slicing.nodes; +import com.github.javaparser.ast.expr.Expression; import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.resolution.Resolvable; import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration; @@ -160,8 +161,21 @@ public abstract class VariableAction { /** A definition of a variable. */ public static class Definition extends VariableAction { + /** The value to which the variable has been defined. */ + protected final Expression expression; + public Definition(NameExpr variable, GraphNode graphNode) { + this(variable, graphNode, null); + } + + public Definition(NameExpr variable, GraphNode graphNode, Expression expression) { super(variable, graphNode); + this.expression = expression; + } + + /** @see #expression */ + public Expression getExpression() { + return expression; } @Override diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableVisitor.java b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableVisitor.java index fffef9244a673cc8fa9a65acff36012d10e975ec..c5dc0abcc8b86ab905b6e10cd92e30ebb90e28dd 100644 --- a/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableVisitor.java +++ b/sdg-core/src/main/java/es/upv/mist/slicing/nodes/VariableVisitor.java @@ -1,5 +1,6 @@ package es.upv.mist.slicing.nodes; +import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.body.VariableDeclarator; import com.github.javaparser.ast.expr.*; @@ -10,7 +11,10 @@ import com.github.javaparser.resolution.Resolvable; import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration; import es.upv.mist.slicing.graphs.GraphNodeContentVisitor; import es.upv.mist.slicing.utils.ASTUtils; +import es.upv.mist.slicing.utils.TriConsumer; +import java.util.Deque; +import java.util.LinkedList; import java.util.Objects; import java.util.function.BiConsumer; @@ -41,13 +45,16 @@ public class VariableVisitor extends GraphNodeContentVisitor, NameExpr> BLANK_CONSUMER = (a, b) -> {}; + protected static final TriConsumer, NameExpr, Expression> BLANK_TRICONSUMER = (a, b, c) -> {}; /** The action to perform when a declaration is found. */ protected final BiConsumer, NameExpr> declConsumer; /** The action to perform when a definition is found. */ - protected final BiConsumer, NameExpr> defConsumer; + protected final TriConsumer, NameExpr, Expression> defConsumer; /** The action to perform when a usage is found. */ protected final BiConsumer, NameExpr> useConsumer; + /** A stack with the last definition expression, to provide it when a variable definition is found. */ + protected final Deque definitionStack = new LinkedList<>(); /** A variable visitor that will add each action to the list of actions of the graph node. * The entry-point for this graph MUST be {@link #startVisit(GraphNode)} or {@link #startVisit(GraphNode, Action)} */ @@ -58,12 +65,22 @@ public class VariableVisitor extends GraphNodeContentVisitor, NameExpr> declConsumer, BiConsumer, NameExpr> defConsumer, BiConsumer, NameExpr> useConsumer) { + public VariableVisitor(BiConsumer, NameExpr> declConsumer, TriConsumer, NameExpr, Expression> defConsumer, BiConsumer, NameExpr> useConsumer) { this.declConsumer = Objects.requireNonNullElse(declConsumer, BLANK_CONSUMER); - this.defConsumer = Objects.requireNonNullElse(defConsumer, BLANK_CONSUMER); + this.defConsumer = Objects.requireNonNullElse(defConsumer, BLANK_TRICONSUMER); this.useConsumer = Objects.requireNonNullElse(useConsumer, BLANK_CONSUMER); } + public void visitAsDefinition(Node node, Expression value) { + visitAsDefinition(node, value, Action.DEFINITION); + } + + public void visitAsDefinition(Node node, Expression value, Action action) { + definitionStack.push(value); + node.accept(this, action.or(Action.DEFINITION)); + definitionStack.pop(); + } + @Override public void startVisit(GraphNode node) { startVisit(node, Action.USE); @@ -76,7 +93,7 @@ public class VariableVisitor extends GraphNodeContentVisitor + * Examples: + *
    + *
  • {@code (Object) new String()}: false.
  • + *
  • {@code (String) new String()}: false
  • + *
  • {@code (String) object}: true.
  • + *
+ */ + public static boolean isDownCast(CastExpr castExpr) { + ResolvedType castType = castExpr.getType().resolve(); + ResolvedType exprType = castExpr.getExpression().calculateResolvedType(); + if (castType.isReferenceType() && exprType.isReferenceType()) { + if (castType.equals(exprType)) + return false; + return castType.asReferenceType().getAllAncestors().contains(exprType.asReferenceType()); + } + throw new IllegalArgumentException("This operation is only valid for reference type cast operations."); + } } diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/utils/StaticTypeSolver.java b/sdg-core/src/main/java/es/upv/mist/slicing/utils/StaticTypeSolver.java new file mode 100644 index 0000000000000000000000000000000000000000..4a9a4ba95a6ae6bc8b8e91cc339e649ff44bef50 --- /dev/null +++ b/sdg-core/src/main/java/es/upv/mist/slicing/utils/StaticTypeSolver.java @@ -0,0 +1,47 @@ +package es.upv.mist.slicing.utils; + +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.symbolsolver.JavaSymbolSolver; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; + +/** A static class whose only purpose is storing a type solver for conversions + * of ResolvedTypeDeclaration objects into ResolvedType ones. */ +public class StaticTypeSolver { + protected static final CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(); + + /** Whether we've added the JRE type solver or not. */ + protected static boolean typeSolverHasJRE = false; + + static { + StaticJavaParser.getConfiguration().setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver)); + } + + /** Append a type solver (typically a {@link com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver JavaParserTypeSolver}. */ + public static void addTypeSolver(TypeSolver typeSolver) { + combinedTypeSolver.add(typeSolver); + } + + /** Append a {@link ReflectionTypeSolver} to the type solver, JRE only. + * This operation can only be performed once, subsequent invocations will + * be discarded. */ + public static void addTypeSolverJRE() { + addTypeSolverJRE(true); + } + + /** Append a {@link ReflectionTypeSolver} to the type solver. + * This operation can only be performed once, subsequent invocations will + * be discarded. */ + public static void addTypeSolverJRE(boolean jreOnly) { + if (!typeSolverHasJRE) { + combinedTypeSolver.add(new ReflectionTypeSolver(true)); + typeSolverHasJRE = true; + } + } + + /** Obtain the type solver. This resulting object should not be manually modified. */ + protected static TypeSolver getTypeSolver() { + return combinedTypeSolver; + } +} diff --git a/sdg-core/src/main/java/es/upv/mist/slicing/utils/TriConsumer.java b/sdg-core/src/main/java/es/upv/mist/slicing/utils/TriConsumer.java new file mode 100644 index 0000000000000000000000000000000000000000..fe933c27bbb5354d34823c597a4a3795a6645a3f --- /dev/null +++ b/sdg-core/src/main/java/es/upv/mist/slicing/utils/TriConsumer.java @@ -0,0 +1,5 @@ +package es.upv.mist.slicing.utils; + +public interface TriConsumer { + void accept(T arg1, U arg2, V arg3); +}