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