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

io.spring.javaformat.checkstyle.check.SpringTernaryCheck Maven / Gradle / Ivy

There is a newer version: 0.0.43
Show newest version
/*
 * Copyright 2017-2023 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.spring.javaformat.checkstyle.check;

import java.util.Locale;

import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;

/**
 * Checks that ternary operations follow Spring conventions. All ternary tests should have
 * parentheses. Not equals to should be used rather than equals as the test for nulls.
 *
 * @author Phillip Webb
 */
public class SpringTernaryCheck extends AbstractSpringCheck {

	private EqualsTest equalsTest = EqualsTest.NEVER_FOR_NULLS;

	@Override
	public int[] getAcceptableTokens() {
		return new int[] { TokenTypes.QUESTION };
	}

	@Override
	public void visitToken(DetailAST ast) {
		if (ast.getType() == TokenTypes.QUESTION) {
			visitQuestion(ast);
		}
	}

	private void visitQuestion(DetailAST ast) {
		DetailAST expression = ast.getFirstChild();
		if (!hasType(expression, TokenTypes.LPAREN)) {
			if (expression != null && requiresParens(expression)) {
				log(ast.getLineNo(), ast.getColumnNo(), "ternary.missingParen");
			}
		}
		while (hasType(expression, TokenTypes.LPAREN)) {
			expression = expression.getNextSibling();
		}
		if (isSimpleEqualsExpression(expression) && !isEqualsTestAllowed(ast)) {
			log(ast.getLineNo(), ast.getColumnNo(), "ternary.equalOperator");
		}
	}

	private boolean requiresParens(DetailAST expression) {
		if (expression != null && expression.getChildCount() > 1) {
			switch (expression.getType()) {
				case TokenTypes.METHOD_CALL:
				case TokenTypes.DOT:
					return false;
			}
			return true;
		}
		return false;
	}

	private boolean isSimpleEqualsExpression(DetailAST expression) {
		if (expression == null || expression.getType() != TokenTypes.EQUAL) {
			return false;
		}
		DetailAST child = expression.getFirstChild();
		while (child != null) {
			if (child.getChildCount() > 0) {
				return false;
			}
			child = child.getNextSibling();
		}
		return true;
	}

	private boolean isEqualsTestAllowed(DetailAST ast) {
		switch (this.equalsTest) {
			case ANY:
				return true;
			case NEVER:
				return false;
			case NEVER_FOR_NULLS:
				DetailAST equal = ast.findFirstToken(TokenTypes.EQUAL);
				return equal.findFirstToken(TokenTypes.LITERAL_NULL) == null;
		}
		throw new IllegalStateException("Unsupported equals test " + this.equalsTest);
	}

	private boolean hasType(DetailAST ast, int type) {
		return (ast != null && ast.getType() == type);
	}

	public void setEqualsTest(String equalsTest) {
		try {
			this.equalsTest = Enum.valueOf(EqualsTest.class, equalsTest.trim().toUpperCase(Locale.ENGLISH));
		}
		catch (final IllegalArgumentException ex) {
			throw new IllegalArgumentException("unable to parse " + equalsTest, ex);
		}
	}

	/**
	 * Type of equals operators allowed in the test condition.
	 */
	public enum EqualsTest {

		/**
		 * Equals checks can be used for any test.
		 */
		ANY,

		/**
		 * Equals tests can never be used.
		 */
		NEVER,

		/**
		 * Equals tests can never be used for {@code null} checks.
		 */
		NEVER_FOR_NULLS

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy