View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.checkstyle;
6   
7   import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
8   import com.puppycrawl.tools.checkstyle.api.DetailAST;
9   import com.puppycrawl.tools.checkstyle.api.TokenTypes;
10  
11  /**
12   * Checks that constructors do not contain a redundant {@code super()}
13   * call when the enclosing class does not extend any class explicitly.
14   *
15   * <p>A class without an {@code extends} clause implicitly extends
16   * {@link Object}. Calling {@code super()} in its constructor invokes
17   * the {@link Object} constructor, which the compiler inserts on its own.
18   * The explicit call is therefore redundant and is most often a sign
19   * of confusion between class extension and interface implementation,
20   * for example:</p>
21   *
22   * <pre>
23   * public class NewAgent implements Agent {
24   *     public NewAgent() {
25   *         super();
26   *     }
27   * }
28   * </pre>
29   *
30   * <p>The rule only applies to constructors of {@code class} declarations.
31   * It does not apply to records or enums, where {@code super(...)}
32   * either targets a fixed superclass or is illegal.</p>
33   *
34   * @since 0.24
35   */
36  public final class RedundantSuperConstructorCheck extends AbstractCheck {
37  
38      /**
39       * Default constructor.
40       */
41      public RedundantSuperConstructorCheck() {
42          // nothing to initialize
43      }
44  
45      @Override
46      public int[] getDefaultTokens() {
47          return new int[] {TokenTypes.CTOR_DEF};
48      }
49  
50      @Override
51      public int[] getAcceptableTokens() {
52          return this.getDefaultTokens();
53      }
54  
55      @Override
56      public int[] getRequiredTokens() {
57          return this.getDefaultTokens();
58      }
59  
60      @Override
61      public void visitToken(final DetailAST ast) {
62          final DetailAST clazz = RedundantSuperConstructorCheck.enclosingClass(ast);
63          if (clazz != null
64              && clazz.findFirstToken(TokenTypes.EXTENDS_CLAUSE) == null) {
65              final DetailAST body = ast.findFirstToken(TokenTypes.SLIST);
66              if (body != null) {
67                  this.reportSuperCalls(body);
68              }
69          }
70      }
71  
72      private static DetailAST enclosingClass(final DetailAST ctor) {
73          DetailAST result = null;
74          final DetailAST block = ctor.getParent();
75          if (block != null && block.getType() == TokenTypes.OBJBLOCK) {
76              final DetailAST owner = block.getParent();
77              if (owner != null && owner.getType() == TokenTypes.CLASS_DEF) {
78                  result = owner;
79              }
80          }
81          return result;
82      }
83  
84      private void reportSuperCalls(final DetailAST node) {
85          for (DetailAST child = node.getFirstChild();
86              child != null; child = child.getNextSibling()) {
87              final int type = child.getType();
88              if (type == TokenTypes.LAMBDA
89                  || type == TokenTypes.OBJBLOCK
90                  || type == TokenTypes.CLASS_DEF) {
91                  continue;
92              }
93              if (type == TokenTypes.SUPER_CTOR_CALL) {
94                  this.log(
95                      child.getLineNo(),
96                      "Redundant super() call when class does not extend any other class"
97                  );
98              }
99              this.reportSuperCalls(child);
100         }
101     }
102 }