View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2025 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.coding;
21  
22  import com.puppycrawl.tools.checkstyle.StatelessCheck;
23  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
24  import com.puppycrawl.tools.checkstyle.api.DetailAST;
25  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26  
27  /**
28   * <div>
29   * Checks that the clone method is not overridden from the
30   * Object class.
31   * </div>
32   *
33   * <p>
34   * This check is almost exactly the same as the {@code NoFinalizerCheck}.
35   * </p>
36   *
37   * <p>
38   * See
39   * <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html#clone()">
40   * Object.clone()</a>
41   * </p>
42   *
43   * <p>
44   * Rationale: The clone method relies on strange, hard to follow rules that
45   * are difficult to get right and do not work in all situations. In some cases,
46   * either a copy constructor or a static factory method can be used instead of
47   * the clone method to return copies of an object. For more information on rules
48   * for the clone method and its issues, see Effective Java:
49   * Programming Language Guide First Edition by Joshua Bloch pages 45-52.
50   * </p>
51   *
52   * <p>
53   * Below are some rules/reasons why the clone method should be avoided.
54   * </p>
55   * <ul>
56   * <li>
57   * Classes supporting the clone method should implement the Cloneable
58   * interface but the Cloneable interface does not include the clone method.
59   * As a result, it doesn't enforce the method override.
60   * </li>
61   * <li>
62   * The Cloneable interface forces the Object's clone method to work
63   * correctly. Without implementing it, the Object's clone method will
64   * throw a CloneNotSupportedException.
65   * </li>
66   * <li>
67   * Non-final classes must return the object returned from a call to
68   * super.clone().
69   * </li>
70   * <li>
71   * Final classes can use a constructor to create a clone which is different
72   * from non-final classes.
73   * </li>
74   * <li>
75   * If a super class implements the clone method incorrectly all subclasses
76   * calling super.clone() are doomed to failure.
77   * </li>
78   * <li>
79   * If a class has references to mutable objects then those object
80   * references must be replaced with copies in the clone method
81   * after calling super.clone().
82   * </li>
83   * <li>
84   * The clone method does not work correctly with final mutable object
85   * references because final references cannot be reassigned.
86   * </li>
87   * <li>
88   * If a super class overrides the clone method then all subclasses must
89   * provide a correct clone implementation.
90   * </li>
91   * </ul>
92   *
93   * <p>Two alternatives to the clone method, in some cases, is a copy constructor
94   * or a static factory method to return copies of an object. Both of these
95   * approaches are simpler and do not conflict with final fields. They do not
96   * force the calling client to handle a CloneNotSupportedException.  They also
97   * are typed therefore no casting is necessary. Finally, they are more
98   * flexible since they can take interface types rather than concrete classes.
99   * </p>
100  *
101  * <p>Sometimes a copy constructor or static factory is not an acceptable
102  * alternative to the clone method.  The example below highlights the
103  * limitation of a copy constructor (or static factory). Assume
104  * Square is a subclass for Shape.
105  * </p>
106  * <pre>
107  * Shape s1 = new Square();
108  * System.out.println(s1 instanceof Square); //true
109  * </pre>
110  *
111  * <p>
112  * ...assume at this point the code knows nothing of s1 being a Square
113  *    that's the beauty of polymorphism but the code wants to copy
114  *    the Square which is declared as a Shape, its super type...
115  * </p>
116  * <pre>
117  * Shape s2 = new Shape(s1); //using the copy constructor
118  * System.out.println(s2 instanceof Square); //false
119  * </pre>
120  *
121  * <p>
122  * The working solution (without knowing about all subclasses and doing many
123  * casts) is to do the following (assuming correct clone implementation).
124  * </p>
125  * <pre>
126  * Shape s2 = s1.clone();
127  * System.out.println(s2 instanceof Square); //true
128  * </pre>
129  *
130  * <p>
131  * Just keep in mind if this type of polymorphic cloning is required
132  * then a properly implemented clone method may be the best choice.
133  * </p>
134  *
135  * <p>Much of this information was taken from Effective Java:
136  * Programming Language Guide First Edition by Joshua Bloch
137  * pages 45-52.  Give Bloch credit for writing an excellent book.
138  * </p>
139  *
140  * <p>
141  * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
142  * </p>
143  *
144  * <p>
145  * Violation Message Keys:
146  * </p>
147  * <ul>
148  * <li>
149  * {@code avoid.clone.method}
150  * </li>
151  * </ul>
152  *
153  * @since 5.0
154  */
155 @StatelessCheck
156 public class NoCloneCheck extends AbstractCheck {
157 
158     /**
159      * A key is pointing to the warning message text in "messages.properties"
160      * file.
161      */
162     public static final String MSG_KEY = "avoid.clone.method";
163 
164     @Override
165     public int[] getDefaultTokens() {
166         return getRequiredTokens();
167     }
168 
169     @Override
170     public int[] getAcceptableTokens() {
171         return getRequiredTokens();
172     }
173 
174     @Override
175     public int[] getRequiredTokens() {
176         return new int[] {TokenTypes.METHOD_DEF};
177     }
178 
179     @Override
180     public void visitToken(DetailAST ast) {
181         final DetailAST mid = ast.findFirstToken(TokenTypes.IDENT);
182         final String name = mid.getText();
183 
184         if ("clone".equals(name)) {
185             final DetailAST params = ast.findFirstToken(TokenTypes.PARAMETERS);
186             final boolean hasEmptyParamList =
187                 params.findFirstToken(TokenTypes.PARAMETER_DEF) == null;
188 
189             if (hasEmptyParamList) {
190                 log(ast, MSG_KEY);
191             }
192         }
193     }
194 
195 }