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 <--------------+ |