AbstractSuperCheck.java

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 java.util.Deque;
23
import java.util.LinkedList;
24
25
import antlr.collections.AST;
26
import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
27
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
28
import com.puppycrawl.tools.checkstyle.api.DetailAST;
29
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
30
import com.puppycrawl.tools.checkstyle.utils.ScopeUtils;
31
32
/**
33
 * <p>
34
 * Abstract class for checking that an overriding method with no parameters
35
 * invokes the super method.
36
 * </p>
37
 * @author Rick Giles
38
 */
39
@FileStatefulCheck
40
public abstract class AbstractSuperCheck
41
        extends AbstractCheck {
42
43
    /**
44
     * A key is pointing to the warning message text in "messages.properties"
45
     * file.
46
     */
47
    public static final String MSG_KEY = "missing.super.call";
48
49
    /** Stack of methods. */
50
    private final Deque<MethodNode> methodStack = new LinkedList<>();
51
52
    /**
53
     * Returns the name of the overriding method.
54
     * @return the name of the overriding method.
55
     */
56
    protected abstract String getMethodName();
57
58
    @Override
59
    public int[] getAcceptableTokens() {
60 1 1. getAcceptableTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return getRequiredTokens();
61
    }
62
63
    @Override
64
    public int[] getDefaultTokens() {
65 1 1. getDefaultTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return getRequiredTokens();
66
    }
67
68
    @Override
69
    public int[] getRequiredTokens() {
70 1 1. getRequiredTokens : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED
        return new int[] {
71
            TokenTypes.METHOD_DEF,
72
            TokenTypes.LITERAL_SUPER,
73
        };
74
    }
75
76
    @Override
77
    public void beginTree(DetailAST rootAST) {
78 1 1. beginTree : removed call to java/util/Deque::clear → KILLED
        methodStack.clear();
79
    }
80
81
    @Override
82
    public void visitToken(DetailAST ast) {
83 1 1. visitToken : negated conditional → KILLED
        if (isOverridingMethod(ast)) {
84
            methodStack.add(new MethodNode(ast));
85
        }
86 1 1. visitToken : negated conditional → KILLED
        else if (isSuperCall(ast)) {
87
            final MethodNode methodNode = methodStack.getLast();
88 1 1. visitToken : removed call to com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck$MethodNode::setCallingSuper → KILLED
            methodNode.setCallingSuper();
89
        }
90
    }
91
92
    /**
93
     * Determines whether a 'super' literal is a call to the super method
94
     * for this check.
95
     * @param literalSuperAst the AST node of a 'super' literal.
96
     * @return true if ast is a call to the super method for this check.
97
     */
98
    private boolean isSuperCall(DetailAST literalSuperAst) {
99
        boolean superCall = false;
100
101 1 1. isSuperCall : negated conditional → KILLED
        if (literalSuperAst.getType() == TokenTypes.LITERAL_SUPER) {
102
            // dot operator?
103
            final DetailAST dotAst = literalSuperAst.getParent();
104
105 1 1. isSuperCall : negated conditional → KILLED
            if (!isSameNameMethod(literalSuperAst)
106 1 1. isSuperCall : negated conditional → KILLED
                && !hasArguments(dotAst)) {
107
                superCall = isSuperCallInOverridingMethod(dotAst);
108
            }
109
        }
110 1 1. isSuperCall : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return superCall;
111
    }
112
113
    /**
114
     * Determines whether a super call in overriding method.
115
     *
116
     * @param ast The AST node of a 'dot operator' in 'super' call.
117
     * @return true if super call in overriding method.
118
     */
119
    private boolean isSuperCallInOverridingMethod(DetailAST ast) {
120
        boolean inOverridingMethod = false;
121
        DetailAST dotAst = ast;
122
123 1 1. isSuperCallInOverridingMethod : negated conditional → KILLED
        while (dotAst.getType() != TokenTypes.CTOR_DEF
124 1 1. isSuperCallInOverridingMethod : negated conditional → KILLED
                && dotAst.getType() != TokenTypes.INSTANCE_INIT) {
125 1 1. isSuperCallInOverridingMethod : negated conditional → KILLED
            if (dotAst.getType() == TokenTypes.METHOD_DEF) {
126
                inOverridingMethod = isOverridingMethod(dotAst);
127
                break;
128
            }
129
            dotAst = dotAst.getParent();
130
        }
131 1 1. isSuperCallInOverridingMethod : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return inOverridingMethod;
132
    }
133
134
    /**
135
     * Does method have any arguments.
136
     * @param methodCallDotAst DOT DetailAST
137
     * @return true if any parameters found
138
     */
139
    private static boolean hasArguments(DetailAST methodCallDotAst) {
140
        final DetailAST argumentsList = methodCallDotAst.getNextSibling();
141 3 1. hasArguments : changed conditional boundary → KILLED
2. hasArguments : negated conditional → KILLED
3. hasArguments : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return argumentsList.getChildCount() > 0;
142
    }
143
144
    /**
145
     * Is same name of method.
146
     * @param ast method AST
147
     * @return true if method name is the same
148
     */
149
    private boolean isSameNameMethod(DetailAST ast) {
150
        AST sibling = ast.getNextSibling();
151
        // ignore type parameters
152 1 1. isSameNameMethod : negated conditional → KILLED
        if (sibling != null
153 1 1. isSameNameMethod : negated conditional → KILLED
            && sibling.getType() == TokenTypes.TYPE_ARGUMENTS) {
154
            sibling = sibling.getNextSibling();
155
        }
156 3 1. isSameNameMethod : negated conditional → KILLED
2. isSameNameMethod : negated conditional → KILLED
3. isSameNameMethod : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return sibling == null || !getMethodName().equals(sibling.getText());
157
    }
158
159
    @Override
160
    public void leaveToken(DetailAST ast) {
161 1 1. leaveToken : negated conditional → KILLED
        if (isOverridingMethod(ast)) {
162
            final MethodNode methodNode =
163
                methodStack.removeLast();
164 1 1. leaveToken : negated conditional → KILLED
            if (!methodNode.isCallingSuper()) {
165
                final DetailAST methodAST = methodNode.getMethod();
166
                final DetailAST nameAST =
167
                    methodAST.findFirstToken(TokenTypes.IDENT);
168 1 1. leaveToken : removed call to com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck::log → KILLED
                log(nameAST.getLineNo(), nameAST.getColumnNo(),
169
                    MSG_KEY, nameAST.getText());
170
            }
171
        }
172
    }
173
174
    /**
175
     * Determines whether an AST is a method definition for this check,
176
     * with 0 parameters.
177
     * @param ast the method definition AST.
178
     * @return true if the method of ast is a method for this check.
179
     */
180
    private boolean isOverridingMethod(DetailAST ast) {
181
        boolean overridingMethod = false;
182
183 1 1. isOverridingMethod : negated conditional → KILLED
        if (ast.getType() == TokenTypes.METHOD_DEF
184 1 1. isOverridingMethod : negated conditional → KILLED
                && !ScopeUtils.isInInterfaceOrAnnotationBlock(ast)) {
185
            final DetailAST nameAST = ast.findFirstToken(TokenTypes.IDENT);
186
            final String name = nameAST.getText();
187
            final DetailAST modifiersAST = ast.findFirstToken(TokenTypes.MODIFIERS);
188
189 1 1. isOverridingMethod : negated conditional → KILLED
            if (getMethodName().equals(name)
190 1 1. isOverridingMethod : negated conditional → KILLED
                    && modifiersAST.findFirstToken(TokenTypes.LITERAL_NATIVE) == null) {
191
                final DetailAST params = ast.findFirstToken(TokenTypes.PARAMETERS);
192 1 1. isOverridingMethod : negated conditional → KILLED
                overridingMethod = params.getChildCount() == 0;
193
            }
194
        }
195 1 1. isOverridingMethod : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
        return overridingMethod;
196
    }
197
198
    /**
199
     * Stack node for a method definition and a record of
200
     * whether the method has a call to the super method.
201
     * @author Rick Giles
202
     */
203
    private static class MethodNode {
204
205
        /** Method definition. */
206
        private final DetailAST method;
207
208
        /** True if the overriding method calls the super method. */
209
        private boolean callingSuper;
210
211
        /**
212
         * Constructs a stack node for a method definition.
213
         * @param ast AST for the method definition.
214
         */
215
        MethodNode(DetailAST ast) {
216
            method = ast;
217
            callingSuper = false;
218
        }
219
220
        /**
221
         * Records that the overriding method has a call to the super method.
222
         */
223
        public void setCallingSuper() {
224
            callingSuper = true;
225
        }
226
227
        /**
228
         * Determines whether the overriding method has a call to the super
229
         * method.
230
         * @return true if the overriding method has a call to the super method.
231
         */
232
        public boolean isCallingSuper() {
233 1 1. isCallingSuper : replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED
            return callingSuper;
234
        }
235
236
        /**
237
         * Returns the overriding method definition AST.
238
         * @return the overriding method definition AST.
239
         */
240
        public DetailAST getMethod() {
241 1 1. getMethod : mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck$MethodNode::getMethod to ( if (x != null) null else throw new RuntimeException ) → KILLED
            return method;
242
        }
243
244
    }
245
246
}

Mutations

60

1.1
Location : getAcceptableTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testTokensNotNull(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck::getAcceptableTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

65

1.1
Location : getDefaultTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testTokensNotNull(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck::getDefaultTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

70

1.1
Location : getRequiredTokens
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testTokensNotNull(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck::getRequiredTokens to ( if (x != null) null else throw new RuntimeException ) → KILLED

78

1.1
Location : beginTree
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testClearState(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
removed call to java/util/Deque::clear → KILLED

83

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

86

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

88

1.1
Location : visitToken
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck$MethodNode::setCallingSuper → KILLED

101

1.1
Location : isSuperCall
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

105

1.1
Location : isSuperCall
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

106

1.1
Location : isSuperCall
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

110

1.1
Location : isSuperCall
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

123

1.1
Location : isSuperCallInOverridingMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

124

1.1
Location : isSuperCallInOverridingMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

125

1.1
Location : isSuperCallInOverridingMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

131

1.1
Location : isSuperCallInOverridingMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

141

1.1
Location : hasArguments
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
changed conditional boundary → KILLED

2.2
Location : hasArguments
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

3.3
Location : hasArguments
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

152

1.1
Location : isSameNameMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

153

1.1
Location : isSameNameMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

156

1.1
Location : isSameNameMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

2.2
Location : isSameNameMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

3.3
Location : isSameNameMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

161

1.1
Location : leaveToken
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

164

1.1
Location : leaveToken
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

168

1.1
Location : leaveToken
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
removed call to com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck::log → KILLED

183

1.1
Location : isOverridingMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

184

1.1
Location : isOverridingMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

189

1.1
Location : isOverridingMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

190

1.1
Location : isOverridingMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

192

1.1
Location : isOverridingMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
negated conditional → KILLED

195

1.1
Location : isOverridingMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

233

1.1
Location : isCallingSuper
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
replaced return of integer sized value with (x == 0 ? 1 : 0) → KILLED

241

1.1
Location : getMethod
Killed by : com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest.testIt(com.puppycrawl.tools.checkstyle.checks.coding.SuperCloneCheckTest)
mutated return of Object value for com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck$MethodNode::getMethod to ( if (x != null) null else throw new RuntimeException ) → KILLED

Active mutators

Tests examined


Report generated by PIT 1.3.1