Parent: [5b3342] (diff)

Download this file

WMC.rsc    113 lines (95 with data), 4.4 kB

module WMC

import lang::java::m3::AST;
import lang::java::m3::Core;
import IO;
import Node;
import List;
import String;
import Map;
import ValueIO;

import analysis::statistics::Frequency;
import analysis::statistics::Inference;

import org::ossmeter::metricprovider::Manager;
import org::ossmeter::metricprovider::ProjectDelta;

@metric{WMC}
@doc{Compute your WMC}
@friendlyName{Weighted Method Count}
map[str class, num wmcCount] getWMC(ProjectDelta delta, map[str, loc] workingCopyFolders, map[str, loc] scratchFolders) {
  map[str class, num wmcCount] result = ();
  map[str, list[str]] changedItemsPerRepo = getChangedItemsPerRepository(delta);
  
  for (str repo <- changedItemsPerRepo) {
    list[str] changedItems = changedItemsPerRepo[repo];
    loc workingCopyFolder = workingCopyFolders[repo];
    loc scratchFolder = scratchFolders[repo];
    
    for (str changedItem <- changedItems) {
      if (exists(workingCopyFolder+changedItem)) {
        loc scratchFile = scratchFolder+changedItem;
        M3 itemM3 = readBinaryValueFile(#M3, scratchFile[extension = scratchFile.extension+".m3"]);
        if (!(unknownFileType(_) := itemM3)) {
          result += (replaceAll(replaceFirst(cl.path, "/", ""), "/", ".") : sum([getCC(m, itemM3.ast) | m <- itemM3.model@containment[cl], isMethod(m)]) | <cl, _> <- itemM3.model@containment, isClass(cl));
        }
      }
    }
  }
  
  return result;
}

map[str class, num wmcCount] getWMC(unknownFileType(int lines)) = ("": -1);
map[str class, int cc] getCC(unknownFileType(int lines)) = ("" : -1);

@metric{CC}
@doc{Compute your McCabe}
@friendlyName{McCabe's Cyclomatic Complexity Metric}
map[str method, int cc] getCC(ProjectDelta delta, map[str, loc] workingCopyFolders, map[str, loc] scratchFolders) {
  map[str method, int cc] result = ();
  map[str, list[str]] changedItemsPerRepo = getChangedItemsPerRepository(delta);
  
  for (str repo <- changedItemsPerRepo) {
    list[str] changedItems = changedItemsPerRepo[repo];
    loc workingCopyFolder = workingCopyFolders[repo];
    loc scratchFolder = scratchFolders[repo];
    
    for (str changedItem <- changedItems) {
      if (exists(workingCopyFolder+changedItem)) {
        loc scratchFile = scratchFolder+changedItem;
        M3 itemM3 = readBinaryValueFile(#M3, scratchFile[extension = scratchFile.extension+".m3"]);
        if (!(unknownFileType(_) := itemM3)) {
          result += (replaceAll(replaceFirst(m.path, "/", ""), "/", ".") : getCC(m, itemM3.ast) | <cl, _> <- itemM3.model@containment, isClass(cl), m <- itemM3.model@containment[cl], isMethod(m));
        }
      }
    }
  }
  
  return result;
}

Declaration getASTOfMethod(loc methodLoc, Declaration fileAST) {
  visit(fileAST) {
    case Declaration d: {
      if ("decl" in getAnnotations(d) && d@decl == methodLoc) {
        return d;
      }
    }
  }
  throw "ast not found for method: <methodLoc>";
}

int getCC(loc m, Declaration ast) {
  int count = 1;
  Declaration methodAST = getASTOfMethod(m, ast);
  
  visit(methodAST) {
    case \foreach(Declaration parameter, Expression collection, Statement body): count += 1;
    case \for(list[Expression] initializers, Expression condition, list[Expression] updaters, Statement body): count += 1;
    case \if(Expression condition, Statement thenBranch, Statement elseBranch): count += 1;
    case \for(list[Expression] initializers, list[Expression] updaters, Statement body): count += 1;
    case \if(Expression condition, Statement thenBranch): count += 1;
    case \case(Expression expression): count += 1;
    case \while(Expression condition, Statement body): count += 1;
    case \do(Statement body, Expression condition): count += 1;
    case \catch(Declaration exception, Statement body): count += 1;
    case \infix(Expression lhs, "||", Expression rhs, list[Expression] extendedOperands): count += 1 + size(extendedOperands);
    case \infix(Expression lhs, "&&", Expression rhs, list[Expression] extendedOperands): count += 1 + size(extendedOperands);
  }
  return count;
}

@metric{ccovermethods}
@doc{Calculates the gini coefficient of cc over methods}
@friendlyName{ccovermethods}
real giniCCOverMethods(ProjectDelta delta, map[str, loc] workingCopyFolders, map[str, loc] scratchFolders) {
  map[str, int] ccMap = getCC(delta, workingCopyFolders, scratchFolders);
  
  distCCOverMethods = distribution(ccMap);
  
  return gini([<0,0>]+[<x, distCCOverMethods[x]> | x <- distCCOverMethods]);
}