From 405ef022ee0dbd92d3436772c4f4369887891e83 Mon Sep 17 00:00:00 2001 From: Martin Wittlinger Date: Sat, 15 Jul 2023 17:40:10 +0200 Subject: [PATCH 1/2] feat(spoon): Add FinalStaticMethod analyzer --- .../analyzer/spoon/AnalyzerResultVisitor.java | 7 ++++ .../spoonutils/matcher/Matchers.java | 9 +++++ .../spoon_analyzer/BadSmellVisitor.java | 5 +++ .../spoon_analyzer/SpoonAnalyzer.java | 2 + .../FinalStaticMethod.java | 40 +++++++++++++++++++ .../FinalStaticMethodAnalyzer.java | 34 ++++++++++++++++ 6 files changed, 97 insertions(+) create mode 100644 spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethod.java create mode 100644 spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethodAnalyzer.java diff --git a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/AnalyzerResultVisitor.java b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/AnalyzerResultVisitor.java index 89ce70095..ed360ac9b 100644 --- a/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/AnalyzerResultVisitor.java +++ b/code-transformation/src/main/java/xyz/keksdose/spoon/code_solver/analyzer/spoon/AnalyzerResultVisitor.java @@ -9,6 +9,7 @@ import io.github.martinwitt.spoon_analyzer.badsmells.access_static_via_instance.AccessStaticViaInstance; import io.github.martinwitt.spoon_analyzer.badsmells.array_can_be_replaced_with_enum_values.ArrayCanBeReplacedWithEnumValues; import io.github.martinwitt.spoon_analyzer.badsmells.charset_object_can_be_used.CharsetObjectCanBeUsed; +import io.github.martinwitt.spoon_analyzer.badsmells.final_static_method.FinalStaticMethod; import io.github.martinwitt.spoon_analyzer.badsmells.innerclass_may_be_static.InnerClassMayBeStatic; import io.github.martinwitt.spoon_analyzer.badsmells.non_protected_constructor_In_abstract_class.NonProtectedConstructorInAbstractClass; import io.github.martinwitt.spoon_analyzer.badsmells.private_final_method.PrivateFinalMethod; @@ -138,4 +139,10 @@ public AnalyzerResult visit(UnnecessaryTostring badSmell) { badSmell.getNotNeededTostring().getOriginalSourceFragment().toString(); return toSpoonAnalyzerResult(badSmell, badSmell.getNotNeededTostring().getPosition(), snippet); } + + @Override + public AnalyzerResult visit(FinalStaticMethod badSmell) { + String snippet = badSmell.getMethod().getSignature(); + return toSpoonAnalyzerResult(badSmell, badSmell.getMethod().getPosition(), snippet); + } } diff --git a/matcher/src/main/java/io/github/martinwitt/laughing_train/spoonutils/matcher/Matchers.java b/matcher/src/main/java/io/github/martinwitt/laughing_train/spoonutils/matcher/Matchers.java index 148d389b0..c7a9bc88c 100644 --- a/matcher/src/main/java/io/github/martinwitt/laughing_train/spoonutils/matcher/Matchers.java +++ b/matcher/src/main/java/io/github/martinwitt/laughing_train/spoonutils/matcher/Matchers.java @@ -59,6 +59,15 @@ public static Matcher isFinal() { return v -> v.getModifiers().contains(ModifierKind.FINAL); } + /** + * Returns a matcher that matches elements that are static. + * + * @return a matcher that matches elements that are static + */ + public static Matcher isStatic() { + return v -> v.isStatic(); + } + /** * Returns a matcher that matches elements that match all of the given matchers. * diff --git a/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/BadSmellVisitor.java b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/BadSmellVisitor.java index a0d1bc174..e3f3bcfd1 100644 --- a/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/BadSmellVisitor.java +++ b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/BadSmellVisitor.java @@ -4,6 +4,7 @@ import io.github.martinwitt.spoon_analyzer.badsmells.access_static_via_instance.AccessStaticViaInstance; import io.github.martinwitt.spoon_analyzer.badsmells.array_can_be_replaced_with_enum_values.ArrayCanBeReplacedWithEnumValues; import io.github.martinwitt.spoon_analyzer.badsmells.charset_object_can_be_used.CharsetObjectCanBeUsed; +import io.github.martinwitt.spoon_analyzer.badsmells.final_static_method.FinalStaticMethod; import io.github.martinwitt.spoon_analyzer.badsmells.innerclass_may_be_static.InnerClassMayBeStatic; import io.github.martinwitt.spoon_analyzer.badsmells.non_protected_constructor_In_abstract_class.NonProtectedConstructorInAbstractClass; import io.github.martinwitt.spoon_analyzer.badsmells.private_final_method.PrivateFinalMethod; @@ -67,6 +68,10 @@ default U visit(UnnecessaryTostring badSmell) { return emptyResult(); } + default U visit(FinalStaticMethod badSmell) { + return emptyResult(); + } + default U emptyResult() { return null; } diff --git a/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/SpoonAnalyzer.java b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/SpoonAnalyzer.java index ce3437a5e..8b93a81a5 100644 --- a/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/SpoonAnalyzer.java +++ b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/SpoonAnalyzer.java @@ -5,6 +5,7 @@ import io.github.martinwitt.spoon_analyzer.badsmells.access_static_via_instance.AccessStaticViaInstanceAnalyzer; import io.github.martinwitt.spoon_analyzer.badsmells.array_can_be_replaced_with_enum_values.ArrayCanBeReplacedWithEnumValuesAnalyzer; import io.github.martinwitt.spoon_analyzer.badsmells.charset_object_can_be_used.CharsetObjectCanBeUsedAnalyzer; +import io.github.martinwitt.spoon_analyzer.badsmells.final_static_method.FinalStaticMethodAnalyzer; import io.github.martinwitt.spoon_analyzer.badsmells.innerclass_may_be_static.InnerClassMayBeStaticAnalyzer; import io.github.martinwitt.spoon_analyzer.badsmells.non_protected_constructor_In_abstract_class.NonProtectedConstructorInAbstractClassAnalyzer; import io.github.martinwitt.spoon_analyzer.badsmells.private_final_method.PrivateFinalMethodAnalyzer; @@ -28,6 +29,7 @@ public SpoonAnalyzer() { localAnalyzers.add(new AccessStaticViaInstanceAnalyzer()); localAnalyzers.add(new ArrayCanBeReplacedWithEnumValuesAnalyzer()); localAnalyzers.add(new CharsetObjectCanBeUsedAnalyzer()); + localAnalyzers.add(new FinalStaticMethodAnalyzer()); localAnalyzers.add(new IndexOfReplaceableByContainsAnalyzer()); localAnalyzers.add(new InnerClassMayBeStaticAnalyzer()); localAnalyzers.add(new NonProtectedConstructorInAbstractClassAnalyzer()); diff --git a/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethod.java b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethod.java new file mode 100644 index 000000000..07ce36e77 --- /dev/null +++ b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethod.java @@ -0,0 +1,40 @@ +package io.github.martinwitt.spoon_analyzer.badsmells.final_static_method; + +import io.github.martinwitt.spoon_analyzer.BadSmell; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; + +public class FinalStaticMethod implements BadSmell { + + private static final String NAME = "FinalStaticMethod"; + private static final String description = + "A final method is a method that cannot be overridden in a subclass. As static methods are bound to the class the cant be overridden only hidden."; + private CtMethod method; + private CtType affectedType; + + public FinalStaticMethod(CtMethod method, CtType affectedType) { + this.method = method; + } + + @Override + public String getName() { + return NAME; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public CtType getAffectedType() { + return affectedType; + } + + /** + * @return the final static method + */ + public CtMethod getMethod() { + return method; + } +} diff --git a/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethodAnalyzer.java b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethodAnalyzer.java new file mode 100644 index 000000000..e1de5f4f0 --- /dev/null +++ b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethodAnalyzer.java @@ -0,0 +1,34 @@ +package io.github.martinwitt.spoon_analyzer.badsmells.final_static_method; + +import io.github.martinwitt.laughing_train.spoonutils.matcher.Matchers; +import io.github.martinwitt.spoon_analyzer.BadSmell; +import io.github.martinwitt.spoon_analyzer.LocalAnalyzer; +import java.util.ArrayList; +import java.util.List; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; +import spoon.reflect.visitor.Filter; + +public class FinalStaticMethodAnalyzer implements LocalAnalyzer { + + @Override + public List analyze(CtType clazz) { + List badSmells = new ArrayList<>(); + List> elements = clazz.getElements(new FinalStaticMethodFilter()); + for (CtMethod method : elements) { + badSmells.add(new FinalStaticMethod(method, clazz)); + } + return badSmells; + } + + /** + * A filter that matches final static methods. + */ + private static class FinalStaticMethodFilter implements Filter> { + + @Override + public boolean matches(CtMethod element) { + return Matchers.allOf(Matchers.isFinal(), (Matchers.isStatic())).matches(element); + } + } +} From 4775dda57af756314ae6a7f7226f7c69e8eafcd4 Mon Sep 17 00:00:00 2001 From: Martin Wittlinger Date: Sat, 15 Jul 2023 17:50:17 +0200 Subject: [PATCH 2/2] up --- .../badsmells/final_static_method/FinalStaticMethod.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethod.java b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethod.java index 07ce36e77..8f5c93158 100644 --- a/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethod.java +++ b/spoon-analyzer/src/main/java/io/github/martinwitt/spoon_analyzer/badsmells/final_static_method/FinalStaticMethod.java @@ -9,11 +9,12 @@ public class FinalStaticMethod implements BadSmell { private static final String NAME = "FinalStaticMethod"; private static final String description = "A final method is a method that cannot be overridden in a subclass. As static methods are bound to the class the cant be overridden only hidden."; - private CtMethod method; - private CtType affectedType; + private final CtMethod method; + private final CtType affectedType; public FinalStaticMethod(CtMethod method, CtType affectedType) { this.method = method; + this.affectedType = affectedType; } @Override