diff --git a/src/ru/artyushov/jmhPlugin/inspection/JmhBenchMethodInvalidSignatureInspection.java b/src/ru/artyushov/jmhPlugin/inspection/JmhBenchMethodInvalidSignatureInspection.java index c58eef1..ca51485 100644 --- a/src/ru/artyushov/jmhPlugin/inspection/JmhBenchMethodInvalidSignatureInspection.java +++ b/src/ru/artyushov/jmhPlugin/inspection/JmhBenchMethodInvalidSignatureInspection.java @@ -8,9 +8,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.uast.UClass; +import org.jetbrains.uast.UField; import org.jetbrains.uast.UMethod; +import java.util.Objects; + import static com.intellij.codeInspection.ProblemHighlightType.ERROR; +import static com.intellij.psi.PsiModifier.ABSTRACT; import static com.intellij.psi.PsiModifier.PUBLIC; import static com.intellij.psi.PsiType.VOID; import static ru.artyushov.jmhPlugin.configuration.ConfigurationUtils.JMH_ANNOTATION_STATE; @@ -22,48 +26,59 @@ public class JmhBenchMethodInvalidSignatureInspection extends AbstractBaseUastLo private static final LocalQuickFix BENCH_METHOD_QUICK_FIX = new BenchMethodSignatureFix(); @Override - public @Nullable ProblemDescriptor[] checkClass(@NotNull UClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) { + public @Nullable ProblemDescriptor[] checkClass(@NotNull UClass klass, @NotNull InspectionManager manager, boolean isOnTheFly) { boolean isBenchmarkClass = false; - final UMethod[] methods = aClass.getMethods(); - for (final UMethod method : methods) { - if (hasBenchmarkAnnotation(method)) { - isBenchmarkClass = true; - ProblemDescriptor[] problem = checkPublicModifier(method, manager, isOnTheFly); - if (problem != null) return problem; - } else if (hasSetupOrTearDownAnnotation(method)) { + UMethod[] methods = klass.getMethods(); + for (UMethod method : methods) { + boolean hasBenchmarkAnnotation = hasBenchmarkAnnotation(method); + boolean hasSetupOrTearDownAnnotation = false; + if (!hasBenchmarkAnnotation) { + hasSetupOrTearDownAnnotation = hasSetupOrTearDownAnnotation(method); + if (hasSetupOrTearDownAnnotation) { + // Check that Setup or TearDown is void + if ((method.getReturnType() == null || !method.getReturnType().equals(VOID))) { + ProblemDescriptor problem = manager.createProblemDescriptor(method, "@Setup or @TearDown method should not return anything", BENCH_METHOD_QUICK_FIX, ERROR, isOnTheFly); + return new ProblemDescriptor[]{problem}; + } + } + } + if (hasBenchmarkAnnotation || hasSetupOrTearDownAnnotation) { isBenchmarkClass = true; - ProblemDescriptor[] problem = checkPublicModifier(method, manager, isOnTheFly); - if (problem != null) return problem; - problem = checkSetupTearDownIsNotVoid(method, manager, isOnTheFly); - if (problem != null) return problem; + if (!method.hasModifierProperty(PUBLIC)) { + ProblemDescriptor problem = manager.createProblemDescriptor(method, "@Benchmark method should be public", BENCH_METHOD_QUICK_FIX, ERROR, isOnTheFly); + return new ProblemDescriptor[]{problem}; + } } } - if (isBenchmarkClass && !hasStateAnnotation(aClass)) { - if (aClass.getFields().length > 0) { - AddAnnotationFix addAnnotationFix = new AddAnnotationFix(JMH_ANNOTATION_STATE, aClass); - ProblemDescriptor problem = manager.createProblemDescriptor(aClass, "@State missing", addAnnotationFix, ERROR, isOnTheFly); + if (!isBenchmarkClass) { + return null; + } + boolean explicitState = hasStateAnnotation(klass); + // validate against rogue fields + if (!explicitState || klass.hasModifierProperty(ABSTRACT)) { + for (UField field : klass.getFields()) { + // allow static fields + if (field.isStatic()) continue; + AddAnnotationFix addAnnotationFix = new AddAnnotationFix(JMH_ANNOTATION_STATE, klass); + ProblemDescriptor problem = manager.createProblemDescriptor(field, "Field is declared within the class not having @State annotation", addAnnotationFix, ERROR, isOnTheFly); return new ProblemDescriptor[]{problem}; } } - return null; - } - @Nullable - private ProblemDescriptor[] checkPublicModifier(@NotNull UMethod method, @NotNull InspectionManager manager, boolean isOnTheFly) { - if (!method.hasModifierProperty(PUBLIC)) { - ProblemDescriptor problem = manager.createProblemDescriptor(method, "@Benchmark method should be public", BENCH_METHOD_QUICK_FIX, ERROR, isOnTheFly); + // if this is a default package + if (Objects.equals(klass.getName(), klass.getQualifiedName())) { +// QuickFixFactory.getInstance().createCreateClassOrPackageFix(aClass, "@State missing", ) + ProblemDescriptor problem = manager.createProblemDescriptor(klass, "Benchmark class should have package other than default", (LocalQuickFix) null, ERROR, isOnTheFly); return new ProblemDescriptor[]{problem}; } - return null; - } - @Nullable - private ProblemDescriptor[] checkSetupTearDownIsNotVoid(@NotNull UMethod method, @NotNull InspectionManager manager, boolean isOnTheFly) { - if ((method.getReturnType() == null || !method.getReturnType().equals(VOID))) { - ProblemDescriptor problem = manager.createProblemDescriptor(method, "@Setup and @TearDown method should return void", BENCH_METHOD_QUICK_FIX, ERROR, isOnTheFly); + if (klass.isFinal()) { + ProblemDescriptor problem = manager.createProblemDescriptor(klass, "Benchmark classes should not be final", (LocalQuickFix) null, ERROR, isOnTheFly); return new ProblemDescriptor[]{problem}; } + return null; } + }