diff --git a/src/main/java/org/ml_methods_group/algorithm/AKMeans.java b/src/main/java/org/ml_methods_group/algorithm/AKMeans.java index 67c50597..105ef624 100755 --- a/src/main/java/org/ml_methods_group/algorithm/AKMeans.java +++ b/src/main/java/org/ml_methods_group/algorithm/AKMeans.java @@ -109,7 +109,7 @@ protected List calculateRefactorings(ExecutionContext context, bool .filter(e -> enableFieldRefactorings || !e.isField()) .map(e -> new Refactoring(e.getName(), dominant.getKey(), getDensityBasedAccuracyRating(dominant.getValue(), community.size()) * ACCURACY, - e.isField())) + e.isField(), e.getElement())) .forEach(refactorings::add); } return refactorings; diff --git a/src/main/java/org/ml_methods_group/algorithm/ARI.java b/src/main/java/org/ml_methods_group/algorithm/ARI.java index 576d3003..4a45eee7 100755 --- a/src/main/java/org/ml_methods_group/algorithm/ARI.java +++ b/src/main/java/org/ml_methods_group/algorithm/ARI.java @@ -84,7 +84,7 @@ private List findRefactoring(Entity entity, List accum if (!targetClassName.equals(entity.getClassName())) { accumulator.add(new Refactoring(entity.getName(), targetClassName, AlgorithmsUtil.getGapBasedAccuracyRating(minDistance, difference) * ACCURACY, - entity.isField())); + entity.isField(), entity.getElement())); } return accumulator; } diff --git a/src/main/java/org/ml_methods_group/algorithm/CCDA.java b/src/main/java/org/ml_methods_group/algorithm/CCDA.java index 6b6ec0a2..dee31df4 100755 --- a/src/main/java/org/ml_methods_group/algorithm/CCDA.java +++ b/src/main/java/org/ml_methods_group/algorithm/CCDA.java @@ -146,7 +146,7 @@ protected List calculateRefactorings(ExecutionContext context, bool if (enableFieldRefactorings || !entry.getKey().isField()) { return new Refactoring(entry.getKey().getName(), entry.getValue(), AlgorithmsUtil.getDensityBasedAccuracyRating(dominant, size) * ACCURACY, - entry.getKey().isField()); + entry.getKey().isField(), entry.getKey().getElement()); } else { return null; } diff --git a/src/main/java/org/ml_methods_group/algorithm/HAC.java b/src/main/java/org/ml_methods_group/algorithm/HAC.java index 7c9dcae9..cea23c8c 100755 --- a/src/main/java/org/ml_methods_group/algorithm/HAC.java +++ b/src/main/java/org/ml_methods_group/algorithm/HAC.java @@ -110,7 +110,7 @@ protected List calculateRefactorings(ExecutionContext context, bool if (enableFieldRefactorings || !entity.isField()) { refactorings.add(new Refactoring(entity.getName(), className, getDensityBasedAccuracyRating(dominantClass.getValue(), entitiesCount) * ACCURACY, - entity.isField())); + entity.isField(), entity.getElement())); } } } diff --git a/src/main/java/org/ml_methods_group/algorithm/MRI.java b/src/main/java/org/ml_methods_group/algorithm/MRI.java index 984cde17..40128514 100755 --- a/src/main/java/org/ml_methods_group/algorithm/MRI.java +++ b/src/main/java/org/ml_methods_group/algorithm/MRI.java @@ -82,7 +82,7 @@ protected List calculateRefactorings(ExecutionContext context, bool processMethod(refactorings, currentEntity, nearestClass, accuracyRating); } else { refactorings.add(new Refactoring(currentEntity.getName(), nearestClass.getName(), accuracyRating, - currentEntity.isField())); + currentEntity.isField(), currentEntity.getElement())); } } @@ -119,7 +119,7 @@ private Holder min(Holder first, Holder second) { private void processMethod(List refactorings, Entity method, ClassEntity target, double accuracy) { if (method.isMovable()) { final ClassEntity containingClass = classesByName.get(method.getClassName()); - refactorings.add(new Refactoring(method.getName(), target.getName(), accuracy, false)); + refactorings.add(new Refactoring(method.getName(), target.getName(), accuracy, false, method.getElement())); containingClass.removeFromClass(method.getName()); target.addToClass(method.getName()); } diff --git a/src/main/java/org/ml_methods_group/algorithm/Refactoring.java b/src/main/java/org/ml_methods_group/algorithm/Refactoring.java index 9ee0ea1b..7967ae35 100644 --- a/src/main/java/org/ml_methods_group/algorithm/Refactoring.java +++ b/src/main/java/org/ml_methods_group/algorithm/Refactoring.java @@ -16,6 +16,7 @@ package org.ml_methods_group.algorithm; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; public class Refactoring { @@ -24,6 +25,12 @@ public class Refactoring { private final double accuracy; private final boolean isUnitField; + public PsiElement getElement() { + return element; + } + + private PsiElement element; + public Refactoring(@NotNull String unit, @NotNull String target, double accuracy, boolean isUnitField) { this.unit = unit; this.target = target; @@ -31,6 +38,14 @@ public Refactoring(@NotNull String unit, @NotNull String target, double accuracy this.isUnitField = isUnitField; } + public Refactoring(@NotNull String unit, @NotNull String target, double accuracy, boolean isUnitField, PsiElement element) { + this.unit = unit; + this.target = target; + this.accuracy = accuracy; + this.isUnitField = isUnitField; + this.element = element; + } + public String getUnit() { return unit; } diff --git a/src/main/java/org/ml_methods_group/algorithm/entity/Entity.java b/src/main/java/org/ml_methods_group/algorithm/entity/Entity.java index afa2eb8b..3bff6e01 100644 --- a/src/main/java/org/ml_methods_group/algorithm/entity/Entity.java +++ b/src/main/java/org/ml_methods_group/algorithm/entity/Entity.java @@ -54,15 +54,23 @@ public abstract class Entity { private final RelevantProperties relevantProperties; private final String name; + + public PsiElement getElement() { + return element; + } + + private PsiElement element; private double[] vector; protected boolean isMovable = true; public Entity(PsiElement element) { + this.element = element; this.name = PsiSearchUtil.getHumanReadableName(element); relevantProperties = new RelevantProperties(); } protected Entity(Entity original) { + this.element = original.element; relevantProperties = original.relevantProperties.copy(); name = original.name; vector = Arrays.copyOf(original.vector, original.vector.length); diff --git a/src/main/java/org/ml_methods_group/config/Logging.java b/src/main/java/org/ml_methods_group/config/Logging.java index 2ef48222..3f182e83 100644 --- a/src/main/java/org/ml_methods_group/config/Logging.java +++ b/src/main/java/org/ml_methods_group/config/Logging.java @@ -16,10 +16,9 @@ package org.ml_methods_group.config; -import org.apache.log4j.ConsoleAppender; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; -import org.apache.log4j.PatternLayout; +import org.apache.log4j.*; + +import java.io.IOException; public class Logging { public static Logger getLogger(Class aClass) { @@ -28,4 +27,11 @@ public static Logger getLogger(Class aClass) { logger.addAppender(new ConsoleAppender(new PatternLayout("%p [%c.%M] - %m%n"))); return logger; } + + public static Logger getRefactoringLogger(Class aClass) throws IOException { + final Logger logger = Logger.getLogger(aClass.getName() + "-refactoring"); + logger.setLevel(Level.INFO); + logger.addAppender(new FileAppender(new PatternLayout("%p [%c.%M] - %m%n"), "~/ArchitectureReloaded/log/refactorings.log", true)); + return logger; + } } diff --git a/src/main/java/org/ml_methods_group/refactoring/RefactorIntentionAction.java b/src/main/java/org/ml_methods_group/refactoring/RefactorIntentionAction.java index 405f6dbd..68583118 100755 --- a/src/main/java/org/ml_methods_group/refactoring/RefactorIntentionAction.java +++ b/src/main/java/org/ml_methods_group/refactoring/RefactorIntentionAction.java @@ -22,6 +22,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.Nls; @@ -40,6 +41,11 @@ public class RefactorIntentionAction extends BaseIntentionAction { this.refactoring = new Refactoring(unit, to, 0, false); } + RefactorIntentionAction(String unit, String to, AnalysisScope scope, PsiElement element) { + this.scope = scope; + this.refactoring = new Refactoring(unit, to, 0, false, element); + } + @NotNull @Override public String getText() { diff --git a/src/main/java/org/ml_methods_group/refactoring/RefactoringAnnotator.java b/src/main/java/org/ml_methods_group/refactoring/RefactoringAnnotator.java index 4166dada..a621891f 100644 --- a/src/main/java/org/ml_methods_group/refactoring/RefactoringAnnotator.java +++ b/src/main/java/org/ml_methods_group/refactoring/RefactoringAnnotator.java @@ -66,7 +66,7 @@ private static void setAnnotations(@NotNull PsiElement element, String.format("Can be moved to %s (%s)", refactorings.get(name), algorithmName)); - annotation.registerFix(new RefactorIntentionAction(name, refactorings.get(name), scope)); + annotation.registerFix(new RefactorIntentionAction(name, refactorings.get(name), scope, element)); } } diff --git a/src/main/java/org/ml_methods_group/ui/ClassRefactoringPanel.java b/src/main/java/org/ml_methods_group/ui/ClassRefactoringPanel.java index dba14892..e67ab884 100755 --- a/src/main/java/org/ml_methods_group/ui/ClassRefactoringPanel.java +++ b/src/main/java/org/ml_methods_group/ui/ClassRefactoringPanel.java @@ -17,12 +17,15 @@ package org.ml_methods_group.ui; import com.intellij.analysis.AnalysisScope; +import com.intellij.psi.*; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.TableSpeedSearch; import com.intellij.ui.components.JBPanel; import com.intellij.ui.table.JBTable; +import org.apache.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.ml_methods_group.algorithm.Refactoring; +import org.ml_methods_group.config.Logging; import org.ml_methods_group.utils.ArchitectureReloadedBundle; import org.ml_methods_group.utils.ExportResultsUtil; import org.ml_methods_group.utils.PsiSearchUtil; @@ -34,8 +37,12 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; import static javax.swing.ListSelectionModel.SINGLE_SELECTION; @@ -65,6 +72,14 @@ class ClassRefactoringPanel extends JPanel { private final Map warnings; private boolean isFieldDisabled; private final List refactorings; + private Logger logger; + { + try { + logger = Logging.getRefactoringLogger(ClassRefactoringPanel.class); + } catch (IOException e) { + e.printStackTrace(); + } + } ClassRefactoringPanel(List refactorings, @NotNull AnalysisScope scope) { this.scope = scope; @@ -166,11 +181,87 @@ private JComponent createButtonsPanel() { return panel; } + private static int countLines(String str){ + String[] lines = str.split("\r\n|\r|\n"); + return lines.length; + } + private void refactorSelected() { doRefactorButton.setEnabled(false); selectAllButton.setEnabled(false); table.setEnabled(false); final List refactorings = model.pullSelected(); + for (Refactoring refactoring : refactorings) { + logger.info("-------"); + logger.info(refactoring.toString()); + logger.info("Is field - " + refactoring.isUnitField()); + if (!refactoring.isUnitField()) { + PsiMethod psiMethod = (PsiMethod) refactoring.getElement(); + String name = psiMethod.getName(); + PsiStatement[] statements = Objects.requireNonNull(psiMethod.getBody()).getStatements(); + int numberOfStatements = 0; + final int numberOfAsserts[] = new int[1]; + final int numberOfLoops[] = new int[1]; + final int numberOfLocalVariables[] = new int[1]; + for (PsiStatement statement : statements){ + statement.accept(new JavaRecursiveElementVisitor() { + + @Override + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + numberOfLocalVariables[0]++; + } + + @Override + public void visitDoWhileStatement(PsiDoWhileStatement statement) { + super.visitDoWhileStatement(statement); + numberOfLoops[0]++; + } + + @Override + public void visitForStatement(PsiForStatement statement) { + super.visitForStatement(statement); + numberOfLoops[0]++; + } + + @Override + public void visitForeachStatement(PsiForeachStatement statement) { + super.visitForeachStatement(statement); + numberOfLoops[0]++; + } + + @Override + public void visitWhileStatement(PsiWhileStatement statement) { + super.visitWhileStatement(statement); + numberOfLoops[0]++; + } + + @Override + public void visitAssertStatement(PsiAssertStatement statement) { + super.visitAssertStatement(statement); + numberOfAsserts[0]++; + } + + + }); + numberOfStatements += countLines(statement.getText().replaceAll("(?m)^[ \t]*\r?\n", "")); + } + logger.info("Number of local variables = " + numberOfLocalVariables[0]); + logger.info("Number of loops = " + numberOfLoops[0]); + logger.info("Number of asserts = " + numberOfAsserts[0]); + logger.info("Number of lines = " + numberOfStatements); + logger.info("Is static = " + psiMethod.getModifierList().hasExplicitModifier("static")); + logger.info("Is private = " + psiMethod.getModifierList().hasExplicitModifier("private")); + logger.info("Number of parameters = " + psiMethod.getParameterList().getParametersCount()); + logger.info("Return type = " + psiMethod.getReturnType()); + logger.info("Is constructor = " + psiMethod.isConstructor()); + logger.info("Throws an exception = " + (psiMethod.getThrowsList().getReferencedTypes().length != 0)); + logger.info("Method's name is (" + name + ") length = " + name.length()); + } + DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + Date date = new Date(); + logger.info(dateFormat.format(date)); + } RefactoringUtil.moveRefactoring(refactorings, scope, model); table.setEnabled(true); doRefactorButton.setEnabled(true); diff --git a/src/main/java/org/ml_methods_group/utils/RefactoringUtil.java b/src/main/java/org/ml_methods_group/utils/RefactoringUtil.java index 45057dcb..1b813cbd 100755 --- a/src/main/java/org/ml_methods_group/utils/RefactoringUtil.java +++ b/src/main/java/org/ml_methods_group/utils/RefactoringUtil.java @@ -35,7 +35,9 @@ import java.util.*; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -50,6 +52,7 @@ public final class RefactoringUtil { private static class CachedMember { public final PsiMember member; public final String oldName; + public CachedMember(@NotNull PsiMember member, @NotNull String oldName) { this.member = member; this.oldName = oldName; @@ -90,7 +93,7 @@ public static void moveRefactoring(@NotNull List refactorings, } private static Set moveMembersRefactoring(Collection elements, PsiClass targetClass, - AnalysisScope scope) { + AnalysisScope scope) { final Map> groupByCurrentClass = elements.stream() .collect(groupingBy((CachedMember cm) -> cm.member.getContainingClass(), Collectors.toSet())); @@ -276,13 +279,21 @@ public static List combine(Collection> refactorin .collect(Collectors.toList()); } + public static Predicate distinctByKey(Function keyExtractor) { + Set seen = ConcurrentHashMap.newKeySet(); + return t -> seen.add(keyExtractor.apply(t)); + } + private static Refactoring combine(List refactorings, String unit, int algorithmsCount) { boolean isUnitField = refactorings.get(0).isUnitField(); final Map target = refactorings.stream() .collect(Collectors.toMap(Refactoring::getTarget, RefactoringUtil::getSquaredAccuarcy, Double::sum)); + final Map element = refactorings.stream() + .filter(distinctByKey(Refactoring::getTarget)) + .collect(Collectors.toMap(Refactoring::getTarget, Refactoring::getElement)); return target.entrySet().stream() .max(Entry.comparingByValue()) - .map(entry -> new Refactoring(unit, entry.getKey(), Math.sqrt(entry.getValue() / algorithmsCount), isUnitField)) + .map(entry -> new Refactoring(unit, entry.getKey(), Math.sqrt(entry.getValue() / algorithmsCount), isUnitField, element.get(entry.getKey()))) .orElse(null); }