-1

Этот вопрос задан Java и Maven. Обратите внимание на дополнительные ограничения ниже, поскольку они отличаются от других вопросов.Получение квалифицированного имени метода по номеру строки

У меня есть несколько проектов Maven (Java) для анализа. Что у меня есть:

  • исходного код
  • Maven-скомпилированный Jave код с двоичными целями/папками

Вопрос заключается в том: Учитывая один файл исходного кода (.java) и номер строки там, как я могу получить полное имя метода, который охватывает эту строку? Если строка не находится в методе, то просто выведите нуль. Допустимыми языками для реализации этого являются: Java, ruby ​​или python.

Не могли бы вы ответить на вопрос одним из двух способов?

  1. использовать бинарный файл и извлечь квалифицированное имя метода этой линии. (Это может быть связано с переплетением информации об отладке, но это нормально.)

  2. напрямую использовать исходный файл, попробуйте его проанализировать и использовать AST.

Использование определенных библиотек (например, BCEL) или любых сторонних (при условии, что они хорошо документированы и пригодны для использования) также в порядке.

Большое спасибо за огромную помощь!

+0

Поскольку исходный код не гарантируется компилируется, это может быть невозможно, к тому же номер строки не может быть в методе вообще. – Andreas

+0

Хммм, хорошо да, позвольте мне сделать его компилируемым точно. – Bruce

ответ

1

К сожалению, Ваш вопрос полон недостатков:

  • Можно, Корсика, разобрать источник входного сигнала (через JavaCC или ANTLR синтаксический анализатор), пока не достигнете желаемой линии. Но кажется, что тратить усилия на разбор одного и того же источника, поскольку у вас уже есть файлы .class.
  • Итак, лучше проанализировать файл .class. Но, к сожалению, у вас нет гарантий, что это класс, в котором ваша линия появляется, потому что может быть более одного класса, определенного в том же исходном файле.

Augh!Это подводит меня к виду сложного решения:

я объявить класс, который будет содержать всю логин:

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.Use 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.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); 
    } 
} 
+0

Большое спасибо, мало. Этот ответ очень близок к тому, что мне нужно. Не могли бы вы немного разобраться в своем ответе? Я вижу, что у вас есть около 4 шагов, но только для последнего, каков способ прямого поиска номера строки? Вы можете предположить, что информация об отладке находится в байтовом коде. – Bruce

+0

Corse: Я обновил свой ответ с подробной информацией о моем предложении. Методы, которые я только что назвал и не реализовали, я считаю их достаточно простыми. –

+0

Я думаю, что это достаточно хорошо, как ответ от угла проверки на генерируемый байт код. Я закончил тем, что разбирал АСТ и получил его полное имя. Как и было обещано, позвольте мне принять этот ответ, чтобы вознаградить вашу помощь. Спасибо, мало. – Bruce

0

Существует множество плагинов Maven с открытым исходным кодом, которые анализируют исходный код и сообщают о каждом методе. Тщательное изучение некоторых из них может быть вашим лучшим выбором.

Примеры включают Checkstyle, FindBugs, PMD, JDepend, JavaNCSS.

Также посмотрите на SonarQube.

+1

Спасибо за ваши предложения, Стюарт. – Bruce

Смежные вопросы