diff --git a/MetricsReloaded.ipr b/MetricsReloaded.ipr
index 34610f3..43ab6b0 100644
--- a/MetricsReloaded.ipr
+++ b/MetricsReloaded.ipr
@@ -55,7 +55,6 @@
-
@@ -71,11 +70,6 @@
-
-
-
-
-
@@ -97,9 +91,6 @@
-
-
-
@@ -288,8 +279,6 @@
-
-
@@ -487,7 +476,7 @@
http://www.w3.org/1999/xhtml
-
+
diff --git a/src/META-INF/plugin.xml b/src/META-INF/plugin.xml
index 5055230..1238fe5 100644
--- a/src/META-INF/plugin.xml
+++ b/src/META-INF/plugin.xml
@@ -60,6 +60,7 @@
+
@@ -68,7 +69,7 @@
-
" + names.get(e) + "\n");
+ }
+ clusterization.append("\n");
+ }
+
+ int moveMethodTotal = 0;
+ int createClassTotal = 0;
+ int removeClassTotal = 0;
+
+ for (PsiClass cl : classes) {
+ if (clusters.get(cl).isEmpty()) {
+ removeClass.append("Remove class: " + names.get(cl) + "\n");
+ removeClassTotal++;
+ }
+ for (PsiMethod el : clusters.get(cl)) {
+ if (!cl.equals(el.getContainingClass())) {
+ moveMethod.append("Move method " + names.get(el) + " to class " + names.get(cl) + "\n");
+ moveMethodTotal++;
+ }
+ }
+ }
+ for (PsiElement el : newClusters) {
+ createClass.append("Create new class for " + names.get(el) + "\n");
+ createClassTotal++;
+ for (PsiMethod m : clusters.get(el)) {
+ moveMethod.append("Move method " + names.get(m) + " to class " + names.get(el) + "\n");
+ moveMethodTotal++;
+ }
+ }
+
+ statistic.append("Move Method count: " + moveMethodTotal + "\n");
+ statistic.append("Create Class count: " + createClassTotal + "\n");
+ statistic.append("Remove Class count: " + removeClassTotal + "\n");
+ statistic.append("Method Count: " + methods.size() + "\n");
+ statistic.append("ClassCount: " + classes.size() + "\n");
+
+ ArrayList els = new ArrayList(names.keySet());
+ ArrayList n = new ArrayList();
+ HashMap> dist = new HashMap>();
+ for (PsiElement el1 : els) {
+ ArrayList tmp = new ArrayList();
+ n.add(names.get(el1));
+ for (PsiElement el2 : els) {
+ double diffConstant = calculateDiffKoef(
+ features.get(el1),
+ features.get(el2)
+ );
+ if (diffConstant == 0) {
+ tmp.add(-1.0);
+ continue;
+ }
+ tmp.add(calculateDistance(metricsVectors.get(el1),
+ metricsVectors.get(el2), diffConstant));
+ }
+ dist.put(names.get(el1), tmp);
+ }
+
+ ServiceManager.getService(project, RefactorRequestGUI.class).show(
+ new RefactorRequestResults(
+ clusterization.toString(),
+ moveMethod.toString(),
+ createClass.toString(),
+ removeClass.toString(),
+ statistic.toString(),
+ n,
+ dist)
+ );
+ }
+ }.execute(profile, metricsRun);
+ }
+
+ private double calculateDistance(List d1, List d2, double diffConstant) {
+ double preanswer = INF - diffConstant;
+ double sum = 0.0;
+ for (int i = 0; i < d1.size(); i++) {
+ sum = sum + (d1.get(i) - d2.get(i)) * (d1.get(i) - d2.get(i));
+ }
+ return Math.sqrt((preanswer + sum)/(d1.size()));
+ }
+
+ private double calculateDiffKoef(Set features1, Set features2) {
+ Set intersection = new HashSet(features1);
+ intersection.retainAll(features2);
+ Set union = new HashSet(features1);
+ union.addAll(features2);
+ return (double)intersection.size() / (double)union.size();
+ }
+
+ private Set calculateFeatures(PsiClass psiClass) {
+ HashSet result = new HashSet();
+ result.add(psiClass);
+ Collections.addAll(result, psiClass.getMethods());
+ Collections.addAll(result, psiClass.getFields());
+ HashSet tmp = new HashSet();
+ Collections.addAll(tmp, psiClass.getSupers());
+ Collections.addAll(tmp, psiClass.getInterfaces());
+ tmp.retainAll(ProjectContainerUtil.getClasses());
+ result.addAll(tmp);
+ return result;
+ }
+
+ private Set calculateFeatures(PsiMethod psiMethod, List additionalFeatures) {
+ HashSet result = new HashSet(additionalFeatures);
+ HashSet methods = new HashSet();
+ HashSet fields = new HashSet();
+ methods.add(psiMethod);
+ Collections.addAll(methods, psiMethod.findSuperMethods());
+ if (psiMethod.getBody() != null) {
+ recursiveFeatureGetter(psiMethod.getBody(), methods, fields);
+ }
+ result.add(psiMethod.getContainingClass());
+ methods.retainAll(ProjectContainerUtil.getMethods());
+ result.addAll(methods);
+ result.addAll(fields);
+ return result;
+ }
+
+ private void recursiveFeatureGetter(PsiElement element, Set methods, Set fields) {
+ if (element != null) {
+ for (PsiElement el : element.getChildren()) {
+ if (el instanceof PsiReference) {
+ PsiElement e = ((PsiReference) el).resolve();
+ if (e == null) {
+ continue;
+ }
+ if (e instanceof PsiMethod) {
+ methods.add(e);
+ }
+ if (e instanceof PsiField) {
+ fields.add(e);
+ }
+ } else {
+ recursiveFeatureGetter(el, methods, fields);
+ }
+ }
+ }
+ }
+
+ public class RefactorRequestResults {
+ private String clusterization;
+ private String moveMethods;
+ private String createClass;
+ private String removeClass;
+ private String statistics;
+ private ArrayList elementNames;
+ private HashMap> distancies;
+
+ public RefactorRequestResults(
+ String clusterization,
+ String moveMethods,
+ String createClass,
+ String removeClass,
+ String statistics,
+ ArrayList elementNames,
+ HashMap> distancies) {
+ this.clusterization = clusterization;
+ this.moveMethods = moveMethods;
+ this.createClass = createClass;
+ this.removeClass = removeClass;
+ this.statistics = statistics;
+ this.elementNames = elementNames;
+ this.distancies = distancies;
+ }
+
+ public String getClusterization() {
+ return clusterization;
+ }
+
+ public String getStatistic() {
+ return statistics;
+ }
+
+ public String getMoveMethods() {
+ return moveMethods;
+ }
+
+ public String getCreateClass() {
+ return createClass;
+ }
+
+ public String getRemoveClass() {
+ return removeClass;
+ }
+
+ public ArrayList getElementsNames() {
+ return elementNames;
+ }
+
+ public HashMap> getDistancies() {
+ return distancies;
+ }
+ }
+}
diff --git a/src/com/sixrr/metrics/plugin/RefactorRequestGUI.java b/src/com/sixrr/metrics/plugin/RefactorRequestGUI.java
new file mode 100644
index 0000000..f5381ca
--- /dev/null
+++ b/src/com/sixrr/metrics/plugin/RefactorRequestGUI.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.metrics.plugin;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowAnchor;
+import com.intellij.openapi.wm.ToolWindowManager;
+import com.intellij.ui.components.JBScrollPane;
+import com.intellij.ui.components.JBTabbedPane;
+import com.intellij.ui.content.Content;
+import org.picocontainer.Disposable;
+
+import javax.swing.*;
+import javax.swing.text.JTextComponent;
+
+import java.awt.*;
+
+import static com.intellij.remoteServer.impl.runtime.ui.DefaultServersToolWindowManager.WINDOW_ID;
+
+public class RefactorRequestGUI implements Disposable{
+ private Project project;
+ private ToolWindow myToolWindow = null;
+ private JTabbedPane component;
+ private JTextComponent clusterizationText;
+ private JTextComponent statisticText;
+ private JTextComponent moveMethodText;
+ private JTextComponent classChangeText;
+ private JPanel distanciesPanel;
+
+ private RefactorRequestGUI(Project project) {
+ this.project = project;
+ register();
+ createGUI();
+ }
+
+ private void register() {
+ final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
+ myToolWindow = toolWindowManager.registerToolWindow(WINDOW_ID, true, ToolWindowAnchor.BOTTOM);
+ myToolWindow.setTitle("Refactor analyze results");
+ myToolWindow.setAvailable(false, null);
+ }
+
+ private void createGUI() {
+ component = new JBTabbedPane();
+ JPanel panel;
+ JScrollPane pane;
+ //clusterization
+ panel = new JPanel(new GridLayout(1, 1));
+ clusterizationText = new JTextPane();
+ clusterizationText.setEditable(false);
+ pane = new JBScrollPane(clusterizationText);
+ panel.add(pane);
+ component.addTab("Разбиение на классы", panel);
+ //move method actions
+ panel = new JPanel(new GridLayout(1, 1));
+ moveMethodText = new JTextPane();
+ moveMethodText.setEditable(false);
+ pane = new JBScrollPane(moveMethodText);
+ panel.add(pane);
+ component.addTab("Перемещение методов", panel);
+ //change class actions
+ panel = new JPanel(new GridLayout(1, 1));
+ classChangeText = new JTextPane();
+ classChangeText.setEditable(false);
+ pane = new JBScrollPane(classChangeText);
+ panel.add(pane);
+ component.addTab("Создание и удаление классов", panel);
+ //statistic
+ panel = new JPanel(new GridLayout(1, 1));
+ statisticText = new JTextPane();
+ statisticText.setEditable(false);
+ pane = new JBScrollPane(statisticText);
+ panel.add(pane);
+ component.addTab("Статистика", panel);
+ //dist
+ panel = new JPanel(new GridLayout(1, 1));
+ distanciesPanel = new JPanel();
+ pane = new JBScrollPane(distanciesPanel);
+ panel.add(pane);
+ component.addTab("Функция расстояния", panel);
+ /*distanciesPanel = new JPanel(new GridLayout(1, 1));
+ component.addTab("Функция расстояния", distanciesPanel);*/
+
+ final Content content = myToolWindow.getContentManager().getFactory()
+ .createContent(component, "Refactor analyze results", true);
+ myToolWindow.getContentManager().addContent(content);
+ }
+
+ public void show(RefactorRequestAction.RefactorRequestResults results) {
+ myToolWindow.setTitle("Refactor analyze results");
+ myToolWindow.setAvailable(true, null);
+ clusterizationText.setText(results.getClusterization());
+ moveMethodText.setText(results.getMoveMethods());
+ classChangeText.setText(results.getCreateClass() + "\n" + results.getRemoveClass());
+ statisticText.setText(results.getStatistic());
+
+ distanciesPanel.removeAll();
+ distanciesPanel.setLayout(new GridLayout(results.getElementsNames().size() + 1,
+ results.getElementsNames().size() + 1));
+ distanciesPanel.add(new JLabel());
+ for (String s : results.getElementsNames()) {
+ distanciesPanel.add(new JLabel(s));
+ }
+ for (String s : results.getElementsNames()) {
+ distanciesPanel.add(new JLabel(s));
+ for (Double d : results.getDistancies().get(s)) {
+ if (d < 0) {
+ distanciesPanel.add(new JLabel("Inf"));
+ } else {
+ distanciesPanel.add(new JLabel(d.toString()));
+ }
+ }
+ }
+ distanciesPanel.setAutoscrolls(true);
+
+ myToolWindow.show(null);
+ }
+
+ @Override
+ public void dispose() {
+ final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
+ toolWindowManager.unregisterToolWindow(WINDOW_ID);
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/JavaMetricProvider.java b/stockmetrics/src/com/sixrr/stockmetrics/JavaMetricProvider.java
index 6dfb4d5..f21a59f 100644
--- a/stockmetrics/src/com/sixrr/stockmetrics/JavaMetricProvider.java
+++ b/stockmetrics/src/com/sixrr/stockmetrics/JavaMetricProvider.java
@@ -104,6 +104,10 @@ private static void initializeClassMetrics(Collection metrics) {
metrics.add(new TodoCommentCountClassMetric());
metrics.add(new TrueCommentRatioClassMetric());
metrics.add(new WeightedMethodComplexityMetric());
+ metrics.add(new FanInClassMetric());
+ metrics.add(new FanOutClassMetric());
+ metrics.add(new DepthInheritanceClassMetric());
+ metrics.add(new NumberOfChildrenClassMetric());
}
private static void initializeInterfaceMetrics(Collection metrics) {
@@ -181,6 +185,10 @@ private static void initializeMethodMetrics(Collection metrics) {
metrics.add(new SourceLinesOfCodeMethodMetric());
metrics.add(new TodoCommentCountMethodMetric());
metrics.add(new TrueCommentRatioMethodMetric());
+ metrics.add(new FanInMethodMetric());
+ metrics.add(new FanOutMethodMetric());
+ metrics.add(new DepthInheritanceMethodMetric());
+ metrics.add(new NumberOfChildrenMethodMetric());
}
private static void initializeModuleMetrics(Collection metrics) {
@@ -329,7 +337,7 @@ private static void initializeProjectMetrics(Collection metrics) {
@NotNull
@Override
public List getPrebuiltProfiles() {
- final List out = new ArrayList(10);
+ final List out = new ArrayList(11);
out.add(createChidamberKemererProfile());
out.add(createClassCountProfile());
out.add(createCodeSizeProfile());
@@ -340,9 +348,33 @@ public List getPrebuiltProfiles() {
out.add(createMartinProfile());
out.add(createMoodProfile());
out.add(createTestProfile());
+ out.add(createFanProfile());
+ out.add(createAutomaticRefactoringProfile());
return out;
}
+ private static PrebuiltMetricProfile createAutomaticRefactoringProfile() {
+ final PrebuiltMetricProfile profile = new PrebuiltMetricProfile(StockMetricsBundle.message("automatic.refactoring.profile.name"));
+ profile.addMetric(FanInClassMetric.class);
+ profile.addMetric(FanOutClassMetric.class);
+ profile.addMetric(FanInMethodMetric.class);
+ profile.addMetric(FanOutMethodMetric.class);
+ profile.addMetric(DepthInheritanceClassMetric.class);
+ profile.addMetric(DepthInheritanceMethodMetric.class);
+ profile.addMetric(NumberOfChildrenMethodMetric.class);
+ profile.addMetric(NumberOfChildrenClassMetric.class);
+ return profile;
+ }
+
+ private static PrebuiltMetricProfile createFanProfile() {
+ final PrebuiltMetricProfile profile = new PrebuiltMetricProfile(StockMetricsBundle.message("fan.profile.name"));
+ profile.addMetric(FanInClassMetric.class);
+ profile.addMetric(FanOutClassMetric.class);
+ profile.addMetric(FanInMethodMetric.class);
+ profile.addMetric(FanOutMethodMetric.class);
+ return profile;
+ }
+
private static PrebuiltMetricProfile createChidamberKemererProfile() {
final PrebuiltMetricProfile profile =
new PrebuiltMetricProfile(StockMetricsBundle.message("chidamber.kemerer.metrics.profile.name"));
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/DepthInheritanceClassCalculator.java b/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/DepthInheritanceClassCalculator.java
new file mode 100644
index 0000000..678de75
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/DepthInheritanceClassCalculator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.classCalculators;
+
+import com.intellij.psi.*;
+import com.sixrr.metrics.utils.ClassUtils;
+import com.sixrr.stockmetrics.utils.ProjectContainerUtil;
+
+import java.util.Set;
+
+public class DepthInheritanceClassCalculator extends ClassCalculator {
+
+ @Override
+ protected PsiElementVisitor createVisitor() {
+ return new Visitor();
+ }
+
+ private class Visitor extends JavaRecursiveElementVisitor {
+
+ @Override
+ public void visitClass(PsiClass psiClass) {
+ if (ClassUtils.isAnonymous(psiClass)) {
+ return;
+ }
+ PsiClass baseClass = psiClass;
+ Set packages = ProjectContainerUtil.getPackages();
+ int counter = 0;
+ boolean implimentedInProject = true;
+ while (psiClass != null && ProjectContainerUtil.getClasses().contains(psiClass)) {
+ counter++;
+ psiClass = psiClass.getSuperClass();
+ }
+ postMetric(baseClass, counter);
+ }
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/FanInClassCalculator.java b/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/FanInClassCalculator.java
new file mode 100644
index 0000000..426a9ea
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/FanInClassCalculator.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.classCalculators;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.sixrr.metrics.utils.ClassUtils;
+import com.sixrr.stockmetrics.utils.FieldUsageMap;
+import com.sixrr.stockmetrics.utils.ProjectContainerUtil;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * @author Aleksandr Chudov.
+ */
+public class FanInClassCalculator extends ClassCalculator {
+
+ @Override
+ protected PsiElementVisitor createVisitor() {
+ return new Visitor();
+ }
+
+ private class Visitor extends JavaRecursiveElementVisitor {
+
+ @Override
+ public void visitClass(PsiClass aClass) {
+ if (ClassUtils.isAnonymous(aClass)) {
+ return;
+ }
+ Set classes = ProjectContainerUtil.getClassUsers(aClass);
+ classes.retainAll(ProjectContainerUtil.getClasses());
+ classes.remove(aClass);
+ postMetric(aClass, classes.size());
+ }
+ }/**/
+ /*@Override
+ public void visitClass(PsiClass c) {
+ if (ClassUtils.isAnonymous(c)) {
+ return;
+ }
+ Set classes = new HashSet();
+ for (PsiField f : c.getAllFields()) {
+ if (f.getType() instanceof PsiClassType) {
+ PsiClass type = ((PsiClassType)f.getType()).resolve();
+ if (type != null) {
+ classes.add(type);
+ }
+ }
+ }
+ for (PsiMethod m : c.getAllMethods()) {
+ if (m.getBody() != null) {
+ for (PsiStatement s : m.getBody().getStatements()) {
+ classes.addAll(findInChildren(s));
+ }
+ }
+ }
+ classes.retainAll(ProjectContainerUtil.getClasses());
+ classes.remove(c);
+ postMetric(c, classes.size());
+ }
+
+ private Set findInChildren(PsiElement el) {
+ HashSet classes = new HashSet();
+ if (el instanceof PsiReference) {
+ PsiElement res = ((PsiReference) el).resolve();
+ if (res != null && res instanceof PsiMethod) {
+ classes.add(((PsiMethod) res).getContainingClass());
+ }
+ }
+ for (PsiElement e : el.getChildren()) {
+ classes.addAll(findInChildren(e));
+ }
+ return classes;
+ }
+ }/**/
+
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/FanOutClassCalculator.java b/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/FanOutClassCalculator.java
new file mode 100644
index 0000000..88837cc
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/FanOutClassCalculator.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.classCalculators;
+
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.sixrr.metrics.Metric;
+import com.sixrr.metrics.MetricsExecutionContext;
+import com.sixrr.metrics.MetricsResultsHolder;
+import com.sixrr.metrics.utils.ClassUtils;
+import com.sixrr.stockmetrics.utils.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * @author Aleksandr Chudov.
+ */
+public class FanOutClassCalculator extends ClassCalculator {
+
+
+
+ @Override
+ protected PsiElementVisitor createVisitor() {
+ return new Visitor();
+ }
+
+ private class Visitor extends JavaRecursiveElementVisitor {
+ @Override
+ public void visitClass(PsiClass c) {
+ if (ClassUtils.isAnonymous(c)) {
+ return;
+ }
+ Set classes = new HashSet();
+ for (PsiField f : c.getAllFields()) {
+ if (f.getType() instanceof PsiClassType) {
+ PsiClass type = ((PsiClassType)f.getType()).resolve();
+ if (type != null) {
+ classes.add(type);
+ }
+ }
+ }
+ for (PsiMethod m : c.getAllMethods()) {
+ if (m.getBody() != null) {
+ for (PsiStatement s : m.getBody().getStatements()) {
+ classes.addAll(findInChildren(s));
+ }
+ }
+ }
+ classes.retainAll(ProjectContainerUtil.getClasses());
+ classes.remove(c);
+ postMetric(c, classes.size());
+ }
+
+ private Set findInChildren(PsiElement el) {
+ HashSet classes = new HashSet();
+ if (el instanceof PsiReference) {
+ PsiElement res = ((PsiReference) el).resolve();
+ if (res != null && res instanceof PsiMethod) {
+ classes.add(((PsiMethod) res).getContainingClass());
+ }
+ }
+ for (PsiElement e : el.getChildren()) {
+ classes.addAll(findInChildren(e));
+ }
+ return classes;
+ }
+ }/**/
+ /*@Override
+ public void visitClass(PsiClass aClass) {
+ if (ClassUtils.isAnonymous(aClass)) {
+ return;
+ }
+ Set classes = ProjectContainerUtil.getClassUsers(aClass);
+ classes.retainAll(ProjectContainerUtil.getClasses());
+ classes.remove(aClass);
+ postMetric(aClass, classes.size());
+ }
+ }/**/
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/NumberOfChildrenClassCalculator.java b/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/NumberOfChildrenClassCalculator.java
new file mode 100644
index 0000000..173ea47
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/classCalculators/NumberOfChildrenClassCalculator.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.classCalculators;
+
+import com.intellij.psi.*;
+import com.intellij.util.containers.ContainerUtil;
+import com.sixrr.metrics.utils.ClassUtils;
+import com.sixrr.stockmetrics.utils.ProjectContainerUtil;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class NumberOfChildrenClassCalculator extends ClassCalculator {
+
+ @Override
+ protected PsiElementVisitor createVisitor() {
+ return new Visitor();
+ }
+
+ private class Visitor extends JavaRecursiveElementVisitor {
+
+ @Override
+ public void visitClass(PsiClass psiClass) {
+ if (ClassUtils.isAnonymous(psiClass)) {
+ return;
+ }
+ Set packages = ProjectContainerUtil.getPackages();
+ Set classes = new HashSet();
+ for (PsiPackage p : packages) {
+ getClasses(p, classes);
+ }
+ int counter = 0;
+ for (PsiClass c : classes) {
+ if (c.isInheritor(psiClass, false)) {
+ counter++;
+ }
+ }
+ postMetric(psiClass, counter);
+ }
+
+ private void getClasses(PsiPackage p, Set classes) {
+ ContainerUtil.addAll(classes, p.getClasses());
+ for (PsiPackage subP : p.getSubPackages()) {
+ getClasses(subP, classes);
+ }
+ }
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/DepthInheritanceClassMetric.java b/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/DepthInheritanceClassMetric.java
new file mode 100644
index 0000000..ef085c0
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/DepthInheritanceClassMetric.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.classMetrics;
+
+import com.sixrr.metrics.MetricCalculator;
+import com.sixrr.metrics.MetricType;
+import com.sixrr.stockmetrics.classCalculators.DepthInheritanceClassCalculator;
+import com.sixrr.stockmetrics.i18n.StockMetricsBundle;
+import org.jetbrains.annotations.NotNull;
+
+public class DepthInheritanceClassMetric extends ClassMetric {
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return StockMetricsBundle.message("depth.in.inheritance.display.name");
+ }
+
+ @NotNull
+ @Override
+ public String getAbbreviation() {
+ return StockMetricsBundle.message("depth.in.inheritance.abbreviation");
+ }
+
+ @NotNull
+ @Override
+ public MetricType getType() {
+ return MetricType.Count;
+ }
+
+ @NotNull
+ @Override
+ public MetricCalculator createCalculator() {
+ return new DepthInheritanceClassCalculator();
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/FanInClassMetric.java b/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/FanInClassMetric.java
new file mode 100644
index 0000000..e600352
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/FanInClassMetric.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.classMetrics;
+
+import com.sixrr.metrics.MetricCalculator;
+import com.sixrr.metrics.MetricType;
+import com.sixrr.stockmetrics.classCalculators.FanInClassCalculator;
+import com.sixrr.stockmetrics.i18n.StockMetricsBundle;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Created by Aleksandr Chudov on 27.03.2017.
+ */
+public class FanInClassMetric extends ClassMetric {
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return StockMetricsBundle.message("fan.in.class.metric.display.name");
+ }
+
+ @NotNull
+ @Override
+ public String getAbbreviation() {
+ return StockMetricsBundle.message("fan.in.class.metric.abbreviation");
+ }
+
+ @NotNull
+ @Override
+ public MetricType getType() {
+ return MetricType.Count;
+ }
+
+ @NotNull
+ @Override
+ public MetricCalculator createCalculator() {
+ return new FanInClassCalculator();
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/FanOutClassMetric.java b/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/FanOutClassMetric.java
new file mode 100644
index 0000000..8ca0d33
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/FanOutClassMetric.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.classMetrics;
+
+import com.sixrr.metrics.MetricCalculator;
+import com.sixrr.metrics.MetricType;
+import com.sixrr.stockmetrics.classCalculators.FanOutClassCalculator;
+import com.sixrr.stockmetrics.i18n.StockMetricsBundle;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Created by Aleksandr Chudov on 28.03.2017.
+ */
+public class FanOutClassMetric extends ClassMetric {
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return StockMetricsBundle.message("fan.out.class.metric.display.name");
+ }
+
+ @NotNull
+ @Override
+ public String getAbbreviation() {
+ return StockMetricsBundle.message("fan.out.class.metric.abbreviation");
+ }
+
+ @NotNull
+ @Override
+ public MetricType getType() {
+ return MetricType.Count;
+ }
+
+ @NotNull
+ @Override
+ public MetricCalculator createCalculator() {
+ return new FanOutClassCalculator();
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/NumberOfChildrenClassMetric.java b/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/NumberOfChildrenClassMetric.java
new file mode 100644
index 0000000..cd8f770
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/classMetrics/NumberOfChildrenClassMetric.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.classMetrics;
+
+import com.sixrr.metrics.MetricCalculator;
+import com.sixrr.metrics.MetricType;
+import com.sixrr.stockmetrics.classCalculators.NumberOfChildrenClassCalculator;
+import com.sixrr.stockmetrics.i18n.StockMetricsBundle;
+import com.sixrr.stockmetrics.methodCalculators.NumberOfChildrenMethodCalculator;
+import org.jetbrains.annotations.NotNull;
+
+public class NumberOfChildrenClassMetric extends ClassMetric {
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return StockMetricsBundle.message("number.of.children.display.name");
+ }
+
+ @NotNull
+ @Override
+ public String getAbbreviation() {
+ return StockMetricsBundle.message("number.of.children.abbreviation");
+ }
+
+ @NotNull
+ @Override
+ public MetricType getType() {
+ return MetricType.Count;
+ }
+
+ @NotNull
+ @Override
+ public MetricCalculator createCalculator() {
+ return new NumberOfChildrenClassCalculator();
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/i18n/StockMetricsBundle.properties b/stockmetrics/src/com/sixrr/stockmetrics/i18n/StockMetricsBundle.properties
index 5d0a934..7881d94 100644
--- a/stockmetrics/src/com/sixrr/stockmetrics/i18n/StockMetricsBundle.properties
+++ b/stockmetrics/src/com/sixrr/stockmetrics/i18n/StockMetricsBundle.properties
@@ -312,6 +312,8 @@ cyclomatic.complexity.display.name=Cyclomatic complexity
cyclomatic.complexity.abbreviation=v(G)
control.density.display.name=Control density
control.density.abbreviation=CDENS
+depth.in.inheritance.display.name=Depth in Inheritance Tree
+depth.in.inheritance.abbreviation=DIT
design.complexity.display.name=Design complexity
design.complexity.abbreviation=iv(G)
essential.cyclomatic.complexity.display.name=Essential cyclomatic complexity
@@ -377,4 +379,16 @@ abstractness.display.name=Abstractness
abstractness.abbreviation=A
number.of.packages.abbreviation=P
number.of.children.display.name=Number of children
-number.of.children.abbreviation=NOC
\ No newline at end of file
+number.of.children.abbreviation=NOC
+fan.profile.name=Fan metrics
+automatic.refactoring.profile.name=Metrics for automatic refactoring
+fan.in.class.metric.display.name=Fan-In class metric
+fan.in.class.metric.abbreviation=FIC
+fan.out.class.metric.display.name=Fan-Out class metric
+fan.out.class.metric.abbreviation=FOC
+fan.in.method.metric.display.name=Fan-In method metric
+fan.in.method.metric.abbreviation=FIM
+fan.out.method.metric.display.name=Fan-Out method metric
+fan.out.method.metric.abbreviation=FOM
+number.of.children.metric.display.name=Number of Children
+number.of.children.metric.abbreviation=NOC
\ No newline at end of file
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/DepthInheritanceMethodCalculator.java b/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/DepthInheritanceMethodCalculator.java
new file mode 100644
index 0000000..e69019d
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/DepthInheritanceMethodCalculator.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.methodCalculators;
+
+import com.intellij.ide.projectView.impl.nodes.PackageUtil;
+import com.intellij.openapi.project.*;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.ui.ListUtil;
+import com.sixrr.metrics.utils.ClassUtils;
+import com.sixrr.stockmetrics.utils.ProjectContainerUtil;
+
+import java.util.*;
+
+import static org.bouncycastle.asn1.iana.IANAObjectIdentifiers.directory;
+
+public class DepthInheritanceMethodCalculator extends MethodCalculator {
+
+ @Override
+ protected PsiElementVisitor createVisitor() {
+ return new Visitor();
+ }
+
+ private class Visitor extends JavaRecursiveElementVisitor {
+
+ @Override
+ public void visitMethod(PsiMethod method) {
+ if (ClassUtils.isAnonymous(method.getContainingClass())) {
+ return;
+ }
+ Set packages = ProjectContainerUtil.getPackages();
+ PsiClass psiClass = (PsiClass) method.getParent();
+ int counter = 0;while (psiClass != null && ProjectContainerUtil.getClasses().contains(psiClass)) {
+ counter++;
+ psiClass = psiClass.getSuperClass();
+ }
+ postMetric(method, counter);
+ }
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/FanInMethodCalculator.java b/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/FanInMethodCalculator.java
new file mode 100644
index 0000000..7a03bd0
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/FanInMethodCalculator.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.methodCalculators;
+
+import com.intellij.psi.*;
+import com.sixrr.metrics.utils.BucketedCount;
+import com.sixrr.metrics.utils.ClassUtils;
+import com.sixrr.stockmetrics.utils.ProjectContainerUtil;
+
+import java.util.*;
+
+/**
+ * @author Aleksandr Chudov.
+ */
+public class FanInMethodCalculator extends MethodCalculator {
+
+ @Override
+ protected PsiElementVisitor createVisitor() {
+ return new Visitor();
+ }
+
+ private class Visitor extends JavaRecursiveElementVisitor {
+ @Override
+ public void visitMethod(PsiMethod method) {
+ if (ClassUtils.isAnonymous(method.getContainingClass())) {
+ return;
+ }
+ Set methods = ProjectContainerUtil.getMethodUsers(method);
+ methods.retainAll(ProjectContainerUtil.getMethods());
+ //methods.remove(method);
+ for (PsiMethod m : method.getContainingClass().getAllMethods()) {
+ methods.remove(m);
+ }
+ postMetric(method, methods.size());
+ }
+
+ private boolean findInChildren(PsiElement el, PsiMethod cl) {
+ if (el instanceof PsiReference) {
+ PsiElement res = ((PsiReference) el).resolve();
+ if (res != null && cl.equals(res)) {
+ return true;
+ }
+ }
+ for (PsiElement e : el.getChildren()) {
+ if (findInChildren(e, cl)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/FanOutMethodCalculator.java b/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/FanOutMethodCalculator.java
new file mode 100644
index 0000000..a6c06c4
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/FanOutMethodCalculator.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.methodCalculators;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.sixrr.metrics.utils.BucketedCount;
+import com.sixrr.metrics.utils.ClassUtils;
+import com.sixrr.metrics.utils.MethodUtils;
+import com.sixrr.stockmetrics.utils.ProjectContainerUtil;
+
+import java.util.*;
+
+/**
+ * @author Aleksandr Chudov.
+ */
+public class FanOutMethodCalculator extends MethodCalculator {
+
+ @Override
+ protected PsiElementVisitor createVisitor() {
+ return new Visitor();
+ }
+
+ private class Visitor extends JavaRecursiveElementVisitor {
+ @Override
+ public void visitMethod(PsiMethod method) {
+ if (ClassUtils.isAnonymous(method.getContainingClass())) {
+ return;
+ }
+ Set methods = new HashSet();
+ if (method.getBody() != null) {
+ for (PsiStatement s : method.getBody().getStatements()) {
+ methods.addAll(findInChildren(s));
+ }
+ }
+ methods.retainAll(ProjectContainerUtil.getMethods());
+ methods.remove(method);
+ for (PsiMethod m : method.getContainingClass().getAllMethods()) {
+ methods.remove(m);
+ }
+ postMetric(method, methods.size());
+ }
+
+ private Set findInChildren(PsiElement el) {
+ Set methods = new HashSet();
+ if (el instanceof PsiReference) {
+ PsiElement res = ((PsiReference) el).resolve();
+ if (res != null && res instanceof PsiMethod) {
+ methods.add((PsiMethod) res);
+ }
+ }
+ for (PsiElement e : el.getChildren()) {
+ methods.addAll(findInChildren(e));
+ }
+ return methods;
+ }
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/NumberOfChildrenMethodCalculator.java b/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/NumberOfChildrenMethodCalculator.java
new file mode 100644
index 0000000..6c179db
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/methodCalculators/NumberOfChildrenMethodCalculator.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.methodCalculators;
+
+import com.intellij.psi.*;
+import com.intellij.util.containers.ContainerUtil;
+import com.sixrr.metrics.utils.ClassUtils;
+import com.sixrr.stockmetrics.utils.ProjectContainerUtil;
+import org.junit.experimental.categories.Categories;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public class NumberOfChildrenMethodCalculator extends MethodCalculator {
+
+ @Override
+ protected PsiElementVisitor createVisitor() {
+ return new Visitor();
+ }
+
+ private class Visitor extends JavaRecursiveElementVisitor {
+
+ @Override
+ public void visitMethod(PsiMethod method) {
+ if (ClassUtils.isAnonymous(method.getContainingClass())) {
+ return;
+ }
+ Set packages = ProjectContainerUtil.getPackages();
+ Set classes = new HashSet();
+ for (PsiPackage p : packages) {
+ getClasses(p, classes);
+ }
+ PsiClass psiClass = (PsiClass) method.getParent();
+ int counter = 0;
+ for (PsiClass c : classes) {
+ if (c.isInheritor(psiClass, false)) {
+ counter++;
+ }
+ }
+ postMetric(method, counter);
+ }
+
+ private void getClasses(PsiPackage p, Set classes) {
+ ContainerUtil.addAll(classes, p.getClasses());
+ for (PsiPackage subP : p.getSubPackages()) {
+ getClasses(subP, classes);
+ }
+ }
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/DepthInheritanceMethodMetric.java b/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/DepthInheritanceMethodMetric.java
new file mode 100644
index 0000000..6d6aa5a
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/DepthInheritanceMethodMetric.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.methodMetrics;
+
+import com.sixrr.metrics.MetricCalculator;
+import com.sixrr.metrics.MetricType;
+import com.sixrr.stockmetrics.i18n.StockMetricsBundle;
+import com.sixrr.stockmetrics.methodCalculators.DepthInheritanceMethodCalculator;
+import org.jetbrains.annotations.NotNull;
+
+public class DepthInheritanceMethodMetric extends MethodMetric {
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return StockMetricsBundle.message("depth.in.inheritance.display.name");
+ }
+
+ @NotNull
+ @Override
+ public String getAbbreviation() {
+ return StockMetricsBundle.message("depth.in.inheritance.abbreviation");
+ }
+
+ @NotNull
+ @Override
+ public MetricType getType() {
+ return MetricType.Count;
+ }
+
+ @NotNull
+ @Override
+ public MetricCalculator createCalculator() {
+ return new DepthInheritanceMethodCalculator();
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/FanInMethodMetric.java b/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/FanInMethodMetric.java
new file mode 100644
index 0000000..31dea1d
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/FanInMethodMetric.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.methodMetrics;
+
+import com.sixrr.metrics.MetricCalculator;
+import com.sixrr.metrics.MetricType;
+import com.sixrr.stockmetrics.i18n.StockMetricsBundle;
+import com.sixrr.stockmetrics.methodCalculators.FanInMethodCalculator;
+import com.sixrr.stockmetrics.methodCalculators.MethodCalculator;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Created by Aleksandr Chudov on 02.04.2017.
+ */
+public class FanInMethodMetric extends MethodMetric {
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return StockMetricsBundle.message("fan.in.method.metric.display.name");
+ }
+
+ @NotNull
+ @Override
+ public String getAbbreviation() {
+ return StockMetricsBundle.message("fan.in.method.metric.abbreviation");
+ }
+
+ @NotNull
+ @Override
+ public MetricType getType() {
+ return MetricType.Count;
+ }
+
+ @NotNull
+ @Override
+ public MetricCalculator createCalculator() {
+ return new FanInMethodCalculator();
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/FanOutMethodMetric.java b/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/FanOutMethodMetric.java
new file mode 100644
index 0000000..acee8b9
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/FanOutMethodMetric.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.methodMetrics;
+
+import com.sixrr.metrics.MetricCalculator;
+import com.sixrr.metrics.MetricType;
+import com.sixrr.stockmetrics.i18n.StockMetricsBundle;
+import com.sixrr.stockmetrics.methodCalculators.FanOutMethodCalculator;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Created by Aleksandr Chudov on 02.04.2017.
+ */
+public class FanOutMethodMetric extends MethodMetric {
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return StockMetricsBundle.message("fan.out.method.metric.display.name");
+ }
+
+ @NotNull
+ @Override
+ public String getAbbreviation() {
+ return StockMetricsBundle.message("fan.out.method.metric.abbreviation");
+ }
+
+ @NotNull
+ @Override
+ public MetricType getType() {
+ return MetricType.Count;
+ }
+
+ @NotNull
+ @Override
+ public MetricCalculator createCalculator() {
+ return new FanOutMethodCalculator();
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/NumberOfChildrenMethodMetric.java b/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/NumberOfChildrenMethodMetric.java
new file mode 100644
index 0000000..46b625a
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/methodMetrics/NumberOfChildrenMethodMetric.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.methodMetrics;
+
+import com.sixrr.metrics.MetricCalculator;
+import com.sixrr.metrics.MetricType;
+import com.sixrr.stockmetrics.i18n.StockMetricsBundle;
+import com.sixrr.stockmetrics.methodCalculators.DepthInheritanceMethodCalculator;
+import com.sixrr.stockmetrics.methodCalculators.NumberOfChildrenMethodCalculator;
+import org.jetbrains.annotations.NotNull;
+
+public class NumberOfChildrenMethodMetric extends MethodMetric {
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return StockMetricsBundle.message("number.of.children.display.name");
+ }
+
+ @NotNull
+ @Override
+ public String getAbbreviation() {
+ return StockMetricsBundle.message("number.of.children.abbreviation");
+ }
+
+ @NotNull
+ @Override
+ public MetricType getType() {
+ return MetricType.Count;
+ }
+
+ @NotNull
+ @Override
+ public MetricCalculator createCalculator() {
+ return new NumberOfChildrenMethodCalculator();
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/utils/FieldUsageMap.java b/stockmetrics/src/com/sixrr/stockmetrics/utils/FieldUsageMap.java
new file mode 100644
index 0000000..e6b7e59
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/utils/FieldUsageMap.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.utils;
+
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiReference;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Set;
+
+/**
+ * @author Aleksandr Chudov.
+ */
+public interface FieldUsageMap {
+ @NotNull
+ Set calculateFieldUsagePoints(PsiField field);
+
+ @NotNull
+ Set calculateTestFieldUsagePoints(PsiField field);
+
+ @NotNull
+ Set calculateProductFieldUsagePoints(PsiField field);
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/utils/FieldUsageMapImpl.java b/stockmetrics/src/com/sixrr/stockmetrics/utils/FieldUsageMapImpl.java
new file mode 100644
index 0000000..456275e
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/utils/FieldUsageMapImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.utils;
+
+import com.intellij.psi.*;
+import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.Query;
+import com.sixrr.metrics.utils.TestUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Aleksandr Chudov.
+ */
+public class FieldUsageMapImpl implements FieldUsageMap {
+ private final Map, Set> fieldUsagePointMap =
+ new HashMap, Set>(1024);
+ private final Map, Set> fieldTestUsagePointMap =
+ new HashMap, Set>(1024);
+ private final Map, Set> fieldProductUsagePointMap =
+ new HashMap, Set>(1024);
+
+ @NotNull
+ @Override
+ public Set calculateFieldUsagePoints(PsiField field) {
+ return getUsages(fieldUsagePointMap, field);
+ }
+
+ @NotNull
+ @Override
+ public Set calculateTestFieldUsagePoints(PsiField field) {
+ return getUsages(fieldTestUsagePointMap, field);
+ }
+
+ @NotNull
+ @Override
+ public Set calculateProductFieldUsagePoints(PsiField field) {
+ return getUsages(fieldProductUsagePointMap, field);
+ }
+
+ private Set getUsages(Map, Set> map, PsiField field) {
+ final SmartPsiElementPointer pointer = getPointer(field);
+ if (!map.containsKey(pointer)) {
+ calculateUsages(field);
+ }
+ return map.get(pointer);
+ }
+
+ @NotNull
+ private SmartPsiElementPointer getPointer(PsiField field) {
+ final SmartPointerManager manager = SmartPointerManager.getInstance(field.getProject());
+ return manager.createSmartPsiElementPointer(field);
+ }
+
+ private void calculateUsages(PsiField field) {
+ final Set allUsages = new HashSet();
+ final Set testUsages = new HashSet();
+ final Set productUsages = new HashSet();
+
+ final Query query = ReferencesSearch.search(field);
+ for (final PsiReference reference : query) {
+ final PsiElement element = reference.getElement();
+
+ final PsiClass referenceClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
+ if (referenceClass == null) {
+ continue;
+ }
+ allUsages.add(reference);
+ if (TestUtils.isTest(referenceClass)) {
+ testUsages.add(reference);
+ }
+ if (TestUtils.isProduction(referenceClass)) {
+ productUsages.add(reference);
+ }
+ }
+ final SmartPsiElementPointer pointer = getPointer(field);
+ fieldUsagePointMap.put(pointer, allUsages);
+ fieldTestUsagePointMap.put(pointer, testUsages);
+ fieldProductUsagePointMap.put(pointer, productUsages);
+ }
+}
diff --git a/stockmetrics/src/com/sixrr/stockmetrics/utils/ProjectContainerUtil.java b/stockmetrics/src/com/sixrr/stockmetrics/utils/ProjectContainerUtil.java
new file mode 100644
index 0000000..cb5b744
--- /dev/null
+++ b/stockmetrics/src/com/sixrr/stockmetrics/utils/ProjectContainerUtil.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2005-2017 Sixth and Red River Software, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sixrr.stockmetrics.utils;
+
+import com.intellij.ide.projectView.ProjectViewSettings;
+import com.intellij.ide.projectView.impl.nodes.PackageUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScopes;
+import com.intellij.psi.util.ClassUtil;
+import com.intellij.util.containers.ContainerUtil;
+import com.sixrr.metrics.utils.ClassUtils;
+
+import java.util.*;
+
+public class ProjectContainerUtil {
+
+ private static Project project = null;
+ private static Set packages = null;
+ private static Set classes = null;
+ private static Set methods = null;
+ private static Map> users = null;
+
+ public static Project getProject() {
+ return project;
+ }
+
+ public static Set getClassUsers(PsiClass psiClass) {
+ calculateUsers();
+ return users.get(psiClass);
+ }
+
+ public static Set getMethodUsers(PsiMethod method) {
+ calculateUsers();
+ return users.get(method);
+ }
+
+ private static void calculateUsers() {
+ if (users == null) {
+ users = new HashMap>();
+ for (PsiClass c : getClasses()) {
+ users.put(c, new HashSet());
+ }
+ for (PsiMethod m : getMethods()) {
+ users.put(m, new HashSet());
+ }
+ for (PsiClass c : getClasses()) {
+ for (PsiField f : c.getAllFields()) {
+ if (f.getType() instanceof PsiClassType) {
+ PsiClass type = ((PsiClassType)f.getType()).resolve();
+ if (type != null && classes.contains(type)) {
+ users.get(type).add(c);
+ }
+ }
+ }
+ for (PsiMethod m : c.getMethods()) {
+ if (m.getBody() != null) {
+ addInRecursion(m.getBody(), m, c);
+ }
+ }
+ }
+ }
+ }
+
+ private static void addInRecursion(PsiElement el, PsiMethod method, PsiClass psiClass) {
+ if (el instanceof PsiReference) {
+ PsiElement res = ((PsiReference) el).resolve();
+ if (res instanceof PsiClass && classes.contains(res)) {
+ users.get(res).add(psiClass);
+ }
+ if (res instanceof PsiMethod && methods.contains(res)) {
+ users.get(res).add(method);
+ }
+ }
+ for (PsiElement e : el.getChildren()) {
+ addInRecursion(e, method, psiClass);
+ }
+ }
+
+ public static Set getMethods() {
+ if (methods == null) {
+ methods = new HashSet();
+ for (PsiClass cl : getClasses()) {
+ Collections.addAll(methods, cl.getAllMethods());
+ }
+ }
+ return methods;
+ }
+
+ public static Set getClasses() {
+ if (classes == null) {
+ classes = new HashSet();
+ for (PsiPackage p : getPackages()) {
+ recursiveGetClasses(p);
+ }
+ }
+ return classes;
+ }
+ private static void recursiveGetClasses(PsiPackage psiPackage) {
+ Collections.addAll(classes, psiPackage.getClasses());
+ for (PsiClass c : psiPackage.getClasses()) {
+ recursiveGetSubClasses(c);
+ }
+ for (PsiPackage p : psiPackage.getSubPackages()) {
+ recursiveGetClasses(p);
+ }
+ }
+
+ private static void recursiveGetSubClasses(PsiClass cl) {
+ classes.add(cl);
+ for (PsiClass c : cl.getInnerClasses()) {
+ recursiveGetSubClasses(c);
+ }
+ }
+
+
+ public static Set getPackages() {
+ if (packages == null) {
+ final List sourceRoots = new ArrayList();
+ final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(project);
+ ContainerUtil.addAll(sourceRoots, projectRootManager.getContentSourceRoots());
+
+ final PsiManager psiManager = PsiManager.getInstance(project);
+ packages = new HashSet();
+
+ for (final VirtualFile root : sourceRoots) {
+ final PsiDirectory directory = psiManager.findDirectory(root);
+ if (directory == null) {
+ continue;
+ }
+ final PsiPackage directoryPackage = JavaDirectoryService.getInstance().getPackage(directory);
+ if (directoryPackage == null || PackageUtil.isPackageDefault(directoryPackage)) {
+ final PsiDirectory[] subdirectories = directory.getSubdirectories();
+ for (PsiDirectory subdirectory : subdirectories) {
+ final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage(subdirectory);
+ if (aPackage != null && !PackageUtil.isPackageDefault(aPackage)) {
+ packages.add(aPackage);
+ }
+ }
+ } else {
+ // this is the case when a source root has package prefix assigned
+ packages.add(directoryPackage);
+ }
+ }
+ }
+ return packages;
+ }
+
+ public static void setProject(Project openedProject) {
+ project = openedProject;
+ packages = null;
+ classes = null;
+ methods = null;
+ users = null;
+ }
+
+}