001///////////////////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
003// Copyright (C) 2001-2024 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018///////////////////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.checks.coding;
021
022import com.puppycrawl.tools.checkstyle.StatelessCheck;
023import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
024import com.puppycrawl.tools.checkstyle.api.DetailAST;
025import com.puppycrawl.tools.checkstyle.api.TokenTypes;
026
027/**
028 * <p>
029 * Checks that the clone method is not overridden from the
030 * Object class.
031 * </p>
032 * <p>
033 * This check is almost exactly the same as the {@code NoFinalizerCheck}.
034 * </p>
035 * <p>
036 * See
037 * <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html#clone()">
038 * Object.clone()</a>
039 * </p>
040 * <p>
041 * Rationale: The clone method relies on strange, hard to follow rules that
042 * are difficult to get right and do not work in all situations. In some cases,
043 * either a copy constructor or a static factory method can be used instead of
044 * the clone method to return copies of an object. For more information on rules
045 * for the clone method and its issues, see Effective Java:
046 * Programming Language Guide First Edition by Joshua Bloch pages 45-52.
047 * </p>
048 * <p>
049 * Below are some rules/reasons why the clone method should be avoided.
050 * </p>
051 * <ul>
052 * <li>
053 * Classes supporting the clone method should implement the Cloneable
054 * interface but the Cloneable interface does not include the clone method.
055 * As a result, it doesn't enforce the method override.
056 * </li>
057 * <li>
058 * The Cloneable interface forces the Object's clone method to work
059 * correctly. Without implementing it, the Object's clone method will
060 * throw a CloneNotSupportedException.
061 * </li>
062 * <li>
063 * Non-final classes must return the object returned from a call to
064 * super.clone().
065 * </li>
066 * <li>
067 * Final classes can use a constructor to create a clone which is different
068 * from non-final classes.
069 * </li>
070 * <li>
071 * If a super class implements the clone method incorrectly all subclasses
072 * calling super.clone() are doomed to failure.
073 * </li>
074 * <li>
075 * If a class has references to mutable objects then those object
076 * references must be replaced with copies in the clone method
077 * after calling super.clone().
078 * </li>
079 * <li>
080 * The clone method does not work correctly with final mutable object
081 * references because final references cannot be reassigned.
082 * </li>
083 * <li>
084 * If a super class overrides the clone method then all subclasses must
085 * provide a correct clone implementation.
086 * </li>
087 * </ul>
088 *
089 * <p>Two alternatives to the clone method, in some cases, is a copy constructor
090 * or a static factory method to return copies of an object. Both of these
091 * approaches are simpler and do not conflict with final fields. They do not
092 * force the calling client to handle a CloneNotSupportedException.  They also
093 * are typed therefore no casting is necessary. Finally, they are more
094 * flexible since they can take interface types rather than concrete classes.
095 * </p>
096 * <p>Sometimes a copy constructor or static factory is not an acceptable
097 * alternative to the clone method.  The example below highlights the
098 * limitation of a copy constructor (or static factory). Assume
099 * 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
145public 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}