1

фона - Вопрос нижеРеализация Metric Люкс с помощью ASTParser в Java

Я в начале реализации метрический набор в Java для Java, однако я обеспокоен тем, что мой подход не подходит.

В настоящее время я использую JDT ASTParser для каждого файла в каталоге. Это началось хорошо, и мне удалось собрать вещи вокруг подсчета строк и средних строк для каждого метода для каждого класса. Это было сделано с помощью класса MethodVisitor, который расширяет ASTVisitor и содержит посещение метода (узел MethodDeclaration).

Теперь я пытаюсь вычислить Cyclomatic Complexity для каждого метода. Я разделил тело метода и имел ComplexityVisitor, который содержит посещение (узел IfStatement) и посещение (узел ReturnStatement).

Использование этой структуры Я знаю, что в коде есть инструкция if, но я не уверен, как узнать, сколько уровней «if else» есть. Единственный метод, который может найти полезен, это node.getElseStatement(), но это возвращает то, что в основном (или мне кажется) является строкой, и поэтому придется использовать регулярное выражение, чтобы узнать количество путей, которые может принять оператор.

Так что мой вопрос:

Есть ли способ вывести сколько уровней в «если - то еще, если - еще» заявление при использовании затмений ASTParser?

или

Должен ли я искать более чистое решение, как IJavaElement или разбора кода сам ввод ключевых слов на список, то цикл обратно через них.

Некоторые образцы кода - очень много в стадии тестирования

public class Test { 

    private static List<ClassInfo> klasses = new ArrayList<ClassInfo>(); 

    // Called for every file where str is what the file contains 
    public static void parse(String str) { 
     ASTParser parser = ASTParser.newParser(AST.JLS3); 
     parser.setSource(str.toCharArray()); 
     parser.setKind(ASTParser.K_COMPILATION_UNIT); 

     final CompilationUnit cu = (CompilationUnit) parser.createAST(null);  

     ClassVisitor cv = new ClassVisitor(); 
     cu.accept(cv); 

     MethodVisitor methodsVisitor = new MethodVisitor(cu); 
     cu.accept(methodsVisitor); 


     ClassInfo klass = new ClassInfo(cv.getClassName(), 
       cu.getLineNumber(cu.getLength() - 1), 
       methodsVisitor.getNumberOfMethods(), 
       methodsVisitor.getAverageLinesPerMethod(), 
       methodsVisitor.getMethods()); 

     for(int i = 0; i < klass.methods.size(); i++){ 
      parser.setSource(klass.methods.get(i).body.toCharArray()); 
      CyclomaticComplexityVisitor ccv = new CyclomaticComplexityVisitor(); 

      cu.accept(ccv); 
     } 
     klasses.add(klass); 
    } 

-

public class MethodVisitor extends ASTVisitor { 

    private CompilationUnit cu; 
    private int numberOfMethods; 
    private int lineCount; 

    private List<MethodInfo> methods = new ArrayList<MethodInfo>(); 


    public MethodVisitor(CompilationUnit cu){ 
     this.cu = cu; 
    } 

    public boolean visit(MethodDeclaration node){ 
     int startPos = cu.getLineNumber(node.getStartPosition()); 
     int endPos = cu.getLineNumber(node.getStartPosition() + node.getLength()); 

     lineCount += (endPos - startPos); 
     numberOfMethods++; 

     String methodBody = node.getBody().toString(); 
     MethodInfo m = new MethodInfo(node.getName().getIdentifier(), 
            (endPos - startPos), 
            node.getReturnType2()); 
     m.body = methodBody; 
     methods.add(m); 

     return true; 
    } 

-

public class CyclomaticComplexityVisitor extends ASTVisitor { 

    private int complexityScore = 0; 
    private int edges = 0; 
    private int nodes = 0; 
    private int exitPoints = 1; 
    private boolean firstReturn = true; 

    public boolean visit(IfStatement node){ 
     System.out.println("THERE WAS AN IF"); 
     String statement = node.toString(); 
     System.out.println(statement); 

     return true; 
    } 

    public boolean visit(ReturnStatement node){ 
     if (firstReturn) { 
      firstReturn = false; 
     } else { 
      exitPoints++; 
     } 
     return true; 
    } 

Приветствия

+0

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

+0

@QPaysTaxes: А? Он хочет знать, как подсчитать глубину вложенности IF-заявлений с использованием JDT. Это точно проблема программирования, а не «мнение». (Я не эксперт JDT, поэтому я не знаю ответа, но это должно быть очень просто сделать, используя API, которые он предлагает.) –

+0

@IraBaxter Я довольно уверен, что OP отредактировал вопрос после того, как я написал, что , Обратите внимание на 20-часовую разницу во времени. Конечно, я все равно ошибаюсь; поэтому я сказал «немного». –

ответ

2

Я не уверен, ответит ли это на ваш вопрос, но для вычисления метрики McCabe Cyclomatic Complexity (McCC) вам не нужно заботиться о уровнях if-else-if. Вам просто нужно подсчитать количество «ветвящихся» инструкций и добавить 1 в конец. См определение в User's Guide нашего SourceMeter инструмента:

Маккейба цикломатическая сложность (MCCC) Метод: сложность метода выражается как число независимых путей потока управления в нем. Он представляет собой нижнюю границу для количества возможных путей выполнения в исходном коде и в то же время это верхняя граница для минимального количества тестовых примеров, необходимых для достижения полного охвата тестирования ветвлений. Значение метрики рассчитывается как число следующих инструкций плюс 1: if, for, foreach, while, do-while, метка case (которая принадлежит команде switch), catch, условное выражение (? :). Кроме того, логический «и» (& &), а логические выражения «или» (||) также добавляют 1 к значению, потому что их оценка короткого замыкания может привести к ветвлению в зависимости от первого операнда.Следующие инструкции не включены: else, switch, default label (который принадлежит команде switch), попробуйте, наконец.

+0

Спасибо за ответ. Если это так, это очень упрощает реализацию для меня, но я пытался следовать уравнению cc = Edges - nodes + exitpoints На самом деле это не нужно? –

+0

@SeanArmstrong: Если у вас есть структурированный язык (например, Java), в котором элемент управления может вводить только блоки извне и оставить блоки, возвращающиеся к вызывающему блоку, работает «упрощенная» схема подсчета Рудольфа. Существует теорема о том, что «подсчет ветвей + 1» эквивалентен «полному определению» МакКейба E-N + X. Если вы должны обработать C или BASIC-код, в котором goto's более распространены, вам понадобится полное определение МакКейба, или вам нужно будет решить, что «более простая» версия достаточно хороша, что и происходит. McCabe - это всего лишь приблизительная оценка реальной сложности. –

+0

@IraBaxter - Спасибо за объяснение. Этот ответ решил мои проблемы с вычислением Cyclomatic Complexity. Проблема с установкой вложенности if может по-прежнему возникать для других аналогичных показателей, но я счастлив пока –