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