From f1068db66553ce070652656301eaa837beddb9a1 Mon Sep 17 00:00:00 2001 From: Martin Wittlinger Date: Sun, 1 May 2022 22:06:00 +0200 Subject: [PATCH 1/4] deadlines deadlines deadlines --- .../analyzer/api/AbstractAnalyzer.java | 10 + .../refactorlizar/analyzer/api/Report.java | 4 +- .../refactorlizar/analyzer/api/Solution.java | 5 +- bad-smells-ma/build.gradle | 21 ++ .../WrongDependencyDirection.java | 39 +++ .../deficient_encapsulation/DataClumbs.java | 108 ++++++++ .../deficient_encapsulation/Repair.java | 163 +++++++++++ .../degraded_modularity/FeatureScatter.java | 47 ++++ .../DuplicateAbstraction.java | 53 ++++ .../SwitchStatements.java | 50 ++++ .../PrimitiveObession.java | 53 ++++ .../analyzer/missing_abstraction/Repair.java | 98 +++++++ .../rebellious_modularity/LanguageBlob.java | 59 ++++ .../analyzer/unused_abstraction/Repair.java | 12 + .../SpeculativeGenerality.java | 75 +++++ .../analyzer/DataClumbsTest.java | 33 +++ .../analyzer/DuplicateAbstractionTest.java | 39 +++ .../analyzer/PrimitiveObessionTest.java | 34 +++ .../analyzer/SpeculativeGeneralityTest.java | 33 +++ .../analyzer/SwitchStatementsTest.java | 33 +++ .../WrongDependencyDirectionTest.java | 33 +++ build.gradle | 2 +- settings.gradle | 4 +- visualization/build.gradle | 37 +++ visualization/src/main/java/Foo.java | 118 ++++++++ .../src/main/java/HelloWorldExample.java | 258 ++++++++++++++++++ 26 files changed, 1416 insertions(+), 5 deletions(-) create mode 100644 bad-smells-ma/build.gradle create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/broken_modularity/WrongDependencyDirection.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/DataClumbs.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/Repair.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/FeatureScatter.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/duplicated_abstraction/DuplicateAbstraction.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/incomplete_abstraction/SwitchStatements.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/PrimitiveObession.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/Repair.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/rebellious_modularity/LanguageBlob.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/Repair.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/SpeculativeGenerality.java create mode 100644 bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/DataClumbsTest.java create mode 100644 bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/DuplicateAbstractionTest.java create mode 100644 bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/PrimitiveObessionTest.java create mode 100644 bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/SpeculativeGeneralityTest.java create mode 100644 bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/SwitchStatementsTest.java create mode 100644 bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/WrongDependencyDirectionTest.java create mode 100644 visualization/build.gradle create mode 100644 visualization/src/main/java/Foo.java create mode 100644 visualization/src/main/java/HelloWorldExample.java diff --git a/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/AbstractAnalyzer.java b/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/AbstractAnalyzer.java index 26f92044..608d178e 100644 --- a/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/AbstractAnalyzer.java +++ b/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/AbstractAnalyzer.java @@ -16,4 +16,14 @@ public Report analyze( protected abstract Report fullAnalysis( ModularLanguage language, SimulatorModel simulatorModel, Settings settings); + + @Override + public String getDescription() { + return "MISSING"; + } + + @Override + public String getName() { + return "MISSING"; + } } diff --git a/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/Report.java b/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/Report.java index 10fa1d72..2a805e4b 100644 --- a/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/Report.java +++ b/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/Report.java @@ -16,8 +16,8 @@ public class Report { private Map> featureScatterings = Collections.emptyMap(); private Map> languageBlobs = Collections.emptyMap(); - public Report(String text, String description, boolean smellFound) { - this.text = text; + public Report(String title, String description, boolean smellFound) { + this.text = title; this.description = description; solutions = Collections.emptyList(); this.smellFound = smellFound; diff --git a/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/Solution.java b/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/Solution.java index 8ac2d2f3..2a0eb9fa 100644 --- a/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/Solution.java +++ b/analyzer-api/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/api/Solution.java @@ -1,10 +1,13 @@ package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; + public interface Solution { String getHeadline(); String getDescription(); - void apply(); + void apply(ModularLanguage language, SimulatorModel simulatorModel); } diff --git a/bad-smells-ma/build.gradle b/bad-smells-ma/build.gradle new file mode 100644 index 00000000..1764461a --- /dev/null +++ b/bad-smells-ma/build.gradle @@ -0,0 +1,21 @@ + + +plugins { + id 'edu.kit.kastel.sdq.case4lang.refactorlizar.java-conventions' +} +dependencies { + implementation project(":"+project.commons) + implementation project(":commons-analyzer") + implementation project(":core") +} +allprojects { + repositories { + maven { url 'https://jitpack.io' } + } +} +description = 'badsmells-ma' +java { + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } +} \ No newline at end of file diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/broken_modularity/WrongDependencyDirection.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/broken_modularity/WrongDependencyDirection.java new file mode 100644 index 00000000..b406bc5e --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/broken_modularity/WrongDependencyDirection.java @@ -0,0 +1,39 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.broken_modularity; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.stream.Collectors; +import spoon.reflect.declaration.CtType; + +public class WrongDependencyDirection extends AbstractAnalyzer { + + @Override + protected void checkSettings(Settings settings) {} + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + var types = + language.getComponents().stream() + .flatMap(c -> c.getTypes().stream()) + .collect(Collectors.toList()); + for (CtType ctType : types) { + var col = + ctType.getReferencedTypes().stream() + .filter( + v -> + simulatorModel.getTypeWithQualifiedName( + v.getQualifiedName()) + != null + && language.getTypeWithQualifiedName( + v.getQualifiedName()) + == null) + .collect(Collectors.toList()); + col.remove(ctType.getReference()); + } + return null; + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/DataClumbs.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/DataClumbs.java new file mode 100644 index 00000000..407394c7 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/DataClumbs.java @@ -0,0 +1,108 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.deficient_encapsulation; + +import com.google.common.collect.Lists; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Component; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypedElement; +import spoon.reflect.reference.CtTypeReference; + +public class DataClumbs extends AbstractAnalyzer { + + @Override + public String getDescription() { + return "null"; + } + + @Override + public String getName() { + return "dataclumbs"; + } + + @Override + protected void checkSettings(Settings settings) {} + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + HashMap>, Integer> map = new HashMap<>(); + Set> types = getAllTypes(simulatorModel); + for (CtType ctType : types) { + for (CtMethod method : ctType.getMethods()) { + if (method.getParameters().size() < 2) { + continue; + } + List>> tuples = createTuples(method); + // unwanted pairs like (a,a) and (b,b) are removed + tuples.removeIf(v -> v.get(0).equals(v.get(1))); + for (List> tuple : tuples) { + new ArrayList<>(tuple) + .sort( + ((o1, o2) -> + o1.getQualifiedName() + .compareTo(o2.getQualifiedName()))); + if (map.containsKey(tuple)) { + map.put(tuple, map.get(tuple) + 1); + } else { + map.put(tuple, 1); + } + } + } + } + // we still have (a,b) and (b,a) pairs included as 2 values so we have 3 as cutoff for now + map.values().removeIf(i -> i < 3); + map.keySet() + .removeIf( + v -> + !(language.getTypeWithQualifiedName(v.get(0).getQualifiedName()) + != null + || language.getTypeWithQualifiedName( + v.get(1).getQualifiedName()) + != null)); + var result = + map.entrySet().stream() + .sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())) + .limit(20) + .collect(Collectors.toList()); + for (Entry>, Integer> entry : result) { + System.out.println( + entry.getKey().get(0).getQualifiedName() + + " " + + entry.getKey().get(1).getQualifiedName() + + " " + + entry.getValue()); + new Repair().repair(language, simulatorModel, entry.getKey()); + } + return null; + } + + private ArrayList>> createTuples(CtMethod method) { + return new ArrayList<>( + Lists.cartesianProduct( + method.getParameters().stream() + .map(CtTypedElement::getType) + .collect(Collectors.toList()), + method.getParameters().stream() + .map(CtTypedElement::getType) + .collect(Collectors.toList()))); + } + + private Set> getAllTypes(SimulatorModel simulatorModel) { + return simulatorModel.getComponents().stream() + .map(Component::getTypes) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/Repair.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/Repair.java new file mode 100644 index 00000000..fee4782a --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/Repair.java @@ -0,0 +1,163 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.deficient_encapsulation; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Component; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import spoon.reflect.code.CtExpression; +import spoon.reflect.code.CtInvocation; +import spoon.reflect.declaration.CtClass; +import spoon.reflect.declaration.CtConstructor; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtPackage; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypedElement; +import spoon.reflect.declaration.ModifierKind; +import spoon.reflect.factory.Factory; +import spoon.reflect.reference.CtParameterReference; +import spoon.reflect.reference.CtTypeReference; +import spoon.reflect.visitor.filter.InvocationFilter; +import spoon.reflect.visitor.filter.TypeFilter; + +public class Repair { + + public void repair( + ModularLanguage language, + SimulatorModel simulatorModel, + List> dataclumbs) { + Component component = simulatorModel.getComponents().iterator().next(); + Set> types = + simulatorModel.getComponents().stream() + .map(Component::getTypes) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + Factory factory = types.iterator().next().getFactory(); + CtClass clazz = createClass(dataclumbs, component, factory); + createFieldsAndGetter(dataclumbs, factory, clazz); + createConstructor(dataclumbs, factory, clazz); + for (CtType ctType : types) { + for (CtMethod ctMethod : ctType.getMethods()) { + if (ctMethod.getParameters().stream() + .map(CtTypedElement::getType) + .collect(Collectors.toList()) + .equals(dataclumbs)) { + CtMethod replacement = ctMethod.clone(); + if (ctMethod.getBody() == null) { + continue; + } + replaceMethodParameters(factory, clazz, replacement); + ctMethod.replace(replacement); + replaceInvocations(types, factory, clazz, ctMethod); + } + } + } + } + + private void replaceInvocations( + Set> types, Factory factory, CtClass clazz, CtMethod ctMethod) { + types.stream() + .map(type -> type.getElements(new InvocationFilter(ctMethod))) + .flatMap(Collection::stream) + .forEach( + invocation -> { + CtInvocation cloned = invocation.clone(); + invocation.replace( + factory.createConstructorCall( + clazz.getReference(), + cloned.getArguments().toArray(CtExpression[]::new))); + }); + } + + private void replaceMethodParameters( + Factory factory, CtClass clazz, CtMethod replacement) { + replacement.setParameters( + List.of( + factory.createParameter( + replacement, + clazz.getReference(), + clazz.getSimpleName().toLowerCase()))); + replacement + .getBody() + .getElements(new TypeFilter<>(CtParameterReference.class)) + .forEach( + v -> { + CtMethod getter = + clazz.getMethods().stream() + .filter( + method -> + v.getType() != null + && v.getType() + .equals( + method + .getType())) + .findFirst() + .orElse(null); + if (getter == null) { + return; + } + factory.createCodeSnippetStatement( + replacement.getParameters().get(0).getSimpleName() + + "." + + getter.getSimpleName() + + "();"); + }); + } + + private CtClass createClass( + List> dataclumbs, Component component, Factory factory) { + CtClass clazz = factory.createClass(); + CtPackage ctPackage = component.getTypes().iterator().next().getPackage(); + clazz.setParent(ctPackage); + String clazzName = + dataclumbs.stream() + .map(CtTypeReference::getSimpleName) + .collect(Collectors.joining()); + clazz.setSimpleName(clazzName); + return clazz; + } + + private void createConstructor( + List> dataclumbs, Factory factory, CtClass clazz) { + CtConstructor constructor = factory.Constructor().createDefault(clazz); + dataclumbs.forEach( + v -> factory.createParameter(constructor, v, v.getSimpleName().toLowerCase())); + constructor.setBody(factory.createBlock()); + constructor.getParameters().stream() + .map( + v -> + "this." + + v.getSimpleName().toLowerCase() + + "=" + + v.getSimpleName().toLowerCase()) + .map(factory::createCodeSnippetStatement) + .forEach(constructor.getBody()::addStatement); + } + + private void createFieldsAndGetter( + List> dataclumbs, Factory factory, CtClass clazz) { + for (CtTypeReference typeReference : dataclumbs) { + factory.Field() + .create( + clazz, + Set.of(ModifierKind.PRIVATE), + typeReference, + typeReference.getSimpleName().toLowerCase(), + null); + CtMethod getter = + factory.Method() + .create( + clazz, + Set.of(ModifierKind.PUBLIC), + typeReference, + "get" + typeReference.getSimpleName().toLowerCase(), + List.of(), + Set.of()); + getter.setBody( + factory.createCodeSnippetStatement( + "return " + typeReference.getSimpleName().toLowerCase())); + } + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/FeatureScatter.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/FeatureScatter.java new file mode 100644 index 00000000..7ae635a6 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/FeatureScatter.java @@ -0,0 +1,47 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.degraded_modularity; + +import com.google.common.graph.MutableNetwork; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.DependencyGraphSupplier; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Edge; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.JavaUtils; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.graphs.TypeGraphs; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypeMember; + +public class FeatureScatter extends AbstractAnalyzer { + + @Override + protected void checkSettings(Settings settings) {} + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + MutableNetwork, Edge, CtTypeMember>> graph = + DependencyGraphSupplier.getTypeGraph(language, simulatorModel); + TypeGraphs.removeNonProjectNodes(language, simulatorModel, graph); + TypeGraphs.removeEdgesWithoutLanguageTarget(language, graph); + TypeGraphs.removeEdgesWithSimulatorAsTarget(graph, simulatorModel); + removeNonScatter(graph, type -> JavaUtils.isLanguageType(language, type)); + return null; + } + + private boolean hasOnePredecessor(MutableNetwork> graph, T type) { + return graph.predecessors(type).size() < 2; + } + + private void removeNonScatter( + MutableNetwork> graph, Predicate isLanguage) { + graph.nodes().stream() + .filter(isLanguage) + .filter(type -> hasOnePredecessor(graph, type)) + .collect(Collectors.toList()) + .forEach(graph::removeNode); + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/duplicated_abstraction/DuplicateAbstraction.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/duplicated_abstraction/DuplicateAbstraction.java new file mode 100644 index 00000000..9f1b08b6 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/duplicated_abstraction/DuplicateAbstraction.java @@ -0,0 +1,53 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.duplicated_abstraction; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Component; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; + +public class DuplicateAbstraction extends AbstractAnalyzer { + + @Override + protected void checkSettings(Settings settings) {} + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + Set> types = + simulatorModel.getComponents().stream() + .map(Component::getTypes) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + List> clones = new ArrayList<>(); + for (CtType origin : types) { + for (CtType target : types) { + for (CtMethod method : origin.getMethods()) { + if (target.getMethods().contains(method) && !origin.equals(target)) { + if (method.getBody() != null && !method.getBody().isImplicit()) { + clones.add(method); + } + } + } + } + } + String title = String.format("%s duplicated methods found", clones.size()); + StringBuilder description = new StringBuilder(); + for (CtMethod ctMethod : clones) { + description.append( + String.format( + "Method %s from type %s is duplicated", + ctMethod.getSignature(), + ctMethod.getDeclaringType().getQualifiedName())); + } + return new Report(title, description.toString(), true); + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/incomplete_abstraction/SwitchStatements.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/incomplete_abstraction/SwitchStatements.java new file mode 100644 index 00000000..f470ba0f --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/incomplete_abstraction/SwitchStatements.java @@ -0,0 +1,50 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.incomplete_abstraction; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.stream.Collectors; +import spoon.reflect.code.CtSwitch; +import spoon.reflect.reference.CtTypeReference; +import spoon.reflect.visitor.filter.TypeFilter; + +public class SwitchStatements extends AbstractAnalyzer { + + @Override + public String getDescription() { + return "null"; + } + + @Override + public String getName() { + return "null"; + } + + @Override + protected void checkSettings(Settings settings) {} + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + var switches = + simulatorModel.getComponents().stream() + .flatMap(c -> c.getTypes().stream()) + .flatMap(t -> t.getElements(new TypeFilter<>(CtSwitch.class)).stream()) + .filter(m -> !m.getSelector().getReferencedTypes().isEmpty()) + .filter(m -> extracted(language, m)) + .collect(Collectors.toList()); + System.out.println(switches.size()); + return null; + } + + private boolean extracted(ModularLanguage language, CtSwitch m) { + for (CtTypeReference ref : m.getSelector().getReferencedTypes()) { + if (language.getTypeWithQualifiedName(ref.getQualifiedName()) != null) { + return true; + } + } + return false; + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/PrimitiveObession.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/PrimitiveObession.java new file mode 100644 index 00000000..c9246681 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/PrimitiveObession.java @@ -0,0 +1,53 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.missing_abstraction; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Component; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; + +public class PrimitiveObession extends AbstractAnalyzer { + + @Override + protected void checkSettings(Settings settings) {} + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + List> methods = new ArrayList<>(); + var types = + simulatorModel.getComponents().stream() + .map(Component::getTypes) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + for (CtType ctType : types) { + for (CtMethod method : ctType.getMethods()) { + if (method.getParameters().stream() + .filter( + v -> + v.getType() + .equals( + v.getFactory() + .Type() + .stringType()) + || v.getType().isPrimitive()) + .count() + > 1) { + methods.add(method); + } + } + } + System.out.println(methods.size()); + for (CtMethod method : methods) { + System.out.println(method.getSignature()); + } + return null; + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/Repair.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/Repair.java new file mode 100644 index 00000000..099ed8ed --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/Repair.java @@ -0,0 +1,98 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.missing_abstraction; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Component; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import spoon.reflect.declaration.CtClass; +import spoon.reflect.declaration.CtConstructor; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtPackage; +import spoon.reflect.declaration.CtParameter; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.ModifierKind; +import spoon.reflect.factory.Factory; +import spoon.reflect.reference.CtTypeReference; + +public class Repair { + + public void repair( + ModularLanguage language, + SimulatorModel simulatorModel, + CtMethod primitiveObession) { + Component component = simulatorModel.getComponents().iterator().next(); + Set> types = + simulatorModel.getComponents().stream() + .map(Component::getTypes) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + Factory factory = types.iterator().next().getFactory(); + CtClass clazz = + createClass(getFirstPrimitiveParameter(primitiveObession), component, factory); + createConstructor(getFirstPrimitiveParameter(primitiveObession).getType(), factory, clazz); + createFieldsAndGetter( + getFirstPrimitiveParameter(primitiveObession).getType(), factory, clazz); + } + + private CtParameter getFirstPrimitiveParameter(CtMethod primitiveObession) { + return primitiveObession.getParameters().stream() + .filter(v -> v.getType() != null) + .filter( + v -> + v.getType().isPrimitive() + || v.getType().getSimpleName().equals("String")) + .findFirst() + .get(); + } + + private CtClass createClass(CtParameter name, Component component, Factory factory) { + CtClass clazz = factory.createClass(); + CtPackage ctPackage = component.getTypes().iterator().next().getPackage(); + clazz.setParent(ctPackage); + String clazzName = name.getSimpleName(); + clazz.setSimpleName(clazzName); + return clazz; + } + + private void createConstructor( + CtTypeReference primitive, Factory factory, CtClass clazz) { + CtConstructor constructor = factory.Constructor().createDefault(clazz); + factory.createParameter(constructor, primitive, primitive.getSimpleName().toLowerCase()); + constructor.setBody(factory.createBlock()); + constructor.getParameters().stream() + .map( + v -> + "this." + + v.getSimpleName().toLowerCase() + + "=" + + v.getSimpleName().toLowerCase()) + .map(factory::createCodeSnippetStatement) + .forEach(constructor.getBody()::addStatement); + } + + private void createFieldsAndGetter( + CtTypeReference primitive, Factory factory, CtClass clazz) { + factory.Field() + .create( + clazz, + Set.of(ModifierKind.PRIVATE), + primitive, + primitive.getSimpleName().toLowerCase(), + null); + CtMethod getter = + factory.Method() + .create( + clazz, + Set.of(ModifierKind.PUBLIC), + primitive, + "get" + primitive.getSimpleName().toLowerCase(), + List.of(), + Set.of()); + getter.setBody( + factory.createCodeSnippetStatement( + "return " + primitive.getSimpleName().toLowerCase())); + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/rebellious_modularity/LanguageBlob.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/rebellious_modularity/LanguageBlob.java new file mode 100644 index 00000000..9213820a --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/rebellious_modularity/LanguageBlob.java @@ -0,0 +1,59 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.rebellious_modularity; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Components; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Component; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.Pair; +import spoon.reflect.declaration.CtType; +import spoon.reflect.reference.CtTypeReference; + +public class LanguageBlob extends AbstractAnalyzer { + + @Override + protected void checkSettings(Settings settings) {} + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + Set> types = + simulatorModel.getComponents().stream() + .flatMap(v -> v.getTypes().stream()) + .collect(Collectors.toSet()); + List, Map>>>> pairs = new ArrayList<>(); + for (CtType ctType : types) { + Set> references = new HashSet<>(ctType.getReferencedTypes()); + references.removeIf( + v -> language.getTypeWithQualifiedName(v.getQualifiedName()) == null); + Map>> map = new HashMap<>(); + for (CtTypeReference ctTypeReference : references) { + Optional component = + Components.findComponent(language, ctTypeReference.getTypeDeclaration()); + component.ifPresent( + v -> + map.merge( + v, + new HashSet<>(Set.of(ctTypeReference)), + (o1, o2) -> { + o1.addAll(o2); + return o1; + })); + } + if (map.size() > 1) { + pairs.add(Pair.of(ctType, map)); + } + } + return null; + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/Repair.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/Repair.java new file mode 100644 index 00000000..e1f8b294 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/Repair.java @@ -0,0 +1,12 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.unused_abstraction; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import spoon.reflect.declaration.CtElement; + +public class Repair { + + public void repair(ModularLanguage language, SimulatorModel simulatorModel, CtElement element) { + element.delete(); + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/SpeculativeGenerality.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/SpeculativeGenerality.java new file mode 100644 index 00000000..2504d37b --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/SpeculativeGenerality.java @@ -0,0 +1,75 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.unused_abstraction; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Component; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import spoon.refactoring.MethodCallState; +import spoon.refactoring.MethodInvocationSearch; +import spoon.reflect.code.CtFieldAccess; +import spoon.reflect.declaration.CtElement; +import spoon.reflect.declaration.CtField; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; +import spoon.reflect.visitor.filter.FieldAccessFilter; + +public class SpeculativeGenerality extends AbstractAnalyzer { + + @Override + public String getDescription() { + return "null"; + } + + @Override + public String getName() { + return "null"; + } + + @Override + protected void checkSettings(Settings settings) {} + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + var types = + simulatorModel.getComponents().stream() + .map(Component::getTypes) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + List removable = new ArrayList<>(); + for (CtType ctType : types) { + for (CtField field : ctType.getFields()) { + if (field.isPrivate()) { + List> elements = + ctType.getElements(new FieldAccessFilter(field.getReference())); + if (elements.isEmpty()) { + removable.add(field); + System.out.println(ctType.getQualifiedName() + "#" + field.getSimpleName()); + } + } + } + var search = new MethodInvocationSearch(); + ctType.accept(search); + for (CtMethod method : ctType.getMethods()) { + if (method.isPrivate()) { + for (MethodCallState state : search.getInvocationsOfMethod()) { + if (state.getMethod() != null + && state.getMethod().equals(method) + && state.checkCallState()) { + removable.add(method); + System.out.println( + ctType.getQualifiedName() + "#" + method.getSimpleName()); + } + } + } + } + } + return null; + } +} diff --git a/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/DataClumbsTest.java b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/DataClumbsTest.java new file mode 100644 index 00000000..9efb564c --- /dev/null +++ b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/DataClumbsTest.java @@ -0,0 +1,33 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.deficient_encapsulation.DataClumbs; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.InputKind; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.ProjectParser; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Project; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class DataClumbsTest { + @Test + void testFullAnalysis() { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/Smart-Grid-ICT-Resilience-Framework"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/SmartGridLang/metamodel/refactored"); + Project project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .parse(); + new DataClumbs() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new DataClumbs().getSettings()); + } +} diff --git a/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/DuplicateAbstractionTest.java b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/DuplicateAbstractionTest.java new file mode 100644 index 00000000..2edb9a15 --- /dev/null +++ b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/DuplicateAbstractionTest.java @@ -0,0 +1,39 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.duplicated_abstraction.DuplicateAbstraction; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.InputKind; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.ProjectParser; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Project; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class DuplicateAbstractionTest { + @Test + void testFullAnalysis() { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/Smart-Grid-ICT-Resilience-Framework"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/SmartGridLang/metamodel/refactored"); + Project project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .ignoreTestFolder(true) + .parse(); + Report report = + new DuplicateAbstraction() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new DuplicateAbstraction().getSettings()); + assertNotNull(report); + } +} diff --git a/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/PrimitiveObessionTest.java b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/PrimitiveObessionTest.java new file mode 100644 index 00000000..a1e3c03d --- /dev/null +++ b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/PrimitiveObessionTest.java @@ -0,0 +1,34 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.missing_abstraction.PrimitiveObession; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.InputKind; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.ProjectParser; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Project; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class PrimitiveObessionTest { + @Test + void testFullAnalysis() { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/Smart-Grid-ICT-Resilience-Framework"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/SmartGridLang/metamodel/refactored"); + Project project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .ignoreTestFolder(true) + .parse(); + new PrimitiveObession() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new PrimitiveObession().getSettings()); + } +} diff --git a/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/SpeculativeGeneralityTest.java b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/SpeculativeGeneralityTest.java new file mode 100644 index 00000000..464b7a39 --- /dev/null +++ b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/SpeculativeGeneralityTest.java @@ -0,0 +1,33 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.unused_abstraction.SpeculativeGenerality; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.InputKind; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.ProjectParser; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Project; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class SpeculativeGeneralityTest { + @Test + void testFullAnalysis() { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/Smart-Grid-ICT-Resilience-Framework"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/SmartGridLang/metamodel/refactored"); + Project project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .parse(); + new SpeculativeGenerality() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new SpeculativeGenerality().getSettings()); + } +} diff --git a/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/SwitchStatementsTest.java b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/SwitchStatementsTest.java new file mode 100644 index 00000000..cbb6c329 --- /dev/null +++ b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/SwitchStatementsTest.java @@ -0,0 +1,33 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.incomplete_abstraction.SwitchStatements; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.InputKind; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.ProjectParser; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Project; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class SwitchStatementsTest { + @Test + void testFullAnalysis() { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/Smart-Grid-ICT-Resilience-Framework"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/SmartGridLang/metamodel/refactored"); + Project project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .parse(); + new SwitchStatements() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new SwitchStatements().getSettings()); + } +} diff --git a/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/WrongDependencyDirectionTest.java b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/WrongDependencyDirectionTest.java new file mode 100644 index 00000000..e9a13b23 --- /dev/null +++ b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/WrongDependencyDirectionTest.java @@ -0,0 +1,33 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.broken_modularity.WrongDependencyDirection; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.InputKind; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.ProjectParser; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Project; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class WrongDependencyDirectionTest { + @Test + void testFullAnalysis() { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/Smart-Grid-ICT-Resilience-Framework"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/SmartGridLang/metamodel/refactored"); + Project project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .parse(); + new WrongDependencyDirection() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new WrongDependencyDirection().getSettings()); + } +} diff --git a/build.gradle b/build.gradle index 1ae1bcaf..cd577288 100644 --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ spotless { target "**/*.java" targetExclude "**/test/resources/**", "**/build/**" trimTrailingWhitespace() - removeUnusedImports() + // removeUnusedImports() googleJavaFormat().aosp() } groovy { diff --git a/settings.gradle b/settings.gradle index 689b44cf..142366e7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -13,4 +13,6 @@ include(":class-split") include(":commons-analyzer") include(":commons") include(":architecture-evaluation") -include(":commons-query") \ No newline at end of file +include(":commons-query") +include(":visualization") +include(":bad-smells-ma") \ No newline at end of file diff --git a/visualization/build.gradle b/visualization/build.gradle new file mode 100644 index 00000000..1b86d199 --- /dev/null +++ b/visualization/build.gradle @@ -0,0 +1,37 @@ + + +plugins { + id 'edu.kit.kastel.sdq.case4lang.refactorlizar.java-conventions' + id 'org.openjfx.javafxplugin' version '0.0.12' +} +dependencies { + implementation project(":"+project.commons) + implementation 'org.jgrapht:jgrapht-core:1.5.1' + implementation("org.jgrapht:jgrapht-ext:+") + implementation("org.jgrapht:jgrapht-guava:+") + implementation 'org.jgrapht:jgrapht-io:1.5.1' + implementation project(":commons-analyzer") + implementation project(":core") + implementation "org.graphstream:gs-core:+" + implementation("org.graphstream:gs-ui-javafx:+") + implementation 'org.neo4j:neo4j:+' + implementation 'org.neo4j.driver:neo4j-java-driver:+' +} +allprojects { + repositories { + maven { url 'https://jitpack.io' } + } +} +description = 'visualization' +javafx { + modules = [ + 'javafx.controls', + 'javafx.fxml', + "javafx.graphics" + ] +} +java { + toolchain { + languageVersion = JavaLanguageVersion.of(11) + } +} \ No newline at end of file diff --git a/visualization/src/main/java/Foo.java b/visualization/src/main/java/Foo.java new file mode 100644 index 00000000..d759420e --- /dev/null +++ b/visualization/src/main/java/Foo.java @@ -0,0 +1,118 @@ +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.InputKind; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.ProjectParser; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Project; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.graphstream.graph.*; +import org.graphstream.graph.implementations.MultiGraph; + +public class Foo { + + public static void main(String[] args) throws IOException { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/Smart-Grid-ICT-Resilience-Framework"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Hiwi/Software/SmartGrid/SmartGridLang/metamodel/refactored"); + Project project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .parse(); + System.setProperty("org.graphstream.ui", "javafx"); + System.setProperty("org.graphstream.debug", "true"); + Graph graph = new MultiGraph("Tutorial 1", false, true); + graph.addNode("A"); + graph.addNode("B"); + graph.addNode("C"); + graph.addEdge("AB", "A", "B"); + graph.addEdge("BC", "B", "C"); + graph.addEdge("CA", "C", "A"); + graph.display(); + + // renderGraphComponent(project.getLanguage(), project.getSimulatorModel()); + // File imgFile = new File("graph.png"); + // imgFile.createNewFile(); + // Graph g = new SimpleGraph<>(DefaultEdge.class); + // g.addVertex("v1"); + // g.addVertex("v2"); + // g.addEdge("v1", "v2"); + // JGraphXAdapter graphAdapter = new JGraphXAdapter<>(g); + // mxIGraphLayout layout = new mxCircleLayout(graphAdapter); + // layout.execute(graphAdapter.getDefaultParent()); + // renderHrefGraph(g); + } + /* + public static void renderGraph(ModularLanguage language, SimulatorModel model) + throws IOException { + MutableNetwork>> graph = + DependencyGraphSupplier.getPackageGraph(language, model); + Graph>> jgrapht = new MutableNetworkAdapter<>(graph); + + DOTExporter>> exporter = new DOTExporter<>(); + exporter.setVertexAttributeProvider(v -> { + Map map = new LinkedHashMap<>(); + map.put("label", DefaultAttribute.createAttribute("\"" + v.getQualifiedName() + "\"")); + return map; + }); + exporter.setEdgeAttributeProvider(v -> { + Map map = new LinkedHashMap<>(); + map.put("label", DefaultAttribute.createAttribute( + "\"" + v.getCause().getQualifiedName() + "#" + v.getCause().getSimpleName() + "\"")); + return map; + }); + exporter.setVertexIdProvider(v -> "\"" + v.getQualifiedName() + "\""); + exporter.setEdgeIdProvider( + v -> "\"" + v.getCause().getQualifiedName() + "#" + v.getCause().getSimpleName() + "\""); + Writer writer = new StringWriter(); + exporter.exportGraph(jgrapht, writer); + Files.writeString(Path.of("graph.dot"), writer.toString()); + } + + public static void renderGraphComponent(ModularLanguage language, SimulatorModel model) + throws IOException { + MutableNetwork> graph = + DependencyGraphSupplier.getComponentGraph(language, model); + graph.edges().stream().filter( v-> v.getCause().getSimpleName().startsWith("java.")).collect(Collectors.toList()).forEach(graph::removeEdge); + Graph> jgrapht = new MutableNetworkAdapter<>(graph); + + DOTExporter> exporter = new DOTExporter<>(); + exporter.setVertexAttributeProvider(v -> { + Map map = new LinkedHashMap<>(); + map.put("label", DefaultAttribute.createAttribute("\"" + v.getName() + "\"")); + return map; + }); + exporter.setEdgeAttributeProvider(v -> { + Map map = new LinkedHashMap<>(); + map.put("label", DefaultAttribute.createAttribute( + "\"" + v.getCause().getQualifiedName() + "#" + v.getCause().getSimpleName() + "\"")); + return map; + }); + exporter.setVertexIdProvider(v -> "\"" + v.getName() + "\""); + exporter.setEdgeIdProvider( + v -> "\"" + v.getCause().getQualifiedName() + "#" + v.getCause().getSimpleName() + "\""); + Writer writer = new StringWriter(); + exporter.exportGraph(jgrapht, writer); + Files.writeString(Path.of("graph.dot"), writer.toString()); + } + + + private static void renderHrefGraph(Graph hrefGraph) throws IOException { + + DOTExporter exporter = new DOTExporter<>(v -> v); + exporter.setVertexAttributeProvider((v) -> { + Map map = new LinkedHashMap<>(); + map.put("label", DefaultAttribute.createAttribute(v.toString())); + return map; + }); + Writer writer = new StringWriter(); + exporter.exportGraph(hrefGraph, writer); + Files.writeString(Path.of("graph.dot"), writer.toString()); + System.out.println(writer.toString()); + } + */ +} diff --git a/visualization/src/main/java/HelloWorldExample.java b/visualization/src/main/java/HelloWorldExample.java new file mode 100644 index 00000000..4c24fb44 --- /dev/null +++ b/visualization/src/main/java/HelloWorldExample.java @@ -0,0 +1,258 @@ +import static org.neo4j.driver.Values.parameters; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.DependencyGraphSupplier; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.InputKind; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.ProjectParser; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Component; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Project; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Result; +import org.neo4j.driver.Session; + +public class HelloWorldExample implements AutoCloseable { + private final Driver driver; + + public HelloWorldExample(String uri, String user, String password) { + driver = GraphDatabase.driver(uri, AuthTokens.basic(user, password)); + } + + @Override + public void close() throws Exception { + driver.close(); + } + + public void printGreeting(final String message) { + try (Session session = driver.session()) { + String greeting = + session.writeTransaction( + tx -> { + Result result = + tx.run( + "CREATE (a:Greeting) " + + "SET a.message = $message " + + "RETURN a.message + ', from node ' + id(a)", + parameters("message", message)); + return result.single().get(0).asString(); + }); + + System.out.println(greeting); + } + } + + public void addSimulatorType() { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Masterarbeit/Projekte/mSimuLizar"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Masterarbeit/Projekte/mPCM_build"); + Project project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .parse(); + + try (Session session = driver.session()) { + session.writeTransaction( + tx -> { + tx.run("Match (a:Simulator) " + "Delete a"); + return "aaa"; + }); + var graph = + DependencyGraphSupplier.getTypeGraph( + project.getLanguage(), project.getSimulatorModel()); + graph.nodes().stream() + .filter( + v -> + project.getSimulatorModel() + .getTypeWithQualifiedName(v.getQualifiedName()) + != null) + .forEach( + node -> + session.writeTransaction( + tx -> { + Result result = + tx.run( + "CREATE (a:Simulator) " + + "SET a.name = $name " + + "SET a.tooltip = $tooltip" + + " RETURN a.name + ', from node ' + id(a)", + parameters( + "name", + node.getQualifiedName(), + "tooltip", + node.getQualifiedName())); + return result.single().get(0).asString(); + })); + graph.nodes().stream() + .filter( + v -> + project.getLanguage() + .getTypeWithQualifiedName(v.getQualifiedName()) + != null) + .forEach( + node -> + session.writeTransaction( + tx -> { + Result result = + tx.run( + "CREATE (a:Language) " + + "SET a.name = $name " + + "SET a.tooltip = $tooltip" + + " RETURN a.name + ', from node ' + id(a)", + parameters( + "name", + node.getQualifiedName(), + "tooltip", + node.getQualifiedName())); + return result.single().get(0).asString(); + })); + + graph.nodes().stream() + .filter( + v -> + project.getSimulatorModel() + .getTypeWithQualifiedName(v.getQualifiedName()) + != null) + .forEach( + node -> + graph.successors(node) + .forEach( + successor -> + session.writeTransaction( + tx -> { + Result result = + tx.run( + "MATCH (a:Simulator), (b:Language) " + + "WHERE a.name = $name AND b.name = $name2 " + + "CREATE (a)-[r:DEPENDS_ON]->(b) " + + "RETURN a.name + ', from node ' + id(a)", + parameters( + "name", + node + .getQualifiedName(), + "name2", + successor + .getQualifiedName())); + return ""; + }))); + } + } + + public void addSimulatorComponent() { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Masterarbeit/Projekte/mSimuLizar"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Masterarbeit/Projekte/mPCM_build"); + Project project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .parse(); + + try (Session session = driver.session()) { + session.writeTransaction( + tx -> { + tx.run("Match (a:Simulator) " + "Delete a"); + return "aaa"; + }); + var graph = + DependencyGraphSupplier.getComponentGraph( + project.getLanguage(), project.getSimulatorModel()); + Set foo = + graph.nodes().stream() + .filter(v -> !v.getTypes().isEmpty()) + .filter( + v -> + project.getSimulatorModel() + .getTypeWithQualifiedName( + v.getTypes() + .iterator() + .next() + .getQualifiedName()) + != null) + .collect(Collectors.toSet()); + foo.forEach( + node -> + session.writeTransaction( + tx -> { + Result result = + tx.run( + "CREATE (a:Simulator) " + + "SET a.name = $name " + + "SET a.tooltip = $tooltip" + + " RETURN a.name + ', from node ' + id(a)", + parameters( + "name", + node.getName(), + "tooltip", + node.getName())); + return result.single().get(0).asString(); + })); + graph.nodes().stream() + .filter(v -> !foo.contains(v)) + .forEach( + node -> + session.writeTransaction( + tx -> { + Result result = + tx.run( + "CREATE (a:Language) " + + "SET a.name = $name " + + "SET a.tooltip = $tooltip" + + " RETURN a.name + ', from node ' + id(a)", + parameters( + "name", + node.getName(), + "tooltip", + node.getName())); + return result.single().get(0).asString(); + })); + + graph.nodes().stream() + .forEach( + node -> + graph.successors(node) + .forEach( + successor -> + session.writeTransaction( + tx -> { + Result result = + tx.run( + "MATCH (a:Simulator), (b:Language) " + + "WHERE a.name = $name AND b.name = $name2 " + + "CREATE (a)-[r:DEPENDS_ON]->(b) " + + "RETURN a.name + ', from node ' + id(a)", + parameters( + "name", + node + .getName(), + "name2", + successor + .getName())); + return ""; + }))); + } + } + + public static void main(String... args) throws Exception { + try (HelloWorldExample greeter = + new HelloWorldExample("bolt://localhost:7687", "neo4j", "test")) { + // greeter.addSimulatorType(); + greeter.addSimulatorComponent(); + // greeter.printGreeting("hello, world"); + } + } +} From 6dd3de41d7882499626cd578851c2810247f5c96 Mon Sep 17 00:00:00 2001 From: Martin Wittlinger Date: Sun, 1 May 2022 22:45:13 +0200 Subject: [PATCH 2/4] add depednency cycle --- .../weakened_modularity/DependencyCycle.java | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/weakened_modularity/DependencyCycle.java diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/weakened_modularity/DependencyCycle.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/weakened_modularity/DependencyCycle.java new file mode 100644 index 00000000..ff11fe20 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/weakened_modularity/DependencyCycle.java @@ -0,0 +1,88 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.weakened_modularity; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.stream.Collectors; +import com.google.common.graph.Graph; +import com.google.common.graph.MutableNetwork; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.DependencyGraphSupplier; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Edge; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Relation; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.algorithm.CycleDetection; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.graphs.TypeGraphs; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypeMember; + +public class DependencyCycle extends AbstractAnalyzer { + + @Override + protected void checkSettings(Settings settings) { + } + + @Override + protected Report fullAnalysis(ModularLanguage language, SimulatorModel simulatorModel, + Settings settings) { + MutableNetwork, Edge, CtTypeMember>> graph = + DependencyGraphSupplier.getTypeGraph(language, simulatorModel); + TypeGraphs.removeLanguageNodes(language, graph); + TypeGraphs.removeNonProjectNodes(language, simulatorModel, graph); + Graph>> cycles = CycleDetection.findStronglyConnectedComponents(graph.asGraph()); + Set, CtTypeMember>>> result = new HashSet<>(); + cycles.nodes().stream().filter(v -> v.size() > 1).map(ArrayDeque::new).map(stack -> { + List, CtTypeMember>> cycle = new ArrayList<>(); + CtType firstElement = stack.peekFirst(); + Queue> types = stack; + while (!types.isEmpty()) { + CtType source = types.poll(); + CtType target = types.isEmpty() ? firstElement : types.peek(); + cycle.add(new Relation<>(source, target, getEdgeValues(graph, source, target))); + } + return cycle; + }).map(this::sort).forEach(result::add); + return null; + } + + private Set getEdgeValues(MutableNetwork> graph, T source, T target) { + return graph.edgesConnecting(source, target).stream().map(Edge::getCause) + .collect(Collectors.toSet()); + } + + private List> sort(List> dependencyEdges) { + if (dependencyEdges.size() < 2) { + return dependencyEdges; + } + List> edges = new ArrayList<>(); + ArrayDeque> availableEdges = new ArrayDeque<>(dependencyEdges); + Relation firstEdge = availableEdges.pollFirst(); + Relation currentEdge = firstEdge; + while (!availableEdges.isEmpty()) { + Relation successor = findSuccessor(availableEdges, currentEdge); + edges.add(currentEdge); + availableEdges.remove(currentEdge); + if (successor == null) { + return edges; + } + currentEdge = successor; + } + return edges; + } + + private Relation findSuccessor(Collection> edges, + Relation currentEdge) { + return edges.stream().filter(v -> isSuccessor(currentEdge, v)).findAny().orElse(null); + } + + private boolean isSuccessor(Relation currentEdge, Relation candidate) { + return candidate.getSource().equals(currentEdge.getTarget()); + } +} From 697e539faf2be1c6473ed2941a2e47c96d0e45b2 Mon Sep 17 00:00:00 2001 From: Martin Wittlinger Date: Tue, 10 May 2022 11:28:29 +0200 Subject: [PATCH 3/4] up --- .../WrongDependencyDirection.java | 42 ++++-- .../deficient_encapsulation/DataClumbs.java | 58 +++++--- .../degraded_modularity/FeatureScatter.java | 2 +- .../TypeLevelReportGeneration.java | 72 ++++++++++ .../DuplicateAbstraction.java | 16 ++- .../folded_hierarchy/FoldedHierarchy.java | 24 ++++ .../SwitchStatements.java | 21 ++- .../PrimitiveObession.java | 34 +++-- .../missing_modularity/LevelAnalyzer.java | 55 +++++++ .../missing_modularity/MissingModularity.java | 19 +++ .../TypeLevelReportGeneration.java | 31 ++++ .../rebellious_modularity/LanguageBlob.java | 27 +++- .../unexploited_Hierarchy/LevelAnalyzer.java | 108 ++++++++++++++ .../TypeLevelReportGeneration.java | 72 ++++++++++ .../UnexploitedHierarchy.java | 19 +++ .../SpeculativeGenerality.java | 10 +- .../weakened_modularity/DependencyCycle.java | 135 ++++++++++-------- .../refactorlizar/eval/SimulizarEval.java | 60 ++++++++ .../refactorlizar/eval/SmartGrid.java | 115 +++++++++++++++ 19 files changed, 786 insertions(+), 134 deletions(-) create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/TypeLevelReportGeneration.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/folded_hierarchy/FoldedHierarchy.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/LevelAnalyzer.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/MissingModularity.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/TypeLevelReportGeneration.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/LevelAnalyzer.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/TypeLevelReportGeneration.java create mode 100644 bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/UnexploitedHierarchy.java create mode 100644 bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/eval/SimulizarEval.java create mode 100644 bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/eval/SmartGrid.java diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/broken_modularity/WrongDependencyDirection.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/broken_modularity/WrongDependencyDirection.java index b406bc5e..80ecc155 100644 --- a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/broken_modularity/WrongDependencyDirection.java +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/broken_modularity/WrongDependencyDirection.java @@ -5,8 +5,10 @@ import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.List; import java.util.stream.Collectors; import spoon.reflect.declaration.CtType; +import spoon.reflect.reference.CtTypeReference; public class WrongDependencyDirection extends AbstractAnalyzer { @@ -16,24 +18,40 @@ protected void checkSettings(Settings settings) {} @Override protected Report fullAnalysis( ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { - var types = - language.getComponents().stream() - .flatMap(c -> c.getTypes().stream()) - .collect(Collectors.toList()); + var types = getLanguageTypes(language); + StringBuilder sb = new StringBuilder(); + int counter = 0; for (CtType ctType : types) { - var col = + List> col = ctType.getReferencedTypes().stream() .filter( v -> - simulatorModel.getTypeWithQualifiedName( - v.getQualifiedName()) - != null - && language.getTypeWithQualifiedName( - v.getQualifiedName()) - == null) + isSimulatorType(simulatorModel, v) + && isLanguageType(language, v)) .collect(Collectors.toList()); col.remove(ctType.getReference()); + for (CtTypeReference dependency : col) { + sb.append(ctType.getQualifiedName()) + .append(" -> ") + .append(dependency.getQualifiedName()) + .append("\n"); + counter++; + } } - return null; + return new Report("WrongDependencyDirection", sb.toString(), counter > 0); + } + + private boolean isLanguageType(ModularLanguage language, CtTypeReference v) { + return language.getTypeWithQualifiedName(v.getQualifiedName()) == null; + } + + private boolean isSimulatorType(SimulatorModel simulatorModel, CtTypeReference v) { + return simulatorModel.getTypeWithQualifiedName(v.getQualifiedName()) != null; + } + + private List> getLanguageTypes(ModularLanguage language) { + return language.getComponents().stream() + .flatMap(c -> c.getTypes().stream()) + .collect(Collectors.toList()); } } diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/DataClumbs.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/DataClumbs.java index 407394c7..0df7da12 100644 --- a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/DataClumbs.java +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/deficient_encapsulation/DataClumbs.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; @@ -37,7 +38,7 @@ protected void checkSettings(Settings settings) {} @Override protected Report fullAnalysis( ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { - HashMap>, Integer> map = new HashMap<>(); + Map>, Integer> map = new HashMap<>(); Set> types = getAllTypes(simulatorModel); for (CtType ctType : types) { for (CtMethod method : ctType.getMethods()) { @@ -48,11 +49,9 @@ protected Report fullAnalysis( // unwanted pairs like (a,a) and (b,b) are removed tuples.removeIf(v -> v.get(0).equals(v.get(1))); for (List> tuple : tuples) { - new ArrayList<>(tuple) - .sort( - ((o1, o2) -> - o1.getQualifiedName() - .compareTo(o2.getQualifiedName()))); + tuple = new ArrayList<>(tuple); + tuple.sort( + ((o1, o2) -> o1.getQualifiedName().compareTo(o2.getQualifiedName()))); if (map.containsKey(tuple)) { map.put(tuple, map.get(tuple) + 1); } else { @@ -66,26 +65,47 @@ protected Report fullAnalysis( map.keySet() .removeIf( v -> - !(language.getTypeWithQualifiedName(v.get(0).getQualifiedName()) - != null - || language.getTypeWithQualifiedName( - v.get(1).getQualifiedName()) - != null)); - var result = + !(isLanguageType(language, v.get(0).getQualifiedName()) + || isLanguageType(language, v.get(1).getQualifiedName()))); + List>, Integer>> result = map.entrySet().stream() .sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue())) .limit(20) .collect(Collectors.toList()); + + StringBuilder sb = new StringBuilder(); for (Entry>, Integer> entry : result) { - System.out.println( - entry.getKey().get(0).getQualifiedName() - + " " - + entry.getKey().get(1).getQualifiedName() + // resugar the report to be more readable + for (CtType type : types) { + for (CtMethod method : type.getMethods()) { + if (method.getParameters().stream() + .map(CtTypedElement::getType) + .collect(Collectors.toSet()) + .containsAll(entry.getKey())) { + sb.append( + method.getDeclaringType().getQualifiedName() + + "#" + + method.getSimpleName()) + .append("\n"); + } + } + } + sb.append("\n"); + sb.append( + entry.getKey().stream() + .map(CtTypeReference::getQualifiedName) + .collect(Collectors.joining(", ")) + " " - + entry.getValue()); - new Repair().repair(language, simulatorModel, entry.getKey()); + + entry.getValue() + + "\n"); + sb.append("\n"); + sb.append("\n"); } - return null; + return new Report(getName(), sb.toString(), sb.length() > 0); + } + + private boolean isLanguageType(ModularLanguage language, String fqName) { + return language.getTypeWithQualifiedName(fqName) != null; } private ArrayList>> createTuples(CtMethod method) { diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/FeatureScatter.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/FeatureScatter.java index 7ae635a6..c3c059d5 100644 --- a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/FeatureScatter.java +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/FeatureScatter.java @@ -29,7 +29,7 @@ protected Report fullAnalysis( TypeGraphs.removeEdgesWithoutLanguageTarget(language, graph); TypeGraphs.removeEdgesWithSimulatorAsTarget(graph, simulatorModel); removeNonScatter(graph, type -> JavaUtils.isLanguageType(language, type)); - return null; + return TypeLevelReportGeneration.generateReport(graph, simulatorModel, language); } private boolean hasOnePredecessor(MutableNetwork> graph, T type) { diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/TypeLevelReportGeneration.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/TypeLevelReportGeneration.java new file mode 100644 index 00000000..ff5a818b --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/degraded_modularity/TypeLevelReportGeneration.java @@ -0,0 +1,72 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.degraded_modularity; + +import static java.lang.String.format; + +import com.google.common.graph.MutableNetwork; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Edge; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.JavaUtils; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.Set; +import java.util.stream.Collectors; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypeMember; + +public class TypeLevelReportGeneration { + + public static Report generateReport( + MutableNetwork, Edge, CtTypeMember>> graph, + SimulatorModel model, + ModularLanguage language) { + long count = + graph.nodes().stream() + .filter(type -> JavaUtils.isLanguageType(language, type)) + .count(); + if (count == 0) { + return new Report("Feature Scatter Analyzer", "No feature scatter was found", false); + } + StringBuilder builder = new StringBuilder(); + builder.append(format("Found %d feature scatter \n", count)); + for (CtType target : graph.nodes()) { + if (JavaUtils.isLanguageType(language, target)) { + builder.append( + format( + "Language Type:\n%s\nis used by types:\n", + target.getQualifiedName())); + graph.predecessors(target).stream() + .forEach( + source -> + builder.append( + generateMemberUsage( + source, + graph.edgesConnecting(source, target)))); + } + } + return new Report("Feature Scatter Analyzer on type level", builder.toString(), true); + } + + private static String generateMemberUsage( + CtType target, Set, CtTypeMember>> causes) { + return format( + "\t%s at positions:\n %s\n\n", + target.getQualifiedName(), generatePositionStringMemberLevel(causes)); + } + + private static String generatePositionStringMemberLevel( + Set, CtTypeMember>> causes) { + return causes.stream() + .map(Edge::getCause) + .map( + member -> + "\t\t" + + member.getDeclaringType().getQualifiedName() + + "#" + + member.getSimpleName() + + " " + + (member.getPosition().isValidPosition() + ? member.getPosition().getLine() + : "ERROR")) + .collect(Collectors.joining("\n")); + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/duplicated_abstraction/DuplicateAbstraction.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/duplicated_abstraction/DuplicateAbstraction.java index 9f1b08b6..6f368410 100644 --- a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/duplicated_abstraction/DuplicateAbstraction.java +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/duplicated_abstraction/DuplicateAbstraction.java @@ -31,10 +31,10 @@ protected Report fullAnalysis( for (CtType origin : types) { for (CtType target : types) { for (CtMethod method : origin.getMethods()) { - if (target.getMethods().contains(method) && !origin.equals(target)) { - if (method.getBody() != null && !method.getBody().isImplicit()) { - clones.add(method); - } + if (target.getMethods().contains(method) + && isSameMethod(origin, target) + && isConcreteMethod(method)) { + clones.add(method); } } } @@ -50,4 +50,12 @@ protected Report fullAnalysis( } return new Report(title, description.toString(), true); } + + private boolean isSameMethod(CtType origin, CtType target) { + return !origin.equals(target); + } + + private boolean isConcreteMethod(CtMethod method) { + return method.getBody() != null && !method.getBody().isImplicit(); + } } diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/folded_hierarchy/FoldedHierarchy.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/folded_hierarchy/FoldedHierarchy.java new file mode 100644 index 00000000..409f6935 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/folded_hierarchy/FoldedHierarchy.java @@ -0,0 +1,24 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.folded_hierarchy; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; + +public class FoldedHierarchy extends AbstractAnalyzer { + + @Override + protected void checkSettings(Settings settings) {} + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + /** + * Hier ist das Problem das fehlende Layer für eine Klasse sich eigetnlich nur über die + * Vererbung feststellen lassen. Die Indentifikation ob eine Methode Layer A oder B ist, ist + * quasi unmöglich. + */ + return null; + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/incomplete_abstraction/SwitchStatements.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/incomplete_abstraction/SwitchStatements.java index f470ba0f..14981524 100644 --- a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/incomplete_abstraction/SwitchStatements.java +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/incomplete_abstraction/SwitchStatements.java @@ -12,16 +12,6 @@ public class SwitchStatements extends AbstractAnalyzer { - @Override - public String getDescription() { - return "null"; - } - - @Override - public String getName() { - return "null"; - } - @Override protected void checkSettings(Settings settings) {} @@ -35,8 +25,15 @@ protected Report fullAnalysis( .filter(m -> !m.getSelector().getReferencedTypes().isEmpty()) .filter(m -> extracted(language, m)) .collect(Collectors.toList()); - System.out.println(switches.size()); - return null; + StringBuilder sb = new StringBuilder(); + int counter = switches.size(); + for (CtSwitch ctSwitch : switches) { + sb.append(ctSwitch.getPosition().getCompilationUnit().getMainType().getQualifiedName()) + .append(" -> ") + .append(ctSwitch.getSelector()) + .append("\n"); + } + return new Report("SwitchStatements", sb.toString(), counter > 0); } private boolean extracted(ModularLanguage language, CtSwitch m) { diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/PrimitiveObession.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/PrimitiveObession.java index c9246681..8c0f5d9c 100644 --- a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/PrimitiveObession.java +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_abstraction/PrimitiveObession.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.stream.Collectors; import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtParameter; import spoon.reflect.declaration.CtType; public class PrimitiveObession extends AbstractAnalyzer { @@ -29,25 +30,28 @@ protected Report fullAnalysis( .collect(Collectors.toSet()); for (CtType ctType : types) { for (CtMethod method : ctType.getMethods()) { - if (method.getParameters().stream() - .filter( - v -> - v.getType() - .equals( - v.getFactory() - .Type() - .stringType()) - || v.getType().isPrimitive()) - .count() - > 1) { + if (hasPrimitiveParameter(method)) { methods.add(method); } } } - System.out.println(methods.size()); - for (CtMethod method : methods) { - System.out.println(method.getSignature()); + String title = String.format("%s methods with primitive parameters found", methods.size()); + StringBuilder description = new StringBuilder(); + for (CtMethod ctMethod : methods) { + description.append( + String.format( + "Method %s from type %s has primitive parameters", + ctMethod.getSignature(), + ctMethod.getDeclaringType().getQualifiedName())); } - return null; + return new Report(title, description.toString(), methods.size() > 0); + } + + private boolean hasPrimitiveParameter(CtMethod method) { + return method.getParameters().stream().filter(this::isPrimitiveType).count() > 1; + } + + private boolean isPrimitiveType(CtParameter v) { + return v.getType().equals(v.getFactory().Type().stringType()) || v.getType().isPrimitive(); } } diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/LevelAnalyzer.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/LevelAnalyzer.java new file mode 100644 index 00000000..b37f7b94 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/LevelAnalyzer.java @@ -0,0 +1,55 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.missing_modularity; + +import com.google.common.graph.MutableNetwork; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Components; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.DependencyGraphSupplier; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Edge; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.graphs.TypeGraphs; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Component; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypeMember; + +public class LevelAnalyzer { + private static final String UNKNOWN_LAYER_IDENTIFIER = "UNKNOWN"; + private ModularLanguage language; + private SimulatorModel model; + + public LevelAnalyzer(ModularLanguage language, SimulatorModel model) { + this.language = language; + this.model = model; + } + + public Report fullAnalysis() { + return findTypeImproperDependencyLayer(language, model); + } + + private Report findTypeImproperDependencyLayer(ModularLanguage language, SimulatorModel model) { + MutableNetwork, Edge, CtTypeMember>> graph = + DependencyGraphSupplier.getTypeGraph(language, model); + TypeGraphs.removeNonProjectNodes(language, model, graph); + removeNodesWithLayer( + graph, + (CtType v) -> + Components.findComponent(model, language, v) + .map(this::isNotUnknownLayer) + .orElse(true)); + return TypeLevelReportGeneration.generateReport(graph, model, language); + } + + private void removeNodesWithLayer( + MutableNetwork> graph, Predicate hasNoLayer) { + graph.nodes().stream() + .filter(hasNoLayer::test) + .collect(Collectors.toList()) + .forEach(graph::removeNode); + } + + private boolean isNotUnknownLayer(Component component) { + return !component.getLayer().equals(UNKNOWN_LAYER_IDENTIFIER); + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/MissingModularity.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/MissingModularity.java new file mode 100644 index 00000000..a3b6a436 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/MissingModularity.java @@ -0,0 +1,19 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.missing_modularity; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; + +public class MissingModularity extends AbstractAnalyzer { + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + return new LevelAnalyzer(language, simulatorModel).fullAnalysis(); + } + + @Override + protected void checkSettings(Settings settings) {} +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/TypeLevelReportGeneration.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/TypeLevelReportGeneration.java new file mode 100644 index 00000000..e181bada --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/missing_modularity/TypeLevelReportGeneration.java @@ -0,0 +1,31 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.missing_modularity; + +import com.google.common.graph.MutableNetwork; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Edge; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.JavaUtils; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypeMember; + +public class TypeLevelReportGeneration { + + public static Report generateReport( + MutableNetwork, Edge, CtTypeMember>> graph, + SimulatorModel model, + ModularLanguage language) { + int count = graph.edges().size(); + if (count == 0) { + return new Report( + "Dependency Layer Analyzer on type-level\n", "All types use layers", false); + } + StringBuilder description = new StringBuilder(); + description.append("There were " + count + " types not using layers found\n"); + graph.nodes().stream() + .filter(type -> JavaUtils.isSimulatorType(model, type)) + .forEach(v -> description.append(v.getQualifiedName() + " uses no layer\n")); + return new Report( + "Dependency layer Analyzer on type-level\n", description.toString(), true); + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/rebellious_modularity/LanguageBlob.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/rebellious_modularity/LanguageBlob.java index 9213820a..b1cc8be0 100644 --- a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/rebellious_modularity/LanguageBlob.java +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/rebellious_modularity/LanguageBlob.java @@ -27,10 +27,7 @@ protected void checkSettings(Settings settings) {} @Override protected Report fullAnalysis( ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { - Set> types = - simulatorModel.getComponents().stream() - .flatMap(v -> v.getTypes().stream()) - .collect(Collectors.toSet()); + Set> types = getAllTypes(simulatorModel); List, Map>>>> pairs = new ArrayList<>(); for (CtType ctType : types) { Set> references = new HashSet<>(ctType.getReferencedTypes()); @@ -54,6 +51,26 @@ protected Report fullAnalysis( pairs.add(Pair.of(ctType, map)); } } - return null; + String title = String.format("%s language blobs found", pairs.size()); + StringBuilder sb = new StringBuilder(); + for (Pair, Map>>> pair : pairs) { + sb.append( + String.format( + "Type %s produces a language blob%n", + pair.getLeft().getQualifiedName())); + sb.append( + String.format( + "\t%s%n", + pair.getRight().keySet().stream() + .map(Component::getName) + .collect(Collectors.joining(", ")))); + } + return new Report(title, sb.toString(), pairs.size() > 0); + } + + private Set> getAllTypes(SimulatorModel simulatorModel) { + return simulatorModel.getComponents().stream() + .flatMap(v -> v.getTypes().stream()) + .collect(Collectors.toSet()); } } diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/LevelAnalyzer.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/LevelAnalyzer.java new file mode 100644 index 00000000..558211d2 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/LevelAnalyzer.java @@ -0,0 +1,108 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.unexploited_Hierarchy; + +import com.google.common.graph.MutableNetwork; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Components; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.DependencyGraphSupplier; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Edge; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.JavaUtils; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.graphs.TypeGraphs; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Component; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypeMember; + +public class LevelAnalyzer { + private static final String UNKNOWN_LAYER_IDENTIFIER = "UNKNOWN"; + private ModularLanguage language; + private SimulatorModel model; + + public LevelAnalyzer(ModularLanguage language, SimulatorModel model) { + this.language = language; + this.model = model; + } + + public Report fullAnalysis() { + return findTypeImproperDependencyLayer(language, model); + } + + private Report findTypeImproperDependencyLayer(ModularLanguage language, SimulatorModel model) { + MutableNetwork, Edge, CtTypeMember>> graph = + DependencyGraphSupplier.getTypeGraph(language, model); + TypeGraphs.removeNonProjectNodes(language, model, graph); + removeNodesWithoutLayer( + graph, + (CtType v) -> + Components.findComponent(model, language, v) + .map(this::isUnknownLayer) + .orElse(true)); + removeProperLayerEdgesType(language, model, graph); + return TypeLevelReportGeneration.generateReport(graph, model, language); + } + + private void removeProperLayerEdgesType( + ModularLanguage language, + SimulatorModel model, + MutableNetwork, Edge, CtTypeMember>> graph) { + removeProperLayerEdges( + graph, + type -> JavaUtils.isSimulatorType(model, type), + type -> JavaUtils.isLanguageType(language, type), + (type) -> Components.findComponent(model, type), + (type) -> Components.findComponent(language, type)); + } + + private void removeProperLayerEdges( + MutableNetwork> graph, + Predicate isSimulator, + Predicate isLanguage, + Function> findSimulatorComponent, + Function> findLanguageComponent) { + Set> removableEdges = new HashSet<>(); + + for (T source : graph.nodes()) { + Optional sourceComponent = findSimulatorComponent.apply(source); + if (isLanguage.test(source) || sourceComponent.isEmpty()) { + continue; + } + for (T target : graph.successors(source)) { + Optional targetComponent = findLanguageComponent.apply(target); + if (isSimulator.test(target) || targetComponent.isEmpty()) { + removableEdges.addAll(graph.edgesConnecting(source, target)); + } else { + if (getLayer(sourceComponent).equals(getLayer(targetComponent))) { + removableEdges.addAll(graph.edgesConnecting(source, target)); + } + } + } + } + removableEdges.forEach(graph::removeEdge); + graph.nodes().stream() + .filter(v -> graph.degree(v) == 0) + .collect(Collectors.toSet()) + .forEach(graph::removeNode); + } + + private String getLayer(Optional sourceComponent) { + return sourceComponent.get().getLayer(); + } + + private void removeNodesWithoutLayer( + MutableNetwork> graph, Predicate hasNoLayer) { + graph.nodes().stream() + .filter(hasNoLayer::test) + .collect(Collectors.toList()) + .forEach(graph::removeNode); + } + + private boolean isUnknownLayer(Component component) { + return component.getLayer().equals(UNKNOWN_LAYER_IDENTIFIER); + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/TypeLevelReportGeneration.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/TypeLevelReportGeneration.java new file mode 100644 index 00000000..871f78ba --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/TypeLevelReportGeneration.java @@ -0,0 +1,72 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.unexploited_Hierarchy; + +import com.google.common.graph.MutableNetwork; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Components; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.Edge; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.JavaUtils; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.Set; +import java.util.stream.Collectors; +import spoon.reflect.declaration.CtType; +import spoon.reflect.declaration.CtTypeMember; + +public class TypeLevelReportGeneration { + + public static Report generateReport( + MutableNetwork, Edge, CtTypeMember>> graph, + SimulatorModel model, + ModularLanguage language) { + int count = graph.edges().size(); + if (count == 0) { + return new Report( + "Dependency Layer Analyzer on type-level\n", + "No dependency layer violation was found", + false); + } + StringBuilder description = new StringBuilder(); + description.append("There were " + count + " dependency layer violations found\n"); + graph.nodes().stream() + .filter(type -> JavaUtils.isSimulatorType(model, type)) + .forEach(type -> description.append(generateUsage(graph, type, model, language))); + return new Report( + "Dependency layer Analyzer on type-level\n", description.toString(), true); + } + + private static String generateUsage( + MutableNetwork, Edge, CtTypeMember>> graph, + CtType source, + SimulatorModel model, + ModularLanguage language) { + Set> successors = graph.successors(source); + StringBuilder violation = new StringBuilder(); + for (CtType target : successors) { + violation.append( + String.format( + "Simulator Type %s at layer %s uses%n\t the Language Type %s at layer %s in%n", + source.getQualifiedName(), + Components.findComponent(model, language, source) + .map(v -> v.getLayer()) + .orElse("ERROR"), + target.getQualifiedName(), + Components.findComponent(model, language, target) + .map(v -> v.getLayer()) + .orElse("ERROR"))); + violation.append(generateCause(graph.edgesConnecting(source, target))); + } + return violation.toString(); + } + + private static String generateCause(Set, CtTypeMember>> edgesConnecting) { + return edgesConnecting.stream() + .map(Edge::getCause) + .map( + v -> + "\t\t" + + v.getDeclaringType().getQualifiedName() + + "#" + + v.getSimpleName()) + .collect(Collectors.joining("\n")); + } +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/UnexploitedHierarchy.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/UnexploitedHierarchy.java new file mode 100644 index 00000000..6f440e41 --- /dev/null +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unexploited_Hierarchy/UnexploitedHierarchy.java @@ -0,0 +1,19 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.unexploited_Hierarchy; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.commons.Settings; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; + +public class UnexploitedHierarchy extends AbstractAnalyzer { + + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + return new LevelAnalyzer(language, simulatorModel).fullAnalysis(); + } + + @Override + protected void checkSettings(Settings settings) {} +} diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/SpeculativeGenerality.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/SpeculativeGenerality.java index 2504d37b..a2a9bd0c 100644 --- a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/SpeculativeGenerality.java +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/unused_abstraction/SpeculativeGenerality.java @@ -50,7 +50,6 @@ protected Report fullAnalysis( ctType.getElements(new FieldAccessFilter(field.getReference())); if (elements.isEmpty()) { removable.add(field); - System.out.println(ctType.getQualifiedName() + "#" + field.getSimpleName()); } } } @@ -63,13 +62,16 @@ protected Report fullAnalysis( && state.getMethod().equals(method) && state.checkCallState()) { removable.add(method); - System.out.println( - ctType.getQualifiedName() + "#" + method.getSimpleName()); } } } } } - return null; + String title = String.format("%s unused elements found", removable.size()); + StringBuilder description = new StringBuilder(); + for (CtElement ctElement : removable) { + description.append(ctElement.getPath() + "\n"); + } + return new Report(title, description.toString(), !removable.isEmpty()); } } diff --git a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/weakened_modularity/DependencyCycle.java b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/weakened_modularity/DependencyCycle.java index ff11fe20..e9cc95d1 100644 --- a/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/weakened_modularity/DependencyCycle.java +++ b/bad-smells-ma/src/main/java/edu/kit/kastel/sdq/case4lang/refactorlizar/analyzer/weakened_modularity/DependencyCycle.java @@ -1,13 +1,5 @@ package edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.weakened_modularity; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Queue; -import java.util.Set; -import java.util.stream.Collectors; import com.google.common.graph.Graph; import com.google.common.graph.MutableNetwork; import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.AbstractAnalyzer; @@ -20,69 +12,88 @@ import edu.kit.kastel.sdq.case4lang.refactorlizar.commons_analyzer.graphs.TypeGraphs; import edu.kit.kastel.sdq.case4lang.refactorlizar.model.ModularLanguage; import edu.kit.kastel.sdq.case4lang.refactorlizar.model.SimulatorModel; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.stream.Collectors; import spoon.reflect.declaration.CtType; import spoon.reflect.declaration.CtTypeMember; public class DependencyCycle extends AbstractAnalyzer { - @Override - protected void checkSettings(Settings settings) { - } + @Override + protected void checkSettings(Settings settings) {} - @Override - protected Report fullAnalysis(ModularLanguage language, SimulatorModel simulatorModel, - Settings settings) { - MutableNetwork, Edge, CtTypeMember>> graph = - DependencyGraphSupplier.getTypeGraph(language, simulatorModel); - TypeGraphs.removeLanguageNodes(language, graph); - TypeGraphs.removeNonProjectNodes(language, simulatorModel, graph); - Graph>> cycles = CycleDetection.findStronglyConnectedComponents(graph.asGraph()); - Set, CtTypeMember>>> result = new HashSet<>(); - cycles.nodes().stream().filter(v -> v.size() > 1).map(ArrayDeque::new).map(stack -> { - List, CtTypeMember>> cycle = new ArrayList<>(); - CtType firstElement = stack.peekFirst(); - Queue> types = stack; - while (!types.isEmpty()) { - CtType source = types.poll(); - CtType target = types.isEmpty() ? firstElement : types.peek(); - cycle.add(new Relation<>(source, target, getEdgeValues(graph, source, target))); - } - return cycle; - }).map(this::sort).forEach(result::add); - return null; - } - - private Set getEdgeValues(MutableNetwork> graph, T source, T target) { - return graph.edgesConnecting(source, target).stream().map(Edge::getCause) - .collect(Collectors.toSet()); - } + @Override + protected Report fullAnalysis( + ModularLanguage language, SimulatorModel simulatorModel, Settings settings) { + MutableNetwork, Edge, CtTypeMember>> graph = + DependencyGraphSupplier.getTypeGraph(language, simulatorModel); + TypeGraphs.removeLanguageNodes(language, graph); + TypeGraphs.removeNonProjectNodes(language, simulatorModel, graph); + Graph>> cycles = + CycleDetection.findStronglyConnectedComponents(graph.asGraph()); + Set, CtTypeMember>>> result = new HashSet<>(); + cycles.nodes().stream() + .filter(v -> v.size() > 1) + .map(ArrayDeque::new) + .map( + stack -> { + List, CtTypeMember>> cycle = new ArrayList<>(); + CtType firstElement = stack.peekFirst(); + Queue> types = stack; + while (!types.isEmpty()) { + CtType source = types.poll(); + CtType target = types.isEmpty() ? firstElement : types.peek(); + cycle.add( + new Relation<>( + source, + target, + getEdgeValues(graph, source, target))); + } + return cycle; + }) + .map(this::sort) + .forEach(result::add); + return null; + } - private List> sort(List> dependencyEdges) { - if (dependencyEdges.size() < 2) { - return dependencyEdges; + private Set getEdgeValues(MutableNetwork> graph, T source, T target) { + return graph.edgesConnecting(source, target).stream() + .map(Edge::getCause) + .collect(Collectors.toSet()); } - List> edges = new ArrayList<>(); - ArrayDeque> availableEdges = new ArrayDeque<>(dependencyEdges); - Relation firstEdge = availableEdges.pollFirst(); - Relation currentEdge = firstEdge; - while (!availableEdges.isEmpty()) { - Relation successor = findSuccessor(availableEdges, currentEdge); - edges.add(currentEdge); - availableEdges.remove(currentEdge); - if (successor == null) { + + private List> sort(List> dependencyEdges) { + if (dependencyEdges.size() < 2) { + return dependencyEdges; + } + List> edges = new ArrayList<>(); + ArrayDeque> availableEdges = new ArrayDeque<>(dependencyEdges); + Relation firstEdge = availableEdges.pollFirst(); + Relation currentEdge = firstEdge; + while (!availableEdges.isEmpty()) { + Relation successor = findSuccessor(availableEdges, currentEdge); + edges.add(currentEdge); + availableEdges.remove(currentEdge); + if (successor == null) { + return edges; + } + currentEdge = successor; + } return edges; - } - currentEdge = successor; } - return edges; - } - - private Relation findSuccessor(Collection> edges, - Relation currentEdge) { - return edges.stream().filter(v -> isSuccessor(currentEdge, v)).findAny().orElse(null); - } - private boolean isSuccessor(Relation currentEdge, Relation candidate) { - return candidate.getSource().equals(currentEdge.getTarget()); - } + private Relation findSuccessor( + Collection> edges, Relation currentEdge) { + return edges.stream().filter(v -> isSuccessor(currentEdge, v)).findAny().orElse(null); + } + + private boolean isSuccessor(Relation currentEdge, Relation candidate) { + return candidate.getSource().equals(currentEdge.getTarget()); + } } diff --git a/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/eval/SimulizarEval.java b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/eval/SimulizarEval.java new file mode 100644 index 00000000..41e5f06e --- /dev/null +++ b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/eval/SimulizarEval.java @@ -0,0 +1,60 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.eval; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.broken_modularity.WrongDependencyDirection; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.deficient_encapsulation.DataClumbs; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.InputKind; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.ProjectParser; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Project; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class SimulizarEval { + + private Project project; + + @BeforeEach + public void setUp() { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Masterarbeit/Projekte/mSimuLizar"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Masterarbeit/Projekte/mPCM_build"); + project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .parse(); + } + + @Test + void brokenModularity() { + Report report = + new WrongDependencyDirection() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new WrongDependencyDirection().getSettings()); + int a = 3; + } + + @Test + void deficient_encapsulation() throws IOException { + Report report = + new DataClumbs() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new DataClumbs().getSettings()); + Files.writeString(Path.of("deficient_encapsulation.md"), report.getDescription()); + int a = 3; + } +} diff --git a/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/eval/SmartGrid.java b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/eval/SmartGrid.java new file mode 100644 index 00000000..69e36bc0 --- /dev/null +++ b/bad-smells-ma/src/test/java/edu/kit/kastel/sdq/case4lang/refactorlizar/eval/SmartGrid.java @@ -0,0 +1,115 @@ +package edu.kit.kastel.sdq.case4lang.refactorlizar.eval; + +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.api.Report; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.broken_modularity.WrongDependencyDirection; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.deficient_encapsulation.DataClumbs; +import edu.kit.kastel.sdq.case4lang.refactorlizar.analyzer.degraded_modularity.FeatureScatter; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.InputKind; +import edu.kit.kastel.sdq.case4lang.refactorlizar.core.ProjectParser; +import edu.kit.kastel.sdq.case4lang.refactorlizar.model.Project; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mosim.refactorlizar.architecture.evaluation.Application; +import org.mosim.refactorlizar.architecture.evaluation.CalculationMode; +import org.mosim.refactorlizar.architecture.evaluation.Result; + +public class SmartGrid { + + private Project project; + + @BeforeEach + public void setUp() { + List simulatorPaths = new ArrayList<>(); + simulatorPaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Masterarbeit/Projekte/Smart-Grid-ICT-Resilience-Framework"); + List languagePaths = new ArrayList<>(); + languagePaths.add( + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Masterarbeit/Projekte/smartgridSprache"); + project = + new ProjectParser() + .setLanguageKind(InputKind.ECLIPSE_PLUGIN) + .setSimulatorKind(InputKind.ECLIPSE_PLUGIN) + .addLanguagePaths(languagePaths) + .addSimulatorPaths(simulatorPaths) + .parse(); + } + + @Test + void brokenModularity() { + Report report = + new WrongDependencyDirection() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new WrongDependencyDirection().getSettings()); + int a = 3; + } + + @Test + void deficient_encapsulation() throws IOException { + Report report = + new DataClumbs() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new DataClumbs().getSettings()); + Files.writeString(Path.of("deficient_encapsulation.md"), report.getDescription()); + int a = 3; + } + + @Test + void deficient_encapsulation_repair() throws IOException { + Report report = + new DataClumbs() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new DataClumbs().getSettings()); + int a = 3; + } + + @Test + void degraded_modularity() throws IOException { + Report report = + new FeatureScatter() + .analyze( + project.getLanguage(), + project.getSimulatorModel(), + new FeatureScatter().getSettings()); + Files.writeString(Path.of("degraded_modularity.md"), report.getDescription()); + int a = 3; + } + + @Test + void evaluateScenario() { + String badSmell = "deficient_encapsulation"; + String scenarioNumber = "01"; + boolean isBefore = false; + String path = + "C:/Users/Martin Wittlinger/OneDrive - bwedu/Uni zeugs/Masterarbeit/Projekte/eval/smartGrid/" + + badSmell + + "/" + + "scenario_" + + scenarioNumber; + if (isBefore) { + path += "/before"; + } else { + path += "/after"; + } + Result result = new Application().evaluate(CalculationMode.ONE_OFFSET, path); + int a = 3; + System.out.println("Complexity " + result.getComplexity().getValue()); + System.out.println("Cohesion " + result.getCohesion().getValue()); + System.out.println("Coupling " + result.getCoupling().getValue()); + /* + Complexity 1017.1144465032035 + Cohesion 0.04705423753984772 + Coupling 132.38525082876478 + */ + } +} From 95d2e2fb0f0a3617bfe355c20bb33f3c8ab82ecc Mon Sep 17 00:00:00 2001 From: Sandro Date: Thu, 2 Feb 2023 09:02:02 +0100 Subject: [PATCH 4/4] docs(rm): add readme --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..c89ff76e --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# RefactorLizar +The RefactorLizar project is a library for analyzing and refactoring model-based analyses. + + +## Contributing +### Pull Requests +Each pull request title follows the format: +`(): ` +#### Type +Must be one of the following: + +feat: A new feature +fix: A bug fix +docs: Documentation only changes +style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) +refactor: A code change that neither fixes a bug nor adds a feature +perf: A code change that improves performance +test: Adding missing or correcting existing tests +chore: Changes to the build process or auxiliary tools and libraries such as documentation generation + +[from] (https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits) \ No newline at end of file