From d5dc7415c6e4b636400df1e71a5e5f456537c8f3 Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Thu, 12 Dec 2019 11:32:42 +0100 Subject: [PATCH 01/19] prepare for release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d28c589..af400e0 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.daanvdh.javadataflow JavaDataFlow - 0.0.2-SNAPSHOT + 0.0.2 jar JavaDataFlow From ea5595278696122ef30c89a31572ef8262121f5f Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Thu, 12 Dec 2019 12:07:40 +0100 Subject: [PATCH 02/19] Javadoc --- src/main/java/dataflow/MethodNodeHandler.java | 2 ++ src/main/java/dataflow/model/DataFlowNode.java | 2 +- src/main/java/dataflow/model/NodeRepresenter.java | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/dataflow/MethodNodeHandler.java b/src/main/java/dataflow/MethodNodeHandler.java index 8ac6294..f826c41 100644 --- a/src/main/java/dataflow/MethodNodeHandler.java +++ b/src/main/java/dataflow/MethodNodeHandler.java @@ -72,6 +72,8 @@ public class MethodNodeHandler { * @param method {@link DataFlowMethod} to add {@link DataFlowNode} to * @param overriddenValues The values that have been overridden in previous iterations. * @param n The {@link Node} to handle. ChildNodes will recursively be handled if needed. + * @param owner The owner for the node to be created. This variable might be removed later, giving the caller of this method the responsibility to set the + * owner. * @return An optional of the {@link DataFlowNode} of the input node. If multiple head nodes are created, (In case of a {@link BlockStmt}) the optional will * be empty. */ diff --git a/src/main/java/dataflow/model/DataFlowNode.java b/src/main/java/dataflow/model/DataFlowNode.java index 1f8a0c1..81082ef 100644 --- a/src/main/java/dataflow/model/DataFlowNode.java +++ b/src/main/java/dataflow/model/DataFlowNode.java @@ -116,7 +116,7 @@ public boolean isInputParameter() { /** * Walks back over incoming edges until predicate is met or no incoming edges are present. * - * @see GraphUtil#walkBackUntil(DataFlowNode, Predicate) + * @see GraphUtil#walkBackUntil(DataFlowNode, Predicate, Predicate) * @param predicate The {@link Predicate} to meet * @param scope The scope for the variable, the search is stopped as soon as the scope does not hold and an empty list is returned. * @return {@link List} of {@link DataFlowNode} diff --git a/src/main/java/dataflow/model/NodeRepresenter.java b/src/main/java/dataflow/model/NodeRepresenter.java index 31742a9..99958a2 100644 --- a/src/main/java/dataflow/model/NodeRepresenter.java +++ b/src/main/java/dataflow/model/NodeRepresenter.java @@ -102,6 +102,7 @@ public String toString() { /** * Creates builder to build {@link NodeRepresenter}. * + * @param The type of the {@link JavaParser} {@link Node} to represent. * @return created builder */ public static Builder> builder() { From d3aaa1d1f50abc31dec9a4706abd09d9c1d83cbf Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Thu, 12 Dec 2019 13:30:48 +0100 Subject: [PATCH 03/19] Change order of pom plugins to fix javadocs not being uploaded --- pom.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index af400e0..4621e35 100644 --- a/pom.xml +++ b/pom.xml @@ -44,28 +44,28 @@ org.apache.maven.plugins - maven-source-plugin - 2.2.1 + maven-javadoc-plugin + 2.9.1 - attach-sources + attach-javadocs deploy - jar-no-fork + jar org.apache.maven.plugins - maven-javadoc-plugin - 2.9.1 + maven-source-plugin + 2.2.1 - attach-javadocs + attach-sources deploy - jar + jar-no-fork From f5038ccd548b57535de85de565bb601170932415 Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Thu, 12 Dec 2019 13:44:23 +0100 Subject: [PATCH 04/19] Ignore default-deploy to generate javadoc before uploading to maven repo --- pom.xml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pom.xml b/pom.xml index 4621e35..1aefef2 100644 --- a/pom.xml +++ b/pom.xml @@ -88,6 +88,32 @@ + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + + default-deploy + deploy + + deploy + + + true + + + + release + deploy + + deploy + + + + + From 91bac4bee22729ae7ff1ed662b125f7f964dbaa7 Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Fri, 20 Dec 2019 08:53:12 +0100 Subject: [PATCH 05/19] Restructured packages, created JavaDataFlow facade class, created readme --- README.md | 77 +++++++++++++++++ pom.xml | 2 +- .../DataFlowException.java | 4 +- src/main/java/facade/JavaDataFlow.java | 53 ++++++++++++ src/main/java/facade/StaticJavaDataFlow.java | 84 +++++++++++++++++++ .../DataFlowGraphFactory.java | 14 ++-- .../DataFlowNodeFactory.java | 6 +- .../MethodNodeHandler.java | 18 ++-- .../NodeCallFactory.java | 15 ++-- .../{dataflow => }/model/DataFlowEdge.java | 2 +- .../{dataflow => }/model/DataFlowGraph.java | 2 +- .../{dataflow => }/model/DataFlowMethod.java | 4 +- .../{dataflow => }/model/DataFlowNode.java | 7 +- .../java/{dataflow => }/model/NodeCall.java | 2 +- .../{dataflow => }/model/NodeRepresenter.java | 2 +- .../java/{dataflow => }/model/OwnedNode.java | 2 +- .../java/{dataflow => }/model/OwnerNode.java | 2 +- .../{dataflow => }/model/ParameterList.java | 12 ++- .../java/{dataflow => util}/GraphUtil.java | 8 +- .../{dataflow => }/util/HashCodeWrapper.java | 2 +- .../{dataflow => }/util/HashMapWrapper.java | 2 +- .../java/{dataflow => util}/ParserUtil.java | 25 +++++- .../DataFlowMethodBuilder.java | 6 +- .../{dataflow => common}/GraphBuilder.java | 10 +-- .../{dataflow => common}/NodeBuilder.java | 4 +- .../common/SymbolSolverSetup.java | 2 +- .../DataFlowGraphFactoryTest.java | 21 +++-- .../MethodNodeHandlerTest.java | 14 ++-- .../NodeCallFactoryTest.java | 11 +-- .../model/DataFlowEdgeTest.java | 2 +- .../model/DataFlowGraphTest.java | 2 +- .../model/DataFlowMethodTest.java | 2 +- .../model/DataFlowNodeTest.java | 6 +- .../{dataflow => }/model/NodeCallTest.java | 2 +- .../model/ParameterListTest.java | 2 +- .../{dataflow => util}/GraphUtilTest.java | 10 ++- 36 files changed, 343 insertions(+), 96 deletions(-) rename src/main/java/{dataflow => common}/DataFlowException.java (95%) create mode 100644 src/main/java/facade/JavaDataFlow.java create mode 100644 src/main/java/facade/StaticJavaDataFlow.java rename src/main/java/{dataflow => factory}/DataFlowGraphFactory.java (97%) rename src/main/java/{dataflow => factory}/DataFlowNodeFactory.java (96%) rename src/main/java/{dataflow => factory}/MethodNodeHandler.java (98%) rename src/main/java/{dataflow => factory}/NodeCallFactory.java (94%) rename src/main/java/{dataflow => }/model/DataFlowEdge.java (98%) rename src/main/java/{dataflow => }/model/DataFlowGraph.java (99%) rename src/main/java/{dataflow => }/model/DataFlowMethod.java (99%) rename src/main/java/{dataflow => }/model/DataFlowNode.java (97%) rename src/main/java/{dataflow => }/model/NodeCall.java (99%) rename src/main/java/{dataflow => }/model/NodeRepresenter.java (99%) rename src/main/java/{dataflow => }/model/OwnedNode.java (98%) rename src/main/java/{dataflow => }/model/OwnerNode.java (98%) rename src/main/java/{dataflow => }/model/ParameterList.java (94%) rename src/main/java/{dataflow => util}/GraphUtil.java (96%) rename src/main/java/{dataflow => }/util/HashCodeWrapper.java (98%) rename src/main/java/{dataflow => }/util/HashMapWrapper.java (98%) rename src/main/java/{dataflow => util}/ParserUtil.java (79%) rename src/test/java/{dataflow => common}/DataFlowMethodBuilder.java (95%) rename src/test/java/{dataflow => common}/GraphBuilder.java (97%) rename src/test/java/{dataflow => common}/NodeBuilder.java (98%) rename src/test/java/{dataflow => }/common/SymbolSolverSetup.java (98%) rename src/test/java/{dataflow => factory}/DataFlowGraphFactoryTest.java (97%) rename src/test/java/{dataflow => factory}/MethodNodeHandlerTest.java (96%) rename src/test/java/{dataflow => factory}/NodeCallFactoryTest.java (94%) rename src/test/java/{dataflow => }/model/DataFlowEdgeTest.java (98%) rename src/test/java/{dataflow => }/model/DataFlowGraphTest.java (99%) rename src/test/java/{dataflow => }/model/DataFlowMethodTest.java (99%) rename src/test/java/{dataflow => }/model/DataFlowNodeTest.java (99%) rename src/test/java/{dataflow => }/model/NodeCallTest.java (99%) rename src/test/java/{dataflow => }/model/ParameterListTest.java (99%) rename src/test/java/{dataflow => util}/GraphUtilTest.java (94%) diff --git a/README.md b/README.md index 0bd663e..8ef8e4d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,79 @@ # JavaDataFlow Creating Data Flow Graphs from java input classes + +With JavaDataFlow you can create data flow graphs. +This is a directed graph where a node represents data (e.g. fields, inputParameters, etc.) and the edges represent a node influencing the state of another node. +Nodes are always defined within a specific method, constructor, codeBlock. +We refer to such a code block as owner. +Every Node has an owner. +Every owner can also have an owner, for instance a method is owned by a class. + + +## Example + +Let's say we have a class as given as below: + + public class JavaDataFlowExampleInputClass { + int a; + public int getA() { + return a; + } + public void setA(int inputA) { + this.a = inputA; + } + } + +Then we can execute the following commands to create a data flow graph from it. +First define the path to your project and setup the path where JavaDataFlow will look for class files. +If you have multiple projects where JavaDataFlow needs to look for class files, you can enter multiple project paths there. +Then create the data flow graph using the absolute input path to the java class. +A DataFlowGraph represents a single class. + + String projectPath = "projectPath"; + String input = "/relativePath/Example.java"; + StaticJavaDataFlow.getConfig().setProjectPaths(projectPath); + DataFlowGraph dfg = JavaDataFlow.create(projectPath + input); + +Now if we want to gather all input nodes to this class that can influence the output of the method "getA", we can do that as given below. +First get the given method. +Now we need to walk back until we reach a node that is an input parameter of a method, for this we can use the method DataFlowNode::isInputParameter. +For this example we don't want to go outside this class so we add dfg::owns as scope to the method walkBackUntil. +The scope determines when to stop walking over the nodes, this can become important multiple data flow graphs are connected to each other. +However, this is currently not supported yet. + + DataFlowMethod getA = dfg.getMethods().stream().filter(m -> m.getName().equals("getA")).findFirst().get(); + List inputNodes = getA.getReturnNode().get().walkBackUntil(DataFlowNode::isInputParameter, dfg::owns); + System.out.println(inputNodes.get(0).getName()); + +The above code will output the name "inputA". + +## Setup +Add the dependency below to the pom of your project. + + + com.github.daanvdh.javadataflow + JavaDataFlow + 0.0.2 + + +## Definitions +- The owner of a DataFlowNode represents structure in which the node is defined. + For the method setA, the parameter inputA has a ParameterList as input. + The ParameterList has the DataFlowMethod for "setA" as owner. + The owner of the method is the DataFlowGraph representing Example.java + +## Features +- JavaDataFlow uses [JavaParser](https://github.com/javaparser/javaparser/) for parsing the input classes. + Each DataFlowNode has a representedNode which is the JavaParser Node that it represents. + If you have a given JavaParser Node you can get the JavaDataFlowNode via DataFlowGraph::getNode. + +## Roadmap +- Include Constructors in the JavaDataFlow graph. +- Model if statements. +- Model primitive functions like: + - * / < >. +- Model for and while loops. +- Connect multiple JavaDataFlow graphs to each other so that we can walk from class to class. + +## License + +JavaDataFlow is available under the terms of the Apache License. http://www.apache.org/licenses/LICENSE-2.0 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1aefef2..9a9d85c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.daanvdh.javadataflow JavaDataFlow - 0.0.2 + 0.0.3 jar JavaDataFlow diff --git a/src/main/java/dataflow/DataFlowException.java b/src/main/java/common/DataFlowException.java similarity index 95% rename from src/main/java/dataflow/DataFlowException.java rename to src/main/java/common/DataFlowException.java index 214950a..7f3e92d 100644 --- a/src/main/java/dataflow/DataFlowException.java +++ b/src/main/java/common/DataFlowException.java @@ -15,9 +15,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package common; -import dataflow.model.DataFlowGraph; +import model.DataFlowGraph; /** * Exception that will be thrown for unexpected behavior or unsupported types while constructing a {@link DataFlowGraph}. diff --git a/src/main/java/facade/JavaDataFlow.java b/src/main/java/facade/JavaDataFlow.java new file mode 100644 index 0000000..d20b068 --- /dev/null +++ b/src/main/java/facade/JavaDataFlow.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 by Daan van den Heuvel. + * + * This file is part of JavaDataFlow. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package facade; + +import com.github.javaparser.ast.CompilationUnit; + +import factory.DataFlowGraphFactory; +import model.DataFlowGraph; +import util.ParserUtil; + +/** + * Facade class to create {@link DataFlowGraph}s. + * + * @author Daan + */ +public class JavaDataFlow { + + /** + * Creates a {@link DataFlowGraph} from the class located at the given classPath. + * + * @param classPath The path to the input class. + * @return A {@link DataFlowGraph} representing the input class. + */ + public static DataFlowGraph create(String classPath) { + return create(new ParserUtil().createCompilationUnit(classPath)); + } + + /** + * Creates a {@link DataFlowGraph} from the given {@link CompilationUnit}. + * + * @param cu The input {@link CompilationUnit}. + * @return A {@link DataFlowGraph} representing the input class. + */ + public static DataFlowGraph create(CompilationUnit cu) { + return new DataFlowGraphFactory().create(cu); + } + +} diff --git a/src/main/java/facade/StaticJavaDataFlow.java b/src/main/java/facade/StaticJavaDataFlow.java new file mode 100644 index 0000000..7b50ea6 --- /dev/null +++ b/src/main/java/facade/StaticJavaDataFlow.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 by Eyefreight BV (www.eyefreight.com). All rights reserved. + * + * This software is provided by the copyright holder and contributors "as is" and any express or implied warranties, including, but + * not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall + * Eyefreight BV or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages + * (including, but not limited to, procurement of substitute goods or services; * loss of use, data, or profits; or business + * interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including + * negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. + */ +package facade; + +import java.io.File; +import java.nio.file.Files; +import java.util.stream.Stream; + +import org.apache.commons.lang3.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.symbolsolver.JavaSymbolSolver; +import com.github.javaparser.symbolsolver.model.resolution.TypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; + +/** + * Contains all static setting for {@link JavaDataFlow}. + * + * @author Daan + */ +public class StaticJavaDataFlow { + private static final Logger LOG = LoggerFactory.getLogger(StaticJavaDataFlow.class); + + /** Used to gather more data about a parsed class, such as resolving imports or super classes. */ + private JavaSymbolSolver symbolSolver; + + private static StaticJavaDataFlow config; + + private StaticJavaDataFlow() { + // don't create it via any constructor + setupSymbolSolver(); + } + + public static synchronized StaticJavaDataFlow getConfig() { + if (config == null) { + config = new StaticJavaDataFlow(); + } + return config; + } + + public final void setSymbolSolver(JavaSymbolSolver symbolSolver) { + this.symbolSolver = symbolSolver; + StaticJavaParser.getConfiguration().setSymbolResolver(symbolSolver); + } + + public JavaSymbolSolver getSymbolSolver() { + return symbolSolver; + } + + /** + * Sets the project paths to be used to find classes. Note that these paths should be the full path to the source folder, typically ending with + * ".../src/main/java" for maven projects. This method will override anything set by the method {@link StaticJavaDataFlow#setSymbolSolver(JavaSymbolSolver)}. + * + * @param paths The full paths to source folders where {@link JavaDataFlow} needs to look for classes that any input class depends on. + */ + public void setProjectPaths(String... paths) { + Stream.of(paths).filter(p -> !Files.exists(new File(p).toPath())).forEach(p -> LOG.error("Could not find the folder located at: " + p)); + JavaParserTypeSolver[] solvers = + Stream.of(paths).filter(p -> Files.exists(new File(p).toPath())).map(JavaParserTypeSolver::new).toArray(JavaParserTypeSolver[]::new); + TypeSolver[] reflTypeSolver = {new ReflectionTypeSolver()}; + TypeSolver typeSolver = new CombinedTypeSolver(ArrayUtils.addAll(reflTypeSolver, solvers)); + JavaSymbolSolver symbolSolver = new JavaSymbolSolver(typeSolver); + setSymbolSolver(symbolSolver); + } + + private final void setupSymbolSolver() { + TypeSolver reflTypeSolver = new ReflectionTypeSolver(); + JavaSymbolSolver symbolSolver = new JavaSymbolSolver(reflTypeSolver); + this.setSymbolSolver(symbolSolver); + } + +} diff --git a/src/main/java/dataflow/DataFlowGraphFactory.java b/src/main/java/factory/DataFlowGraphFactory.java similarity index 97% rename from src/main/java/dataflow/DataFlowGraphFactory.java rename to src/main/java/factory/DataFlowGraphFactory.java index 60cf8de..c2b1e88 100644 --- a/src/main/java/dataflow/DataFlowGraphFactory.java +++ b/src/main/java/factory/DataFlowGraphFactory.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package factory; import java.util.HashMap; import java.util.List; @@ -41,12 +41,12 @@ import com.github.javaparser.resolution.Resolvable; import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserMethodDeclaration; -import dataflow.model.DataFlowGraph; -import dataflow.model.DataFlowMethod; -import dataflow.model.DataFlowNode; -import dataflow.model.NodeCall; -import dataflow.model.OwnedNode; -import dataflow.model.ParameterList; +import model.DataFlowGraph; +import model.DataFlowMethod; +import model.DataFlowNode; +import model.NodeCall; +import model.OwnedNode; +import model.ParameterList; /** * Factory for creating a {@link DataFlowGraph} from a {@link JavaParser} {@link CompilationUnit}. diff --git a/src/main/java/dataflow/DataFlowNodeFactory.java b/src/main/java/factory/DataFlowNodeFactory.java similarity index 96% rename from src/main/java/dataflow/DataFlowNodeFactory.java rename to src/main/java/factory/DataFlowNodeFactory.java index 5b249be..03cf8fc 100644 --- a/src/main/java/dataflow/DataFlowNodeFactory.java +++ b/src/main/java/factory/DataFlowNodeFactory.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package factory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,8 +25,8 @@ import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.printer.Printable; -import dataflow.model.DataFlowNode; -import dataflow.model.OwnedNode; +import model.DataFlowNode; +import model.OwnedNode; /** * Factory for {@link DataFlowNode}s. diff --git a/src/main/java/dataflow/MethodNodeHandler.java b/src/main/java/factory/MethodNodeHandler.java similarity index 98% rename from src/main/java/dataflow/MethodNodeHandler.java rename to src/main/java/factory/MethodNodeHandler.java index f826c41..b69b49b 100644 --- a/src/main/java/dataflow/MethodNodeHandler.java +++ b/src/main/java/factory/MethodNodeHandler.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package factory; import java.util.List; import java.util.Map; @@ -43,13 +43,15 @@ import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.stmt.ReturnStmt; -import dataflow.model.DataFlowEdge; -import dataflow.model.DataFlowGraph; -import dataflow.model.DataFlowMethod; -import dataflow.model.DataFlowNode; -import dataflow.model.NodeCall; -import dataflow.model.OwnedNode; -import dataflow.model.ParameterList; +import common.DataFlowException; +import model.DataFlowEdge; +import model.DataFlowGraph; +import model.DataFlowMethod; +import model.DataFlowNode; +import model.NodeCall; +import model.OwnedNode; +import model.ParameterList; +import util.ParserUtil; /** * Class for handling {@link JavaParser} {@link Node}s while filling a {@link DataFlowMethod}. diff --git a/src/main/java/dataflow/NodeCallFactory.java b/src/main/java/factory/NodeCallFactory.java similarity index 94% rename from src/main/java/dataflow/NodeCallFactory.java rename to src/main/java/factory/NodeCallFactory.java index 54efb04..daaa2b0 100644 --- a/src/main/java/dataflow/NodeCallFactory.java +++ b/src/main/java/factory/NodeCallFactory.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package factory; import java.util.Optional; @@ -29,12 +29,13 @@ import com.github.javaparser.resolution.types.ResolvedPrimitiveType; import com.github.javaparser.resolution.types.ResolvedType; -import dataflow.model.DataFlowGraph; -import dataflow.model.DataFlowMethod; -import dataflow.model.DataFlowNode; -import dataflow.model.NodeCall; -import dataflow.model.OwnedNode; -import dataflow.model.OwnerNode; +import model.DataFlowGraph; +import model.DataFlowMethod; +import model.DataFlowNode; +import model.NodeCall; +import model.OwnedNode; +import model.OwnerNode; +import util.ParserUtil; /** * Class for resolving {@link DataFlowMethod}s and {@link DataFlowNode}s from {@link Node}s and {@link DataFlowGraph}s. diff --git a/src/main/java/dataflow/model/DataFlowEdge.java b/src/main/java/model/DataFlowEdge.java similarity index 98% rename from src/main/java/dataflow/model/DataFlowEdge.java rename to src/main/java/model/DataFlowEdge.java index f24a809..b16bff2 100644 --- a/src/main/java/dataflow/model/DataFlowEdge.java +++ b/src/main/java/model/DataFlowEdge.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; /** * An edge inside a {@link DataFlowGraph} representing a {@link DataFlowNode} influencing the state of another {@link DataFlowNode}. diff --git a/src/main/java/dataflow/model/DataFlowGraph.java b/src/main/java/model/DataFlowGraph.java similarity index 99% rename from src/main/java/dataflow/model/DataFlowGraph.java rename to src/main/java/model/DataFlowGraph.java index d325ab0..948777c 100644 --- a/src/main/java/dataflow/model/DataFlowGraph.java +++ b/src/main/java/model/DataFlowGraph.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/dataflow/model/DataFlowMethod.java b/src/main/java/model/DataFlowMethod.java similarity index 99% rename from src/main/java/dataflow/model/DataFlowMethod.java rename to src/main/java/model/DataFlowMethod.java index 48d842a..b84cce6 100644 --- a/src/main/java/dataflow/model/DataFlowMethod.java +++ b/src/main/java/model/DataFlowMethod.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.ArrayList; import java.util.Arrays; @@ -35,7 +35,7 @@ import com.github.javaparser.ast.Node; import com.github.javaparser.ast.body.CallableDeclaration; -import dataflow.util.HashCodeWrapper; +import util.HashCodeWrapper; /** * DataFlow class representing a method inside a {@link DataFlowGraph}. diff --git a/src/main/java/dataflow/model/DataFlowNode.java b/src/main/java/model/DataFlowNode.java similarity index 97% rename from src/main/java/dataflow/model/DataFlowNode.java rename to src/main/java/model/DataFlowNode.java index 81082ef..16089ec 100644 --- a/src/main/java/dataflow/model/DataFlowNode.java +++ b/src/main/java/model/DataFlowNode.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.ArrayList; import java.util.List; @@ -31,7 +31,7 @@ import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.Node; -import dataflow.GraphUtil; +import util.GraphUtil; /** * A node inside the {@link DataFlowGraph} containing a {@link JavaParser} {@link Node}. The incoming {@link DataFlowEdge}s are {@link DataFlowNode}s that @@ -109,8 +109,7 @@ public boolean isField() { } public boolean isInputParameter() { - return this.getOwner().filter(DataFlowMethod.class::isInstance).map(DataFlowMethod.class::cast).map(dfm -> dfm.getInputParameters().contains(this)) - .orElse(false); + return this.getOwner().filter(ParameterList.class::isInstance).map(ParameterList.class::cast).filter(ParameterList::isInputParametersForMethod).isPresent(); } /** diff --git a/src/main/java/dataflow/model/NodeCall.java b/src/main/java/model/NodeCall.java similarity index 99% rename from src/main/java/dataflow/model/NodeCall.java rename to src/main/java/model/NodeCall.java index 97fc0a7..08e8c9e 100644 --- a/src/main/java/dataflow/model/NodeCall.java +++ b/src/main/java/model/NodeCall.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/dataflow/model/NodeRepresenter.java b/src/main/java/model/NodeRepresenter.java similarity index 99% rename from src/main/java/dataflow/model/NodeRepresenter.java rename to src/main/java/model/NodeRepresenter.java index 99958a2..cd2a35b 100644 --- a/src/main/java/dataflow/model/NodeRepresenter.java +++ b/src/main/java/model/NodeRepresenter.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.Objects; diff --git a/src/main/java/dataflow/model/OwnedNode.java b/src/main/java/model/OwnedNode.java similarity index 98% rename from src/main/java/dataflow/model/OwnedNode.java rename to src/main/java/model/OwnedNode.java index f66caad..59f19a8 100644 --- a/src/main/java/dataflow/model/OwnedNode.java +++ b/src/main/java/model/OwnedNode.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.Optional; diff --git a/src/main/java/dataflow/model/OwnerNode.java b/src/main/java/model/OwnerNode.java similarity index 98% rename from src/main/java/dataflow/model/OwnerNode.java rename to src/main/java/model/OwnerNode.java index 9b4b7ef..7bc3ed1 100644 --- a/src/main/java/dataflow/model/OwnerNode.java +++ b/src/main/java/model/OwnerNode.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.Collection; import java.util.HashSet; diff --git a/src/main/java/dataflow/model/ParameterList.java b/src/main/java/model/ParameterList.java similarity index 94% rename from src/main/java/dataflow/model/ParameterList.java rename to src/main/java/model/ParameterList.java index 73bb4a0..6b067fe 100644 --- a/src/main/java/dataflow/model/ParameterList.java +++ b/src/main/java/model/ParameterList.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.ArrayList; import java.util.Arrays; @@ -29,7 +29,7 @@ import com.github.javaparser.ast.Node; -import dataflow.DataFlowException; +import common.DataFlowException; /** * Represents the set of parameters from a {@link DataFlowMethod}. Every method has at most one {@link ParameterList}. A parameter list can also exist outside @@ -117,6 +117,14 @@ public void connectTo(ParameterList otherParams) { } } + public boolean isInputParametersForMethod() { + boolean isInputParam = false; + if (this.owner != null && this.owner instanceof DataFlowMethod && ((DataFlowMethod) this.owner).getInputParameters() == this) { + isInputParam = true; + } + return isInputParam; + } + @Override public int hashCode() { return Objects.hash(super.hashCode(), nodes); diff --git a/src/main/java/dataflow/GraphUtil.java b/src/main/java/util/GraphUtil.java similarity index 96% rename from src/main/java/dataflow/GraphUtil.java rename to src/main/java/util/GraphUtil.java index d40ac44..1112525 100644 --- a/src/main/java/dataflow/GraphUtil.java +++ b/src/main/java/util/GraphUtil.java @@ -15,16 +15,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package util; import java.util.Collections; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; -import dataflow.model.DataFlowEdge; -import dataflow.model.DataFlowGraph; -import dataflow.model.DataFlowNode; +import model.DataFlowEdge; +import model.DataFlowGraph; +import model.DataFlowNode; /** * Service for methods to be executed on a {@link DataFlowGraph}. diff --git a/src/main/java/dataflow/util/HashCodeWrapper.java b/src/main/java/util/HashCodeWrapper.java similarity index 98% rename from src/main/java/dataflow/util/HashCodeWrapper.java rename to src/main/java/util/HashCodeWrapper.java index 04b3c44..b689a8d 100644 --- a/src/main/java/dataflow/util/HashCodeWrapper.java +++ b/src/main/java/util/HashCodeWrapper.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.util; +package util; import com.github.javaparser.JavaParser; import com.github.javaparser.ast.Node; diff --git a/src/main/java/dataflow/util/HashMapWrapper.java b/src/main/java/util/HashMapWrapper.java similarity index 98% rename from src/main/java/dataflow/util/HashMapWrapper.java rename to src/main/java/util/HashMapWrapper.java index 7943556..e5ac251 100644 --- a/src/main/java/dataflow/util/HashMapWrapper.java +++ b/src/main/java/util/HashMapWrapper.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.util; +package util; import java.util.Collection; import java.util.HashMap; diff --git a/src/main/java/dataflow/ParserUtil.java b/src/main/java/util/ParserUtil.java similarity index 79% rename from src/main/java/dataflow/ParserUtil.java rename to src/main/java/util/ParserUtil.java index ae9d1cf..bd14933 100644 --- a/src/main/java/dataflow/ParserUtil.java +++ b/src/main/java/util/ParserUtil.java @@ -15,8 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package util; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.Optional; import java.util.stream.Stream; @@ -25,14 +28,17 @@ import org.slf4j.LoggerFactory; import com.github.javaparser.JavaParser; +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.Node; import com.github.javaparser.resolution.Resolvable; import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserFieldDeclaration; import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserParameterDeclaration; import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration; +import com.google.common.util.concurrent.UncheckedExecutionException; -import dataflow.model.DataFlowMethod; -import dataflow.model.OwnedNode; +import model.DataFlowMethod; +import model.OwnedNode; public class ParserUtil { private static final Logger LOG = LoggerFactory.getLogger(ParserUtil.class); @@ -78,4 +84,17 @@ public Object resolve(OwnedNode method, Node node) { return resolved; } + public CompilationUnit createCompilationUnit(String inputClass) { + CompilationUnit cu = null; + try (FileInputStream in = new FileInputStream(inputClass)) { + cu = StaticJavaParser.parse(in); + in.close(); + } catch (FileNotFoundException e) { + throw new UncheckedExecutionException("Could not parse class at location: " + inputClass, e); + } catch (IOException e) { + throw new UncheckedExecutionException("Unable to close input stream for: " + inputClass, e); + } + return cu; + } + } diff --git a/src/test/java/dataflow/DataFlowMethodBuilder.java b/src/test/java/common/DataFlowMethodBuilder.java similarity index 95% rename from src/test/java/dataflow/DataFlowMethodBuilder.java rename to src/test/java/common/DataFlowMethodBuilder.java index adb3249..31e9570 100644 --- a/src/test/java/dataflow/DataFlowMethodBuilder.java +++ b/src/test/java/common/DataFlowMethodBuilder.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package common; import java.util.HashMap; import java.util.Map; @@ -24,8 +24,8 @@ import com.github.javaparser.ast.body.VariableDeclarator; import com.github.javaparser.ast.type.VarType; -import dataflow.model.DataFlowMethod; -import dataflow.model.DataFlowNode; +import model.DataFlowMethod; +import model.DataFlowNode; /** * Builder for {@link DataFlowMethod} with some build method only ment for testing. diff --git a/src/test/java/dataflow/GraphBuilder.java b/src/test/java/common/GraphBuilder.java similarity index 97% rename from src/test/java/dataflow/GraphBuilder.java rename to src/test/java/common/GraphBuilder.java index daf4a5c..effc43e 100644 --- a/src/test/java/dataflow/GraphBuilder.java +++ b/src/test/java/common/GraphBuilder.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package common; import java.util.ArrayList; import java.util.Arrays; @@ -29,10 +29,10 @@ import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.type.ClassOrInterfaceType; -import dataflow.model.DataFlowGraph; -import dataflow.model.DataFlowMethod; -import dataflow.model.DataFlowNode; -import dataflow.model.ParameterList; +import model.DataFlowGraph; +import model.DataFlowMethod; +import model.DataFlowNode; +import model.ParameterList; /** * Builder for {@link DataFlowGraph}, only to be used for test purposes. diff --git a/src/test/java/dataflow/NodeBuilder.java b/src/test/java/common/NodeBuilder.java similarity index 98% rename from src/test/java/dataflow/NodeBuilder.java rename to src/test/java/common/NodeBuilder.java index 45558a4..f937ad1 100644 --- a/src/test/java/dataflow/NodeBuilder.java +++ b/src/test/java/common/NodeBuilder.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package common; import java.util.ArrayList; import java.util.Arrays; @@ -24,7 +24,7 @@ import com.github.javaparser.ast.expr.SimpleName; -import dataflow.model.DataFlowNode; +import model.DataFlowNode; /** * Builder for {@link DataFlowNode}, only to be used for test purposes. diff --git a/src/test/java/dataflow/common/SymbolSolverSetup.java b/src/test/java/common/SymbolSolverSetup.java similarity index 98% rename from src/test/java/dataflow/common/SymbolSolverSetup.java rename to src/test/java/common/SymbolSolverSetup.java index b7ccaae..5c1e804 100644 --- a/src/test/java/dataflow/common/SymbolSolverSetup.java +++ b/src/test/java/common/SymbolSolverSetup.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.common; +package common; import com.github.javaparser.StaticJavaParser; import com.github.javaparser.symbolsolver.JavaSymbolSolver; diff --git a/src/test/java/dataflow/DataFlowGraphFactoryTest.java b/src/test/java/factory/DataFlowGraphFactoryTest.java similarity index 97% rename from src/test/java/dataflow/DataFlowGraphFactoryTest.java rename to src/test/java/factory/DataFlowGraphFactoryTest.java index 26b91f6..d4ff309 100644 --- a/src/test/java/dataflow/DataFlowGraphFactoryTest.java +++ b/src/test/java/factory/DataFlowGraphFactoryTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package factory; import java.util.Arrays; import java.util.Collection; @@ -44,14 +44,13 @@ import com.github.javaparser.ast.expr.SimpleName; import com.google.common.base.Functions; -import dataflow.common.SymbolSolverSetup; -import dataflow.model.DataFlowGraph; -import dataflow.model.DataFlowMethod; -import dataflow.model.DataFlowMethod.Builder; -import dataflow.model.DataFlowNode; -import dataflow.model.DataFlowNodeTest; -import dataflow.model.NodeCall; -import dataflow.model.ParameterList; +import common.SymbolSolverSetup; +import model.DataFlowGraph; +import model.DataFlowMethod; +import model.DataFlowNode; +import model.DataFlowNodeTest; +import model.NodeCall; +import model.ParameterList; /** * Unit test for {@link DataFlowGraphFactory}. @@ -332,10 +331,10 @@ private NodeCall createNodeCall(String name, DataFlowNode nodeCallReturn, DataFl return call; } - private Builder createMethod(String name, DataFlowNode... params) { + private DataFlowMethod.Builder createMethod(String name, DataFlowNode... params) { MethodDeclaration m = new MethodDeclaration(); m.setName(new SimpleName(name)); - Builder method = DataFlowMethod.builder().name(name).representedNode(m); + DataFlowMethod.Builder method = DataFlowMethod.builder().name(name).representedNode(m); if (params != null && params.length > 0) { method.inputParameters(ParameterList.builder().name(name + "Parameters").nodes(params).build()); } diff --git a/src/test/java/dataflow/MethodNodeHandlerTest.java b/src/test/java/factory/MethodNodeHandlerTest.java similarity index 96% rename from src/test/java/dataflow/MethodNodeHandlerTest.java rename to src/test/java/factory/MethodNodeHandlerTest.java index 2657f80..ef77d93 100644 --- a/src/test/java/dataflow/MethodNodeHandlerTest.java +++ b/src/test/java/factory/MethodNodeHandlerTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package factory; import java.util.Arrays; import java.util.HashMap; @@ -36,11 +36,13 @@ import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; -import dataflow.model.DataFlowGraph; -import dataflow.model.DataFlowMethod; -import dataflow.model.DataFlowNode; -import dataflow.model.NodeCall; -import dataflow.model.ParameterList; +import factory.MethodNodeHandler; +import factory.NodeCallFactory; +import model.DataFlowGraph; +import model.DataFlowMethod; +import model.DataFlowNode; +import model.NodeCall; +import model.ParameterList; import util.MethodMatcher; /** diff --git a/src/test/java/dataflow/NodeCallFactoryTest.java b/src/test/java/factory/NodeCallFactoryTest.java similarity index 94% rename from src/test/java/dataflow/NodeCallFactoryTest.java rename to src/test/java/factory/NodeCallFactoryTest.java index 99871fb..12fb7af 100644 --- a/src/test/java/dataflow/NodeCallFactoryTest.java +++ b/src/test/java/factory/NodeCallFactoryTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package factory; import java.util.List; import java.util.Optional; @@ -28,10 +28,11 @@ import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.expr.MethodCallExpr; -import dataflow.common.SymbolSolverSetup; -import dataflow.model.DataFlowMethod; -import dataflow.model.DataFlowNode; -import dataflow.model.NodeCall; +import common.SymbolSolverSetup; +import factory.NodeCallFactory; +import model.DataFlowMethod; +import model.DataFlowNode; +import model.NodeCall; /** * Unit test for {@link NodeCallFactory}. diff --git a/src/test/java/dataflow/model/DataFlowEdgeTest.java b/src/test/java/model/DataFlowEdgeTest.java similarity index 98% rename from src/test/java/dataflow/model/DataFlowEdgeTest.java rename to src/test/java/model/DataFlowEdgeTest.java index 507d8e4..a88ba09 100644 --- a/src/test/java/dataflow/model/DataFlowEdgeTest.java +++ b/src/test/java/model/DataFlowEdgeTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import org.junit.Assert; import org.junit.Test; diff --git a/src/test/java/dataflow/model/DataFlowGraphTest.java b/src/test/java/model/DataFlowGraphTest.java similarity index 99% rename from src/test/java/dataflow/model/DataFlowGraphTest.java rename to src/test/java/model/DataFlowGraphTest.java index 84d90d0..c4ce8c7 100644 --- a/src/test/java/dataflow/model/DataFlowGraphTest.java +++ b/src/test/java/model/DataFlowGraphTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.Collections; import java.util.List; diff --git a/src/test/java/dataflow/model/DataFlowMethodTest.java b/src/test/java/model/DataFlowMethodTest.java similarity index 99% rename from src/test/java/dataflow/model/DataFlowMethodTest.java rename to src/test/java/model/DataFlowMethodTest.java index 877a5ad..df9db3a 100644 --- a/src/test/java/dataflow/model/DataFlowMethodTest.java +++ b/src/test/java/model/DataFlowMethodTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.Collections; import java.util.List; diff --git a/src/test/java/dataflow/model/DataFlowNodeTest.java b/src/test/java/model/DataFlowNodeTest.java similarity index 99% rename from src/test/java/dataflow/model/DataFlowNodeTest.java rename to src/test/java/model/DataFlowNodeTest.java index 411b425..6b75b4f 100644 --- a/src/test/java/dataflow/model/DataFlowNodeTest.java +++ b/src/test/java/model/DataFlowNodeTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.Collection; import java.util.Collections; @@ -40,8 +40,8 @@ import com.github.javaparser.ast.stmt.ReturnStmt; import com.google.common.base.Objects; -import dataflow.util.HashCodeWrapper; -import dataflow.util.HashMapWrapper; +import util.HashCodeWrapper; +import util.HashMapWrapper; /** * Unit test for {@link DataFlowNode}. diff --git a/src/test/java/dataflow/model/NodeCallTest.java b/src/test/java/model/NodeCallTest.java similarity index 99% rename from src/test/java/dataflow/model/NodeCallTest.java rename to src/test/java/model/NodeCallTest.java index 999dffd..1176961 100644 --- a/src/test/java/dataflow/model/NodeCallTest.java +++ b/src/test/java/model/NodeCallTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.Optional; import java.util.function.BiFunction; diff --git a/src/test/java/dataflow/model/ParameterListTest.java b/src/test/java/model/ParameterListTest.java similarity index 99% rename from src/test/java/dataflow/model/ParameterListTest.java rename to src/test/java/model/ParameterListTest.java index 0fee2f5..afed19f 100644 --- a/src/test/java/dataflow/model/ParameterListTest.java +++ b/src/test/java/model/ParameterListTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow.model; +package model; import java.util.Collections; import java.util.List; diff --git a/src/test/java/dataflow/GraphUtilTest.java b/src/test/java/util/GraphUtilTest.java similarity index 94% rename from src/test/java/dataflow/GraphUtilTest.java rename to src/test/java/util/GraphUtilTest.java index 4d07b06..977d3a6 100644 --- a/src/test/java/dataflow/GraphUtilTest.java +++ b/src/test/java/util/GraphUtilTest.java @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dataflow; +package util; import java.util.Arrays; import java.util.Collections; @@ -24,9 +24,11 @@ import org.junit.Assert; import org.junit.Test; -import dataflow.model.DataFlowGraph; -import dataflow.model.DataFlowMethod; -import dataflow.model.DataFlowNode; +import common.GraphBuilder; +import common.NodeBuilder; +import model.DataFlowGraph; +import model.DataFlowMethod; +import model.DataFlowNode; /** * Unit test for {@link GraphUtil}. From 194312a69107c236593a5a7a6dd6ac4337a13dff Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Mon, 23 Dec 2019 17:20:28 +0100 Subject: [PATCH 06/19] Update readme --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ef8e4d..e38651c 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ Nodes are always defined within a specific method, constructor, codeBlock. We refer to such a code block as owner. Every Node has an owner. Every owner can also have an owner, for instance a method is owned by a class. +To make it possible to only parse a part of an application we model calls to a method and the dataflow inside the method itself separately. +At any moment the flow through a method can be linked to a call to that method to follow the flow of data though multiple methods or classes. ## Example @@ -57,10 +59,23 @@ Add the dependency below to the pom of your project. ## Definitions -- The owner of a DataFlowNode represents structure in which the node is defined. + +- Any **object or primitive** is modelled as a DataFlowNode. + A DataFlowNode can have 0 or more input or output DataFlowEdge's. + Such an edge represents a data flow from one node to another. +- The **owner** of a DataFlowNode represents structure in which the node is defined. For the method setA, the parameter inputA has a ParameterList as input. The ParameterList has the DataFlowMethod for "setA" as owner. The owner of the method is the DataFlowGraph representing Example.java +- Each **usage of an object** is modelled as a separate DataFlowNode. + A DataFlowNode representing the usage of an earlier defined object will contain an edge as input from either the last usage before that or the definition of the object. + This way the order in which a node was used is maintained. +- A NodeCall represents a **call to another code block**, for instance a method call. + If a NodeCall was called directly on an object, that object will be modelled as a DataFlowNode and the NodeCall will have a reference to that DataFlowNode via NodeCall::getInstance. + That same DataFlowNode will then have a reference to the NodeCall via DataFlowNode::getNodeCall. + A DataFlowNode can only have a single NodeCall, since every object usage is modelled as a separate node. + If a NodeCall was not directly called on an object, it can be found via DataFlowMethod::getNodeCalls on the method in which the NodeCall was done. + ## Features - JavaDataFlow uses [JavaParser](https://github.com/javaparser/javaparser/) for parsing the input classes. From 6e07e3055490d5ac5bbaad5bdfc450549933b503 Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Mon, 23 Dec 2019 17:21:08 +0100 Subject: [PATCH 07/19] Add NodeCall to DataFlowNode and set it in Handler, failing unit tests --- src/main/java/factory/MethodNodeHandler.java | 7 ++++++- src/main/java/factory/NodeCallFactory.java | 5 ++--- src/main/java/model/DataFlowMethod.java | 3 ++- src/main/java/model/DataFlowNode.java | 22 ++++++++++++++++++++ src/main/java/model/NodeCall.java | 7 +++++++ 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/main/java/factory/MethodNodeHandler.java b/src/main/java/factory/MethodNodeHandler.java index b69b49b..c6d8f40 100644 --- a/src/main/java/factory/MethodNodeHandler.java +++ b/src/main/java/factory/MethodNodeHandler.java @@ -166,7 +166,12 @@ private Optional handleMethodCallExpr(DataFlowGraph graph, DataFlo } calledMethod.setIn(params.build()); - method.addMethodCall(calledMethod); + if (instance == null) { + method.addMethodCall(calledMethod); + } else { + instance.setNodeCall(calledMethod); + } + calledMethod.getReturnNode().ifPresent(method::addNode); // Return the return node of the called method so that the return value can be assigned to the caller. return calledMethod.getReturnNode(); diff --git a/src/main/java/factory/NodeCallFactory.java b/src/main/java/factory/NodeCallFactory.java index daaa2b0..3732ad8 100644 --- a/src/main/java/factory/NodeCallFactory.java +++ b/src/main/java/factory/NodeCallFactory.java @@ -68,9 +68,8 @@ public Optional create(OwnedNode owner, MethodCallExpr node, DataFl } private NodeCall createMethodCall(OwnedNode owner, ResolvedMethodLikeDeclaration resolved, MethodCallExpr node, DataFlowNode instance) { - NodeCall methodCall = - NodeCall.builder().name(resolved.getName()).claz(resolved.getClassName()).peckage(resolved.getPackageName()).owner(owner).representedNode(node).build(); - methodCall.setInstance(instance); + NodeCall methodCall = NodeCall.builder().name(resolved.getName()).claz(resolved.getClassName()).peckage(resolved.getPackageName()).owner(owner) + .representedNode(node).instance(instance).build(); setReturn(methodCall, owner, node, resolved); return methodCall; } diff --git a/src/main/java/model/DataFlowMethod.java b/src/main/java/model/DataFlowMethod.java index b84cce6..615c59c 100644 --- a/src/main/java/model/DataFlowMethod.java +++ b/src/main/java/model/DataFlowMethod.java @@ -180,7 +180,8 @@ public void addChangedFields(DataFlowNode... fields) { } /** - * @return List of {@link DataFlowMethod}s containing both the input and output methods. + * @return List of {@link NodeCall}s representing the method calls that where not called directly on an object, for instance static or methods from within the + * same class. */ public List getNodeCalls() { return this.nodeCalls; diff --git a/src/main/java/model/DataFlowNode.java b/src/main/java/model/DataFlowNode.java index 16089ec..8bed2a2 100644 --- a/src/main/java/model/DataFlowNode.java +++ b/src/main/java/model/DataFlowNode.java @@ -56,6 +56,13 @@ public class DataFlowNode extends OwnedNode { */ private OwnedNode owner; + /** + * If a method was called on the current {@link DataFlowNode} this {@link NodeCall} will represent that NodeCall. Each {@link DataFlowNode} can only have a + * single nodeCall, since each usage of a single variable is modeled to be a separate dataFlowNode. All method called on a given dataFlowNode can be collected + * by walking through the graph. This value will be null if no method was called. + */ + private NodeCall nodeCall; + public DataFlowNode(Node representedNode) { super(representedNode); } @@ -72,6 +79,7 @@ private DataFlowNode(Builder builder) { this.out.addAll(builder.out); this.setType(builder.type); this.owner = builder.owner; + this.nodeCall = builder.nodeCall; } public List getIn() { @@ -104,6 +112,14 @@ public void setType(String type) { this.type = type; } + public NodeCall getNodeCall() { + return nodeCall; + } + + public void setNodeCall(NodeCall nodeCall) { + this.nodeCall = nodeCall; + } + public boolean isField() { return this.getOwner().map(DataFlowGraph.class::isInstance).orElse(false); } @@ -241,6 +257,7 @@ public static final class Builder extends NodeRepresenter.Builder in = new ArrayList<>(); private List out = new ArrayList<>(); private String type; + private NodeCall nodeCall; private Builder() { // Builder should only be constructed via the parent class @@ -268,6 +285,11 @@ public Builder owner(OwnedNode owner) { return this; } + public Builder nodeCall(NodeCall nodeCall) { + this.nodeCall = nodeCall; + return this; + } + public DataFlowNode build() { return new DataFlowNode(this); } diff --git a/src/main/java/model/NodeCall.java b/src/main/java/model/NodeCall.java index 08e8c9e..82b32e4 100644 --- a/src/main/java/model/NodeCall.java +++ b/src/main/java/model/NodeCall.java @@ -76,6 +76,7 @@ private NodeCall(Builder builder) { this.claz = builder.claz == null ? this.claz : builder.claz; this.peckage = builder.peckage == null ? this.peckage : builder.peckage; this.returnNode = builder.returnNode == null ? this.returnNode : builder.returnNode; + this.instance = builder.instance == null ? this.instance : builder.instance; } @Override @@ -199,6 +200,7 @@ public static final class Builder extends NodeRepresenter.Builder Date: Tue, 24 Dec 2019 12:49:05 +0100 Subject: [PATCH 08/19] Fixed MethodNodeHandlerTest --- src/main/java/model/DataFlowNode.java | 4 ++-- .../java/factory/MethodNodeHandlerTest.java | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/model/DataFlowNode.java b/src/main/java/model/DataFlowNode.java index 8bed2a2..03376b5 100644 --- a/src/main/java/model/DataFlowNode.java +++ b/src/main/java/model/DataFlowNode.java @@ -112,8 +112,8 @@ public void setType(String type) { this.type = type; } - public NodeCall getNodeCall() { - return nodeCall; + public Optional getNodeCall() { + return Optional.ofNullable(nodeCall); } public void setNodeCall(NodeCall nodeCall) { diff --git a/src/test/java/factory/MethodNodeHandlerTest.java b/src/test/java/factory/MethodNodeHandlerTest.java index ef77d93..a6a28c2 100644 --- a/src/test/java/factory/MethodNodeHandlerTest.java +++ b/src/test/java/factory/MethodNodeHandlerTest.java @@ -36,8 +36,6 @@ import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.NameExpr; -import factory.MethodNodeHandler; -import factory.NodeCallFactory; import model.DataFlowGraph; import model.DataFlowMethod; import model.DataFlowNode; @@ -72,12 +70,15 @@ public void testHandleMethodCallExpr_inputMethod() { NodeCall methodCall = NodeCall.builder().in(ParameterList.builder().nodes(Arrays.asList(DataFlowNode.builder().name("param1").build())).build()) .returnNode(returnNode).build(); DataFlowMethod method = DataFlowMethod.builder().build(); - mockNodeCallFactory(method, node, cu.findAll(NameExpr.class).get(0), methodCall); + NameExpr sbUsage = cu.findAll(NameExpr.class).get(0); + mockNodeCallFactory(method, node, sbUsage, methodCall); Optional resultNode = execute(node, method); Assert.assertTrue(resultNode.isPresent()); - Assert.assertEquals(Arrays.asList(methodCall), method.getNodeCalls()); + Assert.assertEquals(returnNode, resultNode.get()); + Assert.assertEquals(methodCall, method.getNode(sbUsage).getNodeCall().get()); + Assert.assertTrue(method.getNodeCalls().isEmpty()); } @Test @@ -93,12 +94,15 @@ public void testHandleMethodCallExpr_outputMethod() { NodeCall methodCall = NodeCall.builder().in(ParameterList.builder().nodes(Arrays.asList(DataFlowNode.builder().name("param1").build())).build()) .returnNode(returnNode).build(); DataFlowMethod method = DataFlowMethod.builder().build(); - mockNodeCallFactory(method, node, cu.findAll(NameExpr.class).get(0), methodCall); + NameExpr sbUsage = cu.findAll(NameExpr.class).get(0); + mockNodeCallFactory(method, node, sbUsage, methodCall); Optional resultNode = execute(node, method); Assert.assertTrue(resultNode.isPresent()); - Assert.assertEquals(Arrays.asList(methodCall), method.getNodeCalls()); + Assert.assertEquals(returnNode, resultNode.get()); + Assert.assertEquals(methodCall, method.getNode(sbUsage).getNodeCall().get()); + Assert.assertTrue(method.getNodeCalls().isEmpty()); } @Test @@ -124,7 +128,10 @@ public void testHandleMethodCallExpr_methodConcatenation() { Optional resultNode = execute(charrAt, method); Assert.assertTrue(resultNode.isPresent()); - Assert.assertEquals(Arrays.asList(appendCall, charrAtCall), method.getNodeCalls()); + Assert.assertEquals(dfnCharrAt, resultNode.get()); + Assert.assertEquals(appendCall, method.getNode(instance).getNodeCall().get()); + Assert.assertEquals(charrAtCall, method.getNode(append).getNodeCall().get()); + Assert.assertTrue(method.getNodeCalls().isEmpty()); } private void mockNodeCallFactory(DataFlowMethod method, MethodCallExpr node, Node instance, NodeCall methodCall) { From 718c65dbcc64963bbd06192f8805f68db492049d Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Tue, 24 Dec 2019 12:51:04 +0100 Subject: [PATCH 09/19] Fixed builder, all tests green --- src/main/java/model/NodeCall.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/model/NodeCall.java b/src/main/java/model/NodeCall.java index 82b32e4..0d71d04 100644 --- a/src/main/java/model/NodeCall.java +++ b/src/main/java/model/NodeCall.java @@ -236,6 +236,11 @@ public Builder peckage(String peckage) { return this; } + public Builder instance(DataFlowNode instance) { + this.instance = instance; + return this; + } + public Builder returnNode(DataFlowNode node) { this.returnNode = node; return this; @@ -245,11 +250,6 @@ public NodeCall build() { return new NodeCall(this); } - public Builder instance(DataFlowNode instance) { - this.instance = instance; - return null; - } - } } From 46d9ca3ff52af3c4c4a0613c088efd65a3183c4e Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Tue, 24 Dec 2019 12:59:17 +0100 Subject: [PATCH 10/19] Prepare for release --- README.md | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e38651c..238b102 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Add the dependency below to the pom of your project. com.github.daanvdh.javadataflow JavaDataFlow - 0.0.2 + 0.0.4 ## Definitions diff --git a/pom.xml b/pom.xml index 9a9d85c..a86caa2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.daanvdh.javadataflow JavaDataFlow - 0.0.3 + 0.0.4 jar JavaDataFlow From 170dbb03296cec5edcccd57b61ac42ee3b08ad2a Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Tue, 24 Dec 2019 16:52:33 +0100 Subject: [PATCH 11/19] Implement collectNodeCalls method and rename getInputParameters --- README.md | 2 ++ src/main/java/factory/MethodNodeHandler.java | 5 ++- src/main/java/model/DataFlowMethod.java | 2 +- src/main/java/model/DataFlowNode.java | 27 ++++++++++++++++ src/main/java/model/NodeCall.java | 2 +- src/main/java/model/ParameterList.java | 2 +- src/test/java/common/GraphBuilder.java | 2 +- .../factory/DataFlowGraphFactoryTest.java | 6 ++-- .../java/factory/MethodNodeHandlerTest.java | 6 ++-- src/test/java/model/DataFlowMethodTest.java | 4 +-- src/test/java/model/DataFlowNodeTest.java | 32 +++++++++++++++++++ src/test/java/util/GraphUtilTest.java | 6 ++-- 12 files changed, 78 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 238b102..a2c1b55 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,8 @@ Add the dependency below to the pom of your project. - JavaDataFlow uses [JavaParser](https://github.com/javaparser/javaparser/) for parsing the input classes. Each DataFlowNode has a representedNode which is the JavaParser Node that it represents. If you have a given JavaParser Node you can get the JavaDataFlowNode via DataFlowGraph::getNode. +- Collect all methods that where called on a given object by executing DataFlowNode::collectNodeCalls. + A scope can be added to this method to only find calls within a certain method or graph, you can for example use DataFlowMethod::owns. ## Roadmap - Include Constructors in the JavaDataFlow graph. diff --git a/src/main/java/factory/MethodNodeHandler.java b/src/main/java/factory/MethodNodeHandler.java index c6d8f40..01b73b0 100644 --- a/src/main/java/factory/MethodNodeHandler.java +++ b/src/main/java/factory/MethodNodeHandler.java @@ -166,11 +166,10 @@ private Optional handleMethodCallExpr(DataFlowGraph graph, DataFlo } calledMethod.setIn(params.build()); - if (instance == null) { - method.addMethodCall(calledMethod); - } else { + if (instance != null) { instance.setNodeCall(calledMethod); } + method.addMethodCall(calledMethod); calledMethod.getReturnNode().ifPresent(method::addNode); // Return the return node of the called method so that the return value can be assigned to the caller. diff --git a/src/main/java/model/DataFlowMethod.java b/src/main/java/model/DataFlowMethod.java index 615c59c..261d914 100644 --- a/src/main/java/model/DataFlowMethod.java +++ b/src/main/java/model/DataFlowMethod.java @@ -111,7 +111,7 @@ public final void setReturnNode(DataFlowNode returnNode) { this.addNode(returnNode); } - public ParameterList getInputParameters() { + public ParameterList getParameters() { return inputParameters; } diff --git a/src/main/java/model/DataFlowNode.java b/src/main/java/model/DataFlowNode.java index 03376b5..9adbfab 100644 --- a/src/main/java/model/DataFlowNode.java +++ b/src/main/java/model/DataFlowNode.java @@ -18,10 +18,12 @@ package model; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; +import java.util.stream.Collectors; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; @@ -140,6 +142,25 @@ public List walkBackUntil(Predicate predicate, Predi return GraphUtil.walkBackUntil(this, predicate, scope); } + /** + * Returns all {@link NodeCall} that are called directly on this {@link DataFlowNode} or on any other {@link DataFlowNode} that has an {@link DataFlowEdge} + * resulting from this node. Only nodes within the defined scope are considered. + * + * @param scope The scope for searching for {@link NodeCall}s. + * @return List of {@link NodeCall}. + */ + public List collectNodeCalls(Predicate scope) { + if (!scope.test(this)) { + return new ArrayList<>(); + } + List collect = + this.getOut().stream().map(DataFlowEdge::getTo).map(dfn -> dfn.collectNodeCalls(scope)).flatMap(List::stream).collect(Collectors.toList()); + if (this.nodeCall != null) { + collect.add(nodeCall); + } + return collect; + } + /** * @param node The {@link DataFlowNode} to check. * @return True if this node is equal to the given node or has a direct incoming edge from the input node, false otherwise. @@ -275,6 +296,12 @@ public Builder out(List out) { return this; } + public Builder out(DataFlowEdge... out) { + this.out.clear(); + this.out.addAll(Arrays.asList(out)); + return this; + } + public Builder type(String type) { this.type = type; return this; diff --git a/src/main/java/model/NodeCall.java b/src/main/java/model/NodeCall.java index 0d71d04..015bf17 100644 --- a/src/main/java/model/NodeCall.java +++ b/src/main/java/model/NodeCall.java @@ -99,7 +99,7 @@ public Optional getCalledMethod() { public void setCalledMethod(DataFlowMethod calledMethod) { this.calledMethod = calledMethod; - this.in.connectTo(calledMethod.getInputParameters()); + this.in.connectTo(calledMethod.getParameters()); if (this.returnNode != null) { if (calledMethod.getReturnNode().isPresent()) { calledMethod.getReturnNode().get().addEdgeTo(returnNode); diff --git a/src/main/java/model/ParameterList.java b/src/main/java/model/ParameterList.java index 6b067fe..1a55a95 100644 --- a/src/main/java/model/ParameterList.java +++ b/src/main/java/model/ParameterList.java @@ -119,7 +119,7 @@ public void connectTo(ParameterList otherParams) { public boolean isInputParametersForMethod() { boolean isInputParam = false; - if (this.owner != null && this.owner instanceof DataFlowMethod && ((DataFlowMethod) this.owner).getInputParameters() == this) { + if (this.owner != null && this.owner instanceof DataFlowMethod && ((DataFlowMethod) this.owner).getParameters() == this) { isInputParam = true; } return isInputParam; diff --git a/src/test/java/common/GraphBuilder.java b/src/test/java/common/GraphBuilder.java index effc43e..9cfb965 100644 --- a/src/test/java/common/GraphBuilder.java +++ b/src/test/java/common/GraphBuilder.java @@ -100,7 +100,7 @@ private void addNode(DataFlowGraph graph, NodeBuilder nodeBuilder, Map assertMethodsEqual(Collection exp, Coll } private Optional assertMethodEqual(DataFlowMethod expMethod, DataFlowMethod equalMethod) { - Optional parametersEqual = dfnTest.assertNodesEqual(expMethod.getInputParameters().getNodes(), equalMethod.getInputParameters().getNodes()) + Optional parametersEqual = dfnTest.assertNodesEqual(expMethod.getParameters().getNodes(), equalMethod.getParameters().getNodes()) .map(s -> "for " + expMethod.getName() + " parameters not equal: " + s); Optional nodesEqual = parametersEqual.isPresent() ? parametersEqual : dfnTest.assertNodesEqual(expMethod.getNodes(), equalMethod.getNodes()).map(s -> "for " + expMethod.getName() + ": " + s); @@ -398,8 +398,8 @@ private Matcher createMatcher(DataFlowMethod method) { EqualFeatureMatcher methodNameMatcher = new EqualFeatureMatcher<>(DataFlowMethod::getName, method.getName(), "methodName"); EqualFeatureMatcher> parameterMatcher = - new EqualFeatureMatcher<>((m) -> m.getInputParameters().getNodes().stream().map(DataFlowNode::getName).collect(Collectors.toList()), - method.getInputParameters().getNodes().stream().map(DataFlowNode::getName).collect(Collectors.toList()), "methodParameters"); + new EqualFeatureMatcher<>((m) -> m.getParameters().getNodes().stream().map(DataFlowNode::getName).collect(Collectors.toList()), + method.getParameters().getNodes().stream().map(DataFlowNode::getName).collect(Collectors.toList()), "methodParameters"); return Matchers.allOf(methodNameMatcher, parameterMatcher); } diff --git a/src/test/java/factory/MethodNodeHandlerTest.java b/src/test/java/factory/MethodNodeHandlerTest.java index a6a28c2..dd3826f 100644 --- a/src/test/java/factory/MethodNodeHandlerTest.java +++ b/src/test/java/factory/MethodNodeHandlerTest.java @@ -78,7 +78,7 @@ public void testHandleMethodCallExpr_inputMethod() { Assert.assertTrue(resultNode.isPresent()); Assert.assertEquals(returnNode, resultNode.get()); Assert.assertEquals(methodCall, method.getNode(sbUsage).getNodeCall().get()); - Assert.assertTrue(method.getNodeCalls().isEmpty()); + Assert.assertEquals(Arrays.asList(methodCall), method.getNodeCalls()); } @Test @@ -102,7 +102,7 @@ public void testHandleMethodCallExpr_outputMethod() { Assert.assertTrue(resultNode.isPresent()); Assert.assertEquals(returnNode, resultNode.get()); Assert.assertEquals(methodCall, method.getNode(sbUsage).getNodeCall().get()); - Assert.assertTrue(method.getNodeCalls().isEmpty()); + Assert.assertEquals(Arrays.asList(methodCall), method.getNodeCalls()); } @Test @@ -131,7 +131,7 @@ public void testHandleMethodCallExpr_methodConcatenation() { Assert.assertEquals(dfnCharrAt, resultNode.get()); Assert.assertEquals(appendCall, method.getNode(instance).getNodeCall().get()); Assert.assertEquals(charrAtCall, method.getNode(append).getNodeCall().get()); - Assert.assertTrue(method.getNodeCalls().isEmpty()); + Assert.assertEquals(Arrays.asList(appendCall, charrAtCall), method.getNodeCalls()); } private void mockNodeCallFactory(DataFlowMethod method, MethodCallExpr node, Node instance, NodeCall methodCall) { diff --git a/src/test/java/model/DataFlowMethodTest.java b/src/test/java/model/DataFlowMethodTest.java index df9db3a..f791533 100644 --- a/src/test/java/model/DataFlowMethodTest.java +++ b/src/test/java/model/DataFlowMethodTest.java @@ -45,7 +45,7 @@ public class DataFlowMethodTest { public void testDataFlowMethod_minimum() { DataFlowMethod dataFlowMethod = DataFlowMethod.builder().build(); - Assert.assertNull("Unexpected inputParameters", dataFlowMethod.getInputParameters()); + Assert.assertNull("Unexpected inputParameters", dataFlowMethod.getParameters()); Assert.assertTrue("Unexpected inputFields", dataFlowMethod.getInputFields().isEmpty()); Assert.assertTrue("Unexpected changedFields", dataFlowMethod.getChangedFields().isEmpty()); } @@ -54,7 +54,7 @@ public void testDataFlowMethod_minimum() { public void testDataFlowMethod_maximum() { DataFlowMethod dataFlowMethod = createAndFillBuilder().build(); - Assert.assertEquals("Unexpected inputParameters", INPUT_PARAMETERS, dataFlowMethod.getInputParameters()); + Assert.assertEquals("Unexpected inputParameters", INPUT_PARAMETERS, dataFlowMethod.getParameters()); Assert.assertEquals("Unexpected inputFields", INPUT_FIELDS, dataFlowMethod.getInputFields()); Assert.assertEquals("Unexpected changedFields", CHANGED_FIELDS, dataFlowMethod.getChangedFields()); } diff --git a/src/test/java/model/DataFlowNodeTest.java b/src/test/java/model/DataFlowNodeTest.java index 6b75b4f..6a5f459 100644 --- a/src/test/java/model/DataFlowNodeTest.java +++ b/src/test/java/model/DataFlowNodeTest.java @@ -106,6 +106,38 @@ public void testHashCode_Different() { verifyHashCode_Different(DataFlowNode.Builder::out, Collections.singletonList(DataFlowEdge.builder().build())); } + @Test + public void testCollectNodeCalls_empty() { + Assert.assertTrue(DataFlowNode.builder().build().collectNodeCalls(x -> true).isEmpty()); + } + + @Test + public void testCollectNodeCalls() { + DataFlowNode n3 = DataFlowNode.builder().nodeCall(NodeCall.builder().build()).build(); + DataFlowNode n2 = DataFlowNode.builder().out(DataFlowEdge.builder().to(n3).build()).build(); + DataFlowNode n1 = DataFlowNode.builder().out(DataFlowEdge.builder().to(n2).build()).nodeCall(NodeCall.builder().build()).build(); + + Assert.assertEquals(2, n1.collectNodeCalls(x -> true).size()); + } + + @Test + public void testCollectNodeCalls_predicate() { + DataFlowNode n3 = DataFlowNode.builder().nodeCall(NodeCall.builder().build()).build(); + DataFlowNode n2 = DataFlowNode.builder().out(DataFlowEdge.builder().to(n3).build()).build(); + DataFlowNode n1 = DataFlowNode.builder().out(DataFlowEdge.builder().to(n2).build()).nodeCall(NodeCall.builder().build()).build(); + + Assert.assertEquals(1, n1.collectNodeCalls(x -> !x.equals(n3)).size()); + } + + @Test + public void testCollectNodeCalls_predicateFalseForFirst() { + DataFlowNode n3 = DataFlowNode.builder().nodeCall(NodeCall.builder().build()).build(); + DataFlowNode n2 = DataFlowNode.builder().out(DataFlowEdge.builder().to(n3).build()).build(); + DataFlowNode n1 = DataFlowNode.builder().out(DataFlowEdge.builder().to(n2).build()).nodeCall(NodeCall.builder().build()).build(); + + Assert.assertEquals(0, n1.collectNodeCalls(x -> !x.equals(n1)).size()); + } + /** * Assert that the names and all incoming and outgoing edges are equal, regardless of the order. * diff --git a/src/test/java/util/GraphUtilTest.java b/src/test/java/util/GraphUtilTest.java index 977d3a6..8d1405d 100644 --- a/src/test/java/util/GraphUtilTest.java +++ b/src/test/java/util/GraphUtilTest.java @@ -42,7 +42,7 @@ public void testWalkBackUntil_simple() { DataFlowGraph graph = GraphBuilder.withStartingNodes(NodeBuilder.ofParameter("setS", "a").to("setS.a").to("setS.b").to(NodeBuilder.ofField("s"))).build(); DataFlowMethod m = graph.getMethods().iterator().next(); DataFlowNode node = m.getChangedFields().get(0); - DataFlowNode expected = m.getInputParameters().getNodes().get(0); + DataFlowNode expected = m.getParameters().getNodes().get(0); List result = GraphUtil.walkBackUntil(node, m::isInputBoundary, graph::owns); Assert.assertEquals(Collections.singletonList(expected), result); @@ -52,7 +52,7 @@ public void testWalkBackUntil_simple() { public void testWalkBackUntil_inputIsBoundaryNode() { DataFlowGraph graph = GraphBuilder.withStartingNodes(NodeBuilder.ofParameter("setS", "a").to("setS.a").to("setS.b").to(NodeBuilder.ofField("s"))).build(); DataFlowMethod m = graph.getMethods().iterator().next(); - DataFlowNode expected = m.getInputParameters().getNodes().get(0); + DataFlowNode expected = m.getParameters().getNodes().get(0); List result = GraphUtil.walkBackUntil(expected, m::isInputBoundary, graph::owns); Assert.assertEquals(Collections.singletonList(expected), result); @@ -69,7 +69,7 @@ public void testWalkBackUntil_multipleOutput() { DataFlowGraph graph = withStartingNodes.build(); DataFlowMethod m = graph.getMethods().iterator().next(); DataFlowNode node = m.getChangedFields().get(0); - List parameters = m.getInputParameters().getNodes(); + List parameters = m.getParameters().getNodes(); List result = GraphUtil.walkBackUntil(node, m::isInputBoundary, graph::owns); Assert.assertEquals(Arrays.asList(parameters.get(0), parameters.get(1)), result); From b09400c5186033c041b84ae3cd32d3a08e22e366 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 17:40:25 +0000 Subject: [PATCH 12/19] Bump junit from 4.12 to 4.13.1 Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1. - [Release notes](https://github.com/junit-team/junit4/releases) - [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md) - [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1) Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9a9d85c..4784ad0 100644 --- a/pom.xml +++ b/pom.xml @@ -140,7 +140,7 @@ junit junit - 4.12 + 4.13.1 test From 33c68eaa97a7a24ab68fef68a40864f254e0284c Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Wed, 14 Oct 2020 08:40:34 +0200 Subject: [PATCH 13/19] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8ef8e4d..3ebd93f 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,8 @@ A DataFlowGraph represents a single class. Now if we want to gather all input nodes to this class that can influence the output of the method "getA", we can do that as given below. First get the given method. Now we need to walk back until we reach a node that is an input parameter of a method, for this we can use the method DataFlowNode::isInputParameter. -For this example we don't want to go outside this class so we add dfg::owns as scope to the method walkBackUntil. -The scope determines when to stop walking over the nodes, this can become important multiple data flow graphs are connected to each other. +For this example we don't want to go outside of this class so we add dfg::owns as scope to the method walkBackUntil. +The scope determines when to stop walking over the nodes, this can become important if multiple data flow graphs are connected to each other. However, this is currently not supported yet. DataFlowMethod getA = dfg.getMethods().stream().filter(m -> m.getName().equals("getA")).findFirst().get(); @@ -76,4 +76,4 @@ Add the dependency below to the pom of your project. ## License -JavaDataFlow is available under the terms of the Apache License. http://www.apache.org/licenses/LICENSE-2.0 \ No newline at end of file +JavaDataFlow is available under the terms of the Apache License. http://www.apache.org/licenses/LICENSE-2.0 From 37862e5276ab241031f4755a188aa1af666fc247 Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Thu, 10 Feb 2022 17:22:29 +0100 Subject: [PATCH 14/19] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3ebd93f..5e0640a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![Join the chat at https://gitter.im/JavaDataFlow/community](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/JavaDataFlow/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + # JavaDataFlow Creating Data Flow Graphs from java input classes From aee27aca58382737c8792e39e19cc420c604a8d8 Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Thu, 10 Mar 2022 17:04:51 +0100 Subject: [PATCH 15/19] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5e0640a..57ca51f 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ However, this is currently not supported yet. List inputNodes = getA.getReturnNode().get().walkBackUntil(DataFlowNode::isInputParameter, dfg::owns); System.out.println(inputNodes.get(0).getName()); -The above code will output the name "inputA". +The above code will output the name "inputA". All code above is also given in an [example project](https://github.com/daanvdh/JavaDataFlowExample). ## Setup Add the dependency below to the pom of your project. @@ -55,7 +55,7 @@ Add the dependency below to the pom of your project. com.github.daanvdh.javadataflow JavaDataFlow - 0.0.2 + 0.0.3 ## Definitions From 47b5a1ce7595628e4ff289a5a97dc065b175a5a5 Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Thu, 10 Mar 2022 17:30:05 +0100 Subject: [PATCH 16/19] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c34815f..ce596e4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![Join the chat at https://gitter.im/JavaDataFlow/community](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/JavaDataFlow/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Maven Central](https://img.shields.io/maven-central/v/com.github.javaparser/javaparser-core.svg)](https://search.maven.org/search?q=g:com.github.daanvdh.javadataflow) # JavaDataFlow Creating Data Flow Graphs from java input classes From 535e0d1a06a8cf66b57a7a3d6316d108b8406f80 Mon Sep 17 00:00:00 2001 From: Daan van den Heuvel Date: Thu, 10 Mar 2022 17:52:31 +0100 Subject: [PATCH 17/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce596e4..20b5192 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![Join the chat at https://gitter.im/JavaDataFlow/community](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/JavaDataFlow/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Maven Central](https://img.shields.io/maven-central/v/com.github.javaparser/javaparser-core.svg)](https://search.maven.org/search?q=g:com.github.daanvdh.javadataflow) +[![maven-central](https://img.shields.io/maven-central/v/com.github.daanvdh.javadataflow/JavaDataFlow.svg)](https://search.maven.org/search?q=g:com.github.daanvdh.javadataflow) # JavaDataFlow Creating Data Flow Graphs from java input classes From e6d6d05840deb2e3d5bdf63434279a07d60fce2c Mon Sep 17 00:00:00 2001 From: "daan.vandenheuvel" Date: Tue, 22 Mar 2022 14:05:13 +0100 Subject: [PATCH 18/19] Bump JP version --- README.md | 6 ++--- pom.xml | 4 +-- .../java/factory/DataFlowNodeFactory.java | 9 ++++--- src/main/java/factory/MethodNodeHandler.java | 26 +++++++++---------- src/main/java/util/ParserUtil.java | 6 ++--- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index a2c1b55..6eff6a5 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ A DataFlowGraph represents a single class. String input = "/relativePath/Example.java"; StaticJavaDataFlow.getConfig().setProjectPaths(projectPath); DataFlowGraph dfg = JavaDataFlow.create(projectPath + input); - + Now if we want to gather all input nodes to this class that can influence the output of the method "getA", we can do that as given below. First get the given method. Now we need to walk back until we reach a node that is an input parameter of a method, for this we can use the method DataFlowNode::isInputParameter. @@ -46,7 +46,7 @@ However, this is currently not supported yet. DataFlowMethod getA = dfg.getMethods().stream().filter(m -> m.getName().equals("getA")).findFirst().get(); List inputNodes = getA.getReturnNode().get().walkBackUntil(DataFlowNode::isInputParameter, dfg::owns); System.out.println(inputNodes.get(0).getName()); - + The above code will output the name "inputA". ## Setup @@ -55,7 +55,7 @@ Add the dependency below to the pom of your project. com.github.daanvdh.javadataflow JavaDataFlow - 0.0.4 + 0.0.5 ## Definitions diff --git a/pom.xml b/pom.xml index a86caa2..962a3f2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.daanvdh.javadataflow JavaDataFlow - 0.0.4 + 0.0.5 jar JavaDataFlow @@ -154,7 +154,7 @@ com.github.javaparser javaparser-symbol-solver-core - 3.15.4 + 3.24.0 diff --git a/src/main/java/factory/DataFlowNodeFactory.java b/src/main/java/factory/DataFlowNodeFactory.java index 03cf8fc..613d66e 100644 --- a/src/main/java/factory/DataFlowNodeFactory.java +++ b/src/main/java/factory/DataFlowNodeFactory.java @@ -21,9 +21,10 @@ import org.slf4j.LoggerFactory; import com.github.javaparser.ast.Node; +import com.github.javaparser.ast.expr.SimpleName; import com.github.javaparser.ast.nodeTypes.NodeWithSimpleName; import com.github.javaparser.ast.stmt.ReturnStmt; -import com.github.javaparser.printer.Printable; +import com.github.javaparser.printer.Stringable; import model.DataFlowNode; import model.OwnedNode; @@ -45,8 +46,10 @@ public DataFlowNode create(Node n, OwnedNode owner) { if (nodeWithName instanceof NodeWithSimpleName) { builder.name(((NodeWithSimpleName) nodeWithName).getNameAsString()); - } else if (nodeWithName instanceof Printable) { - builder.name(((Printable) nodeWithName).asString()); + } else if (nodeWithName instanceof Stringable) { + builder.name(((Stringable) nodeWithName).asString()); + } else if (nodeWithName instanceof SimpleName) { + builder.name(((SimpleName) nodeWithName).asString()); } else { LOG.warn("Not supported to add a name to a created DataFlowNode for node of type {}, input node is {}", n.getClass(), n); } diff --git a/src/main/java/factory/MethodNodeHandler.java b/src/main/java/factory/MethodNodeHandler.java index 01b73b0..444c0a9 100644 --- a/src/main/java/factory/MethodNodeHandler.java +++ b/src/main/java/factory/MethodNodeHandler.java @@ -268,30 +268,30 @@ private Optional handleAssignExpr(DataFlowGraph graph, DataFlowMet return Optional.of(flowNode); } - /** - * TODO javadoc - * - * @param graph - * @param method - * @param overwriddenValues - * @param node - * @return - */ private Optional getDataFlowNode(DataFlowGraph graph, DataFlowMethod method, Map overwriddenValues, Node node) { Optional optionalResolvedNode = parserUtil.getJavaParserNode(method, node); DataFlowNode flowNode = null; if (optionalResolvedNode.isPresent()) { Node resolvedNode = optionalResolvedNode.get(); - flowNode = overwriddenValues.get(resolvedNode); - flowNode = flowNode != null ? flowNode : graph.getNode(resolvedNode); - flowNode = flowNode != null ? flowNode : method.getNode(resolvedNode); + flowNode = getLastFlowNode(graph, method, overwriddenValues, resolvedNode); + flowNode = (flowNode != null && !(resolvedNode instanceof VariableDeclarationExpr)) ? flowNode + : ((VariableDeclarationExpr) resolvedNode).getVariables().stream().map(child -> getLastFlowNode(graph, method, overwriddenValues, child)) + .filter(n -> n != null).findFirst().orElse(null); } if (flowNode == null) { - LOG.warn("In method {} did not resolve the type of node {} of type {}", method.getName(), node, node.getClass()); + LOG.warn("In method {} did not resolve the type of node {} of type {}, resolvedNode was {}", method.getName(), node, node.getClass(), + optionalResolvedNode); } return Optional.ofNullable(flowNode); } + private DataFlowNode getLastFlowNode(DataFlowGraph graph, DataFlowMethod method, Map overwriddenValues, Node resolvedNode) { + DataFlowNode flowNode = overwriddenValues.get(resolvedNode); + flowNode = flowNode != null ? flowNode : method.getNode(resolvedNode); + flowNode = flowNode != null ? flowNode : graph.getNode(resolvedNode); + return flowNode; + } + private String nameForInBetweenNode(DataFlowMethod method, Map overriddenValues, Node realAssignedJP, NodeWithSimpleName nodeWithName) { String namePostFix = ""; diff --git a/src/main/java/util/ParserUtil.java b/src/main/java/util/ParserUtil.java index bd14933..fe5afeb 100644 --- a/src/main/java/util/ParserUtil.java +++ b/src/main/java/util/ParserUtil.java @@ -34,7 +34,7 @@ import com.github.javaparser.resolution.Resolvable; import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserFieldDeclaration; import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserParameterDeclaration; -import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserSymbolDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserVariableDeclaration; import com.google.common.util.concurrent.UncheckedExecutionException; import model.DataFlowMethod; @@ -58,8 +58,8 @@ public Optional getJavaParserNode(DataFlowMethod method, Node node) { resolvedNode = ((JavaParserFieldDeclaration) resolved).getVariableDeclarator(); } else if (resolved instanceof JavaParserParameterDeclaration) { resolvedNode = ((JavaParserParameterDeclaration) resolved).getWrappedNode(); - } else if (resolved instanceof JavaParserSymbolDeclaration) { - resolvedNode = ((JavaParserSymbolDeclaration) resolved).getWrappedNode(); + } else if (resolved instanceof JavaParserVariableDeclaration) { + resolvedNode = ((JavaParserVariableDeclaration) resolved).getWrappedNode(); } else { LOG.warn("In method {}, resolving is not supported for node {} of type {}", method.getName(), node, resolved == null ? null : resolved.getClass()); } From 8961addb4d28b5b0884f1cc5874422ef7ff01bed Mon Sep 17 00:00:00 2001 From: "daan.vandenheuvel" Date: Tue, 22 Mar 2022 14:22:38 +0100 Subject: [PATCH 19/19] fix class cast exception in mvn --- src/main/java/factory/MethodNodeHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/factory/MethodNodeHandler.java b/src/main/java/factory/MethodNodeHandler.java index 444c0a9..c6127a4 100644 --- a/src/main/java/factory/MethodNodeHandler.java +++ b/src/main/java/factory/MethodNodeHandler.java @@ -274,7 +274,7 @@ private Optional getDataFlowNode(DataFlowGraph graph, DataFlowMeth if (optionalResolvedNode.isPresent()) { Node resolvedNode = optionalResolvedNode.get(); flowNode = getLastFlowNode(graph, method, overwriddenValues, resolvedNode); - flowNode = (flowNode != null && !(resolvedNode instanceof VariableDeclarationExpr)) ? flowNode + flowNode = (flowNode != null || !(resolvedNode instanceof VariableDeclarationExpr)) ? flowNode : ((VariableDeclarationExpr) resolvedNode).getVariables().stream().map(child -> getLastFlowNode(graph, method, overwriddenValues, child)) .filter(n -> n != null).findFirst().orElse(null); }