通过行号获取合格的方法名称
Getting qualified method name by the line number
这个问题是 Java 和 Maven 特定的。请注意下面的附加限制,因为它们与其他问题不同。
我有几个 Maven (Java) 项目要分析。我有的是:
- 源代码
- maven 编译的 Jave 代码和 target/ 文件夹中的二进制文件
问题是:
给定一个源代码文件 (.java) 和其中的行号,我如何获得跨越该行的方法 的 完全限定名称?如果该行不在方法中,则只输出 null。可接受的语言是:Java、ruby 或 python.
能否请您用以下两种方式之一回答问题?
使用二进制文件并提取该行的合格方法名称。 (这可能涉及编织调试信息,但这很好。)
直接使用给定的源文件,尝试解析并使用AST。
也可以使用特定的库(如 BCEL)或任何第 3 方库(只要它们有充分的文档记录和可用)。
非常感谢您的大力帮助!
有许多开源 Maven 插件可以分析源代码,并在每个方法的基础上进行报告。仔细研究其中一些可能是您最好的选择。
示例包括 Checkstyle、FindBugs、PMD、JDepend、JavaNCSS。
也看看 SonarQube。
不幸的是,你的问题充满了缺点:
- 当然,您可以解析输入源(通过 Javacc 或 ANTLR 解析器),直到到达所需的行。但是解析同一个源似乎是浪费精力,因为你已经有了
.class
个文件。
- 所以,分析
.class
文件似乎更好。但不幸的是,您无法保证这是您的行生成的 class,因为在同一个源文件中可以定义 多个 class .
哎呀!这让我想到了一种复杂的解决方案:
我将声明一个 class,其中将包含所有登录信息:
public class SourceMethodsIndexer
{
private final SortedMap<Integer, List<Method>> indexOfMethodsByFirstLineNumber;
}
构造函数将是这样的:
public SourceMethodsIndexer(File sourceFile)
...并且应该完成这些任务:
1.Browse目标包相关的class目录
File targetPackageDir=getTargetPackageDir(sourceFile);
File[] classFiles=targetPackageDir.listFiles(new FileFilter(){
public boolean accept(File dir, String name){
return name.endsWith(".class");
}
});
2.Use Apache BCEL 收集属于您的输入源文件的所有非 public classes(您可以调用 JavaClass.getSourceFileName()
来过滤 class es),加上你输入的源文件名对应的publicclass
Collection<JavaClass> targetClasses=getNonPublicClasses(classFiles, sourceFile.getName());
targetClasses.add(publicClass);
3.Collect 然后每个 class.
中的所有方法
Set<Method> targetMethods=new HashSet<Method>(1024);
for (JavaClass javaClass:targetClasses)
{
targetMethods.addAll(Arrays.asList(javaClass.getMethods()));
}
4.Now 你可以直接搜索你的行号,或者先按行号索引方法以便稍后更快地访问它们: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);
}
}
这个问题是 Java 和 Maven 特定的。请注意下面的附加限制,因为它们与其他问题不同。
我有几个 Maven (Java) 项目要分析。我有的是:
- 源代码
- maven 编译的 Jave 代码和 target/ 文件夹中的二进制文件
问题是: 给定一个源代码文件 (.java) 和其中的行号,我如何获得跨越该行的方法 的 完全限定名称?如果该行不在方法中,则只输出 null。可接受的语言是:Java、ruby 或 python.
能否请您用以下两种方式之一回答问题?
使用二进制文件并提取该行的合格方法名称。 (这可能涉及编织调试信息,但这很好。)
直接使用给定的源文件,尝试解析并使用AST。
也可以使用特定的库(如 BCEL)或任何第 3 方库(只要它们有充分的文档记录和可用)。
非常感谢您的大力帮助!
有许多开源 Maven 插件可以分析源代码,并在每个方法的基础上进行报告。仔细研究其中一些可能是您最好的选择。
示例包括 Checkstyle、FindBugs、PMD、JDepend、JavaNCSS。
也看看 SonarQube。
不幸的是,你的问题充满了缺点:
- 当然,您可以解析输入源(通过 Javacc 或 ANTLR 解析器),直到到达所需的行。但是解析同一个源似乎是浪费精力,因为你已经有了
.class
个文件。 - 所以,分析
.class
文件似乎更好。但不幸的是,您无法保证这是您的行生成的 class,因为在同一个源文件中可以定义 多个 class .
哎呀!这让我想到了一种复杂的解决方案:
我将声明一个 class,其中将包含所有登录信息:
public class SourceMethodsIndexer
{
private final SortedMap<Integer, List<Method>> indexOfMethodsByFirstLineNumber;
}
构造函数将是这样的:
public SourceMethodsIndexer(File sourceFile)
...并且应该完成这些任务:
1.Browse目标包相关的class目录
File targetPackageDir=getTargetPackageDir(sourceFile);
File[] classFiles=targetPackageDir.listFiles(new FileFilter(){
public boolean accept(File dir, String name){
return name.endsWith(".class");
}
});
2.Use Apache BCEL 收集属于您的输入源文件的所有非 public classes(您可以调用 JavaClass.getSourceFileName()
来过滤 class es),加上你输入的源文件名对应的publicclass
Collection<JavaClass> targetClasses=getNonPublicClasses(classFiles, sourceFile.getName());
targetClasses.add(publicClass);
3.Collect 然后每个 class.
中的所有方法Set<Method> targetMethods=new HashSet<Method>(1024);
for (JavaClass javaClass:targetClasses)
{
targetMethods.addAll(Arrays.asList(javaClass.getMethods()));
}
4.Now 你可以直接搜索你的行号,或者先按行号索引方法以便稍后更快地访问它们: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);
}
}