0

I'm attempting to retrieve all parameter names in all methods found in a given source file using CheckStyle. Here is the relevant code:


public int[] getDefaultTokens()
{
   return new int[] { TokenTypes.METHOD_DEF};
}


public void visitToken(DetailAST aDetailAST)
{
String returnType;        // The return type of the method.
int numberOfParameters;   // The number of parameters in the method's parameter list... not    returned in log.
String [] parameterNames; // The names of all method parameters.
int openingBraceLine;     // The line number of the opening method bracket.

  returnType = aDetailAST.findFirstToken(TokenTypes.TYPE).getFirstChild().getText(); // get the return type.

  numberOfParameters = aDetailAST.findFirstToken(TokenTypes.PARAMETERS).getChildCount(TokenTypes.PARAMETER_DEF); // get num of parameters.
  parameterNames = new String[numberOfParameters]; // create array to store the parameter names.
  if (numberOfParameters > 0) // only bother if parameters existed.
  {
     List <DetailAST> parameters = DetailASTUtil.getDetailASTsForTypeInBranch                       // Get all PARAMETER_DEF nodes.
                                             (aDetailAST.findFirstToken(TokenTypes.PARAMETERS)
                                                                  , TokenTypes.PARAMETER_DEF);

     int i = 0;

     for (DetailAST currentParameter: parameters) // iterate through all parameters.
     {
        parameterNames[i] = currentParameter.findFirstToken(TokenTypes.IDENT).getText();
        // Get the parameter name, store it in the array.
        i++; // iterate to next parameter name array storage index.
     }
  }

  // parameterNames now contains all parameter names in the parameter list. Format it for log message.

  String formattedParameterNames = "";


  if (numberOfParameters > 1) // if more than one parameter was present, then create comma list.
  {
     for (int i = 0; i < parameterNames.length-1; i++) // put all names in comma-separated string except for last.
     {
        formattedParameterNames += parameterNames[i] + ", ";
     }

     formattedParameterNames += parameterNames[numberOfParameters-1]; // add the last element of the comma list.
  }
  else if (numberOfParameters == 1) // only one parameter -- don't comma-delimit.
  {
     formattedParameterNames = parameterNames[0];
  }

  if (numberOfParameters == 2) // debug to see if string formatting is messing up the parameter names or if tree traversal is bad.
  {
     formattedParameterNames = "Param 1: " + parameterNames[0] + " Param 2: " + parameterNames[1];
  }

  log(aDetailAST.getLineNo(), "[" + returnType + "]" + ", [" + formattedParameterNames + "], ");
  // will be further parsed in actual applet since I don't think there's a way to get individual lines of code via CheckStyle... I would like if a getTextForLineofCode(lineNumber) func existed with CheckStyle, but I don't think it does.
}

public static List<DetailAST> getDetailASTsForTypeInBranch(DetailAST expr,
        int tokenType) {
    return getDetailASTsForTypeInBranch(expr, tokenType, null);
}

private static List<DetailAST> getDetailASTsForTypeInBranch(DetailAST expr,
        int tokenType, List<DetailAST> list) {
    if (list == null)
        list = new ArrayList<DetailAST>();
    DetailAST child = (DetailAST) expr.getFirstChild();
    while (child != null) {
        if (child.getType() == tokenType) {
            list.add(child);
        } else {
            list = getDetailASTsForTypeInBranch(child, tokenType, list);
        }
        child = (DetailAST) child.getNextSibling();
    }
    return list;
}

When I retrieve this log message back in my main applet, functions with no/single parameter lists appear just fine, but the double parameter functions either don't get registered at all or return the message "secondParmeterNameHere]" where secondParameterNameHere was the specific function's second parameter name.

Any ideas on what is wrong with my algorithm for getting all of the parameter names? Thanks.

2 Answers2

0

My two cents to optimise your code.

Use a for-loop

In your recursive helper method you can replace

    DetailAST child = (DetailAST) expr.getFirstChild();
while (child != null) {
    if (child.getType() == tokenType) {
        list.add(child);
    } else {
        list = getDetailASTsForTypeInBranch(child, tokenType, list);
    }
    child = (DetailAST) child.getNextSibling();
}

by

for(DetailAST child = (DetailAST) expr.getFirstChild(); child != null; child = (DetailAST) child.getNextSibling()) {
    if (child.getType() == tokenType) {
        list.add(child);
    } else {
        list = getDetailASTsForTypeInBranch(child, tokenType, list);
    }
}

Decide for one way to allocate "list"

This is some kind of "allocation duplication:

list = getDetailASTsForTypeInBranch(child, tokenType, list);

You're passing "list" by reference. And during the recursion you operate on this reference (list.add(..)). But still you return this list later on as a return value. And in the recursion you reassign this return value to your original input variable, although this has already been modified during the recursion?!

You should either work with return values and don't pass a list as input parameter. Or you can pass the list, but your method shouldn't have a return value then.

Reduce code to format parameter names

The variable parameterNames is obsolete, as you only use it to iterate it again and concatenate a String. Your string concatenation is also duplicated and inefficient. I would propose the following solution:

        StringBuilder formattedParameterNames = new StringBuilder();
    for (Iterator<DetailAST> iterator = parameters.iterator(); iterator.hasNext();) {
        DetailAST detailAST = iterator.next();
        formattedParameterNames.append(detailAST.findFirstToken(TokenTypes.IDENT).getText());
        if(iterator.hasNext()) {
            formattedParameterNames.append(", ");
        }
    }

You can call toString() on the StringBuilder to get your logging statement.

Peter Wippermann
  • 4,125
  • 5
  • 35
  • 48
0

Hope the below code snippet will help you

@Override
public int[] getDefaultTokens() {
    return new int[] { TokenTypes.METHOD_DEF};
}


@Override
public void visitToken(DetailAST ast) {
    String methodName = null;
    String returnType = null;
    int numberOfParameters = 0;

    methodName = ast.findFirstToken(TokenTypes.IDENT).getText();

    DetailAST typeElt = ast.findFirstToken(TokenTypes.TYPE);
    returnType = typeElt.getFirstChild().getText();

    DetailAST parametersElt = ast.findFirstToken(TokenTypes.PARAMETERS); 
    numberOfParameters = parametersElt.getChildCount(TokenTypes.PARAMETER_DEF);

    log(ast,"Method Name : "+methodName);
    log(ast,"Return Type : "+returnType);
    log(ast,"No Of Parameters : "+numberOfParameters);

    DetailAST paraElt = parametersElt.findFirstToken(TokenTypes.PARAMETER_DEF);

    int i=1;
    while(paraElt != null){
        if(paraElt.getType() == TokenTypes.PARAMETER_DEF){
            String dataType = paraElt.findFirstToken(TokenTypes.TYPE).getFirstChild().getText();
            String paraName = paraElt.findFirstToken(TokenTypes.IDENT).getText();
            log(ast,"Parameter "+i+" ("+dataType+" "+paraName+")");
            i++;    
        }
        paraElt = paraElt.getNextSibling();
    }
}

The output will be like

[ERROR] path\Test.java:8:9: Method Name : add [ListMethodParameters]
[ERROR] path\Test.java:8:9: No Of Parameters : 0 [ListMethodParameters]
[ERROR] path\Test.java:8:9: Return Type : void [ListMethodParameters]
[ERROR] path\Test.java:12:9: Method Name : sub [ListMethodParameters]
[ERROR] path\Test.java:12:9: No Of Parameters : 3 [ListMethodParameters]
[ERROR] path\Test.java:12:9: Parameter 1 (int a) [ListMethodParameters]
[ERROR] path\Test.java:12:9: Parameter 2 (int b) [ListMethodParameters]
[ERROR] path\Test.java:12:9: Parameter 3 (int c) [ListMethodParameters]
[ERROR] path\Test.java:12:9: Return Type : int [ListMethodParameters]

Java file is used to test the above code

public class Test {
    public void add(){
        name.length();
    }
    public int sub(int a,int b,int c){
        return a+b+c;
    }
}
Sathish
  • 1,481
  • 5
  • 20
  • 33