1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3 * SPDX-License-Identifier: MIT
4 */
5 package com.qulice.pmd.rules;
6
7 import net.sourceforge.pmd.lang.java.ast.ASTClassDeclaration;
8 import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
9 import net.sourceforge.pmd.lang.java.ast.JModifier;
10 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
11
12 /**
13 * Rule to check that a class does not declare too many fields. Like the PMD
14 * built-in {@code TooManyFields} rule, this implementation counts the
15 * fields declared in the body of the class, skipping the static and the
16 * final ones, since those are constants rather than state, and reports a
17 * class that declares more than fifteen of them. Unlike the built-in
18 * rule, it skips a class that extends
19 * {@code org.apache.maven.plugin.AbstractMojo}: a Maven Mojo declares one
20 * field per {@code @Parameter} it exposes to users of the plugin goal,
21 * because the Maven Plugin API requires each configurable parameter as a
22 * directly annotated field on the Mojo, so that count tracks the number of
23 * options the goal accepts rather than the cohesion of the class.
24 * Skipping them here instead of through a
25 * {@code violationSuppressXPath} keeps a redundant
26 * {@code @SuppressWarnings("PMD.TooManyFields")} visible to
27 * {@code UnnecessaryWarningSuppression}, which PMD credits to the
28 * annotation whenever the annotation suppressor runs first.
29 *
30 * @since 1.0
31 */
32 public final class TooManyFieldsRule extends AbstractJavaRulechainRule {
33
34 /**
35 * The base class of every Maven Mojo.
36 */
37 private static final NamedSupertype MOJO = new NamedSupertype(
38 "org.apache.maven.plugin.AbstractMojo"
39 );
40
41 /**
42 * Default constructor.
43 */
44 public TooManyFieldsRule() {
45 super(ASTClassDeclaration.class);
46 }
47
48 @Override
49 public Object visit(final ASTClassDeclaration type, final Object data) {
50 if (!TooManyFieldsRule.MOJO.matches(type.getSuperClassTypeNode())
51 && TooManyFieldsRule.state(type) > 15) {
52 this.asCtx(data).addViolation(type);
53 }
54 return data;
55 }
56
57 private static long state(final ASTClassDeclaration type) {
58 return type.getDeclarations(ASTFieldDeclaration.class)
59 .filter(TooManyFieldsRule::mutable)
60 .count();
61 }
62
63 private static boolean mutable(final ASTFieldDeclaration field) {
64 return !field.hasModifiers(JModifier.FINAL)
65 && !field.hasModifiers(JModifier.STATIC);
66 }
67 }