pmd其实有简单的数据流,但是网上搜了下,没有什么文章
寻找方法
查看pmd文档其中有一段介绍data flow analysis的文字

从中可以推断pmd通过net.sourceforge.pmd.SourceCodeProcessor来遍历AST建立CFG和数据流,寻找这个类中进行DFA的地方

可以看到调用了userDFA,最终会找到一个类net.sourceforge.pmd.lang.java.dfa.DataFlowFacade

在这个类中,对方法定义跟构造函数定义进行了处理,接下来就只对方法定义的处理过程做说明
处理过程
在net.sourceforge.pmd.lang.java.dfa.StatementAndBraceFinder中,定义了几种AST节点的数据流建立规则。在阅读之前,需要了解一些其他类做的工作
数据结构
在net.sourceforge.pmd.lang.dfa.Structure中,定义了三个变量

dataFlow用于存取Node

braceStack包含对数据流有影响的点,cbrStack包含continue, break, return节点。至于分为两个栈来处理,是因为处理continue, break, return的过程与一般点不一样

NodeType与序列
在net.sourceforge.pmd.lang.dfa.SequenceChecker中,定义了不同点的控制类型(?)以及先后关系

并对braceStack中的点进行分割,简化描述为从0开始,寻找第i个isLastStep的点,从0-i为一组分割
遍历AST
回到StatementAndBraceFinder

对ASTMethodDeclaration中的点进行遍历,这里只对if过程进行说明


这是个if的伪代码,根据代码,会取ASTExpression,判断父节点类型是否为ASTIfStatement,是则创建一个dataflow node,加入dataflow的list中,并打上IF_EXPR的标签,压入braceStack中


继续遍历AST就会取到ASTStatement,中间的super.visit是遍历ASTStatement的子节点,为了处理嵌套的情况,这里就先不管了。然后就会判断这个ASTStatement的父节点是不是ASTIfStatement,如果是,就判断ASTIfStatement是否存在else,如果没有else,就将ASTStatement里最后一个ASTStatementExpression(上述代码的情况下)打上IF_LAST_STATEMENT_WITHOUT_ELSE的标签压入braceStack中

如果存在else,并且当前Statement下标为1,说明是if的body,给最后一个ASTStatementExpression打上IF_LAST_STATEMENT的标签,压入braceStack

如果当前Statement下标不为1,说明是else的body,给最后一个ASTStatementExpression打上ELSE_LAST_STATEMENT的标签,压入braceStack
建立路径
第一种是在把createNewNode时,会创建路径,就是上一个添加的点指向当前创建的点

第二种是根据具体的控制语句,修正路径

对braceStack进行分割,找到第一组firstIndex和lastIndex

如果第一个对象为IF_EXPR,计算是否存在else,对应两种不同的建立方式,这里就以3个参数的computeIf说明

各个点这里就用一张图来解释

如果存在if-body,就将原先if-body(ifEnd)到else-body(elseStart)的路径删除,增加if-body(ifEnd)到end的路径,再增加ifStart到else-body(elseStart)的路径
如果if-body不存在(ifEnd不为StatementExpression),这时ifStart到elseStart的路径存在,只需增加ifStart到end的路径即可
如果else-body不存在(elseStart不为StatementExpression),ifEnd到end的路径存在,只需增加ifStart到end的路径即可
以第一种为例,计算结束后,路径应该为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | +---------+ifStart
| +
| |
| |
| |
| |
| v
| ifEnd+--------------+
| |
| |
+---> elseStart & elseEnd |
+ |
| |
| |
v |
end <--------------+ |