Определение LCOM4 (отсутствие единства в методах) путем анализа байт-кода Java с использованием BCEL
Я построил программу, которая берет предоставленный файл ".class" и анализирует его, используя BCEL, но я немного растерялся, когда речь заходит об использовании результирующего объекта для определения значения LCOM4. Я просмотрел всю сеть, пытаясь найти подходящий учебник по этому вопросу, но пока не смог (я прочитал весь Javadoc относительно BCEL). Поэтому я хотел бы помочь с этой проблемой, например, в некоторых подробных руководствах или фрагментах кода, которые помогут мне понять, как это сделать.
1 ответ
Хорошо, давайте определим класс для представления группы полей и методов:
public class Group {
private final Set<String> fields = new HashSet<>();
private final Set<String> methods = new HashSet<>();
public Group addFields(String...fields) {
for (String field: fields) {
this.fields.add(field);
}
return this;
}
public Group addMethods(String... methods) {
for (String method: methods) {
this.methods.add(method);
}
return this;
}
public int fields() {
return fields.size();
}
public int methods() {
return methods.size();
}
public boolean intersects(Group other) {
for (String field: other.fields) {
if (fields.contains(field)) {
return true;
}
}
for (String method: other.methods) {
if (methods.contains(method)) {
return true;
}
}
return false;
}
public void merge(Group other) {
fields.addAll(other.fields);
methods.addAll(other.methods);
}
@Override
public String toString() {
return "Group{" + "fields=" + fields + ", methods=" + methods + '}';
}
}
Мы запускаем процесс, заполняя список групп группой для каждого поля, определенного в классе, затем для каждого метода мы строим группу с полями и методами, на которые есть ссылки в коде, а затем сокращаем список групп путем слияния. и удаление каждой группы, которая пересекает группу метода.
Вот код Java для загрузки групп класса. LCOM4 это groups.size():
private List<Group> loadGroups(File file) throws IOException {
try (InputStream in = new FileInputStream(file)) {
ClassParser parser = new ClassParser(in, file.getName());
JavaClass clazz = parser.parse();
String className = clazz.getClassName();
ConstantPoolGen cp = new ConstantPoolGen(clazz.getConstantPool());
List<Group> groups = new ArrayList<Group>();
for (Field field: clazz.getFields()) {
groups.add(new Group().addFields(field.getName()));
}
for (Method method: clazz.getMethods()) {
Group group = new Group().addMethods(method.getName());
Code code = method.getCode();
InstructionList instrs = new InstructionList(code.getCode());
for (InstructionHandle ih: instrs) {
Instruction instr = ih.getInstruction();
if (instr instanceof FieldInstruction) {
FieldInstruction fld = (FieldInstruction)instr;
if (fld.getClassName(cp).equals(className)) {
group.addFields(fld.getFieldName(cp));
}
} else if (instr instanceof InvokeInstruction) {
InvokeInstruction inv = (InvokeInstruction)instr;
if (inv.getClassName(cp).equals(className)) {
group.addMethods(inv.getMethodName(cp));
}
}
}
if (group.fields() > 0 || group.methods() > 1) {
int i = groups.size();
while (i > 0) {
--i;
Group g = groups.get(i);
if (g.intersects(group)) {
group.merge(g);
groups.remove(i);
}
}
groups.add(group);
}
}
return groups;
}
}