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

com.liferay.source.formatter.checkstyle.checks.StaticBlockCheck Maven / Gradle / Ivy

There is a newer version: 1.0.1437
Show newest version
/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * 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.
 */

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

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

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Hugo Huijser
 */
public class StaticBlockCheck extends BaseCheck {

	@Override
	public int[] getDefaultTokens() {
		return new int[] {TokenTypes.STATIC_INIT};
	}

	@Override
	protected void doVisitToken(DetailAST detailAST) {
		List classObjectNames = _getClassObjectNames(detailAST);

		if (classObjectNames.isEmpty()) {
			return;
		}

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

		if (methodCallDetailASTList.isEmpty()) {
			return;
		}

		Map> identDetailASTMap = _getIdentDetailASTMap(
			detailAST);

		Map variableDefMap = _getVariableDefMap(
			detailAST, identDetailASTMap);

		for (DetailAST methodCallDetailAST : methodCallDetailASTList) {
			_checkMethodCall(
				methodCallDetailAST, classObjectNames, identDetailASTMap,
				variableDefMap);
		}
	}

	private void _checkMethodCall(
		DetailAST methodCallDetailAST, List classObjectNames,
		Map> identDetailASTMap,
		Map variableDefMap) {

		String variableName = getVariableName(methodCallDetailAST);

		if (!classObjectNames.contains(variableName) ||
			variableName.equals("_log")) {

			return;
		}

		DetailAST topLevelDetailAST = _getTopLevelDetailAST(
			methodCallDetailAST);

		int statementEndLineNumber = getEndLineNumber(topLevelDetailAST);

		List variableDetailASTList = identDetailASTMap.get(
			variableName);

		DetailAST firstUseVariableDetailAST = variableDetailASTList.get(0);

		topLevelDetailAST = _getTopLevelDetailAST(firstUseVariableDetailAST);

		int statementStartLineNumber = getStartLineNumber(topLevelDetailAST);

		if (!_isRequiredMethodCall(
				variableName, classObjectNames, identDetailASTMap,
				variableDefMap, statementStartLineNumber,
				statementEndLineNumber)) {

			DetailAST dotDetailAST = methodCallDetailAST.findFirstToken(
				TokenTypes.DOT);

			FullIdent fullIdent = FullIdent.createFullIdent(dotDetailAST);

			log(
				methodCallDetailAST, _MSG_UNNEEDED_STATIC_BLOCK,
				fullIdent.getText());
		}
	}

	private List _getClassObjectNames(DetailAST staticInitDetailAST) {
		List staticObjectNames = new ArrayList<>();

		List immutableFieldTypes = getAttributeValues(
			_IMMUTABLE_FIELD_TYPES_KEY);

		DetailAST previousSiblingDetailAST =
			staticInitDetailAST.getPreviousSibling();

		while (previousSiblingDetailAST != null) {
			DetailAST modifiersDetailAST =
				previousSiblingDetailAST.findFirstToken(TokenTypes.MODIFIERS);

			if (modifiersDetailAST == null) {
				previousSiblingDetailAST =
					previousSiblingDetailAST.getPreviousSibling();

				continue;
			}

			DetailAST nameDetailAST = previousSiblingDetailAST.findFirstToken(
				TokenTypes.IDENT);

			String name = nameDetailAST.getText();

			if (previousSiblingDetailAST.getType() != TokenTypes.VARIABLE_DEF) {
				staticObjectNames.add(name);
			}
			else {
				if (!immutableFieldTypes.contains(
						getTypeName(previousSiblingDetailAST, true))) {

					staticObjectNames.add(name);
				}
			}

			previousSiblingDetailAST =
				previousSiblingDetailAST.getPreviousSibling();
		}

		return staticObjectNames;
	}

	private Map> _getIdentDetailASTMap(
		DetailAST staticInitDetailAST) {

		Map> identDetailASTMap = new HashMap<>();

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

		for (DetailAST identDetailAST : identDetailASTList) {
			List list = identDetailASTMap.get(
				identDetailAST.getText());

			if (list == null) {
				list = new ArrayList<>();
			}

			list.add(identDetailAST);

			identDetailASTMap.put(identDetailAST.getText(), list);
		}

		return identDetailASTMap;
	}

	private DetailAST _getTopLevelDetailAST(DetailAST detailAST) {
		DetailAST topLevelDetailAST = null;

		DetailAST parentDetailAST = detailAST;

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

			if (grandParentDetailAST.getType() == TokenTypes.STATIC_INIT) {
				return topLevelDetailAST;
			}

			if (grandParentDetailAST.getType() == TokenTypes.SLIST) {
				topLevelDetailAST = parentDetailAST;
			}

			parentDetailAST = grandParentDetailAST;
		}
	}

	private Map _getVariableDefMap(
		DetailAST staticInitDetailAST,
		Map> identDetailASTMap) {

		Map variableDefMap = new HashMap<>();

		List variableDefinitionDetailASTList = getAllChildTokens(
			staticInitDetailAST, true, TokenTypes.VARIABLE_DEF);

		for (DetailAST variableDefinitionDetailAST :
				variableDefinitionDetailASTList) {

			DetailAST nameDetailAST =
				variableDefinitionDetailAST.findFirstToken(TokenTypes.IDENT);

			String name = nameDetailAST.getText();

			List identDetailASTList = identDetailASTMap.get(name);

			DetailAST firstIdentDetailAST = identDetailASTList.get(0);
			DetailAST lastIdentDetailAST = identDetailASTList.get(
				identDetailASTList.size() - 1);

			variableDefMap.put(
				name,
				new DetailAST[] {firstIdentDetailAST, lastIdentDetailAST});
		}

		return variableDefMap;
	}

	private boolean _isRequiredMethodCall(
		String variableName, List classObjectNames,
		Map> identDetailASTMap,
		Map variableDefMap, int start, int end) {

		for (Map.Entry> entry :
				identDetailASTMap.entrySet()) {

			String name = entry.getKey();

			if (name.equals(variableName)) {
				for (DetailAST detailAST : entry.getValue()) {
					if (detailAST.getLineNo() > end) {
						break;
					}

					DetailAST parentDetailAST = detailAST.getParent();

					if (parentDetailAST.getType() == TokenTypes.DOT) {
						continue;
					}

					if (parentDetailAST.getType() == TokenTypes.ASSIGN) {
						DetailAST literalNewDetailAST =
							parentDetailAST.findFirstToken(
								TokenTypes.LITERAL_NEW);

						if (literalNewDetailAST != null) {
							continue;
						}
					}

					return true;
				}

				continue;
			}

			for (DetailAST detailAST : entry.getValue()) {
				if ((detailAST.getLineNo() < start) ||
					(detailAST.getLineNo() > end)) {

					continue;
				}

				if (classObjectNames.contains(name)) {
					return true;
				}

				DetailAST[] firstAndLastUsedDetailASTArray = variableDefMap.get(
					name);

				if (firstAndLastUsedDetailASTArray == null) {
					continue;
				}

				DetailAST lastUsedDetailAST = firstAndLastUsedDetailASTArray[1];

				if (lastUsedDetailAST.getLineNo() > end) {
					return true;
				}

				DetailAST firstUsedDetailAST =
					firstAndLastUsedDetailASTArray[0];

				if (firstUsedDetailAST.getLineNo() < start) {
					DetailAST topLevelDetailAST = _getTopLevelDetailAST(
						firstUsedDetailAST);

					int statementStartLineNumber = getStartLineNumber(
						topLevelDetailAST);

					return _isRequiredMethodCall(
						variableName, classObjectNames, identDetailASTMap,
						variableDefMap, statementStartLineNumber, end);
				}
			}
		}

		return false;
	}

	private static final String _IMMUTABLE_FIELD_TYPES_KEY =
		"immutableFieldTypes";

	private static final String _MSG_UNNEEDED_STATIC_BLOCK =
		"static.block.unneeded";

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy