Skip to content

Commit c86d72c

Browse files
committed
Add further metrics
1 parent 010d27c commit c86d72c

9 files changed

Lines changed: 249 additions & 77 deletions

File tree

src/main/java/net/explorviz/code/analysis/handler/TextFileDataHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public void calculateMetrics(final String content) {
2727
return;
2828
}
2929

30-
final int loc = content.split("\r\n|\r|\n").length;
30+
final long loc = content.lines().count();
3131
addMetric("loc", String.valueOf(loc));
3232

3333
// Add file size in bytes

src/main/java/net/explorviz/code/analysis/listener/CommonFileDataListener.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
* Common methods for file data listeners.
77
*/
88
public interface CommonFileDataListener {
9+
String FILE_SIZE = "size";
10+
String SLOC = "sloc";
11+
String LOC = "loc";
12+
String CLOC = "cloc";
13+
String FUNCTION_COUNT = "functionCount";
14+
String VARIABLE_COUNT = "variableCount";
915

1016
default int calculateLoc(final ParserRuleContext ctx) {
1117
if (ctx == null || ctx.start == null || ctx.stop == null) {
@@ -24,6 +30,67 @@ default int getLoc(final ParserRuleContext ctx) {
2430
return ctx.stop.getLine();
2531
}
2632

33+
/**
34+
* Calculates the Source Lines of Code (SLOC) by counting unique lines that contain tokens on the
35+
* default channel (channel 0). This excludes comments and whitespace if the grammar follows
36+
* standard conventions.
37+
*
38+
* @param tokens The token stream
39+
* @return The number of lines containing code tokens
40+
*/
41+
default int getSloc(final org.antlr.v4.runtime.CommonTokenStream tokens) {
42+
if (tokens == null) {
43+
return 0;
44+
}
45+
final java.util.Set<Integer> codeLines = new java.util.HashSet<>();
46+
for (int i = 0; i < tokens.size(); i++) {
47+
final org.antlr.v4.runtime.Token token = tokens.get(i);
48+
if (token.getChannel() == 0) {
49+
final String text = token.getText();
50+
if (text != null && !text.trim().isEmpty()) {
51+
codeLines.add(token.getLine());
52+
}
53+
}
54+
}
55+
return codeLines.size();
56+
}
57+
58+
/**
59+
* Calculates the Source Lines of Code (SLOC) for a specific context by counting unique lines that
60+
* contain tokens on the default channel (channel 0) within the range of the context.
61+
*
62+
* @param ctx The parser rule context
63+
* @param tokens The token stream
64+
* @return The number of lines containing code tokens within the context's range
65+
*/
66+
default int getSloc(final ParserRuleContext ctx, final org.antlr.v4.runtime.CommonTokenStream tokens) {
67+
if (ctx == null || ctx.start == null || ctx.stop == null || tokens == null) {
68+
return 0;
69+
}
70+
final int startLine = ctx.start.getLine();
71+
final int endLine = ctx.stop.getLine();
72+
final java.util.Set<Integer> codeLines = new java.util.HashSet<>();
73+
74+
// Find tokens within the line range of the context
75+
// We can optimize this by starting from ctx.start.getTokenIndex() to ctx.stop.getTokenIndex()
76+
for (int i = ctx.start.getTokenIndex(); i <= ctx.stop.getTokenIndex(); i++) {
77+
if (i < 0 || i >= tokens.size()) {
78+
continue;
79+
}
80+
final org.antlr.v4.runtime.Token token = tokens.get(i);
81+
if (token.getChannel() == 0) {
82+
final String text = token.getText();
83+
if (text != null && !text.trim().isEmpty()) {
84+
final int line = token.getLine();
85+
if (line >= startLine && line <= endLine) {
86+
codeLines.add(line);
87+
}
88+
}
89+
}
90+
}
91+
return codeLines.size();
92+
}
93+
2794
default String getClassPathFromFqn(final String fqn, final String fileExtension,
2895
final String currentFilePath, final String currentPackage) {
2996
if (fqn == null || fqn.isEmpty()) {

src/main/java/net/explorviz/code/analysis/listener/CppFileDataListener.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@
1717
*/
1818
public class CppFileDataListener extends CPP14ParserBaseListener implements CommonFileDataListener {
1919

20-
public static final String LOC = "loc";
21-
public static final String CLOC = "cloc";
22-
2320
private static final Logger LOGGER = LoggerFactory.getLogger(CppFileDataListener.class);
2421

2522
private final CppFileDataHandler fileDataHandler;
2623
private final CommonTokenStream tokens;
24+
private int functionCount = 0;
25+
private int variableCount = 0;
2726

2827
public CppFileDataListener(final CppFileDataHandler fileDataHandler,
2928
final CommonTokenStream tokens) {
@@ -33,20 +32,26 @@ public CppFileDataListener(final CppFileDataHandler fileDataHandler,
3332

3433
@Override
3534
public void enterTranslationUnit(final CPP14Parser.TranslationUnitContext ctx) {
36-
// Calculate LOC and CLOC for the entire file
37-
final int loc = getLoc(ctx);
35+
// Calculate total source SLOC and CLOC for the entire file
36+
final int sloc = getSloc(tokens);
3837
final int cloc = getCloc(ctx);
3938

40-
fileDataHandler.addMetric(LOC, String.valueOf(loc));
39+
fileDataHandler.addMetric(SLOC, String.valueOf(sloc));
4140
fileDataHandler.addMetric(CLOC, String.valueOf(cloc));
4241

4342
// Extract #include directives
4443
extractIncludes();
4544

4645
LOGGER.atTrace()
4746
.addArgument(fileDataHandler.getFileName())
48-
.addArgument(loc)
49-
.log("{} - LOC: {}");
47+
.addArgument(sloc)
48+
.log("{} - SLOC: {}");
49+
}
50+
51+
@Override
52+
public void exitTranslationUnit(final CPP14Parser.TranslationUnitContext ctx) {
53+
fileDataHandler.addMetric(FUNCTION_COUNT, String.valueOf(functionCount));
54+
fileDataHandler.addMetric(VARIABLE_COUNT, String.valueOf(variableCount));
5055
}
5156

5257
/**
@@ -162,8 +167,9 @@ public void enterClassSpecifier(final CPP14Parser.ClassSpecifierContext ctx) {
162167
classData.setIsClass();
163168
}
164169

165-
// Calculate class LOC
170+
// Calculate class SLOC and LOC
166171
final int classLoc = calculateLoc(ctx);
172+
classData.addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
167173
classData.addMetric(LOC, String.valueOf(classLoc));
168174

169175
// Handle base classes
@@ -205,6 +211,7 @@ public void enterEnumSpecifier(final CPP14Parser.EnumSpecifierContext ctx) {
205211
final var classData = fileDataHandler.getCurrentClassData();
206212
if (classData != null) {
207213
classData.setIsEnum();
214+
classData.addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
208215
classData.addMetric(LOC, String.valueOf(calculateLoc(ctx)));
209216
}
210217

@@ -241,6 +248,8 @@ public void enterFunctionDefinition(final CPP14Parser.FunctionDefinitionContext
241248
return;
242249
}
243250

251+
functionCount++;
252+
244253
final String functionName = extractFunctionName(ctx.declarator());
245254
if (functionName == null) {
246255
return;
@@ -293,6 +302,7 @@ public void enterFunctionDefinition(final CPP14Parser.FunctionDefinitionContext
293302
methodData.setLines(ctx.start.getLine(), ctx.stop.getLine());
294303
}
295304

305+
methodData.addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
296306
methodData.addMetric(LOC, String.valueOf(functionLoc));
297307

298308
LOGGER.atTrace()
@@ -312,6 +322,7 @@ public void enterFunctionDefinition(final CPP14Parser.FunctionDefinitionContext
312322
if (ctx.start != null && ctx.stop != null) {
313323
methodHandler.setLines(ctx.start.getLine(), ctx.stop.getLine());
314324
}
325+
methodHandler.addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
315326
methodHandler.addMetric(LOC, String.valueOf(functionLoc));
316327

317328
addFunctionParameters(methodHandler, ctx.declarator());
@@ -325,6 +336,7 @@ public void enterFunctionDefinition(final CPP14Parser.FunctionDefinitionContext
325336
if (ctx.start != null && ctx.stop != null) {
326337
methodHandler.setLines(ctx.start.getLine(), ctx.stop.getLine());
327338
}
339+
methodHandler.addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
328340
methodHandler.addMetric(LOC, String.valueOf(functionLoc));
329341

330342
addFunctionParameters(methodHandler, ctx.declarator());
@@ -822,6 +834,13 @@ private boolean hasArrayBracketsInNoPointer(
822834
/**
823835
* Get comment lines of code by counting tokens on the hidden channel.
824836
*/
837+
@Override
838+
public void enterSimpleDeclaration(final CPP14Parser.SimpleDeclarationContext ctx) {
839+
if (ctx.initDeclaratorList() != null) {
840+
variableCount += ctx.initDeclaratorList().initDeclarator().size();
841+
}
842+
}
843+
825844
private int getCloc(final ParserRuleContext ctx) {
826845
if (ctx == null || tokens == null) {
827846
return 0;

src/main/java/net/explorviz/code/analysis/listener/JavaFileDataListener.java

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@
1818
*/
1919
public class JavaFileDataListener extends Java20ParserBaseListener implements CommonFileDataListener {
2020

21-
public static final String FILE_SIZE = "size";
22-
public static final String LOC = "loc";
23-
public static final String CLOC = "cloc";
24-
2521
private static final Logger LOGGER = LoggerFactory.getLogger(JavaFileDataListener.class);
2622

2723
private final JavaFileDataHandler fileDataHandler;
@@ -30,6 +26,8 @@ public class JavaFileDataListener extends Java20ParserBaseListener implements Co
3026
private String wildcardImport;
3127
private String currentPackage = "";
3228
private final org.antlr.v4.runtime.CommonTokenStream tokens;
29+
private int functionCount = 0;
30+
private int variableCount = 0;
3331

3432
public JavaFileDataListener(final JavaFileDataHandler fileDataHandler,
3533
final boolean wildcardImportProperty,
@@ -43,17 +41,23 @@ public JavaFileDataListener(final JavaFileDataHandler fileDataHandler,
4341

4442
@Override
4543
public void enterCompilationUnit(final Java20Parser.CompilationUnitContext ctx) {
46-
// Calculate LOC and CLOC
47-
final int loc = getLoc(ctx);
44+
// Calculate total source SLOC and CLOC
45+
final int sloc = getSloc(tokens);
4846
final int cloc = getCloc(ctx);
4947

50-
fileDataHandler.addMetric(LOC, String.valueOf(loc));
48+
fileDataHandler.addMetric(SLOC, String.valueOf(sloc));
5149
fileDataHandler.addMetric(CLOC, String.valueOf(cloc));
5250

5351
LOGGER.atTrace()
5452
.addArgument(fileDataHandler.getFileName())
55-
.addArgument(loc)
56-
.log("{} - LOC: {}");
53+
.addArgument(sloc)
54+
.log("{} - SLOC: {}");
55+
}
56+
57+
@Override
58+
public void exitCompilationUnit(final Java20Parser.CompilationUnitContext ctx) {
59+
fileDataHandler.addMetric(FUNCTION_COUNT, String.valueOf(functionCount));
60+
fileDataHandler.addMetric(VARIABLE_COUNT, String.valueOf(variableCount));
5761
}
5862

5963
@Override
@@ -111,7 +115,8 @@ public void enterNormalClassDeclaration(final Java20Parser.NormalClassDeclaratio
111115
// Add modifiers
112116
addModifiers(ctx.classModifier());
113117

114-
// Add LOC
118+
// Add SLOC and LOC
119+
fileDataHandler.getCurrentClassData().addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
115120
fileDataHandler.getCurrentClassData().addMetric(LOC, String.valueOf(getLoc(ctx)));
116121

117122
// Handle extends
@@ -149,7 +154,8 @@ public void enterNormalInterfaceDeclaration(
149154
// Add modifiers
150155
addModifiers(ctx.interfaceModifier());
151156

152-
// Add LOC
157+
// Add SLOC and LOC
158+
fileDataHandler.getCurrentClassData().addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
153159
fileDataHandler.getCurrentClassData().addMetric(LOC, String.valueOf(getLoc(ctx)));
154160

155161
// Handle extends
@@ -179,7 +185,8 @@ public void enterEnumDeclaration(final Java20Parser.EnumDeclarationContext ctx)
179185
// Add modifiers
180186
addModifiers(ctx.classModifier());
181187

182-
// Add LOC
188+
// Add SLOC and LOC
189+
fileDataHandler.getCurrentClassData().addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
183190
fileDataHandler.getCurrentClassData().addMetric(LOC, String.valueOf(getLoc(ctx)));
184191
}
185192

@@ -207,6 +214,7 @@ public void enterFieldDeclaration(final Java20Parser.FieldDeclarationContext ctx
207214
fileDataHandler.enterMethod(fieldFqn);
208215
fileDataHandler.getCurrentClassData().addField(fieldName, fieldType, modifiers);
209216
fileDataHandler.leaveMethod();
217+
variableCount++;
210218
}
211219
}
212220
}
@@ -231,6 +239,7 @@ public void enterMethodDeclaration(final Java20Parser.MethodDeclarationContext c
231239
+ "#" + parameterHash;
232240

233241
fileDataHandler.enterMethod(methodFqn);
242+
functionCount++;
234243

235244
// Get return type
236245
String returnType = "void";
@@ -256,7 +265,8 @@ public void enterMethodDeclaration(final Java20Parser.MethodDeclarationContext c
256265
methodData.setLines(ctx.start.getLine(), ctx.stop.getLine());
257266
}
258267

259-
// Add LOC
268+
// Add SLOC and LOC
269+
methodData.addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
260270
methodData.addMetric(LOC, String.valueOf(getLoc(ctx)));
261271
}
262272

@@ -286,6 +296,7 @@ public void enterInterfaceMethodDeclaration(
286296
+ "#" + parameterHash;
287297

288298
fileDataHandler.enterMethod(methodFqn);
299+
functionCount++;
289300

290301
// Get return type
291302
String returnType = "void";
@@ -311,7 +322,8 @@ public void enterInterfaceMethodDeclaration(
311322
methodData.setLines(ctx.start.getLine(), ctx.stop.getLine());
312323
}
313324

314-
// Add LOC
325+
// Add SLOC and LOC
326+
methodData.addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
315327
methodData.addMetric(LOC, String.valueOf(getLoc(ctx)));
316328
}
317329

@@ -336,6 +348,7 @@ public void enterConstructorDeclaration(final Java20Parser.ConstructorDeclaratio
336348
+ "#" + parameterHash;
337349

338350
fileDataHandler.enterMethod(constructorFqn);
351+
functionCount++;
339352

340353
final MethodDataHandler constructor = fileDataHandler.getCurrentClassData()
341354
.addConstructor(constructorName, constructorFqn);
@@ -353,7 +366,8 @@ public void enterConstructorDeclaration(final Java20Parser.ConstructorDeclaratio
353366
constructor.setLines(ctx.start.getLine(), ctx.stop.getLine());
354367
}
355368

356-
// Add LOC
369+
// Add SLOC and LOC
370+
constructor.addMetric(SLOC, String.valueOf(getSloc(ctx, tokens)));
357371
constructor.addMetric(LOC, String.valueOf(getLoc(ctx)));
358372
}
359373

@@ -635,6 +649,13 @@ private String resolveTypeName(final String typeName) {
635649
return typeName;
636650
}
637651

652+
@Override
653+
public void enterLocalVariableDeclaration(final Java20Parser.LocalVariableDeclarationContext ctx) {
654+
if (ctx.variableDeclaratorList() != null) {
655+
variableCount += ctx.variableDeclaratorList().variableDeclarator().size();
656+
}
657+
}
658+
638659
private boolean isPrimitiveType(final String type) {
639660
return Arrays.asList("byte", "short", "int", "long", "float", "double",
640661
"boolean", "char", "void").contains(type);

0 commit comments

Comments
 (0)