Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies {
implementation("org.ow2.asm:asm-tree:9.5")
implementation("org.ow2.asm:asm-analysis:9.5")
implementation("org.ow2.asm:asm-util:9.5")
implementation("com.fasterxml.jackson.core:jackson-databind:2.17.0")

testImplementation(platform("org.junit:junit-bom:5.10.0"))
testImplementation("org.junit.jupiter:junit-jupiter")
Expand Down
46 changes: 46 additions & 0 deletions output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[ {
"metricType" : "MAX_DEPTH_COUNT",
"items" : [ {
"description" : "Max depth",
"value" : "P1: 2"
} ]
}, {
"metricType" : "AVERAGE_DEPTH_COUNT",
"items" : [ {
"description" : "Average depth",
"value" : "1.5"
} ]
}, {
"metricType" : "AVERAGE_OVERRIDES_COUNT",
"items" : [ {
"description" : "getX",
"value" : "0"
}, {
"description" : "getY",
"value" : "0"
}, {
"description" : "box",
"value" : "0"
}, {
"description" : "<init>",
"value" : "0"
} ]
}, {
"metricType" : "AVERAGE_FIELDS_COUNT",
"items" : [ {
"description" : "Average fields amount",
"value" : "9.333333333333334"
} ]
}, {
"metricType" : "ABC_COUNT",
"items" : [ {
"description" : "Average assignments count",
"value" : "6.0"
}, {
"description" : "Average branches count",
"value" : "5.375"
}, {
"description" : "Average conditions count",
"value" : "7.0"
} ]
} ]
2 changes: 0 additions & 2 deletions src/main/java/org/example/Example.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
public class Example {

public static void main(String[] args) throws IOException {
// var printer = new ByteCodePrinter();
// printer.printBubbleSortBytecode();
try (JarFile sampleJar = new JarFile("src/main/resources/sample.jar")) {
Enumeration<JarEntry> enumeration = sampleJar.entries();

Expand Down
84 changes: 84 additions & 0 deletions src/main/java/org/example/LabMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.example;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.visitor.AbcVisitor;
import org.example.visitor.ClassMapVisitor;
import org.example.workers.*;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

public class LabMain {

private static final String PATH_TO_JAR = "src/main/resources/sample.jar";

public static void main(String[] args) throws IOException {
boolean toFile;
try {
toFile = Boolean.parseBoolean(args[0]);
} catch (Exception e) {
toFile = false;
}

ClassMapVisitor classMapVisitor = new ClassMapVisitor();
AbcVisitor abcVisitor = new AbcVisitor();

PrintStream ps = null;
try {
OutputStream os;
if (toFile) {
os = new FileOutputStream("output.txt");
} else {
os = System.out;
}

ps = new PrintStream(os);
} catch (IOException e) {
e.printStackTrace();
}

assert ps != null;
List<StatItemDto> resultStats = new ArrayList<>();

MaxDepthCounterWorker maxDepthCounterWorker = new MaxDepthCounterWorker();
StatItemDto maxDepthCounterWorkerStat = maxDepthCounterWorker.doTheJob(PATH_TO_JAR, classMapVisitor);
resultStats.add(maxDepthCounterWorkerStat);

AverageDepthCounterWorker averageDepthCounterWorker = new AverageDepthCounterWorker();
StatItemDto averageDepthCounterWorkerStat = averageDepthCounterWorker.doTheJob(PATH_TO_JAR, classMapVisitor);
resultStats.add(averageDepthCounterWorkerStat);

AverageOverridesCounterWorker averageOverridesCounterWorker = new AverageOverridesCounterWorker();
StatItemDto averageOverridesCounterWorkerStat = averageOverridesCounterWorker.doTheJob(PATH_TO_JAR, classMapVisitor);
resultStats.add(averageOverridesCounterWorkerStat);

AverageFieldsCountWorker averageFieldsCountWorker = new AverageFieldsCountWorker();
StatItemDto averageFieldsCountWorkerStat = averageFieldsCountWorker.doTheJob(PATH_TO_JAR, classMapVisitor);
resultStats.add(averageFieldsCountWorkerStat);

AbcWorker abcWorker = new AbcWorker();
StatItemDto abcWorkerStat = abcWorker.doTheJob(PATH_TO_JAR, abcVisitor);
resultStats.add(abcWorkerStat);

printAsJson(resultStats, ps);

if (toFile) {
ps.close();
}
}

private static void printAsJson(List<?> list, PrintStream out) {
try {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(list);
out.println(json);
} catch (Exception e) {
e.printStackTrace(out);
}
}
}
43 changes: 43 additions & 0 deletions src/main/java/org/example/StatItemDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.example;

import org.example.workers.MetricEnum;

import java.util.List;

public class StatItemDto {

public static class Item {

private final String description;
private final String value;

public Item(String description, String value) {
this.description = description;
this.value = value;
}

public String getDescription() {
return description;
}

public String getValue() {
return value;
}
}

private final MetricEnum metricType;
private final List<Item> items;

public StatItemDto(MetricEnum metricType, List<Item> items) {
this.metricType = metricType;
this.items = items;
}

public MetricEnum getMetricType() {
return metricType;
}

public List<Item> getItems() {
return items;
}
}
110 changes: 110 additions & 0 deletions src/main/java/org/example/visitor/AbcVisitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package org.example.visitor;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.util.HashMap;
import java.util.Map;

public class AbcVisitor extends ClassVisitor {

private String className;

private final Map<String, Integer> assignmentCount = new HashMap<>();
private final Map<String, Integer> branchCount = new HashMap<>();
private final Map<String, Integer> conditionCount = new HashMap<>();

public AbcVisitor() {
super(Opcodes.ASM9);
}

@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
className = name;
super.visit(version, access, name, signature, superName, interfaces);
}

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
return new MethodVisitor(Opcodes.ASM9, mv) {

@Override
public void visitVarInsn(int opcode, int var) {
if ((opcode >= Opcodes.ISTORE && opcode <= 78) || opcode == Opcodes.IINC) {
assignmentCount.merge(className, 1, Integer::sum);
}
super.visitVarInsn(opcode, var);
}

@Override
public void visitIincInsn(int var, int increment) {
assignmentCount.merge(className, 1, Integer::sum);
super.visitIincInsn(var, increment);
}

// ------------------------------
// B — Branches
// ------------------------------
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
branchCount.merge(className, 1, Integer::sum);
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}

@Override
public void visitTypeInsn(int opcode, String type) {
if (opcode == Opcodes.NEW) {
branchCount.merge(className, 1, Integer::sum);
}
super.visitTypeInsn(opcode, type);
}


@Override
public void visitJumpInsn(int opcode, Label label) {
if (opcode >= Opcodes.IFEQ && opcode <= Opcodes.IF_ACMPNE) {
conditionCount.merge(className, 1, Integer::sum);
}

if (opcode == Opcodes.GOTO) {
conditionCount.merge(className, 1, Integer::sum);
}

super.visitJumpInsn(opcode, label);
}

@Override
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
conditionCount.merge(className, 1, Integer::sum);
super.visitLookupSwitchInsn(dflt, keys, labels);
}

@Override
public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
conditionCount.merge(className, 1, Integer::sum);
super.visitTableSwitchInsn(min, max, dflt, labels);
}

@Override
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
conditionCount.merge(className, 1, Integer::sum);
super.visitTryCatchBlock(start, end, handler, type);
}
};
}

public Map<String, Integer> getAssignmentCount() {
return assignmentCount;
}

public Map<String, Integer> getBranchCount() {
return branchCount;
}

public Map<String, Integer> getConditionCount() {
return conditionCount;
}
}
56 changes: 56 additions & 0 deletions src/main/java/org/example/visitor/ClassMapVisitor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.example.visitor;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.objectweb.asm.Opcodes.ASM8;

public class ClassMapVisitor extends ClassVisitor {

private final Map<String, String> superMap = new HashMap<>();

private final Map<String, Integer> fieldCount = new HashMap<>();

private final Map<String, List<String>> methods = new HashMap<>();

public ClassMapVisitor() {
super(ASM8);
}

public Map<String, String> getSuperMap() {
return superMap;
}

public Map<String, Integer> getFieldCount() {
return fieldCount;
}

public Map<String, List<String>> getMethods() {
return methods;
}

@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
superMap.put(name, superName);
}

@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
fieldCount.merge(name, 1, Integer::sum);
return super.visitField(access, name, descriptor, signature, value);
}

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
methods.computeIfAbsent(name, k -> new ArrayList<>())
.add(name + descriptor);

return super.visitMethod(access, name, descriptor, signature, exceptions);
}
}
Loading