-1

这个问题是 Java 和 Maven 特定的。请注意下面的附加限制,因为它们与其他问题不同。

我有几个 Maven (Java) 项目要分析。我所拥有的是:

  • 源代码
  • maven 编译的 Jave 代码,包含 target/ 文件夹中的二进制文件

问题是:给定一个源代码文件 (.java) 和那里的行号,我怎样才能获得跨越该行的方法的完全限定名称?如果该行不在方法中,则仅输出 null。实现这一点的可接受语言是:Java、ruby 或 python。

您能否以以下两种方式之一回答问题?

  1. 使用二进制文件并提取该行的限定方法名称。(这可能涉及调试信息的编织,但这很好。)

  2. 直接使用给定的源文件,尝试解析它并使用 AST。

使用特定的库(如 BCEL)或任何第 3 方库(只要它们有据可查且可用)也是可以的。

非常感谢您的大力帮助!

4

2 回答 2

1

不幸的是,您的问题充满了缺点:

  • 当然,您可以解析输入源(通过 Javacc 或 ANTLR 解析器),直到到达所需的行。.class但是,由于您已经拥有文件,因此解析相同的源似乎是浪费精力。
  • .class因此,分析文件似乎更好。但不幸的是,你不能保证这是你的行产生的类,因为在同一个源文件中可以定义多个类。

啊!这让我想到了一种复杂的解决方案:

我将声明一个包含所有登录名的类:

public class SourceMethodsIndexer
{
    private final SortedMap<Integer, List<Method>> indexOfMethodsByFirstLineNumber;
}

构造函数将是这样的:

public SourceMethodsIndexer(File sourceFile)

...并且应该执行以下任务:

1.浏览目标包相关的类目录。

File targetPackageDir=getTargetPackageDir(sourceFile);
File[] classFiles=targetPackageDir.listFiles(new FileFilter(){
    public boolean accept(File dir, String name){
        return name.endsWith(".class");
}

});

2.使用Apache BCEL收集属于你的输入源文件的所有非公共类(你可以调用JavaClass.getSourceFileName()过滤类),加上你的输入源文件名对应的公共类。

Collection<JavaClass> targetClasses=getNonPublicClasses(classFiles, sourceFile.getName());
targetClasses.add(publicClass);

3.然后收集每个类中的所有方法。

Set<Method> targetMethods=new HashSet<Method>(1024);
for (JavaClass javaClass:targetClasses)
{
    targetMethods.addAll(Arrays.asList(javaClass.getMethods()));
}

4.现在您可以直接搜索您的行号,也可以先按行号索引方法以便稍后更快地访问它们:(JavaClass.getMethods()[n].getLineNumberTable().getSourceLine(0)注意可能存在重复值)。

this.indexOfMethodsByFirstLineNumber=new TreeMap<Integer, List<Method>>((int)(1.7d*methods.size()));
for (Method method: methods)
{
    // Note: The -1 in this line stands to make the SortedMap work properly when searching for ranges.
    int firstLine=getLineNumberTable().getSourceLine(0)-1;
    List<Method> methodsInTheSameLine=indexOfMethodsByFirstLineNumber.get(firstLine);
    if (methodsInTheSameLine==null)
    {
        methodsInTheSameLine=new ArrayList<Method>();
        indexOfMethodsByFirstLineNumber.put(firstLine,methodsInTheSameLine);
    }
    methodsInTheSameLine.add(method);
}

5.Public一个方法来做搜索:

public Method getMethodByLine(int lineNumber)
{
    Set<Method> methodsInTheSameLine=this.indexOfMethodsByFirstLineNumber.headMap(lineNumber).lastKey();
    if (methodsInTheSameLine.size()==0)
    {
        // There are no methods method in that line: Absurd.
    }
    else if (methodsInTheSameLine.size()>1)
    {
        // There are more than one method in that line. Hardly probable, but possible.
    }
    else
    {
        // There is one method in that line:
        return methods.get(0);
    }
}
于 2015-12-22T00:57:14.870 回答
0

有许多开源 Maven 插件可以分析源代码,并基于每个方法进行报告。仔细研究其中一些可能是你最好的选择。

示例包括 Checkstyle、FindBugs、PMD、JDepend、JavaNCSS。

还可以看看 SonarQube。

于 2015-12-20T23:59:28.503 回答