diff --git a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/ICFGDotExporter.java b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/ICFGDotExporter.java index 036b4dade8e..1c0a4c563a8 100644 --- a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/ICFGDotExporter.java +++ b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/ICFGDotExporter.java @@ -1,7 +1,30 @@ package sootup.analysis.interprocedural.icfg; +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2022-2023 Palaniappan Muthuraman, Jonas Klauke + * %% + * This program 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 2.1 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 Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + import java.util.*; import java.util.stream.Collectors; +import sootup.callgraph.CallGraph; import sootup.core.graph.BasicBlock; import sootup.core.graph.StmtGraph; import sootup.core.jimple.common.expr.JNewExpr; @@ -11,7 +34,6 @@ import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; import sootup.core.signatures.MethodSubSignature; -import sootup.core.typehierarchy.MethodDispatchResolver; import sootup.core.types.VoidType; import sootup.core.util.DotExporter; import sootup.core.views.View; @@ -19,11 +41,13 @@ public class ICFGDotExporter { public static String buildICFGGraph( - Map signatureToStmtGraph, View> view) { + Map signatureToStmtGraph, + View> view, + CallGraph callGraph) { final StringBuilder sb = new StringBuilder(); DotExporter.buildDiGraphObject(sb); Map calls; - calls = computeCalls(signatureToStmtGraph, view); + calls = computeCalls(signatureToStmtGraph, view, callGraph); for (Map.Entry entry : signatureToStmtGraph.entrySet()) { String graph = DotExporter.buildGraph(entry.getValue(), true, calls, entry.getKey()); sb.append(graph + "\n"); @@ -37,9 +61,13 @@ public static String buildICFGGraph( * methods. */ public static Map computeCalls( - Map stmtGraphSet, View> view) { + Map stmtGraphSet, + View> view, + CallGraph callgraph) { Map calls = new HashMap<>(); - for (StmtGraph stmtGraph : stmtGraphSet.values()) { + for (Map.Entry entry : stmtGraphSet.entrySet()) { + StmtGraph stmtGraph = entry.getValue(); + MethodSignature source = entry.getKey(); Collection> blocks; try { blocks = stmtGraph.getBlocksSorted(); @@ -50,11 +78,11 @@ public static Map computeCalls( List stmts = block.getStmts(); for (Stmt stmt : stmts) { if (stmt.containsInvokeExpr()) { - MethodSignature methodSignature = stmt.getInvokeExpr().getMethodSignature(); + MethodSignature target = stmt.getInvokeExpr().getMethodSignature(); int hashCode = stmt.hashCode(); - calls.put(hashCode, methodSignature); + calls.put(hashCode, target); // compute all the classes that are made to the subclasses as well - connectEdgesToSubClasses(methodSignature, view, calls); + connectEdgesToSubClasses(source, target, view, calls, callgraph); } else if (stmt instanceof JAssignStmt) { JAssignStmt jAssignStmt = (JAssignStmt) stmt; Integer currentHashCode = stmt.hashCode(); @@ -85,44 +113,40 @@ public static Map computeCalls( } public static Set getMethodSignatureInSubClass( - MethodSignature targetMethodSignature, View> view) { - try { - return MethodDispatchResolver.resolveAllDispatches(view, targetMethodSignature).stream() - .map( - methodSignature -> - MethodDispatchResolver.resolveConcreteDispatch(view, methodSignature)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet()); - } catch (Exception e) { - return null; + MethodSignature source, MethodSignature target, CallGraph callGraph) { + if (!callGraph.containsMethod(source) || !callGraph.containsMethod(target)) { + return Collections.emptySet(); } + return callGraph.callsFrom(source).stream() + .filter( + methodSignature -> methodSignature.getSubSignature().equals(target.getSubSignature())) + .collect(Collectors.toSet()); } public static void connectEdgesToSubClasses( - MethodSignature methodSignature, + MethodSignature source, + MethodSignature target, View> view, - Map calls) { + Map calls, + CallGraph callgraph) { Set methodSignatureInSubClass = - getMethodSignatureInSubClass(methodSignature, view); - if (methodSignatureInSubClass != null) { - methodSignatureInSubClass.forEach( - subclassmethodSignature -> { - Optional method = view.getMethod(methodSignature); - MethodSignature initMethod = - new MethodSignature( - subclassmethodSignature.getDeclClassType(), - new MethodSubSignature( - "", Collections.emptyList(), VoidType.getInstance())); - if (method.isPresent() - && !subclassmethodSignature.toString().equals(initMethod.toString())) { - if (method.get().hasBody()) { - calls.put( - method.get().getBody().getStmtGraph().getStartingStmt().hashCode(), - subclassmethodSignature); - } + getMethodSignatureInSubClass(source, target, callgraph); + methodSignatureInSubClass.forEach( + subclassmethodSignature -> { + Optional method = view.getMethod(target); + MethodSignature initMethod = + new MethodSignature( + subclassmethodSignature.getDeclClassType(), + new MethodSubSignature( + "", Collections.emptyList(), VoidType.getInstance())); + if (method.isPresent() + && !subclassmethodSignature.toString().equals(initMethod.toString())) { + if (method.get().hasBody()) { + calls.put( + method.get().getBody().getStmtGraph().getStartingStmt().hashCode(), + subclassmethodSignature); } - }); - } + } + }); } } diff --git a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/JimpleBasedInterproceduralCFG.java b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/JimpleBasedInterproceduralCFG.java index 1e9faa7cc42..fc675e9f5bb 100644 --- a/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/JimpleBasedInterproceduralCFG.java +++ b/sootup.analysis/src/main/java/sootup/analysis/interprocedural/icfg/JimpleBasedInterproceduralCFG.java @@ -152,13 +152,23 @@ public JimpleBasedInterproceduralCFG( public String buildICFGGraph(CallGraph callGraph) { Map signatureToStmtGraph = new LinkedHashMap<>(); computeAllCalls(mainMethodSignature, signatureToStmtGraph, callGraph); - return ICFGDotExporter.buildICFGGraph(signatureToStmtGraph, view); + return ICFGDotExporter.buildICFGGraph(signatureToStmtGraph, view, callGraph); } public void computeAllCalls( MethodSignature methodSignature, Map signatureToStmtGraph, CallGraph callGraph) { + ArrayList visitedMethods = new ArrayList<>(); + computeAllCalls(methodSignature, signatureToStmtGraph, callGraph, visitedMethods); + } + + private void computeAllCalls( + MethodSignature methodSignature, + Map signatureToStmtGraph, + CallGraph callGraph, + List visitedMethods) { + visitedMethods.add(methodSignature); final Optional methodOpt = view.getMethod(methodSignature); // return if the methodSignature is already added to the hashMap to avoid stackoverflow error. if (signatureToStmtGraph.containsKey(methodSignature)) return; @@ -169,11 +179,12 @@ public void computeAllCalls( signatureToStmtGraph.put(methodSignature, stmtGraph); } } - callGraph - .callsFrom(methodSignature) + callGraph.callsFrom(methodSignature).stream() + .filter(methodSignature1 -> !visitedMethods.contains(methodSignature1)) .forEach( nextMethodSignature -> - computeAllCalls(nextMethodSignature, signatureToStmtGraph, callGraph)); + computeAllCalls( + nextMethodSignature, signatureToStmtGraph, callGraph, visitedMethods)); } private CallGraph initCallGraph() { diff --git a/sootup.analysis/src/test/java/sootup/analysis/interprocedural/icfg/ICFGDotExporterTest.java b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/icfg/ICFGDotExporterTest.java index 2a009388e75..25bddb3617e 100644 --- a/sootup.analysis/src/test/java/sootup/analysis/interprocedural/icfg/ICFGDotExporterTest.java +++ b/sootup.analysis/src/test/java/sootup/analysis/interprocedural/icfg/ICFGDotExporterTest.java @@ -187,7 +187,7 @@ public String edgesFromCallGraph( Map signatureToStmtGraph = new LinkedHashMap<>(); icfg.computeAllCalls(methodSignature, signatureToStmtGraph, callGraph); Map calls; - calls = ICFGDotExporter.computeCalls(signatureToStmtGraph, view); + calls = ICFGDotExporter.computeCalls(signatureToStmtGraph, view, callGraph); final Optional methodOpt = view.getMethod(methodSignature); if (methodOpt.isPresent()) { SootMethod sootMethod = methodOpt.get(); diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/AbstractCallGraphAlgorithm.java b/sootup.callgraph/src/main/java/sootup/callgraph/AbstractCallGraphAlgorithm.java index cf8877e083f..7ab1607c983 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/AbstractCallGraphAlgorithm.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/AbstractCallGraphAlgorithm.java @@ -28,6 +28,7 @@ import javax.annotation.Nonnull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import sootup.core.IdentifierFactory; import sootup.core.jimple.basic.Value; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JStaticInvokeExpr; @@ -40,6 +41,8 @@ import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; import sootup.core.signatures.MethodSubSignature; +import sootup.core.typehierarchy.HierarchyComparator; +import sootup.core.typehierarchy.TypeHierarchy; import sootup.core.types.ClassType; import sootup.core.views.View; import sootup.java.core.JavaIdentifierFactory; @@ -143,6 +146,11 @@ final void processWorkList( // skip if already processed if (processed.contains(currentMethodSignature)) continue; + // skip if library class + SootClass currentClass = + view.getClass(currentMethodSignature.getDeclClassType()).orElse(null); + if (currentClass == null || currentClass.isLibraryClass()) continue; + // perform pre-processing if needed preProcessingMethod(view, currentMethodSignature, workList, cg); @@ -151,9 +159,7 @@ final void processWorkList( // transform the method signature to the actual SootMethod SootMethod currentMethod = - view.getClass(currentMethodSignature.getDeclClassType()) - .flatMap(c -> c.getMethod(currentMethodSignature.getSubSignature())) - .orElse(null); + currentClass.getMethod(currentMethodSignature.getSubSignature()).orElse(null); // get all call targets of invocations in the method body Stream invocationTargets = resolveAllCallsFromSourceMethod(currentMethod); @@ -276,47 +282,6 @@ protected Stream resolveAllStaticInitializerCallsFromSourceMeth .map(SootClassMember::getSignature); } - /** - * searches the method object in the given hierarchy - * - * @param view it contains all classes - * @param sig the signature of the searched method - * @param the generic type of the searched method object - * @return the found method object, or null if the method was not found. - */ - protected final T findMethodInHierarchy( - @Nonnull View> view, @Nonnull MethodSignature sig) { - Optional> optSc = view.getClass(sig.getDeclClassType()); - - if (optSc.isPresent()) { - SootClass sc = optSc.get(); - - List superClasses = view.getTypeHierarchy().superClassesOf(sc.getType()); - Set interfaces = view.getTypeHierarchy().implementedInterfacesOf(sc.getType()); - superClasses.addAll(interfaces); - - for (ClassType superClassType : superClasses) { - Optional> superClassOpt = view.getClass(superClassType); - if (superClassOpt.isPresent()) { - SootClass superClass = superClassOpt.get(); - Optional methodOpt = superClass.getMethod(sig.getSubSignature()); - if (methodOpt.isPresent()) { - return (T) methodOpt.get(); - } - } - } - logger.warn( - "Could not find \"" - + sig.getSubSignature() - + "\" in " - + sig.getDeclClassType().getClassName() - + " and in its superclasses"); - } else { - logger.trace("Could not find \"" + sig.getDeclClassType() + "\" in view"); - } - return null; - } - /** * This method enables optional pre-processing of a method in the call graph algorithm * @@ -438,7 +403,7 @@ public MethodSignature findMainMethod() { "There are more than 1 main method present.\n Below main methods are found: \n" + mainMethods + "\n initialize() method can be used if only one main method exists. \n You can specify these main methods as entry points by passing them as parameter to initialize method."); - } else if (mainMethods.size() == 0) { + } else if (mainMethods.isEmpty()) { throw new RuntimeException( "No main method is present in the input programs. initialize() method can be used if only one main method exists in the input program and that should be used as entry point for call graph. \n Please specify entry point as a parameter to initialize method."); } @@ -458,4 +423,87 @@ public MethodSignature findMainMethod() { @Nonnull protected abstract Stream resolveCall( SootMethod method, AbstractInvokeExpr invokeExpr); + + /** + * Searches for the signature of the method that is the concrete implementation of m. + * This is done by checking each superclass and the class itself for whether it contains the + * concrete implementation. + */ + @Nonnull + public static Optional resolveConcreteDispatch( + View> view, MethodSignature m) { + Optional methodOp = findConcreteMethod(view, m); + if (methodOp.isPresent()) { + SootMethod method = methodOp.get(); + if (method.isAbstract()) { + return Optional.empty(); + } + return Optional.of(method.getSignature()); + } + return Optional.empty(); + } + + /** + * searches the method object in the given hierarchy + * + * @param view it contains all classes + * @param sig the signature of the searched method + * @return the found method object, or null if the method was not found. + */ + public static Optional findConcreteMethod( + @Nonnull View> view, @Nonnull MethodSignature sig) { + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + SootClass startclass = view.getClass(sig.getDeclClassType()).orElse(null); + if (startclass == null) { + logger.warn( + "Could not find \"" + + sig.getDeclClassType() + + "\" of method" + + sig + + " to resolve the concrete method"); + return Optional.empty(); + } + Optional startMethod = startclass.getMethod(sig.getSubSignature()); + if (startMethod.isPresent()) { + return startMethod; + } + TypeHierarchy typeHierarchy = view.getTypeHierarchy(); + + List superClasses = typeHierarchy.superClassesOf(sig.getDeclClassType()); + for (ClassType superClassType : superClasses) { + Optional method = + view.getMethod( + identifierFactory.getMethodSignature(superClassType, sig.getSubSignature())); + if (method.isPresent()) { + return method; + } + } + Set interfaces = typeHierarchy.implementedInterfacesOf(sig.getDeclClassType()); + // interface1 is a sub-interface of interface2 + // interface1 is a super-interface of interface2 + // due to multiple inheritance in interfaces + final HierarchyComparator hierarchyComparator = new HierarchyComparator(view); + Optional defaultMethod = + interfaces.stream() + .map( + classType -> + view.getMethod( + identifierFactory.getMethodSignature(classType, sig.getSubSignature()))) + .filter(Optional::isPresent) + .map(Optional::get) + .min( + (m1, m2) -> + hierarchyComparator.compare( + m1.getDeclaringClassType(), m2.getDeclaringClassType())); + if (defaultMethod.isPresent()) { + return defaultMethod; + } + logger.warn( + "Could not find \"" + + sig.getSubSignature() + + "\" in " + + sig.getDeclClassType().getClassName() + + " and in its superclasses and interfaces"); + return Optional.empty(); + } } diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithm.java b/sootup.callgraph/src/main/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithm.java index d0f22f5323c..f360c852089 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithm.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithm.java @@ -25,14 +25,16 @@ import java.util.*; import java.util.stream.Stream; import javax.annotation.Nonnull; +import sootup.core.IdentifierFactory; import sootup.core.jimple.common.expr.AbstractInvokeExpr; import sootup.core.jimple.common.expr.JDynamicInvokeExpr; +import sootup.core.jimple.common.expr.JInterfaceInvokeExpr; import sootup.core.jimple.common.expr.JSpecialInvokeExpr; import sootup.core.model.MethodModifier; import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.MethodDispatchResolver; +import sootup.core.types.ClassType; import sootup.core.views.View; /** @@ -81,39 +83,68 @@ protected Stream resolveCall(SootMethod method, AbstractInvokeE return Stream.empty(); } - Stream result = Stream.of(targetMethodSignature); - - SootMethod targetMethod = - view.getClass(targetMethodSignature.getDeclClassType()) - .flatMap(clazz -> clazz.getMethod(targetMethodSignature.getSubSignature())) - .orElseGet(() -> findMethodInHierarchy(view, targetMethodSignature)); + SootMethod targetMethod = findConcreteMethod(view, targetMethodSignature).orElse(null); if (targetMethod == null || MethodModifier.isStatic(targetMethod.getModifiers()) || (invokeExpr instanceof JSpecialInvokeExpr)) { - return result; + return Stream.of(targetMethodSignature); } else { - if (targetMethod.isAbstract()) { - return resolveAllSubClassCallTargets(targetMethodSignature); + ArrayList noImplementedMethod = new ArrayList<>(); + List targets = + resolveAllCallTargets(targetMethodSignature, noImplementedMethod); + if (!targetMethod.isAbstract()) { + targets.add(targetMethod.getSignature()); + } + if (invokeExpr instanceof JInterfaceInvokeExpr) { + IdentifierFactory factory = view.getIdentifierFactory(); + noImplementedMethod.stream() + .map( + classType -> + resolveConcreteDispatch( + view, + factory.getMethodSignature( + classType, targetMethodSignature.getSubSignature()))) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(targets::add); } - return MethodDispatchResolver.resolveConcreteDispatch(view, targetMethodSignature) - .map( - methodSignature -> - Stream.concat( - Stream.of(methodSignature), - resolveAllSubClassCallTargets(targetMethodSignature))) - .orElseGet(() -> resolveAllSubClassCallTargets(targetMethodSignature)); + return targets.stream(); } } - private Stream resolveAllSubClassCallTargets( - MethodSignature targetMethodSignature) { - return MethodDispatchResolver.resolveAllDispatches(view, targetMethodSignature).stream() - .map( - methodSignature -> - MethodDispatchResolver.resolveConcreteDispatch(view, methodSignature)) - .filter(Optional::isPresent) - .map(Optional::get); + private List resolveAllCallTargets( + MethodSignature targetMethodSignature, ArrayList noImplementedMethod) { + ArrayList targets = new ArrayList<>(); + view.getTypeHierarchy() + .subtypesOf(targetMethodSignature.getDeclClassType()) + .forEach( + classType -> { + SootClass clazz = view.getClass(classType).orElse(null); + if (clazz == null) return; + // check if method is implemented + SootMethod method = + clazz.getMethod(targetMethodSignature.getSubSignature()).orElse(null); + if (method != null && !method.isAbstract()) targets.add(method.getSignature()); + // save classes with no implementation of the searched method + if (method == null && !clazz.isInterface()) noImplementedMethod.add(classType); + // collect all default methods + clazz + .getInterfaces() + .forEach( + interfaceType -> { + SootMethod defaultMethod = + view.getMethod( + view.getIdentifierFactory() + .getMethodSignature( + interfaceType, targetMethodSignature.getSubSignature())) + .orElse(null); + // contains an implemented default method + if (defaultMethod != null && !defaultMethod.isAbstract()) + targets.add(defaultMethod.getSignature()); + }); + }); + return targets; } @Override diff --git a/sootup.callgraph/src/main/java/sootup/callgraph/RapidTypeAnalysisAlgorithm.java b/sootup.callgraph/src/main/java/sootup/callgraph/RapidTypeAnalysisAlgorithm.java index d92abca3183..5bc3b472f2a 100644 --- a/sootup.callgraph/src/main/java/sootup/callgraph/RapidTypeAnalysisAlgorithm.java +++ b/sootup.callgraph/src/main/java/sootup/callgraph/RapidTypeAnalysisAlgorithm.java @@ -22,7 +22,6 @@ * #L% */ -import com.google.common.collect.Sets; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -35,7 +34,6 @@ import sootup.core.model.SootClass; import sootup.core.model.SootMethod; import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.MethodDispatchResolver; import sootup.core.types.ClassType; import sootup.core.views.View; @@ -100,9 +98,9 @@ public CallGraph initialize(@Nonnull List entryPoints) { * * @param method this object contains the method body which is inspected. */ - protected void collectInstantiatedClassesInMethod(SootMethod method) { + protected List collectInstantiatedClassesInMethod(SootMethod method) { if (method == null || method.isAbstract() || method.isNative()) { - return; + return Collections.emptyList(); } Set instantiated = @@ -112,7 +110,12 @@ protected void collectInstantiatedClassesInMethod(SootMethod method) { .filter(value -> value instanceof JNewExpr) .map(value -> ((JNewExpr) value).getType()) .collect(Collectors.toSet()); + List newInstantiatedClassTypes = + instantiated.stream() + .filter(classType -> !instantiatedClasses.contains(classType)) + .collect(Collectors.toList()); instantiatedClasses.addAll(instantiated); + return newInstantiatedClassTypes; } /** @@ -121,80 +124,93 @@ protected void collectInstantiatedClassesInMethod(SootMethod method) { * is instantiated and if it contains an implementation of the methods called in the invoke * expression. * - * @param method the method object that contains the given invoke expression in the body. + * @param sourceMethod the method object that contains the given invoke expression in the body. * @param invokeExpr it contains the call which is resolved. * @return a stream containing all reachable method signatures after applying the RTA call graph * algorithm */ @Override @Nonnull - protected Stream resolveCall(SootMethod method, AbstractInvokeExpr invokeExpr) { - MethodSignature targetMethodSignature = invokeExpr.getMethodSignature(); - Stream result = Stream.of(targetMethodSignature); + protected Stream resolveCall( + SootMethod sourceMethod, AbstractInvokeExpr invokeExpr) { + MethodSignature resolveBaseMethodSignature = invokeExpr.getMethodSignature(); + Stream result = Stream.of(resolveBaseMethodSignature); - SootMethod targetMethod = - view.getClass(targetMethodSignature.getDeclClassType()) - .flatMap(clazz -> clazz.getMethod(targetMethodSignature.getSubSignature())) - .orElseGet(() -> findMethodInHierarchy(view, targetMethodSignature)); + SootMethod concreteBaseMethod = + findConcreteMethod(view, resolveBaseMethodSignature).orElse(null); - if (targetMethod == null - || MethodModifier.isStatic(targetMethod.getModifiers()) + if (concreteBaseMethod == null + || MethodModifier.isStatic(concreteBaseMethod.getModifiers()) || (invokeExpr instanceof JSpecialInvokeExpr)) { return result; } else { - Set notInstantiatedCallTargets = Sets.newHashSet(); - Set implAndOverrides = - MethodDispatchResolver.resolveAllDispatchesInClasses( - view, targetMethodSignature, instantiatedClasses, notInstantiatedCallTargets); - // the class of the actual method call is instantiated - boolean targetMethodClassIsInstantiated = - instantiatedClasses.contains(targetMethodSignature.getDeclClassType()); - - // add the targetMethod to the ignoredCalls - if (!targetMethodClassIsInstantiated) { - notInstantiatedCallTargets.add(targetMethodSignature); + if (instantiatedClasses.contains(resolveBaseMethodSignature.getDeclClassType())) { + return Stream.concat( + Stream.of(concreteBaseMethod.getSignature()), + resolveAllCallTargets(sourceMethod.getSignature(), resolveBaseMethodSignature)); + } else { + saveIgnoredCall(sourceMethod.getSignature(), resolveBaseMethodSignature); + return resolveAllCallTargets(sourceMethod.getSignature(), resolveBaseMethodSignature); } + } + } - // save filtered calls to include them later when their class is instantiated - notInstantiatedCallTargets.forEach( - ignoredMethodSignature -> { - ClassType notInstantiatedClass = ignoredMethodSignature.getDeclClassType(); - List calls = ignoredCalls.get(notInstantiatedClass); - if (calls == null) { - calls = new ArrayList<>(); - calls.add(new Call(method.getSignature(), ignoredMethodSignature)); - ignoredCalls.put(notInstantiatedClass, calls); - } else { - calls.add(new Call(method.getSignature(), ignoredMethodSignature)); - } - }); - - // find the concrete dispatch of all possible dispatches - Set concreteCallTargets = - implAndOverrides.stream() - .map( - methodSignature -> - MethodDispatchResolver.resolveConcreteDispatch(view, methodSignature)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toSet()); - - // add the concrete of the targetMethod if the class is instantiated - if (targetMethodClassIsInstantiated) { - MethodDispatchResolver.resolveConcreteDispatch(view, targetMethodSignature) - .ifPresent(concreteCallTargets::add); - } + /** + * Resolves all targets of the given signature of the call. Only instantiated classes are + * considered as target. All possible class of non instantiated classes are saved to the + * ignoredCall Hashmap, because the classes can be instantiated at a later time + * + * @param source the method which contains call + * @param resolveBaseMethodSignature the base of the resolving. All subtypes of the declaring + * class are analyzed as potential targets + * @return a stream of all method signatures of instantiated classes that can be resolved as + * target from the given base method signature. + */ + private Stream resolveAllCallTargets( + MethodSignature source, MethodSignature resolveBaseMethodSignature) { + return view.getTypeHierarchy().subtypesOf(resolveBaseMethodSignature.getDeclClassType()) + .stream() + .map( + classType -> { + MethodSignature method = + view.getIdentifierFactory() + .getMethodSignature(classType, resolveBaseMethodSignature.getSubSignature()); + if (instantiatedClasses.contains(classType)) { + return resolveConcreteDispatch(view, method); + } else { + saveIgnoredCall(source, method); + return Optional.empty(); + } + }) + .filter(Optional::isPresent) + .map(Optional::get); + } - return concreteCallTargets.stream(); + /** + * This method saves an ignored call If this is the first ignored call of the class type in the + * target method, an entry for the class type is created in the ignoredCalls Hashmap + * + * @param source the source method of the call + * @param target the target method of the call + */ + private void saveIgnoredCall(MethodSignature source, MethodSignature target) { + ClassType notInstantiatedClass = target.getDeclClassType(); + List calls = ignoredCalls.get(notInstantiatedClass); + Call ignoredCall = new Call(source, target); + if (calls == null) { + calls = new ArrayList<>(); + ignoredCalls.put(notInstantiatedClass, calls); } + calls.add(ignoredCall); } /** * Preprocessing of a method in the RTA call graph algorithm * *

Before processing the method, all instantiated types are collected inside the body of the - * sourceMethod. + * sourceMethod. If a new instantiated class has previously ignored calls to this class, they are + * added to call graph * * @param view view * @param sourceMethod the processed method @@ -213,35 +229,15 @@ protected void preProcessingMethod( .orElse(null); if (method == null) return; - collectInstantiatedClassesInMethod(method); - } - - /** - * Postprocessing of a method in the RTA call graph algorithm - * - *

RTA has to add previously ignored calls because a found instantiation of a class could - * enable a call to a ignored method at a later time. - * - * @param view view - * @param sourceMethod the processed method - * @param workList the current worklist that is extended by methods that have to be analyzed. - * @param cg the current cg is extended by new call targets and calls - */ - @Override - protected void postProcessingMethod( - View> view, - MethodSignature sourceMethod, - @Nonnull Deque workList, - @Nonnull MutableCallGraph cg) { - instantiatedClasses.forEach( + List newInstantiatedClasses = collectInstantiatedClassesInMethod(method); + newInstantiatedClasses.forEach( instantiatedClassType -> { List newEdges = ignoredCalls.get(instantiatedClassType); if (newEdges != null) { newEdges.forEach( call -> { MethodSignature concreteTarget = - MethodDispatchResolver.resolveConcreteDispatch(view, call.target) - .orElse(null); + resolveConcreteDispatch(view, call.target).orElse(null); if (concreteTarget == null) { return; } @@ -260,4 +256,21 @@ protected void postProcessingMethod( } }); } + + /** + * Postprocessing is not needed in RTA + * + * @param view view + * @param sourceMethod the processed method + * @param workList the current worklist that is extended by methods that have to be analyzed. + * @param cg the current cg is extended by new call targets and calls + */ + @Override + protected void postProcessingMethod( + View> view, + MethodSignature sourceMethod, + @Nonnull Deque workList, + @Nonnull MutableCallGraph cg) { + // not needed + } } diff --git a/sootup.callgraph/src/test/java/sootup/callgraph/CallGraphTestBase.java b/sootup.callgraph/src/test/java/sootup/callgraph/CallGraphTestBase.java index f504b20b337..26c41ee37b8 100644 --- a/sootup.callgraph/src/test/java/sootup/callgraph/CallGraphTestBase.java +++ b/sootup.callgraph/src/test/java/sootup/callgraph/CallGraphTestBase.java @@ -130,8 +130,8 @@ public void testRecursiveCall() { assertTrue(cg.containsMethod(mainMethodSignature)); assertTrue(cg.containsMethod(method)); assertFalse(cg.containsMethod(uncalledMethod)); - // 2 methods + Object::clinit + Object::registerNatives - TestCase.assertEquals(4, cg.getMethodSignatures().size()); + // 2 methods + Object::clinit + TestCase.assertEquals(3, cg.getMethodSignatures().size()); assertTrue(cg.containsCall(mainMethodSignature, mainMethodSignature)); assertTrue(cg.containsCall(mainMethodSignature, method)); @@ -141,7 +141,7 @@ public void testRecursiveCall() { @Test public void testConcreteCall() { - CallGraph cg = loadCallGraph("ConcreteCall", "cvc.Class"); + CallGraph cg = loadCallGraph("ConcreteCall", false, "cvc.Class"); MethodSignature targetMethod = identifierFactory.getMethodSignature( identifierFactory.getClassType("cvc.Class"), "target", "void", Collections.emptyList()); @@ -160,9 +160,28 @@ public void testConcreteCallInSuperClass() { assertTrue(cg.containsCall(mainMethodSignature, targetMethod)); } + @Test + public void testConcreteCallDifferentDefaultMethodInSubClass() { + CallGraph cg = loadCallGraph("ConcreteCall", false, "cvcscddi.Class"); + MethodSignature interfaceMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("cvcscddi.Interface"), + "target", + "void", + Collections.emptyList()); + MethodSignature subInterfaceMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("cvcscddi.SubInterface"), + "target", + "void", + Collections.emptyList()); + assertTrue(cg.containsCall(mainMethodSignature, interfaceMethod)); + assertTrue(cg.containsCall(mainMethodSignature, subInterfaceMethod)); + } + @Test public void testConcreteCallInSuperClassWithDefaultInterface() { - CallGraph cg = loadCallGraph("ConcreteCall", "cvcscwi.Class"); + CallGraph cg = loadCallGraph("ConcreteCall", false, "cvcscwi.Class"); MethodSignature targetMethod = identifierFactory.getMethodSignature( identifierFactory.getClassType("cvcscwi.SuperClass"), @@ -174,7 +193,7 @@ public void testConcreteCallInSuperClassWithDefaultInterface() { @Test public void testConcreteCallInInterface() { - CallGraph cg = loadCallGraph("ConcreteCall", "cvci.Class"); + CallGraph cg = loadCallGraph("ConcreteCall", false, "cvci.Class"); MethodSignature targetMethod = identifierFactory.getMethodSignature( identifierFactory.getClassType("cvci.Interface"), @@ -186,7 +205,7 @@ public void testConcreteCallInInterface() { @Test public void testConcreteCallInSubInterface() { - CallGraph cg = loadCallGraph("ConcreteCall", "cvcsi.Class"); + CallGraph cg = loadCallGraph("ConcreteCall", false, "cvcsi.Class"); MethodSignature targetMethod = identifierFactory.getMethodSignature( identifierFactory.getClassType("cvcsi.SubInterface"), @@ -198,7 +217,7 @@ public void testConcreteCallInSubInterface() { @Test public void testConcreteCallInSuperClassSubInterface() { - CallGraph cg = loadCallGraph("ConcreteCall", "cvcscsi.Class"); + CallGraph cg = loadCallGraph("ConcreteCall", false, "cvcscsi.Class"); MethodSignature targetMethod = identifierFactory.getMethodSignature( identifierFactory.getClassType("cvcscsi.SubInterface"), @@ -443,9 +462,28 @@ public void testVirtualCall4() { assertTrue(cg.containsCall(mainMethodSignature, callMethod)); } + @Test + public void testDynamicInterfaceMethod0() { + CallGraph cg = loadCallGraph("InterfaceMethod", false, "j8dim0.Class"); + MethodSignature interfaceMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("j8dim0.Interface"), + "method", + "void", + Collections.emptyList()); + MethodSignature classMethod = + identifierFactory.getMethodSignature( + identifierFactory.getClassType("j8dim0.Class"), + "method", + "void", + Collections.emptyList()); + assertFalse(cg.containsCall(mainMethodSignature, interfaceMethod)); + assertTrue(cg.containsCall(mainMethodSignature, classMethod)); + } + @Test public void testDynamicInterfaceMethod1() { - CallGraph cg = loadCallGraph("InterfaceMethod", "j8dim1.Class"); + CallGraph cg = loadCallGraph("InterfaceMethod", false, "j8dim1.Class"); MethodSignature callMethod = identifierFactory.getMethodSignature( identifierFactory.getClassType("j8dim1.Interface"), @@ -457,7 +495,7 @@ public void testDynamicInterfaceMethod1() { @Test public void testDynamicInterfaceMethod2() { - CallGraph cg = loadCallGraph("InterfaceMethod", "j8dim2.SuperClass"); + CallGraph cg = loadCallGraph("InterfaceMethod", false, "j8dim2.SuperClass"); MethodSignature callMethod = identifierFactory.getMethodSignature( @@ -470,7 +508,7 @@ public void testDynamicInterfaceMethod2() { @Test public void testDynamicInterfaceMethod3() { - CallGraph cg = loadCallGraph("InterfaceMethod", "j8dim3.SuperClass"); + CallGraph cg = loadCallGraph("InterfaceMethod", false, "j8dim3.SuperClass"); MethodSignature callMethod = identifierFactory.getMethodSignature( @@ -480,7 +518,7 @@ public void testDynamicInterfaceMethod3() { @Test public void testDynamicInterfaceMethod4() { - CallGraph cg = loadCallGraph("InterfaceMethod", "j8dim4.SuperClass"); + CallGraph cg = loadCallGraph("InterfaceMethod", false, "j8dim4.SuperClass"); MethodSignature callMethod = identifierFactory.getMethodSignature( @@ -493,7 +531,7 @@ public void testDynamicInterfaceMethod4() { @Test public void testDynamicInterfaceMethod5() { - CallGraph cg = loadCallGraph("InterfaceMethod", "j8dim5.SuperClass"); + CallGraph cg = loadCallGraph("InterfaceMethod", false, "j8dim5.SuperClass"); MethodSignature method = identifierFactory.getMethodSignature( @@ -540,7 +578,7 @@ public void testDynamicInterfaceMethod6() { @Test public void testStaticInterfaceMethod() { - CallGraph cg = loadCallGraph("InterfaceMethod", "j8sim.Class"); + CallGraph cg = loadCallGraph("InterfaceMethod", false, "j8sim.Class"); MethodSignature method = identifierFactory.getMethodSignature( @@ -676,4 +714,43 @@ public void testNoMainMethod() { "No main method is present in the input programs. initialize() method can be used if only one main method exists in the input program and that should be used as entry point for call graph. \n Please specify entry point as a parameter to initialize method."); } } + + /** + * Test uses initialize() method to create call graph, but no main method is present in input java + * source files. Expected result is RuntimeException. + */ + @Test + public void testStopAtLibraryClass() { + + String classPath = "src/test/resources/callgraph/Library/binary/"; + JavaProject.JavaProjectBuilder javaProjectBuilder = + JavaProject.builder(new JavaLanguage(8)) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + System.getProperty("java.home") + "/lib/rt.jar", SourceType.Library)) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + classPath + "application/", SourceType.Application)) + .addInputLocation( + new JavaClassPathAnalysisInputLocation(classPath + "library/", SourceType.Library)); + JavaView view = javaProjectBuilder.build().createView(); + + MethodSignature mainMethodSignature = + identifierFactory.getMethodSignature( + "app.Application", "main", "void", Collections.singletonList("java.lang.String[]")); + CallGraphAlgorithm algorithm = createAlgorithm(view); + CallGraph cg = algorithm.initialize(Collections.singletonList(mainMethodSignature)); + + assertFalse(cg.callsFrom(mainMethodSignature).isEmpty()); + + SootClass libraryClass = + view.getClass(view.getIdentifierFactory().getClassType("lib.Library")).orElse(null); + assertNotNull(libraryClass); + for (SootMethod method : libraryClass.getMethods()) { + MethodSignature ms = method.getSignature(); + if (cg.containsMethod(ms)) { + assertEquals(0, cg.callsFrom(method.getSignature()).size()); + } + } + } } diff --git a/sootup.callgraph/src/test/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithmTest.java b/sootup.callgraph/src/test/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithmTest.java index 88d8b83677e..f9c6bdc1875 100644 --- a/sootup.callgraph/src/test/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithmTest.java +++ b/sootup.callgraph/src/test/java/sootup/callgraph/ClassHierarchyAnalysisAlgorithmTest.java @@ -188,44 +188,34 @@ public void testMiscExample1() { assertEquals( cg.toString().replace("\n", "").replace("\t", ""), - "GraphBasedCallGraph(16):" + "GraphBasedCallGraph(14):" + "()>:" + "to ()>" + "from ()>" + "from ()>" + "from ()>" - + "" + ":" + "from " - + "" + "()>:" + "to ()>" + "from " - + "" + ":" + "from " - + "" + ":" + "from " - + "" + "()>:" + "to ()>" + "from " - + "" + "()>:" + "to ()>" + "from ()>" - + "" + ":" + "from " - + "" + "()>:" + "to ()>" + "from " - + "" + ":" + "from " - + "" + ":" + "to " + "to ()>" @@ -236,17 +226,9 @@ public void testMiscExample1() { + "to ()>" + "to " + "to ()>" - + "" + "()>:" - + "to ()>" - + "to " + "from " - + "from ()>" - + "" + "()>:" - + "from ()>" - + "" - + ":" - + "from ()>"); + + "from ()>"); } } diff --git a/sootup.callgraph/src/test/java/sootup/callgraph/ConcreteDispatchTest.java b/sootup.callgraph/src/test/java/sootup/callgraph/ConcreteDispatchTest.java new file mode 100644 index 00000000000..d8d8ce95836 --- /dev/null +++ b/sootup.callgraph/src/test/java/sootup/callgraph/ConcreteDispatchTest.java @@ -0,0 +1,187 @@ +package sootup.callgraph; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertNotNull; +import static org.junit.Assert.assertFalse; + +import categories.Java8Test; +import java.util.Collections; +import java.util.Optional; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import sootup.core.IdentifierFactory; +import sootup.core.signatures.MethodSignature; +import sootup.core.types.ClassType; +import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.core.JavaProject; +import sootup.java.core.language.JavaLanguage; +import sootup.java.core.views.JavaView; + +/** @author : Hasitha Rajapakse, Jonas Klauke * */ +@Category(Java8Test.class) +public class ConcreteDispatchTest { + public ClassType getClassType(String className) { + return view.getIdentifierFactory().getClassType(className); + } + + private static JavaView view; + + @BeforeClass + public static void setUp() { + JavaProject project = + JavaProject.builder(new JavaLanguage(8)) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + "src/test/resources/callgraph/ConcreteDispatch/binary")) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + System.getProperty("java.home") + "/lib/rt.jar")) + .build(); + view = project.createView(); + } + + @Test + public void invalidResolveConcreteDispatch() { + IdentifierFactory factory = view.getIdentifierFactory(); + Optional incompleteMethod = + AbstractCallGraphAlgorithm.resolveConcreteDispatch( + view, factory.parseMethodSignature("cvcscincomplete.Class#target(): void")); + assertFalse(incompleteMethod.isPresent()); + } + + @Test() + public void invalidResolveConcreteDispatchOfAbstractMethod() { + IdentifierFactory factory = view.getIdentifierFactory(); + Optional abstractMethod = + AbstractCallGraphAlgorithm.resolveConcreteDispatch( + view, + factory.parseMethodSignature("java.util.AbstractList#get(int): java.lang.Object")); + assertFalse(abstractMethod.isPresent()); + + Optional interfaceMethod = + AbstractCallGraphAlgorithm.resolveConcreteDispatch( + view, factory.parseMethodSignature("java.util.Collection#size(): int")); + assertFalse(interfaceMethod.isPresent()); + } + + @Test + public void testResolveOfANotImplementedMethodInAbstractClass() { + IdentifierFactory factory = view.getIdentifierFactory(); + Optional emptySig = + AbstractCallGraphAlgorithm.resolveConcreteDispatch( + view, + factory.parseMethodSignature( + "com.sun.java.util.jar.pack.ConstantPool$LiteralEntry#equals(java.lang.Object): boolean")); + assertFalse(emptySig.isPresent()); + } + + @Test + public void resolveConcreteDispatch() { + IdentifierFactory factory = view.getIdentifierFactory(); + MethodSignature strToStringSig = + factory.parseMethodSignature("java.lang.String#toString(): java.lang.String"); + + MethodSignature concreteMethodSig = + AbstractCallGraphAlgorithm.resolveConcreteDispatch(view, strToStringSig).orElse(null); + Assert.assertNotNull(concreteMethodSig); + Assert.assertEquals( + "String.toString() should resolve to itself", strToStringSig, concreteMethodSig); + + MethodSignature concreteMethodSig2 = + AbstractCallGraphAlgorithm.resolveConcreteDispatch( + view, factory.parseMethodSignature("A#hashCode(): int")) + .orElse(null); + Assert.assertNotNull(concreteMethodSig2); + Assert.assertEquals( + "A.hashCode() should resolve to java.lang.Object.hashCode()", + factory.parseMethodSignature("java.lang.Object#hashCode(): int"), + concreteMethodSig2); + } + + @Test + public void method() { + // test concrete method in super class + ClassType sootClassTypeA = getClassType("A"); + ClassType sootClassTypeB = getClassType("B"); + + IdentifierFactory identifierFactory = view.getIdentifierFactory(); + MethodSignature sootMethod1 = + identifierFactory.getMethodSignature( + sootClassTypeA, "method", "void", Collections.emptyList()); + MethodSignature sootMethod2 = + identifierFactory.getMethodSignature( + sootClassTypeA, "method2", "void", Collections.emptyList()); + MethodSignature sootMethod3 = + identifierFactory.getMethodSignature( + sootClassTypeB, "method2", "void", Collections.emptyList()); + + MethodSignature candidate1 = + AbstractCallGraphAlgorithm.resolveConcreteDispatch(view, sootMethod1).orElse(null); + assertNotNull(candidate1); + assertEquals(candidate1, sootMethod1); + + MethodSignature candidate2 = + AbstractCallGraphAlgorithm.resolveConcreteDispatch(view, sootMethod2).orElse(null); + assertNotNull(candidate2); + assertEquals(candidate2, sootMethod3); + + // test concrete method in interface + ClassType sootClassInterfaceI = getClassType("I"); + MethodSignature sootInterfaceMethod = + identifierFactory.getMethodSignature( + sootClassInterfaceI, "interfaceMethod", "void", Collections.emptyList()); + + MethodSignature sootInterfaceMethodA = + identifierFactory.getMethodSignature( + sootClassTypeA, "interfaceMethod", "void", Collections.emptyList()); + + MethodSignature candidateInterface = + AbstractCallGraphAlgorithm.resolveConcreteDispatch(view, sootInterfaceMethodA).orElse(null); + assertNotNull(candidateInterface); + assertEquals(candidateInterface, sootInterfaceMethod); + + // test concrete method in super-interface + ClassType sootClassInterfaceJ = getClassType("J"); + MethodSignature sootSuperInterfaceMethod = + identifierFactory.getMethodSignature( + sootClassInterfaceJ, "superInterfaceMethod", "void", Collections.emptyList()); + + MethodSignature sootSuperInterfaceMethodA = + identifierFactory.getMethodSignature( + sootClassTypeA, "superInterfaceMethod", "void", Collections.emptyList()); + + MethodSignature candidateSuperInterface = + AbstractCallGraphAlgorithm.resolveConcreteDispatch(view, sootSuperInterfaceMethodA) + .orElse(null); + assertNotNull(candidateSuperInterface); + assertEquals(candidateSuperInterface, sootSuperInterfaceMethod); + + // test concrete method with two possible default methods but one is in the sub-interface + ClassType sootClassTypeC = getClassType("C"); + ClassType sootClassTypeD = getClassType("D"); + MethodSignature subInterfaceMethod = + identifierFactory.getMethodSignature( + sootClassInterfaceI, "interfaceMethod", "void", Collections.emptyList()); + + MethodSignature sootSuperInterfaceMethodD = + identifierFactory.getMethodSignature( + sootClassTypeD, "interfaceMethod", "void", Collections.emptyList()); + + MethodSignature sootSuperInterfaceMethodC = + identifierFactory.getMethodSignature( + sootClassTypeC, "interfaceMethod", "void", Collections.emptyList()); + + MethodSignature candidateSubInterface = + AbstractCallGraphAlgorithm.resolveConcreteDispatch(view, sootSuperInterfaceMethodD) + .orElse(null); + assertNotNull(candidateSubInterface); + assertEquals(candidateSubInterface, subInterfaceMethod); + MethodSignature candidateSubInterface2 = + AbstractCallGraphAlgorithm.resolveConcreteDispatch(view, sootSuperInterfaceMethodC) + .orElse(null); + assertNotNull(candidateSubInterface2); + assertEquals(candidateSubInterface, candidateSubInterface2); + } +} diff --git a/sootup.callgraph/src/test/java/sootup/callgraph/RapidTypeAnalysisAlgorithmTest.java b/sootup.callgraph/src/test/java/sootup/callgraph/RapidTypeAnalysisAlgorithmTest.java index ef03efc3265..19781a95323 100644 --- a/sootup.callgraph/src/test/java/sootup/callgraph/RapidTypeAnalysisAlgorithmTest.java +++ b/sootup.callgraph/src/test/java/sootup/callgraph/RapidTypeAnalysisAlgorithmTest.java @@ -180,41 +180,32 @@ public void testMiscExample1() { assertEquals( cg.toString().replace("\n", "").replace("\t", ""), - "GraphBasedCallGraph(15):" + "GraphBasedCallGraph(13):" + "()>:" + "to ()>" + "from ()>" + "from ()>" + "from ()>" - + "" + "()>:" + "to ()>" + "from " - + "" + ":" + "from " - + "" + ":" + "from " - + "" + "()>:" + "to ()>" + "from " - + "" + "()>:" + "to ()>" + "from ()>" - + "" + ":" + "from " - + "" + "()>:" + "to ()>" + "from " - + "" + ":" + "from " - + "" + ":" + "to ()>" + "to " @@ -224,18 +215,10 @@ public void testMiscExample1() { + "to ()>" + "to " + "to ()>" - + "" + "()>:" - + "to ()>" - + "to " + "from " - + "from ()>" - + "" + "()>:" - + "from ()>" - + "" - + ":" - + "from ()>"); + + "from ()>"); } @Test diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCall.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCall.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCall.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCall.java diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultInterface.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallDefaultInterface.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultInterface.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallDefaultInterface.java diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultSubInterface.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallDefaultSubInterface.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallDefaultSubInterface.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallDefaultSubInterface.java diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSubClassDiffDefaultInterface.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSubClassDiffDefaultInterface.java new file mode 100644 index 00000000000..7e6c61695de --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSubClassDiffDefaultInterface.java @@ -0,0 +1,30 @@ +package cvcscddi; + +class Class implements Interface{ + + public static void main(String[] args){ + Class cls = new Class(); + Class cls2 = new SubClass(); + cls.target(); + } +} + +class SubClass extends Class implements SubInterface{ + + public static void main(String[] args){ + Class cls = new Class(); + cls.target(); + } +} + +interface Interface { + + default void target(){ } + +} + +interface SubInterface extends Interface { + + default void target(){ } + +} diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassDefaultSubInterface.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSuperClassDefaultSubInterface.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassDefaultSubInterface.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSuperClassDefaultSubInterface.java diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassWithDefaultInterface.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSuperClassWithDefaultInterface.java similarity index 92% rename from sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassWithDefaultInterface.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSuperClassWithDefaultInterface.java index f16a278fdb8..b2b750b4937 100644 --- a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/source/ConcreteCallSuperClassWithDefaultInterface.java +++ b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/ConcreteCallSuperClassWithDefaultInterface.java @@ -15,7 +15,7 @@ public void target(){ } } -class Interface { +interface Interface { default void target(){ } diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvc/Class.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvc/Class.class new file mode 100644 index 00000000000..413b6747ffd Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvc/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvci/Class.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvci/Class.class new file mode 100644 index 00000000000..ebfa4e1a496 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvci/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvci/Interface.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvci/Interface.class new file mode 100644 index 00000000000..5e818d13203 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvci/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/Class.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/Class.class new file mode 100644 index 00000000000..3181ff804c8 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/Interface.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/Interface.class new file mode 100644 index 00000000000..0f041d01fcb Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/SubClass.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/SubClass.class new file mode 100644 index 00000000000..df26b49de76 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/SubClass.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/SubInterface.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/SubInterface.class new file mode 100644 index 00000000000..e308473e8c4 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscddi/SubInterface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/Class.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/Class.class new file mode 100644 index 00000000000..430e73707e9 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/Interface.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/Interface.class new file mode 100644 index 00000000000..587d1e68aac Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/SubInterface.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/SubInterface.class new file mode 100644 index 00000000000..781af7f185b Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/SubInterface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/SuperClass.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/SuperClass.class new file mode 100644 index 00000000000..61e6a34952a Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscsi/SuperClass.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscwi/Class.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscwi/Class.class new file mode 100644 index 00000000000..56a3212b2e7 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscwi/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscwi/Interface.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscwi/Interface.class new file mode 100644 index 00000000000..0374a362f67 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscwi/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscwi/SuperClass.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscwi/SuperClass.class new file mode 100644 index 00000000000..2e2733e8a47 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcscwi/SuperClass.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcsi/Class.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcsi/Class.class new file mode 100644 index 00000000000..b0f3d819239 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcsi/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcsi/Interface.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcsi/Interface.class new file mode 100644 index 00000000000..5b43aee51da Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcsi/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcsi/SubInterface.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcsi/SubInterface.class new file mode 100644 index 00000000000..19f701e592a Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteCall/binary/cvcsi/SubInterface.class differ diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/A.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/A.java similarity index 100% rename from sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/A.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/A.java diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/B.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/B.java similarity index 100% rename from sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/B.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/B.java diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/C.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/C.java similarity index 100% rename from sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/C.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/C.java diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/ConcreteCallSuperClassIncomplete.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/ConcreteCallSuperClassIncomplete.java new file mode 100644 index 00000000000..a46ececd498 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/ConcreteCallSuperClassIncomplete.java @@ -0,0 +1,17 @@ +// cvc/Class.java +package cvcscincomplete; + +class Class extends SuperClass{ + + public static void main(String[] args){ + Class cls = new Class(); + cls.target(); + } +} + +//class file of the superclass is not in the inputlocation +class SuperClass { + + public void target(){ } + +} diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/D.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/D.java similarity index 100% rename from sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/D.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/D.java diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/I.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/I.java similarity index 100% rename from sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/I.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/I.java diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/J.java b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/J.java similarity index 100% rename from sootup.tests/src/test/resources/methoddispatchresolver/ConcreteDispatch/J.java rename to sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/J.java diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/A.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/A.class new file mode 100644 index 00000000000..2c6b3cd9c77 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/A.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/B.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/B.class new file mode 100644 index 00000000000..dc3f1fe55ab Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/B.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/C.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/C.class new file mode 100644 index 00000000000..11c37bfe175 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/C.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/D.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/D.class new file mode 100644 index 00000000000..bf0e309a8b8 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/D.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/I.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/I.class new file mode 100644 index 00000000000..e836f09f4ad Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/I.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/J.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/J.class new file mode 100644 index 00000000000..cbb7535064d Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/J.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/cvcscincomplete/Class.class b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/cvcscincomplete/Class.class new file mode 100644 index 00000000000..7f60d2089b0 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/ConcreteDispatch/binary/cvcscincomplete/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM0.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM0.java new file mode 100644 index 00000000000..37ffe538759 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM0.java @@ -0,0 +1,19 @@ +// j8dim/Class.java +package j8dim0; + +// import lib.annotations.callgraph.DirectCall; + +class Class implements Interface { + + public void method(){ + + } + public static void main(String[] args){ + Interface i = new Class(); + i.method(); + } +} + +interface Interface { + public void method(); +} \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM1.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM1.java similarity index 96% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM1.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM1.java index 71a5c63921d..b5895367536 100644 --- a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM1.java +++ b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM1.java @@ -14,6 +14,7 @@ public static void main(String[] args){ interface Interface { default void method() { + int x=3; // do something } } \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM2.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM2.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM2.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM2.java diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM3.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM3.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM3.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM3.java diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM4.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM4.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM4.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM4.java diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM5.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM5.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8DIM5.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8DIM5.java diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8SIM.java b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8SIM.java similarity index 100% rename from sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/source/J8SIM.java rename to sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/J8SIM.java diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim0/Class.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim0/Class.class new file mode 100644 index 00000000000..b844d07cebd Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim0/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim0/Interface.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim0/Interface.class new file mode 100644 index 00000000000..acf45c29d50 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim0/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim1/Class.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim1/Class.class new file mode 100644 index 00000000000..0815d28b26a Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim1/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim1/Interface.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim1/Interface.class new file mode 100644 index 00000000000..f76e234bb54 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim1/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim2/Interface.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim2/Interface.class new file mode 100644 index 00000000000..34672fc6502 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim2/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim2/SubClass.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim2/SubClass.class new file mode 100644 index 00000000000..029fbd7eba0 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim2/SubClass.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim2/SuperClass.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim2/SuperClass.class new file mode 100644 index 00000000000..0673b14edbf Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim2/SuperClass.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim3/Interface.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim3/Interface.class new file mode 100644 index 00000000000..5c863f722ef Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim3/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim3/SubClass.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim3/SubClass.class new file mode 100644 index 00000000000..65da4ba8f0d Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim3/SubClass.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim3/SuperClass.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim3/SuperClass.class new file mode 100644 index 00000000000..0e887b72ebd Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim3/SuperClass.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim4/Interface.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim4/Interface.class new file mode 100644 index 00000000000..21e7659b2cd Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim4/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim4/SubClass.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim4/SubClass.class new file mode 100644 index 00000000000..0c3e1838380 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim4/SubClass.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim4/SuperClass.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim4/SuperClass.class new file mode 100644 index 00000000000..eb24c2fa63b Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim4/SuperClass.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/Class.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/Class.class new file mode 100644 index 00000000000..8625dc21d5b Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/DirectInterface.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/DirectInterface.class new file mode 100644 index 00000000000..5179317d732 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/DirectInterface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/Interface1.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/Interface1.class new file mode 100644 index 00000000000..c16a7ba9cee Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/Interface1.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/Interface2.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/Interface2.class new file mode 100644 index 00000000000..ec52fef02b4 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/Interface2.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/SuperClass.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/SuperClass.class new file mode 100644 index 00000000000..4559d17866d Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8dim5/SuperClass.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8sim/Class.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8sim/Class.class new file mode 100644 index 00000000000..f32ff7c3c89 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8sim/Class.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8sim/Interface.class b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8sim/Interface.class new file mode 100644 index 00000000000..49a8ad82098 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/InterfaceMethod/binary/j8sim/Interface.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/Library/binary/Application.java b/sootup.callgraph/src/test/resources/callgraph/Library/binary/Application.java new file mode 100644 index 00000000000..7fba38aef09 --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/Library/binary/Application.java @@ -0,0 +1,14 @@ +package app; + +import lib.Library; +public class Application { + + public static void main(String[] args) { + Library lib = new Library(); + lib.use(); + test(); + } + public static void test() { + + } +} diff --git a/sootup.callgraph/src/test/resources/callgraph/Library/binary/Library.java b/sootup.callgraph/src/test/resources/callgraph/Library/binary/Library.java new file mode 100644 index 00000000000..35e7b975a9b --- /dev/null +++ b/sootup.callgraph/src/test/resources/callgraph/Library/binary/Library.java @@ -0,0 +1,18 @@ +package lib; + +public class Library { + + public Library (){ + c(); + } + public void use() { + a(); + b(); + } + public void a() { + } + public void b() { + } + public void c() { + } +} \ No newline at end of file diff --git a/sootup.callgraph/src/test/resources/callgraph/Library/binary/application/app/Application.class b/sootup.callgraph/src/test/resources/callgraph/Library/binary/application/app/Application.class new file mode 100644 index 00000000000..8d99354bc49 Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/Library/binary/application/app/Application.class differ diff --git a/sootup.callgraph/src/test/resources/callgraph/Library/binary/library/lib/Library.class b/sootup.callgraph/src/test/resources/callgraph/Library/binary/library/lib/Library.class new file mode 100644 index 00000000000..277179fbfde Binary files /dev/null and b/sootup.callgraph/src/test/resources/callgraph/Library/binary/library/lib/Library.class differ diff --git a/sootup.core/src/main/java/sootup/core/typehierarchy/HierarchyComparator.java b/sootup.core/src/main/java/sootup/core/typehierarchy/HierarchyComparator.java new file mode 100644 index 00000000000..f2a2612ab02 --- /dev/null +++ b/sootup.core/src/main/java/sootup/core/typehierarchy/HierarchyComparator.java @@ -0,0 +1,55 @@ +package sootup.core.typehierarchy; +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 2023 Jonas Klauke + * %% + * This program 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 2.1 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 Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ + +import java.util.Comparator; +import javax.annotation.Nonnull; +import sootup.core.model.SootClass; +import sootup.core.types.ClassType; +import sootup.core.views.View; + +/** + * Comparator to sort ClassTypes which are ideally connected in a Hierarchy. subtypes will be before + * super classes in the resulting order. + */ +public class HierarchyComparator implements Comparator { + + TypeHierarchy typeHierarchy; + + public HierarchyComparator(@Nonnull View> view) { + this(view.getTypeHierarchy()); + } + + public HierarchyComparator(@Nonnull TypeHierarchy hierarchy) { + this.typeHierarchy = hierarchy; + } + + @Override + public int compare(ClassType classType1, ClassType classType2) { + // classType1 is a subclass type of classType2 + if (typeHierarchy.isSubtype(classType2, classType1)) return -1; + // classType1 is a subclass type of classType2 + if (typeHierarchy.isSubtype(classType1, classType2)) return 1; + // classType1 and classType2 are on the same hierarchy level + return 0; + } +} diff --git a/sootup.core/src/main/java/sootup/core/typehierarchy/MethodDispatchResolver.java b/sootup.core/src/main/java/sootup/core/typehierarchy/MethodDispatchResolver.java deleted file mode 100644 index 3a642172219..00000000000 --- a/sootup.core/src/main/java/sootup/core/typehierarchy/MethodDispatchResolver.java +++ /dev/null @@ -1,315 +0,0 @@ -package sootup.core.typehierarchy; -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 2019-2022 Christian Brüggemann, Jonas Klauke - * %% - * This program 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 2.1 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 Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ - -import com.google.common.collect.Sets; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.annotation.Nonnull; -import sootup.core.frontend.ResolveException; -import sootup.core.jimple.common.expr.JSpecialInvokeExpr; -import sootup.core.model.Method; -import sootup.core.model.SootClass; -import sootup.core.model.SootMethod; -import sootup.core.signatures.MethodSignature; -import sootup.core.types.ClassType; -import sootup.core.views.View; - -public final class MethodDispatchResolver { - private MethodDispatchResolver() {} - - /** - * Searches the view for classes that are subtypes of the class contained in the signature. - * returns method signatures to all subtypes. Abstract methods are filtered the returned set can - * contain signatures of not implemented methods. - */ - @Nonnull - public static Set resolveAllDispatches( - View> view, MethodSignature m) { - TypeHierarchy hierarchy = view.getTypeHierarchy(); - - return hierarchy.subtypesOf(m.getDeclClassType()).stream() - .map( - subtype -> - view.getClass(subtype) - .orElseThrow( - () -> - new ResolveException( - "Could not resolve " + subtype + ", but found it in hierarchy."))) - .filter( - sootClass -> { - SootMethod sootMethod = sootClass.getMethod(m.getSubSignature()).orElse(null); - // method is not implemented or not abstract - return sootMethod == null || !sootMethod.isAbstract(); - }) - .map(sootClass -> new MethodSignature(sootClass.getType(), m.getSubSignature())) - .collect(Collectors.toSet()); - } - - /** - * Searches the view for classes that implement or override the method m and returns - * the set of method signatures that a method call could resolve to. - */ - @Nonnull - public static Set resolveAbstractDispatch( - View> view, MethodSignature m) { - TypeHierarchy hierarchy = view.getTypeHierarchy(); - - return hierarchy.subtypesOf(m.getDeclClassType()).stream() - .map( - subtype -> - view.getClass(subtype) - .orElseThrow( - () -> - new ResolveException( - "Could not resolve " + subtype + ", but found it in hierarchy."))) - .map(sootClass -> sootClass.getMethod(m.getSubSignature())) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(method -> !method.isAbstract()) - .map(Method::getSignature) - .collect(Collectors.toSet()); - } - - /** - * Searches the view for classes that implement or override the method m and returns - * the set of method signatures that a method call could resolve to within the given classes. - */ - @Nonnull - public static Set resolveAllDispatchesInClasses( - View> view, MethodSignature m, Set classes) { - TypeHierarchy hierarchy = view.getTypeHierarchy(); - - return hierarchy.subtypesOf(m.getDeclClassType()).stream() - .map( - subtype -> - view.getClass(subtype) - .orElseThrow( - () -> - new ResolveException( - "Could not resolve " + subtype + ", but found it in hierarchy."))) - .filter(c -> classes.contains(c.getType())) - .map(sootClass -> sootClass.getMethod(m.getSubSignature())) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(method -> !method.isAbstract()) - .map(Method::getSignature) - .collect(Collectors.toSet()); - } - - /** - * Resolves all dispatches of a given call filtered by a set of given classes - * - *

searches the view for classes that can override the method m and returns the - * set of method signatures that a method call could resolve to within the given classes. All - * filtered signatures are added to the given set filteredSignatures. - * - * @param view it contains all classes and their connections. - * @param m it defines the actual invoked method signature. - * @param classes the set of classes that define possible dispatch targets of method signatures - * @param filteredSignatures the set of method signatures which is filled with filtered method - * signatures in the execution of this method. - * @return a set of method signatures that a method call could resolve to within the given classes - */ - @Nonnull - public static Set resolveAllDispatchesInClasses( - View> view, - MethodSignature m, - Set classes, - Set filteredSignatures) { - - Set allSignatures = resolveAllDispatches(view, m); - Set signatureInClasses = Sets.newHashSet(); - allSignatures.forEach( - methodSignature -> { - if (classes.contains(methodSignature.getDeclClassType())) { - signatureInClasses.add(methodSignature); - } else { - filteredSignatures.add(methodSignature); - } - }); - - return signatureInClasses; - } - - /** - * Warning! Assumes that for an abstract dispatch, potentialTarget is declared - * in the same or a subtype of the declaring class of called. - * - *

For a concrete dispatch, assumes that potentialTarget is declared in the same - * or a supertype of the declaring class of called. - * - * @return Whether name and parameters are equal and the return type of potentialTarget - * is compatible with the return type of called. - */ - public static boolean canDispatch( - MethodSignature called, MethodSignature potentialTarget, TypeHierarchy hierarchy) { - return called.getName().equals(potentialTarget.getName()) - && called.getParameterTypes().equals(potentialTarget.getParameterTypes()) - && (called.getType().equals(potentialTarget.getType()) // return types are equal - || hierarchy.isSubtype(called.getType(), potentialTarget.getType())); // covariant - } - - /** - * Returns all superclasses of classType(inclusive) up to java.lang.Object - * , which will be the last entry in the list, or till one of the superclasses is not - * contained in view. - */ - private static List> findSuperClassesInclusive( - View> view, ClassType classType) { - return Stream.concat( - Stream.of(classType), view.getTypeHierarchy().superClassesOf(classType).stream()) - .flatMap(t -> view.getClass(t).map(Stream::of).orElseGet(Stream::empty)) - .collect(Collectors.toList()); - } - - /** - * Searches for the signature of the method that is the concrete implementation of m. - * This is done by checking each superclass and the class itself for whether it contains the - * concrete implementation. - */ - @Nonnull - public static Optional resolveConcreteDispatch( - View> view, MethodSignature m) { - TypeHierarchy hierarchy = view.getTypeHierarchy(); - ClassType current = m.getDeclClassType(); - SootClass startClass = view.getClass(current).orElse(null); - List> classesInHierarchyOrder = findSuperClassesInclusive(view, current); - - for (SootClass currentClass : classesInHierarchyOrder) { - SootMethod method = currentClass.getMethod(m.getSubSignature()).orElse(null); - if (method != null) { - if (!method.isAbstract()) { - // found method is not abstract - return Optional.of(method.getSignature()); - } else { - if (startClass.isAbstract() - && !startClass.getType().equals(method.getDeclaringClassType())) { - // A not implemented method of an abstract class results into an abstract method - return Optional.empty(); - } - // found method is abstract and the startClass is not abstract - throw new ResolveException( - "Could not find concrete method for " + m + " because the method is abstract"); - } - } - } - - // No super class contains the implemented method, search the concrete method in interfaces - // first collect all interfaces and super interfaces - List> worklist = - classesInHierarchyOrder.stream() - .flatMap(sootClass -> getSootClassesOfInterfaces(view, sootClass).stream()) - .collect(Collectors.toList()); - ArrayList> processedInterface = new ArrayList<>(); - ArrayList possibleDefaultMethods = new ArrayList<>(); - while (!worklist.isEmpty()) { - SootClass currentInterface = worklist.remove(0); - if (processedInterface.contains(currentInterface)) { - // interface was already processed - continue; - } - - // add found default method to possibleDefaultMethods - Optional concreteMethod = - currentInterface.getMethod(m.getSubSignature()); - concreteMethod.ifPresent(possibleDefaultMethods::add); - - // if no default message is found search the default message in super interfaces - if (!concreteMethod.isPresent()) { - worklist.addAll(getSootClassesOfInterfaces(view, currentInterface)); - } - processedInterface.add(currentInterface); - } - - if (!possibleDefaultMethods.isEmpty()) { - // the interfaces are sorted by hierarchy - possibleDefaultMethods.sort( - (interface1, interface2) -> { - // interface1 is a sub-interface of interface2 - if (hierarchy.isSubtype( - interface2.getDeclaringClassType(), interface1.getDeclaringClassType())) return -1; - // interface1 is a super-interface of interface2 - if (hierarchy.isSubtype( - interface1.getDeclaringClassType(), interface2.getDeclaringClassType())) return 1; - // due to multiple inheritance in interfaces - return 0; - }); - // return the lowest element in the hierarchy - return Optional.of(possibleDefaultMethods.get(0).getSignature()); - } - throw new ResolveException("Could not find concrete method for " + m); - } - - /** - * Returns all SootClasses of interfaces that are implemented in the given SootClass - * - *

returns a list of all SootClass Objects of interfaces that are associated with the given - * sootClass parameter. The ClassTypes of the interfaces are converted to SootClasses and not - * contained Interfaces are filtered. - * - * @param view the view that contains all searched SootClasses - * @param sootClass it contains the interfaces - * @return a list of SootClasses of the interfaces of sootClass - */ - private static List> getSootClassesOfInterfaces( - View> view, SootClass sootClass) { - return sootClass.getInterfaces().stream() - .map(view::getClass) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toList()); - } - - /** - * Resolves the actual method called by the specialInvokeExpr that is contained by - * container. - */ - public static MethodSignature resolveSpecialDispatch( - View> view, - JSpecialInvokeExpr specialInvokeExpr, - MethodSignature container) { - MethodSignature specialMethodSig = specialInvokeExpr.getMethodSignature(); - if (specialMethodSig.getSubSignature().getName().equals("")) { - return specialMethodSig; - } - - SootMethod specialMethod = - view.getClass(specialMethodSig.getDeclClassType()) - .flatMap(cl -> cl.getMethod(specialMethodSig.getSubSignature())) - .orElse(null); - if (specialMethod != null && specialMethod.isPrivate()) { - return specialMethodSig; - } - - if (view.getTypeHierarchy() - .isSubtype(container.getDeclClassType(), specialMethodSig.getDeclClassType())) { - return resolveConcreteDispatch(view, specialMethodSig).orElse(null); - } - - return specialMethodSig; - } -} diff --git a/sootup.tests/src/test/java/sootup/tests/typehierarchy/HierarchyComparatorTest.java b/sootup.tests/src/test/java/sootup/tests/typehierarchy/HierarchyComparatorTest.java new file mode 100644 index 00000000000..e431486ae2d --- /dev/null +++ b/sootup.tests/src/test/java/sootup/tests/typehierarchy/HierarchyComparatorTest.java @@ -0,0 +1,151 @@ +package sootup.tests.typehierarchy; + +import static org.junit.Assert.assertEquals; + +import categories.Java8Test; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import sootup.core.model.SootClass; +import sootup.core.typehierarchy.HierarchyComparator; +import sootup.core.types.ClassType; +import sootup.core.views.View; +import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.core.JavaProject; +import sootup.java.core.language.JavaLanguage; +import sootup.java.sourcecode.inputlocation.JavaSourcePathAnalysisInputLocation; + +@Category(Java8Test.class) +public class HierarchyComparatorTest { + + private static View> view; + + @BeforeClass + public static void setUp() { + JavaProject project = + JavaProject.builder(new JavaLanguage(8)) + .addInputLocation( + new JavaSourcePathAnalysisInputLocation( + Collections.singleton("src/test/resources/javatypehierarchy/Comparator"))) + .addInputLocation( + new JavaClassPathAnalysisInputLocation( + System.getProperty("java.home") + "/lib/rt.jar")) + .build(); + view = project.createView(); + } + + @Test + public void testHierarchyComparatorOnClasses() { + ClassType superclass = view.getIdentifierFactory().getClassType("Superclass", ""); + ClassType subclass = view.getIdentifierFactory().getClassType("Subclass", ""); + ClassType subSubclass = view.getIdentifierFactory().getClassType("SubSubclass", ""); + + HierarchyComparator hc = new HierarchyComparator(view); + assertEquals(-1, hc.compare(subclass, superclass)); + assertEquals(-1, hc.compare(subSubclass, superclass)); + assertEquals(-1, hc.compare(subSubclass, subclass)); + assertEquals(1, hc.compare(superclass, subclass)); + assertEquals(1, hc.compare(superclass, subSubclass)); + assertEquals(1, hc.compare(subclass, subSubclass)); + + ArrayList classes = new ArrayList<>(); + classes.add(superclass); + classes.add(subSubclass); + classes.add(subclass); + List classesSorted = classes.stream().sorted(hc).collect(Collectors.toList()); + assertEquals(subSubclass, classesSorted.get(0)); + assertEquals(subclass, classesSorted.get(1)); + assertEquals(superclass, classesSorted.get(2)); + } + + @Test + public void testHierarchyComparatorOnInterfaces() { + ClassType Interface = view.getIdentifierFactory().getClassType("Interface", ""); + ClassType subInterface = view.getIdentifierFactory().getClassType("SubInterface", ""); + ClassType subSubInterface2 = view.getIdentifierFactory().getClassType("SubSubInterface", ""); + + HierarchyComparator hc = new HierarchyComparator(view); + assertEquals(-1, hc.compare(subInterface, Interface)); + assertEquals(-1, hc.compare(subSubInterface2, Interface)); + assertEquals(-1, hc.compare(subSubInterface2, subInterface)); + assertEquals(1, hc.compare(Interface, subInterface)); + assertEquals(1, hc.compare(Interface, subSubInterface2)); + assertEquals(1, hc.compare(subInterface, subSubInterface2)); + + ArrayList classes = new ArrayList<>(); + classes.add(Interface); + classes.add(subSubInterface2); + classes.add(subInterface); + List classesSorted = classes.stream().sorted(hc).collect(Collectors.toList()); + assertEquals(subSubInterface2, classesSorted.get(0)); + assertEquals(subInterface, classesSorted.get(1)); + assertEquals(Interface, classesSorted.get(2)); + } + + @Test + public void testHierarchyComparatorOnMixed() { + ClassType Interface = view.getIdentifierFactory().getClassType("Interface", ""); + ClassType subInterface = view.getIdentifierFactory().getClassType("SubInterface", ""); + ClassType subSubInterface = view.getIdentifierFactory().getClassType("SubSubInterface", ""); + ClassType superclass = view.getIdentifierFactory().getClassType("Superclass", ""); + ClassType subclass = view.getIdentifierFactory().getClassType("Subclass", ""); + ClassType subSubclass = view.getIdentifierFactory().getClassType("SubSubclass", ""); + + HierarchyComparator hc = new HierarchyComparator(view); + + assertEquals(-1, hc.compare(subSubInterface, Interface)); + assertEquals(-1, hc.compare(subSubInterface, subInterface)); + assertEquals(1, hc.compare(subSubInterface, superclass)); + assertEquals(1, hc.compare(subSubInterface, subclass)); + assertEquals(1, hc.compare(subSubInterface, subSubclass)); + + assertEquals(-1, hc.compare(subInterface, Interface)); + assertEquals(1, hc.compare(subInterface, subSubInterface)); + assertEquals(1, hc.compare(subInterface, superclass)); + assertEquals(1, hc.compare(subInterface, subclass)); + assertEquals(1, hc.compare(subInterface, subSubclass)); + + assertEquals(1, hc.compare(Interface, subInterface)); + assertEquals(1, hc.compare(Interface, subSubInterface)); + assertEquals(1, hc.compare(Interface, superclass)); + assertEquals(1, hc.compare(Interface, subclass)); + assertEquals(1, hc.compare(Interface, subSubclass)); + + assertEquals(-1, hc.compare(superclass, Interface)); + assertEquals(-1, hc.compare(superclass, subInterface)); + assertEquals(-1, hc.compare(superclass, subSubInterface)); + assertEquals(1, hc.compare(superclass, subclass)); + assertEquals(1, hc.compare(superclass, subSubclass)); + + assertEquals(-1, hc.compare(subclass, Interface)); + assertEquals(-1, hc.compare(subclass, subInterface)); + assertEquals(-1, hc.compare(subclass, subSubInterface)); + assertEquals(-1, hc.compare(subclass, superclass)); + assertEquals(1, hc.compare(subclass, subSubclass)); + + assertEquals(-1, hc.compare(subSubclass, Interface)); + assertEquals(-1, hc.compare(subSubclass, subInterface)); + assertEquals(-1, hc.compare(subSubclass, subSubInterface)); + assertEquals(-1, hc.compare(subSubclass, superclass)); + assertEquals(-1, hc.compare(subSubclass, subclass)); + + ArrayList classes = new ArrayList<>(); + classes.add(Interface); + classes.add(subclass); + classes.add(subSubInterface); + classes.add(superclass); + classes.add(subInterface); + classes.add(subSubclass); + List classesSorted = classes.stream().sorted(hc).collect(Collectors.toList()); + assertEquals(subSubclass, classesSorted.get(0)); + assertEquals(subclass, classesSorted.get(1)); + assertEquals(superclass, classesSorted.get(2)); + assertEquals(subSubInterface, classesSorted.get(3)); + assertEquals(subInterface, classesSorted.get(4)); + assertEquals(Interface, classesSorted.get(5)); + } +} diff --git a/sootup.tests/src/test/java/sootup/tests/typehierarchy/MethodDispatchBase.java b/sootup.tests/src/test/java/sootup/tests/typehierarchy/MethodDispatchBase.java deleted file mode 100644 index 2cab39ad2dc..00000000000 --- a/sootup.tests/src/test/java/sootup/tests/typehierarchy/MethodDispatchBase.java +++ /dev/null @@ -1,78 +0,0 @@ -package sootup.tests.typehierarchy; - -import categories.Java8Test; -import java.util.Collections; -import org.junit.ClassRule; -import org.junit.experimental.categories.Category; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; -import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; -import sootup.java.core.JavaIdentifierFactory; -import sootup.java.core.JavaProject; -import sootup.java.core.language.JavaLanguage; -import sootup.java.core.types.JavaClassType; -import sootup.java.core.views.JavaView; -import sootup.java.sourcecode.inputlocation.JavaSourcePathAnalysisInputLocation; - -/** @author Hasitha Rajapakse */ -@Category(Java8Test.class) -public class MethodDispatchBase { - static final String baseDir = "src/test/resources/methoddispatchresolver/"; - protected JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); - - @ClassRule - public static MethodDispatchBase.CustomTestWatcher customTestWatcher = - new MethodDispatchBase.CustomTestWatcher(); - - public static class CustomTestWatcher extends TestWatcher { - private String className = MethodDispatchBase.class.getSimpleName(); - private JavaView view; - - @Override - protected void starting(Description description) { - String prevClassName = getClassName(); - setClassName(extractClassName(description.getClassName())); - if (!prevClassName.equals(getClassName())) { - JavaProject project = - JavaProject.builder(new JavaLanguage(8)) - .addInputLocation( - new JavaSourcePathAnalysisInputLocation( - Collections.singleton(baseDir + "/" + getClassName()))) - .addInputLocation( - new JavaClassPathAnalysisInputLocation( - System.getProperty("java.home") + "/lib/rt.jar")) - .build(); - setView(project.createView()); - } - } - - public String getClassName() { - return className; - } - - private void setClassName(String className) { - this.className = className; - } - - private void setView(JavaView view) { - this.view = view; - } - - public JavaView getView() { - return view; - } - } - - public JavaClassType getClassType(String className) { - return identifierFactory.getClassType(className); - } - - public static String extractClassName(String classPath) { - String classPathArray = classPath.substring(classPath.lastIndexOf(".") + 1); - String testDirectoryName = ""; - if (!classPathArray.isEmpty()) { - testDirectoryName = classPathArray.substring(0, classPathArray.length() - 4); - } - return testDirectoryName; - } -} diff --git a/sootup.tests/src/test/java/sootup/tests/typehierarchy/MethodDispatchResolverTest.java b/sootup.tests/src/test/java/sootup/tests/typehierarchy/MethodDispatchResolverTest.java deleted file mode 100644 index 1e6fb17efee..00000000000 --- a/sootup.tests/src/test/java/sootup/tests/typehierarchy/MethodDispatchResolverTest.java +++ /dev/null @@ -1,225 +0,0 @@ -package sootup.tests.typehierarchy; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import categories.Java8Test; -import java.io.File; -import java.lang.management.ManagementFactory; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import sootup.core.IdentifierFactory; -import sootup.core.frontend.ResolveException; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.common.expr.JSpecialInvokeExpr; -import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.MethodDispatchResolver; -import sootup.core.types.ClassType; -import sootup.core.util.ImmutableUtils; -import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; -import sootup.java.core.JavaProject; -import sootup.java.core.language.JavaJimple; -import sootup.java.core.language.JavaLanguage; -import sootup.java.core.views.JavaView; - -/** @author Kaustubh Kelkar update on 22.04.2020 */ -@Category(Java8Test.class) -public class MethodDispatchResolverTest { - - private JavaView view; - public static final String jarFile = "../shared-test-resources/java-miniapps/MiniApp.jar"; - - @Before - public void setUp() { - assertTrue("File " + jarFile + " not found.", new File(jarFile).exists()); - String currentClassPath = - System.getProperty("java.class.path") - + File.pathSeparator - + ManagementFactory.getRuntimeMXBean().getBootClassPath(); - String rtJarClassPath = - Arrays.stream(currentClassPath.split(File.pathSeparator)) - .filter(pathEntry -> pathEntry.endsWith(File.separator + "rt.jar")) - .distinct() - .collect(Collectors.joining(File.pathSeparator)); - JavaClassPathAnalysisInputLocation analysisInputLocation = - new JavaClassPathAnalysisInputLocation(jarFile + File.pathSeparator + rtJarClassPath); - JavaProject p = - JavaProject.builder(new JavaLanguage(8)).addInputLocation(analysisInputLocation).build(); - view = p.createView(); - } - - @Test - public void resolveAbstractDispatch() { - IdentifierFactory factory = view.getIdentifierFactory(); - MethodSignature collectionSize = - factory.parseMethodSignature("java.util.Collection#size(): int"); - MethodSignature abstractListSize = - factory.parseMethodSignature("java.util.AbstractList#size(): int"); - MethodSignature setSize = factory.parseMethodSignature("java.util.HashSet#size(): int"); - MethodSignature listSize = factory.parseMethodSignature("java.util.ArrayList#size(): int"); - MethodSignature enumSetClone = - factory.parseMethodSignature("java.util.EnumSet#clone(): java.lang.Object"); - MethodSignature objectClone = - factory.parseMethodSignature("java.lang.Object#clone(): java.lang.Object"); - MethodSignature arrayDequeueClone = - factory.parseMethodSignature("java.util.ArrayDeque#clone(): java.util.ArrayDequeue"); - - Set candidates = - MethodDispatchResolver.resolveAbstractDispatch(view, collectionSize); - assertTrue(collectionSize + " can resolve to " + setSize, candidates.contains(setSize)); - assertTrue(collectionSize + " can resolve to " + listSize, candidates.contains(listSize)); - - assertTrue( - abstractListSize + " can resolve to " + listSize, - MethodDispatchResolver.resolveAbstractDispatch(view, abstractListSize).contains(listSize)); - - assertTrue( - objectClone + " can resolve to " + enumSetClone, - MethodDispatchResolver.resolveAbstractDispatch(view, objectClone).contains(enumSetClone)); - assertFalse( - arrayDequeueClone + " cannot resolve to " + enumSetClone, - MethodDispatchResolver.resolveAbstractDispatch(view, arrayDequeueClone) - .contains(enumSetClone)); - } - - @Test - public void testResolveAllDispatchesInClasses() { - IdentifierFactory factory = view.getIdentifierFactory(); - MethodSignature collectionSize = - factory.parseMethodSignature("java.util.Collection#size(): int"); - MethodSignature abstractListSize = - factory.parseMethodSignature("java.util.AbstractList#size(): int"); - MethodSignature setSize = factory.parseMethodSignature("java.util.HashSet#size(): int"); - MethodSignature listSize = factory.parseMethodSignature("java.util.ArrayList#size(): int"); - - Set classes = new HashSet<>(); - classes.add(factory.getClassType("java.util.HashSet")); - classes.add(factory.getClassType("java.util.ArrayList")); - Set candidates = - MethodDispatchResolver.resolveAllDispatchesInClasses(view, collectionSize, classes); - assertTrue(collectionSize + " can resolve to " + setSize, candidates.contains(setSize)); - assertTrue(collectionSize + " can resolve to " + listSize, candidates.contains(listSize)); - assertFalse( - collectionSize + " can resolve to " + abstractListSize, - candidates.contains(abstractListSize)); - } - - @Test - public void testCanDispatch() { - IdentifierFactory factory = view.getIdentifierFactory(); - MethodSignature collectionSize = - factory.parseMethodSignature("java.util.Collection#size(): int"); - MethodSignature setSize = factory.parseMethodSignature("java.util.HashSet#size(): int"); - assertTrue( - MethodDispatchResolver.canDispatch(collectionSize, setSize, view.getTypeHierarchy())); - - MethodSignature objectClone = - factory.parseMethodSignature("java.lang.Object#clone(): java.lang.Object"); - MethodSignature arrayDequeueClone = - factory.parseMethodSignature("java.util.ArrayDeque#clone(): java.util.ArrayDequeue"); - assertTrue( - MethodDispatchResolver.canDispatch( - objectClone, arrayDequeueClone, view.getTypeHierarchy())); - - MethodSignature collectionHashCode = - factory.parseMethodSignature("java.util.Collection#hasCode(): int"); - assertFalse( - MethodDispatchResolver.canDispatch( - collectionSize, collectionHashCode, view.getTypeHierarchy())); - - MethodSignature objectWait1Param = - factory.parseMethodSignature("java.lang.Object#wait(long): void"); - MethodSignature objectWait2Param = - factory.parseMethodSignature("java.util.Collection#hasCode(long,int): int"); - assertFalse( - MethodDispatchResolver.canDispatch( - objectWait1Param, objectWait2Param, view.getTypeHierarchy())); - } - - @Test(expected = ResolveException.class) - public void invalidResolveConcreteDispatch() { - IdentifierFactory factory = view.getIdentifierFactory(); - MethodDispatchResolver.resolveConcreteDispatch( - view, factory.parseMethodSignature("java.util.Collection#size(): int")); - } - - @Test(expected = ResolveException.class) - public void invalidResolveConcreteDispatchOfAbstractMethod() { - IdentifierFactory factory = view.getIdentifierFactory(); - MethodDispatchResolver.resolveConcreteDispatch( - view, factory.parseMethodSignature("java.util.AbstractList#get(int): java.lang.Object")); - } - - @Test - public void testResolveOfANotImplementedMethodInAbstractClass() { - IdentifierFactory factory = view.getIdentifierFactory(); - Optional emptySig = - MethodDispatchResolver.resolveConcreteDispatch( - view, - factory.parseMethodSignature( - "com.sun.java.util.jar.pack.ConstantPool$LiteralEntry#equals(java.lang.Object): boolean")); - assertFalse(emptySig.isPresent()); - } - - @Test - public void resolveConcreteDispatch() { - IdentifierFactory factory = view.getIdentifierFactory(); - MethodSignature strToStringSig = - factory.parseMethodSignature("java.lang.String#toString(): java.lang.String"); - - MethodSignature concreteMethodSig = - MethodDispatchResolver.resolveConcreteDispatch(view, strToStringSig).orElse(null); - assertNotNull(concreteMethodSig); - assertEquals("String.toString() should resolve to itself", strToStringSig, concreteMethodSig); - - MethodSignature concreteMethodSig2 = - MethodDispatchResolver.resolveConcreteDispatch( - view, factory.parseMethodSignature("ds.AbstractDataStrcture#hashCode(): int")) - .orElse(null); - assertNotNull(concreteMethodSig2); - assertEquals( - "ds.AbstractDataStrcture.hashCode() should resolve to java.lang.Object.hashCode()", - factory.parseMethodSignature("java.lang.Object#hashCode(): int"), - concreteMethodSig2); - } - - @Test - public void resolveSpecialDispatch() { - IdentifierFactory factory = view.getIdentifierFactory(); - MethodSignature strInit = - factory.parseMethodSignature("java.lang.String#(java.lang.String): void"); - MethodSignature strToStringSig = - factory.parseMethodSignature("java.lang.String#toString(): java.lang.String"); - - JSpecialInvokeExpr strInitInvoke = - new JSpecialInvokeExpr( - new Local("str", factory.getClassType("java.lang.String")), - strInit, - ImmutableUtils.immutableList(JavaJimple.getInstance().newStringConstant("abc"))); - - assertEquals( - "String init should resolve to itself", - strInit, - MethodDispatchResolver.resolveSpecialDispatch(view, strInitInvoke, strToStringSig)); - - MethodSignature privateExplode = - factory.parseMethodSignature("ds.Employee#setEmpName(java.lang.String): java.lang.String"); - JSpecialInvokeExpr privateExplodeInvoke = - new JSpecialInvokeExpr( - new Local("jcp", factory.getClassType("ds.Employee")), - privateExplode, - ImmutableUtils.immutableList(JavaJimple.getInstance().newStringConstant("abc"))); - assertEquals( - privateExplode + " is private and should resolve to itself", - privateExplode, - MethodDispatchResolver.resolveSpecialDispatch(view, privateExplodeInvoke, strToStringSig)); - } -} diff --git a/sootup.tests/src/test/java/sootup/tests/typehierarchy/ViewTypeHierarchyTest.java b/sootup.tests/src/test/java/sootup/tests/typehierarchy/ViewTypeHierarchyTest.java index d830eed46d5..df6bc16e8f7 100644 --- a/sootup.tests/src/test/java/sootup/tests/typehierarchy/ViewTypeHierarchyTest.java +++ b/sootup.tests/src/test/java/sootup/tests/typehierarchy/ViewTypeHierarchyTest.java @@ -51,7 +51,7 @@ public class ViewTypeHierarchyTest { @Before public void setup() { - String jarFile = MethodDispatchResolverTest.jarFile; + String jarFile = "../shared-test-resources/java-miniapps/MiniApp.jar"; assertTrue("File " + jarFile + " not found.", new File(jarFile).exists()); String currentClassPath = System.getProperty("java.class.path") diff --git a/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/AbstractDispatchTest.java b/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/AbstractDispatchTest.java deleted file mode 100644 index f3a1862d659..00000000000 --- a/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/AbstractDispatchTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package sootup.tests.typehierarchy.methoddispatchtestcase; - -import static org.junit.Assert.*; - -import categories.Java8Test; -import java.util.Collections; -import java.util.Set; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.MethodDispatchResolver; -import sootup.core.types.ClassType; -import sootup.tests.typehierarchy.MethodDispatchBase; - -/** @author : Hasitha Rajapakse * */ -@Category(Java8Test.class) -public class AbstractDispatchTest extends MethodDispatchBase { - @Test - public void method() { - - ClassType sootClassTypeA = getClassType("A"); - ClassType sootClassTypeB = getClassType("B"); - ClassType sootClassTypeC = getClassType("C"); - ClassType sootClassTypeAbstract = getClassType("AbstractClass"); - - MethodSignature sootMethodA = - identifierFactory.getMethodSignature( - sootClassTypeA, "method", "void", Collections.emptyList()); - MethodSignature sootMethodB = - identifierFactory.getMethodSignature( - sootClassTypeB, "method", "void", Collections.emptyList()); - MethodSignature sootMethodC = - identifierFactory.getMethodSignature( - sootClassTypeC, "method", "void", Collections.emptyList()); - MethodSignature sootMethodAbstract = - identifierFactory.getMethodSignature( - sootClassTypeAbstract, "method", "void", Collections.emptyList()); - - Set candidatesAbstract = - MethodDispatchResolver.resolveAbstractDispatch( - customTestWatcher.getView(), - identifierFactory.getMethodSignature( - sootClassTypeA, "method", "void", Collections.emptyList())); - assertFalse(candidatesAbstract.contains(sootMethodAbstract)); - assertFalse(candidatesAbstract.contains(sootMethodA)); - assertFalse(candidatesAbstract.contains(sootMethodB)); - assertFalse(candidatesAbstract.contains(sootMethodC)); - - Set candidatesSuper = - MethodDispatchResolver.resolveAbstractDispatch( - customTestWatcher.getView(), - identifierFactory.getMethodSignature( - sootClassTypeAbstract, "method", "void", Collections.emptyList())); - assertFalse(candidatesSuper.contains(sootMethodAbstract)); - assertFalse(candidatesSuper.contains(sootMethodA)); - assertFalse(candidatesSuper.contains(sootMethodB)); - assertTrue(candidatesSuper.contains(sootMethodC)); - } -} diff --git a/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/AllDispatchTest.java b/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/AllDispatchTest.java deleted file mode 100644 index 93ed01a6156..00000000000 --- a/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/AllDispatchTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package sootup.tests.typehierarchy.methoddispatchtestcase; - -import static org.junit.Assert.*; - -import categories.Java8Test; -import java.util.Collections; -import java.util.Set; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.MethodDispatchResolver; -import sootup.core.types.ClassType; -import sootup.tests.typehierarchy.MethodDispatchBase; - -/** @author : Jonas Klauke * */ -@Category(Java8Test.class) -public class AllDispatchTest extends MethodDispatchBase { - @Test - public void method() { - - ClassType sootClassTypeA = getClassType("A"); - ClassType sootClassTypeB = getClassType("B"); - ClassType sootClassTypeC = getClassType("C"); - ClassType sootClassTypeAbstract = getClassType("AbstractClass"); - - MethodSignature sootMethodB = - identifierFactory.getMethodSignature( - sootClassTypeB, "method", "void", Collections.emptyList()); - MethodSignature sootMethodC = - identifierFactory.getMethodSignature( - sootClassTypeC, "method", "void", Collections.emptyList()); - MethodSignature sootMethodAbstract = - identifierFactory.getMethodSignature( - sootClassTypeAbstract, "method", "void", Collections.emptyList()); - - Set candidatesAbstract = - MethodDispatchResolver.resolveAllDispatches( - customTestWatcher.getView(), - identifierFactory.getMethodSignature( - sootClassTypeA, "method", "void", Collections.emptyList())); - - assertTrue(candidatesAbstract.contains(sootMethodB)); - assertTrue(candidatesAbstract.contains(sootMethodC)); - assertFalse(candidatesAbstract.contains(sootMethodAbstract)); - } -} diff --git a/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/ConcreteDispatchTest.java b/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/ConcreteDispatchTest.java deleted file mode 100644 index 2db176d856e..00000000000 --- a/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/ConcreteDispatchTest.java +++ /dev/null @@ -1,107 +0,0 @@ -package sootup.tests.typehierarchy.methoddispatchtestcase; - -import static junit.framework.TestCase.*; - -import categories.Java8Test; -import java.util.Collections; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.MethodDispatchResolver; -import sootup.core.types.ClassType; -import sootup.tests.typehierarchy.MethodDispatchBase; - -/** @author : Hasitha Rajapakse, Jonas Klauke * */ -@Category(Java8Test.class) -public class ConcreteDispatchTest extends MethodDispatchBase { - @Test - public void method() { - // test concrete method in super class - ClassType sootClassTypeA = getClassType("A"); - ClassType sootClassTypeB = getClassType("B"); - - MethodSignature sootMethod1 = - identifierFactory.getMethodSignature( - sootClassTypeA, "method", "void", Collections.emptyList()); - MethodSignature sootMethod2 = - identifierFactory.getMethodSignature( - sootClassTypeA, "method2", "void", Collections.emptyList()); - MethodSignature sootMethod3 = - identifierFactory.getMethodSignature( - sootClassTypeB, "method2", "void", Collections.emptyList()); - - MethodSignature candidate1 = - MethodDispatchResolver.resolveConcreteDispatch(customTestWatcher.getView(), sootMethod1) - .orElse(null); - assertNotNull(candidate1); - assertEquals(candidate1, sootMethod1); - - MethodSignature candidate2 = - MethodDispatchResolver.resolveConcreteDispatch(customTestWatcher.getView(), sootMethod2) - .orElse(null); - assertNotNull(candidate2); - assertEquals(candidate2, sootMethod3); - - // test concrete method in interface - ClassType sootClassInterfaceI = getClassType("I"); - MethodSignature sootInterfaceMethod = - identifierFactory.getMethodSignature( - sootClassInterfaceI, "interfaceMethod", "void", Collections.emptyList()); - - MethodSignature sootInterfaceMethodA = - identifierFactory.getMethodSignature( - sootClassTypeA, "interfaceMethod", "void", Collections.emptyList()); - - MethodSignature candidateInterface = - MethodDispatchResolver.resolveConcreteDispatch( - customTestWatcher.getView(), sootInterfaceMethodA) - .orElse(null); - assertNotNull(candidateInterface); - assertEquals(candidateInterface, sootInterfaceMethod); - - // test concrete method in super-interface - ClassType sootClassInterfaceJ = getClassType("J"); - MethodSignature sootSuperInterfaceMethod = - identifierFactory.getMethodSignature( - sootClassInterfaceJ, "superInterfaceMethod", "void", Collections.emptyList()); - - MethodSignature sootSuperInterfaceMethodA = - identifierFactory.getMethodSignature( - sootClassTypeA, "superInterfaceMethod", "void", Collections.emptyList()); - - MethodSignature candidateSuperInterface = - MethodDispatchResolver.resolveConcreteDispatch( - customTestWatcher.getView(), sootSuperInterfaceMethodA) - .orElse(null); - assertNotNull(candidateSuperInterface); - assertEquals(candidateSuperInterface, sootSuperInterfaceMethod); - - // test concrete method with two possible default methods but one is in the sub-interface - ClassType sootClassTypeC = getClassType("C"); - ClassType sootClassTypeD = getClassType("D"); - MethodSignature subInterfaceMethod = - identifierFactory.getMethodSignature( - sootClassInterfaceI, "interfaceMethod", "void", Collections.emptyList()); - - MethodSignature sootSuperInterfaceMethodD = - identifierFactory.getMethodSignature( - sootClassTypeD, "interfaceMethod", "void", Collections.emptyList()); - - MethodSignature sootSuperInterfaceMethodC = - identifierFactory.getMethodSignature( - sootClassTypeC, "interfaceMethod", "void", Collections.emptyList()); - - MethodSignature candidateSubInterface = - MethodDispatchResolver.resolveConcreteDispatch( - customTestWatcher.getView(), sootSuperInterfaceMethodD) - .orElse(null); - assertNotNull(candidateSubInterface); - assertEquals(candidateSubInterface, subInterfaceMethod); - MethodSignature candidateSubInterface2 = - MethodDispatchResolver.resolveConcreteDispatch( - customTestWatcher.getView(), sootSuperInterfaceMethodC) - .orElse(null); - assertNotNull(candidateSubInterface2); - assertEquals(candidateSubInterface, candidateSubInterface2); - } -} diff --git a/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/CovarianceDispatchTest.java b/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/CovarianceDispatchTest.java deleted file mode 100644 index 4a6c2e090f4..00000000000 --- a/sootup.tests/src/test/java/sootup/tests/typehierarchy/methoddispatchtestcase/CovarianceDispatchTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package sootup.tests.typehierarchy.methoddispatchtestcase; - -import static org.junit.Assert.*; - -import categories.Java8Test; -import java.util.Set; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import sootup.core.signatures.MethodSignature; -import sootup.core.typehierarchy.MethodDispatchResolver; -import sootup.tests.typehierarchy.MethodDispatchBase; - -/** @author : Jonas Klauke * */ -@Category(Java8Test.class) -public class CovarianceDispatchTest extends MethodDispatchBase { - @Test - public void method() { - // sourcecode frontend test - Set sourcecodeCandidates = - MethodDispatchResolver.resolveAllDispatches( - customTestWatcher.getView(), - identifierFactory.parseMethodSignature("Superclass#method(): java.lang.Object")); - - assertFalse( - sourcecodeCandidates.contains( - identifierFactory.parseMethodSignature("Subclass#method(): Subclass"))); - assertTrue( - sourcecodeCandidates.contains( - identifierFactory.parseMethodSignature("Subclass#method(): java.lang.Object"))); - - // bytecode frontend test - Set bytecodeCandidates = - MethodDispatchResolver.resolveAllDispatches( - customTestWatcher.getView(), - identifierFactory.parseMethodSignature( - "java.util.AbstractSet#clone(): java.lang.Object")); - assertFalse( - bytecodeCandidates.contains( - identifierFactory.parseMethodSignature( - "java.util.EnumSet#clone(): java.util.EnumSet"))); - assertTrue( - bytecodeCandidates.contains( - identifierFactory.parseMethodSignature("java.util.EnumSet#clone(): java.lang.Object"))); - } -} diff --git a/sootup.tests/src/test/resources/javatypehierarchy/Comparator/Interface.java b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/Interface.java new file mode 100644 index 00000000000..326a0e6bca3 --- /dev/null +++ b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/Interface.java @@ -0,0 +1,3 @@ +interface Interface{ + +} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/javatypehierarchy/Comparator/SubInterface.java b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/SubInterface.java new file mode 100644 index 00000000000..04920dfd902 --- /dev/null +++ b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/SubInterface.java @@ -0,0 +1,3 @@ +interface SubInterface extends Interface{ + +} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/javatypehierarchy/Comparator/SubSubInterface.java b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/SubSubInterface.java new file mode 100644 index 00000000000..2b1a50eb17f --- /dev/null +++ b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/SubSubInterface.java @@ -0,0 +1,3 @@ +interface SubSubInterface extends SubInterface{ + +} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/javatypehierarchy/Comparator/SubSubclass.java b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/SubSubclass.java new file mode 100644 index 00000000000..a325111b873 --- /dev/null +++ b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/SubSubclass.java @@ -0,0 +1,3 @@ +class SubSubclass extends Subclass{ + +} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/javatypehierarchy/Comparator/Subclass.java b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/Subclass.java new file mode 100644 index 00000000000..4567627f2b1 --- /dev/null +++ b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/Subclass.java @@ -0,0 +1,3 @@ +class Subclass extends Superclass{ + +} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/javatypehierarchy/Comparator/Superclass.java b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/Superclass.java new file mode 100644 index 00000000000..491f0e44eb0 --- /dev/null +++ b/sootup.tests/src/test/resources/javatypehierarchy/Comparator/Superclass.java @@ -0,0 +1,3 @@ +class Superclass implements SubSubInterface{ + +} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/A.java b/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/A.java deleted file mode 100644 index 3210ccd9c79..00000000000 --- a/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/A.java +++ /dev/null @@ -1,8 +0,0 @@ - -/** @author: Hasitha Rajapakse **/ - -public class A { - public void method(){ - int num = 5; - } -} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/AbstractClass.java b/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/AbstractClass.java deleted file mode 100644 index 52e0dc27863..00000000000 --- a/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/AbstractClass.java +++ /dev/null @@ -1,6 +0,0 @@ - -/** @author: Hasitha Rajapakse **/ - -public abstract class AbstractClass{ - public abstract void method(); -} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/B.java b/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/B.java deleted file mode 100644 index 8194752b9d7..00000000000 --- a/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/B.java +++ /dev/null @@ -1,5 +0,0 @@ - -/** @author: Hasitha Rajapakse **/ - -public class B extends AbstractClass { -} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/C.java b/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/C.java deleted file mode 100644 index 9bb6eaeb8e6..00000000000 --- a/sootup.tests/src/test/resources/methoddispatchresolver/AbstractDispatch/C.java +++ /dev/null @@ -1,8 +0,0 @@ - -/** @author: Hasitha Rajapakse **/ - -public class C extends AbstractClass { - public void method(){ - int num = 20; - } -} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/A.java b/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/A.java deleted file mode 100644 index ee9d7735d8e..00000000000 --- a/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/A.java +++ /dev/null @@ -1,7 +0,0 @@ - -/** @author: Jonas Klauke **/ - -public class A { - public void method(){ - } -} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/AbstractClass.java b/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/AbstractClass.java deleted file mode 100644 index 3de86bb38d1..00000000000 --- a/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/AbstractClass.java +++ /dev/null @@ -1,6 +0,0 @@ - -/** @author: Jonas Klauke **/ - -public abstract class AbstractClass extends A{ - public abstract void method(); -} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/B.java b/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/B.java deleted file mode 100644 index 30144f71c34..00000000000 --- a/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/B.java +++ /dev/null @@ -1,5 +0,0 @@ - -/** @author: Jonas Klauke **/ - -public class B extends AbstractClass { -} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/C.java b/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/C.java deleted file mode 100644 index f482c4f0787..00000000000 --- a/sootup.tests/src/test/resources/methoddispatchresolver/AllDispatch/C.java +++ /dev/null @@ -1,8 +0,0 @@ - -/** @author: Jonas Klauke **/ - -public class C extends A { - public void method(){ - int num = 20; - } -} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/CovarianceDispatch/Subclass.java b/sootup.tests/src/test/resources/methoddispatchresolver/CovarianceDispatch/Subclass.java deleted file mode 100644 index 138c1993d73..00000000000 --- a/sootup.tests/src/test/resources/methoddispatchresolver/CovarianceDispatch/Subclass.java +++ /dev/null @@ -1,8 +0,0 @@ - -/** @author: Jonas Klauke **/ - -public class Subclass extends Superclass { - public Superclass method(){ - return new Superclass(); - } -} \ No newline at end of file diff --git a/sootup.tests/src/test/resources/methoddispatchresolver/CovarianceDispatch/Superclass.java b/sootup.tests/src/test/resources/methoddispatchresolver/CovarianceDispatch/Superclass.java deleted file mode 100644 index f041d65e412..00000000000 --- a/sootup.tests/src/test/resources/methoddispatchresolver/CovarianceDispatch/Superclass.java +++ /dev/null @@ -1,8 +0,0 @@ - -/** @author: Jonas Klauke **/ - -public class Superclass{ - public Object method(){ - return new Object(); - } -} \ No newline at end of file