I am trying to write a basic static code analysis tool for code written in beanshell that would perform some basic checks like unused variables, methods and possibly conditions that would never evaluate to true.
I have tried using the parser that comes with the beanshell source distribution in the way shown in a few examples like following:
import java.io.FileInputStream;
import java.io.IOException;
import bsh.ParseException;
import bsh.Parser;
import bsh.SimpleNode;
public class FindUnusedVariablesTask {
String sourseFilePath;
public FindUnusedVariablesTask(String sourseFilePath) {
this.sourseFilePath = sourseFilePath;
}
public String perform() throws ParseException, IOException {
FileInputStream sourceStream = new FileInputStream(sourseFilePath);
Parser p = new Parser(sourceStream);
while (!p.Line()) {
SimpleNode node = p.popNode();
System.out.println(node.getText());
for (int i=0; i<node.jjtGetNumChildren(); i++)
System.out.println(node.getChild(i).getText());
}
sourceStream.close();
return "";
}
}
For the following beanshell code:
f1 () {
return 1;
}
String f2(String x) {
return x + f1() + " OK";
}
The output is as follows:
f1 ( ) {
( )
{
String f2 ( String x ) {
String
( String x )
{
Basically I'm only getting the parsed method declarations. I cannot find a way access the parsed statements within. How can that be done?
The BeanShell parser produces an AST. Generally speaking, ASTs can be fairly deep in their structure. The code you give above only looks 1 layer deep into the AST.
Try a recursive traversal (I don't have the devkit, so consider this as pseudocode):
import bsh.Node; //you need this as well
public String perform() throws ParseException, IOException {
FileInputStream sourceStream = new FileInputStream(sourseFilePath);
Parser p = new Parser(sourceStream);
while (!p.Line()) {
recursive_print(p.popNode(), "");
}
sourceStream.close();
return "";
}
public void recursive_print(Node node, String prefix)
{
System.out.println(prefix + node.getText());
for (int i=0; i<node.jjtGetNumChildren(); i++)
recursive_print(node.getChild(i), prefix+" ");
}