0

CheckStyle を使用して、特定のソース ファイルで見つかったすべてのメソッドのすべてのパラメーター名を取得しようとしています。関連するコードは次のとおりです。


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;
}

メイン アプレットでこのログ メッセージを取得すると、パラメータ リストがない関数や単一のパラメータ リストを含む関数は正常に表示されますが、二重パラメータ関数はまったく登録されないか、"secondParmeterNameHere]" というメッセージが返されます。ここで、secondParameterNameHere は特定の関数の2 番目のパラメーター名。

すべてのパラメーター名を取得するためのアルゴリズムの何が問題なのかについてのアイデアはありますか? ありがとう。

4

2 に答える 2

0

あなたのコードを最適化するための私の 2 セント。

for ループを使用する

再帰ヘルパー メソッドでは、置き換えることができます

    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();
}

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);
    }
}

「リスト」を割り当てる方法を 1 つ決定する

これはある種の「割り当ての重複:

list = getDetailASTsForTypeInBranch(child, tokenType, list);

「リスト」を参照渡ししています。そして、再帰中にこの参照 (list.add(..)) を操作します。それでも、後でこのリストを戻り値として返します。そして、再帰では、この戻り値を元の入力変数に再割り当てしますが、これは再帰中に既に変更されていますか?!

戻り値を操作し、入力パラメーターとしてリストを渡さないでください。または、リストを渡すこともできますが、その場合、メソッドは戻り値を持つべきではありません。

コードを減らしてパラメーター名をフォーマットする

変数parameterNamesは廃止されました。これは、再度反復して文字列を連結するためにのみ使用するためです。文字列の連結も重複しており、非効率的です。次の解決策を提案します。

        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(", ");
        }
    }

StringBuilder で toString() を呼び出して、ログ ステートメントを取得できます。

于 2012-06-18T12:21:32.433 に答える
0

以下のコード スニペットがお役に立てば幸いです

@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();
    }
}

出力は次のようになります

[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 ファイルは、上記のコードをテストするために使用されます

public class Test {
    public void add(){
        name.length();
    }
    public int sub(int a,int b,int c){
        return a+b+c;
    }
}
于 2019-12-13T13:52:46.477 に答える