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

com.liferay.source.formatter.checkstyle.check.BaseAsUsedCheck Maven / Gradle / Ivy

There is a newer version: 1.0.1457
Show newest version
/**
 * SPDX-FileCopyrightText: (c) 2000 Liferay, Inc. https://liferay.com
 * SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
 */

package com.liferay.source.formatter.checkstyle.check;

import com.liferay.petra.string.StringBundler;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.tools.ToolsUtil;

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

import java.util.List;
import java.util.Objects;

/**
 * @author Hugo Huijser
 */
public abstract class BaseAsUsedCheck extends BaseCheck {

	protected void checkInline(
		DetailAST assignDetailAST, String variableName,
		DetailAST identDetailAST, List dependentIdentDetailASTList) {

		if (!variableName.equals(identDetailAST.getText())) {
			return;
		}

		DetailAST assignExpressionDetailAST = _getAssignExpressionDetailAST(
			assignDetailAST);

		if (assignExpressionDetailAST == null) {
			return;
		}

		String assignExpressionType = null;
		boolean chainStyle = false;

		if (assignExpressionDetailAST.getType() == TokenTypes.METHOD_CALL) {
			if (_hasChainStyle(
					assignExpressionDetailAST, "build", "create.*", "map",
					"put")) {

				if (_isInsideStatementClause(identDetailAST)) {
					return;
				}

				chainStyle = true;
			}
			else {
				if (((getStartLineNumber(assignExpressionDetailAST) !=
						getEndLineNumber(assignExpressionDetailAST)) &&
					 (hasParentWithTokenType(
						 identDetailAST, ARITHMETIC_OPERATOR_TOKEN_TYPES) ||
					  hasParentWithTokenType(
						  identDetailAST, RELATIONAL_OPERATOR_TOKEN_TYPES)) &&
					 hasParentWithTokenType(
						 identDetailAST, TokenTypes.METHOD_CALL)) ||
					(_isInsideStatementClause(identDetailAST) &&
					 hasParentWithTokenType(
						 identDetailAST, RELATIONAL_OPERATOR_TOKEN_TYPES))) {

					return;
				}

				if (!_matchesGetOrSetCall(
						assignExpressionDetailAST, identDetailAST,
						variableName)) {

					return;
				}
			}

			assignExpressionType = "method call";
		}
		else if (assignExpressionDetailAST.getType() ==
					TokenTypes.LITERAL_NEW) {

			DetailAST objBlockDetailAST =
				assignExpressionDetailAST.findFirstToken(TokenTypes.OBJBLOCK);

			if (objBlockDetailAST != null) {
				return;
			}

			List typeArgumentsDetailASTList = null;

			DetailAST parentDetailAST = assignDetailAST.getParent();

			if (parentDetailAST.getType() == TokenTypes.VARIABLE_DEF) {
				typeArgumentsDetailASTList = getAllChildTokens(
					parentDetailAST, true, TokenTypes.TYPE_ARGUMENTS);
			}
			else {
				typeArgumentsDetailASTList = getAllChildTokens(
					assignDetailAST, true, TokenTypes.TYPE_ARGUMENTS);
			}

			if (!typeArgumentsDetailASTList.isEmpty()) {
				return;
			}

			DetailAST elistDetailAST = assignExpressionDetailAST.findFirstToken(
				TokenTypes.ELIST);

			if ((elistDetailAST == null) ||
				(elistDetailAST.getChildCount() > 0)) {

				return;
			}

			assignExpressionType = "new instance";
		}
		else {
			return;
		}

		if (_isInsideMockitoMethodCall(identDetailAST)) {
			return;
		}

		DetailAST parentDetailAST = identDetailAST.getParent();

		if (parentDetailAST.getType() == TokenTypes.LNOT) {
			parentDetailAST = parentDetailAST.getParent();
		}

		boolean toString = false;

		if (parentDetailAST.getType() == TokenTypes.DOT) {
			FullIdent fullIdent = FullIdent.createFullIdent(parentDetailAST);

			if (!Objects.equals(
					fullIdent.getText(), variableName + ".toString")) {

				return;
			}

			toString = true;
		}
		else if (parentDetailAST.getType() != TokenTypes.EXPR) {
			return;
		}

		int endLineNumber = getEndLineNumber(assignDetailAST);

		for (DetailAST dependentIdentDetailAST : dependentIdentDetailASTList) {
			if (variableName.equals(dependentIdentDetailAST.getText()) &&
				!equals(dependentIdentDetailAST, identDetailAST) &&
				(dependentIdentDetailAST.getLineNo() > endLineNumber)) {

				return;
			}
		}

		parentDetailAST = getParentWithTokenType(
			identDetailAST, TokenTypes.LAMBDA, TokenTypes.LITERAL_DO,
			TokenTypes.LITERAL_FOR, TokenTypes.LITERAL_NEW,
			TokenTypes.LITERAL_SYNCHRONIZED, TokenTypes.LITERAL_TRY,
			TokenTypes.LITERAL_WHILE);

		if ((parentDetailAST != null) &&
			(parentDetailAST.getLineNo() >= assignDetailAST.getLineNo())) {

			return;
		}

		int emptyLineCount = 0;

		for (int i = endLineNumber; i <= identDetailAST.getLineNo(); i++) {
			if (Validator.isNull(getLine(i - 1))) {
				emptyLineCount++;

				if (emptyLineCount > 1) {
					return;
				}
			}
		}

		if (!toString) {
			log(
				assignDetailAST, _MSG_INLINE_VARIABLE, variableName,
				assignExpressionType, identDetailAST.getLineNo());
		}
		else if (chainStyle) {
			String variableTypeName = getVariableTypeName(
				identDetailAST, variableName, false);

			if (variableTypeName.equals("JSONArray") ||
				variableTypeName.equals("JSONObject")) {

				log(
					identDetailAST, _MSG_ADD_TO_STRING,
					assignDetailAST.getLineNo());
			}
		}
		else {
			log(
				identDetailAST, _MSG_USE_STRING_VALUE_OF,
				assignDetailAST.getLineNo(), identDetailAST.getLineNo());
		}
	}

	protected void checkMoveAfterBranchingStatement(
		DetailAST detailAST, DetailAST assignDetailAST, String variableName,
		DetailAST firstDependentIdentDetailAST, int actionLineNumber) {

		int endLineNumber = getEndLineNumber(assignDetailAST);

		DetailAST lastBranchingStatementDetailAST =
			_getLastBranchingStatementDetailAST(
				detailAST, endLineNumber,
				_getClosestParentLineNumber(
					firstDependentIdentDetailAST, endLineNumber));

		if (lastBranchingStatementDetailAST == null) {
			return;
		}

		int lineNumber = lastBranchingStatementDetailAST.getLineNo();

		if ((actionLineNumber == -1) || (actionLineNumber > lineNumber)) {
			log(
				assignDetailAST, _MSG_MOVE_VARIABLE_AFTER_BRANCHING_STATEMENT,
				variableName, lastBranchingStatementDetailAST.getText(),
				lastBranchingStatementDetailAST.getLineNo());
		}
	}

	protected void checkMoveInsideIfStatement(
		DetailAST assignDetailAST, DetailAST nameDetailAST, String variableName,
		DetailAST firstDependentIdentDetailAST,
		DetailAST lastDependentIdentDetailAST, int actionLineNumber) {

		DetailAST elseOrIfStatementDetailAST = _getElseOrIfStatementDetailAST(
			firstDependentIdentDetailAST, getEndLineNumber(assignDetailAST));

		if (elseOrIfStatementDetailAST == null) {
			return;
		}

		DetailAST parentDetailAST = getParentWithTokenType(
			elseOrIfStatementDetailAST, TokenTypes.LAMBDA,
			TokenTypes.LITERAL_DO, TokenTypes.LITERAL_FOR,
			TokenTypes.LITERAL_NEW, TokenTypes.LITERAL_SYNCHRONIZED,
			TokenTypes.LITERAL_TRY, TokenTypes.LITERAL_WHILE);

		if ((parentDetailAST != null) &&
			(parentDetailAST.getLineNo() >= assignDetailAST.getLineNo())) {

			return;
		}

		DetailAST slistDetailAST = elseOrIfStatementDetailAST.findFirstToken(
			TokenTypes.SLIST);

		if (getEndLineNumber(slistDetailAST) <=
				lastDependentIdentDetailAST.getLineNo()) {

			return;
		}

		if (actionLineNumber != -1) {
			parentDetailAST = elseOrIfStatementDetailAST;

			while (true) {
				DetailAST grandParentDetailAST = parentDetailAST.getParent();

				if ((grandParentDetailAST.getType() ==
						TokenTypes.LITERAL_ELSE) ||
					(grandParentDetailAST.getType() == TokenTypes.LITERAL_IF)) {

					parentDetailAST = grandParentDetailAST;

					continue;
				}

				if (actionLineNumber < parentDetailAST.getLineNo()) {
					return;
				}

				break;
			}
		}

		if (elseOrIfStatementDetailAST.getType() == TokenTypes.LITERAL_ELSE) {
			log(
				nameDetailAST, _MSG_MOVE_VARIABLE_INSIDE_IF_STATEMENT,
				variableName, "else", elseOrIfStatementDetailAST.getLineNo());
		}
		else {
			parentDetailAST = elseOrIfStatementDetailAST.getParent();

			if (parentDetailAST.getType() == TokenTypes.LITERAL_ELSE) {
				log(
					nameDetailAST, _MSG_MOVE_VARIABLE_INSIDE_IF_STATEMENT,
					variableName, "else if",
					elseOrIfStatementDetailAST.getLineNo());
			}
			else {
				log(
					nameDetailAST, _MSG_MOVE_VARIABLE_INSIDE_IF_STATEMENT,
					variableName, "if", elseOrIfStatementDetailAST.getLineNo());
			}
		}
	}

	protected int getActionLineNumber(DetailAST detailAST) {
		String actionNameRegex = StringBundler.concat(
			"_?(re|un)?(add|calculate|channel|close|copy|create|decode|delete|",
			"encode|execute|finish|import|increment|manage|next|open|post|put|",
			"read|register|resolve|run|send|set|start|stop|test|transform|",
			"update|upsert|zip)([A-Z].*)?");

		if (_containsMethodName(
				detailAST, actionNameRegex, "currentTimeMillis",
				"getCurrentTimeMillis", "nextVersion", "toString") ||
			_containsVariableType(detailAST, "ActionQueue", "File")) {

			return detailAST.getLineNo();
		}

		if (detailAST.getType() != TokenTypes.VARIABLE_DEF) {
			return -1;
		}

		List dependentIdentDetailASTList =
			getDependentIdentDetailASTList(
				detailAST, detailAST.getLineNo(), true);

		for (DetailAST dependentIdentDetailAST : dependentIdentDetailASTList) {
			DetailAST elistDetailAST = getParentWithTokenType(
				dependentIdentDetailAST, TokenTypes.ELIST);

			if (elistDetailAST == null) {
				continue;
			}

			DetailAST parentDetailAST = elistDetailAST.getParent();

			if (parentDetailAST.getType() == TokenTypes.METHOD_CALL) {
				String methodName = getMethodName(parentDetailAST);

				if (methodName.matches(actionNameRegex)) {
					return dependentIdentDetailAST.getLineNo();
				}
			}
		}

		return -1;
	}

	private boolean _containsMethodName(
		DetailAST variableDefinitionDetailAST, String... methodNameRegexArray) {

		List methodCallDetailASTList = getAllChildTokens(
			variableDefinitionDetailAST, true, TokenTypes.METHOD_CALL);

		for (DetailAST methodCallDetailAST : methodCallDetailASTList) {
			String methodName = getMethodName(methodCallDetailAST);

			for (String methodNameRegex : methodNameRegexArray) {
				if (methodName.matches(methodNameRegex)) {
					return true;
				}
			}
		}

		return false;
	}

	private boolean _containsVariableType(
		DetailAST variableDefinitionDetailAST, String... variableTypeNames) {

		List identDetailASTList = getAllChildTokens(
			variableDefinitionDetailAST, true, TokenTypes.IDENT);

		for (DetailAST identDetailAST : identDetailASTList) {
			if (ArrayUtil.contains(
					variableTypeNames,
					getVariableTypeName(
						identDetailAST, identDetailAST.getText(), false))) {

				return true;
			}
		}

		return false;
	}

	private DetailAST _getAssignExpressionDetailAST(DetailAST assignDetailAST) {
		DetailAST firstChildDetailAST = assignDetailAST.getFirstChild();

		if (firstChildDetailAST == null) {
			return null;
		}

		if (firstChildDetailAST.getType() == TokenTypes.EXPR) {
			return firstChildDetailAST.getFirstChild();
		}

		if (firstChildDetailAST.getType() == TokenTypes.IDENT) {
			return firstChildDetailAST.getNextSibling();
		}

		return null;
	}

	private int _getClosestParentLineNumber(
		DetailAST firstNameDetailAST, int lineNumber) {

		int closestLineNumber = firstNameDetailAST.getLineNo();

		DetailAST parentDetailAST = firstNameDetailAST.getParent();

		while (true) {
			if (parentDetailAST.getLineNo() <= lineNumber) {
				return closestLineNumber;
			}

			closestLineNumber = parentDetailAST.getLineNo();

			parentDetailAST = parentDetailAST.getParent();
		}
	}

	private DetailAST _getElseOrIfStatementDetailAST(
		DetailAST detailAST, int lineNumber) {

		DetailAST elseOrIfStatementDetailAST = null;

		DetailAST slistDetailAST = getParentWithTokenType(
			detailAST, TokenTypes.SLIST);

		while (true) {
			if ((slistDetailAST == null) ||
				(slistDetailAST.getLineNo() < lineNumber)) {

				return elseOrIfStatementDetailAST;
			}

			DetailAST parentDetailAST = slistDetailAST.getParent();

			if ((parentDetailAST.getType() == TokenTypes.LITERAL_ELSE) ||
				(parentDetailAST.getType() == TokenTypes.LITERAL_IF)) {

				elseOrIfStatementDetailAST = parentDetailAST;
			}

			slistDetailAST = getParentWithTokenType(
				slistDetailAST, TokenTypes.SLIST);
		}
	}

	private DetailAST _getLastBranchingStatementDetailAST(
		DetailAST detailAST, int start, int end) {

		DetailAST lastBranchingStatementDetailAST = null;

		List branchingStatementDetailASTList = getAllChildTokens(
			detailAST, true, TokenTypes.LITERAL_BREAK,
			TokenTypes.LITERAL_CONTINUE, TokenTypes.LITERAL_RETURN,
			TokenTypes.LITERAL_THROW);

		for (DetailAST branchingStatementDetailAST :
				branchingStatementDetailASTList) {

			int lineNumber = getEndLineNumber(branchingStatementDetailAST);

			if ((start >= lineNumber) || (end <= lineNumber)) {
				continue;
			}

			DetailAST branchedStatementDetailAST = null;

			if ((branchingStatementDetailAST.getType() ==
					TokenTypes.LITERAL_BREAK) ||
				(branchingStatementDetailAST.getType() ==
					TokenTypes.LITERAL_CONTINUE)) {

				branchedStatementDetailAST = getParentWithTokenType(
					branchingStatementDetailAST, TokenTypes.LITERAL_DO,
					TokenTypes.LITERAL_FOR, TokenTypes.LITERAL_WHILE);
			}
			else {
				branchedStatementDetailAST = getParentWithTokenType(
					branchingStatementDetailAST, TokenTypes.CTOR_DEF,
					TokenTypes.LAMBDA, TokenTypes.METHOD_DEF);
			}

			if ((branchedStatementDetailAST != null) &&
				(branchedStatementDetailAST.getLineNo() < start) &&
				((lastBranchingStatementDetailAST == null) ||
				 (branchingStatementDetailAST.getLineNo() >
					 lastBranchingStatementDetailAST.getLineNo()))) {

				lastBranchingStatementDetailAST = branchingStatementDetailAST;
			}
		}

		return lastBranchingStatementDetailAST;
	}

	private boolean _hasChainStyle(
		DetailAST methodCallDetailAST, String... methodNameRegexArray) {

		int startLineNumber = getStartLineNumber(methodCallDetailAST);

		String line = getLine(startLineNumber - 1);

		if (!line.endsWith("(") || (ToolsUtil.getLevel(line) != 1)) {
			return false;
		}

		for (String methodNameRegex : methodNameRegexArray) {
			if (!line.matches(".*[\\.>]" + methodNameRegex + "\\(")) {
				continue;
			}

			int level = 1;

			for (int i = startLineNumber + 1;
				 i <= getEndLineNumber(methodCallDetailAST); i++) {

				line = StringUtil.trim(getLine(i - 1));

				if (line.startsWith(").") && (level == 1)) {
					return true;
				}

				level += ToolsUtil.getLevel(line);
			}
		}

		return false;
	}

	private boolean _isInsideMockitoMethodCall(DetailAST detailAST) {
		DetailAST methodCallDetailAST = getParentWithTokenType(
			detailAST, TokenTypes.METHOD_CALL);

		if (methodCallDetailAST == null) {
			return false;
		}

		for (String name : getNames(methodCallDetailAST, true)) {
			if (Objects.equals(name, "Mockito")) {
				return true;
			}
		}

		return false;
	}

	private boolean _isInsideStatementClause(DetailAST detailAST) {
		DetailAST parentDetailAST = detailAST.getParent();

		while (true) {
			DetailAST grandParentDetailAST = parentDetailAST.getParent();

			if (grandParentDetailAST == null) {
				return false;
			}

			if (grandParentDetailAST.getType() == TokenTypes.LITERAL_FOR) {
				if ((parentDetailAST.getType() == TokenTypes.FOR_CONDITION) ||
					(parentDetailAST.getType() == TokenTypes.FOR_EACH_CLAUSE) ||
					(parentDetailAST.getType() == TokenTypes.FOR_INIT) ||
					(parentDetailAST.getType() == TokenTypes.FOR_ITERATOR)) {

					return true;
				}

				return false;
			}

			if (grandParentDetailAST.getType() == TokenTypes.LITERAL_TRY) {
				if (parentDetailAST.getType() ==
						TokenTypes.RESOURCE_SPECIFICATION) {

					return true;
				}

				return false;
			}

			if (grandParentDetailAST.getType() == TokenTypes.LITERAL_WHILE) {
				if (parentDetailAST.getType() == TokenTypes.EXPR) {
					return true;
				}

				return false;
			}

			parentDetailAST = grandParentDetailAST;
		}
	}

	private boolean _matchesGetOrSetCall(
		DetailAST assignMethodCallDetailAST, DetailAST identDetailAST,
		String variableName) {

		String methodName = getMethodName(assignMethodCallDetailAST);

		if (methodName.matches("(?i)_?get" + variableName)) {
			return true;
		}

		DetailAST parentDetailAST = identDetailAST.getParent();

		if (parentDetailAST.getType() != TokenTypes.EXPR) {
			return false;
		}

		parentDetailAST = parentDetailAST.getParent();

		if ((parentDetailAST.getType() != TokenTypes.ELIST) ||
			(parentDetailAST.getChildCount() != 1)) {

			return false;
		}

		parentDetailAST = parentDetailAST.getParent();

		if (parentDetailAST.getType() != TokenTypes.METHOD_CALL) {
			return false;
		}

		methodName = getMethodName(parentDetailAST);

		if (methodName.matches("(?i)_?set" + variableName)) {
			return true;
		}

		return false;
	}

	private static final String _MSG_ADD_TO_STRING = "to.string.add";

	private static final String _MSG_INLINE_VARIABLE = "variable.inline";

	private static final String _MSG_MOVE_VARIABLE_AFTER_BRANCHING_STATEMENT =
		"variable.move.after.branching.statement";

	private static final String _MSG_MOVE_VARIABLE_INSIDE_IF_STATEMENT =
		"variable.move.inside.if.statement";

	private static final String _MSG_USE_STRING_VALUE_OF =
		"string.value.of.use";

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy