All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.puppycrawl.tools.checkstyle.checks.coding.ExplicitInitializationCheck Maven / Gradle / Ivy

Go to download

Checkstyle is a development tool to help programmers write Java code that adheres to a coding standard

There is a newer version: 10.18.1
Show newest version
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2019 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
////////////////////////////////////////////////////////////////////////////////

package com.puppycrawl.tools.checkstyle.checks.coding;

import com.puppycrawl.tools.checkstyle.StatelessCheck;
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.utils.CheckUtil;
import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;

/**
 * 

* Checks if any class or object member is explicitly initialized * to default for its type value ({@code null} for object * references, zero for numeric types and {@code char} * and {@code false} for {@code boolean}. *

*

* Rationale: Each instance variable gets * initialized twice, to the same value. Java * initializes each instance variable to its default * value ({@code 0} or {@code null}) before performing any * initialization specified in the code. * So there is a minor inefficiency. *

*
    *
  • * Property {@code onlyObjectReferences} - control whether only explicit * initializations made to null for objects should be checked. * Default value is {@code false}. *
  • *
*

* To configure the check: *

*
 * <module name="ExplicitInitialization"/>
 * 
*

* To configure the check so that it only checks for objects that explicitly initialize to null: *

*
 * <module name="ExplicitInitialization">
 *   <property name="onlyObjectReferences" value="true"/>
 * </module>
 * 
*

* Example: *

*
 * public class Test {
 *   private int a = 0;
 *   private int b = 1;
 *   private int c = 2;
 *
 *   private boolean a = true;
 *   private boolean b = false;
 *   private boolean c = true;
 *   private boolean d = false;
 *   private boolean e = false;
 *
 *   private A a = new A();
 *   private A b = null; // violation
 *   private C c = null; // violation
 *   private D d = new D();
 *
 *   int ar1[] = null; // violation
 *   int ar2[] = new int[];
 *   int ar3[];
 *   private Bar<String> bar = null; // violation
 *   private Bar<String>[] barArray = null; // violation
 *
 *   public static void main( String [] args ) {
 *   }
 * }
 * 
* * @since 3.2 */ @StatelessCheck public class ExplicitInitializationCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" * file. */ public static final String MSG_KEY = "explicit.init"; /** * Control whether only explicit initializations made to null for objects should be checked. **/ private boolean onlyObjectReferences; @Override public final int[] getDefaultTokens() { return getRequiredTokens(); } @Override public final int[] getRequiredTokens() { return new int[] {TokenTypes.VARIABLE_DEF}; } @Override public final int[] getAcceptableTokens() { return getRequiredTokens(); } /** * Setter to control whether only explicit initializations made to null * for objects should be checked. * @param onlyObjectReferences whether only explicit initialization made to null * should be checked */ public void setOnlyObjectReferences(boolean onlyObjectReferences) { this.onlyObjectReferences = onlyObjectReferences; } @Override public void visitToken(DetailAST ast) { if (!isSkipCase(ast)) { final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN); final DetailAST exprStart = assign.getFirstChild().getFirstChild(); if (exprStart.getType() == TokenTypes.LITERAL_NULL) { final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT); log(ident, MSG_KEY, ident.getText(), "null"); } if (!onlyObjectReferences) { validateNonObjects(ast); } } } /** * Checks for explicit initializations made to 'false', '0' and '\0'. * @param ast token being checked for explicit initializations */ private void validateNonObjects(DetailAST ast) { final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT); final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN); final DetailAST exprStart = assign.getFirstChild().getFirstChild(); final DetailAST type = ast.findFirstToken(TokenTypes.TYPE); final int primitiveType = type.getFirstChild().getType(); if (primitiveType == TokenTypes.LITERAL_BOOLEAN && exprStart.getType() == TokenTypes.LITERAL_FALSE) { log(ident, MSG_KEY, ident.getText(), "false"); } if (isNumericType(primitiveType) && isZero(exprStart)) { log(ident, MSG_KEY, ident.getText(), "0"); } if (primitiveType == TokenTypes.LITERAL_CHAR && isZeroChar(exprStart)) { log(ident, MSG_KEY, ident.getText(), "\\0"); } } /** * Examine char literal for initializing to default value. * @param exprStart expression * @return true is literal is initialized by zero symbol */ private static boolean isZeroChar(DetailAST exprStart) { return isZero(exprStart) || exprStart.getType() == TokenTypes.CHAR_LITERAL && "'\\0'".equals(exprStart.getText()); } /** * Checks for cases that should be skipped: no assignment, local variable, final variables. * @param ast Variable def AST * @return true is that is a case that need to be skipped. */ private static boolean isSkipCase(DetailAST ast) { boolean skipCase = true; // do not check local variables and // fields declared in interface/annotations if (!ScopeUtil.isLocalVariableDef(ast) && !ScopeUtil.isInInterfaceOrAnnotationBlock(ast)) { final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN); if (assign != null) { final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); skipCase = modifiers.findFirstToken(TokenTypes.FINAL) != null; } } return skipCase; } /** * Determine if a given type is a numeric type. * @param type code of the type for check. * @return true if it's a numeric type. * @see TokenTypes */ private static boolean isNumericType(int type) { return type == TokenTypes.LITERAL_BYTE || type == TokenTypes.LITERAL_SHORT || type == TokenTypes.LITERAL_INT || type == TokenTypes.LITERAL_FLOAT || type == TokenTypes.LITERAL_LONG || type == TokenTypes.LITERAL_DOUBLE; } /** * Checks if given node contains numeric constant for zero. * * @param expr node to check. * @return true if given node contains numeric constant for zero. */ private static boolean isZero(DetailAST expr) { final int type = expr.getType(); final boolean isZero; switch (type) { case TokenTypes.NUM_FLOAT: case TokenTypes.NUM_DOUBLE: case TokenTypes.NUM_INT: case TokenTypes.NUM_LONG: final String text = expr.getText(); isZero = Double.compare(CheckUtil.parseDouble(text, type), 0.0) == 0; break; default: isZero = false; } return isZero; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy