diff --git a/README.md b/README.md index a2c1b55..f439d73 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +[![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.daanvdh.javadataflow/JavaDataFlow.svg)](https://search.maven.org/search?q=g:com.github.daanvdh.javadataflow) + # JavaDataFlow Creating Data Flow Graphs from java input classes @@ -35,19 +38,19 @@ 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. -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(); 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,9 +58,8 @@ Add the dependency below to the pom of your project. com.github.daanvdh.javadataflow JavaDataFlow - 0.0.4 + 0.0.5 - ## Definitions - Any **object or primitive** is modelled as a DataFlowNode. @@ -93,4 +95,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 diff --git a/pom.xml b/pom.xml index a86caa2..97d0b23 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.daanvdh.javadataflow JavaDataFlow - 0.0.4 + 0.0.5 jar JavaDataFlow @@ -140,7 +140,7 @@ junit junit - 4.12 + 4.13.1 test @@ -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..c6127a4 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()); }