Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LPD-43765 Add TransformUtilUtilCheck #2956

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
/**
* SPDX-FileCopyrightText: (c) 2024 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.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.StringUtil;

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

import java.util.List;

/**
* @author Alan Huang
*/
public class TransformUtilCheck extends BaseCheck {

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

@Override
protected void doVisitToken(DetailAST detailAST) {
List<DetailAST> forEachClauseDetailASTList = getAllChildTokens(
detailAST, true, TokenTypes.FOR_EACH_CLAUSE);

outerLoop:
for (DetailAST forEachClauseDetailAST : forEachClauseDetailASTList) {
DetailAST exprDetailAST = forEachClauseDetailAST.findFirstToken(
TokenTypes.EXPR);

DetailAST firstChildDetailAST = exprDetailAST.getFirstChild();

if (firstChildDetailAST.getType() != TokenTypes.IDENT) {
continue;
}

String variableTypeName = getVariableTypeName(
firstChildDetailAST, firstChildDetailAST.getText(), true);

if ((variableTypeName == null) ||
(!variableTypeName.startsWith("List<") &&
!variableTypeName.endsWith(">"))) {

continue;
}

String typeArguments = variableTypeName.substring(
5, variableTypeName.length() - 1);

if (typeArguments.contains("<") || typeArguments.contains("[")) {
continue;
}

DetailAST parentDetailAST = forEachClauseDetailAST.getParent();

DetailAST nextSiblingDetailAST = parentDetailAST.getNextSibling();

if ((nextSiblingDetailAST == null) ||
(nextSiblingDetailAST.getType() != TokenTypes.LITERAL_RETURN)) {

continue;
}

firstChildDetailAST = nextSiblingDetailAST.getFirstChild();

if (firstChildDetailAST.getType() != TokenTypes.EXPR) {
continue;
}

firstChildDetailAST = firstChildDetailAST.getFirstChild();

if (firstChildDetailAST.getType() != TokenTypes.IDENT) {
continue;
}

String returnVariableName = firstChildDetailAST.getText();

String returnVariableTypeName = getVariableTypeName(
firstChildDetailAST, returnVariableName, false);

if ((returnVariableTypeName == null) ||
!returnVariableTypeName.equals("List")) {

continue;
}

DetailAST returnVariableDefinitionDetailAST =
getVariableDefinitionDetailAST(
firstChildDetailAST, returnVariableName, false);

if ((returnVariableDefinitionDetailAST == null) ||
!isAssignNewArrayList(returnVariableDefinitionDetailAST)) {

continue;
}

List<DetailAST> variableCallerDetailASTList =
getVariableCallerDetailASTList(
returnVariableDefinitionDetailAST, returnVariableName);

for (DetailAST variableCallerDetailAST :
variableCallerDetailASTList) {

int lineNumber = variableCallerDetailAST.getLineNo();

if (lineNumber < forEachClauseDetailAST.getLineNo()) {
continue outerLoop;
}

if (lineNumber >= nextSiblingDetailAST.getLineNo()) {
break;
}

if (!_isAddMethodCall(
variableCallerDetailAST, returnVariableName)) {

continue outerLoop;
}
}

nextSiblingDetailAST = forEachClauseDetailAST.getNextSibling();

if (nextSiblingDetailAST.getType() != TokenTypes.RPAREN) {
continue;
}

nextSiblingDetailAST = nextSiblingDetailAST.getNextSibling();

if (nextSiblingDetailAST.getType() != TokenTypes.SLIST) {
continue;
}

List<DetailAST> childDetailASTList = getAllChildTokens(
nextSiblingDetailAST, true, TokenTypes.DEC, TokenTypes.DO_WHILE,
TokenTypes.INC, TokenTypes.LITERAL_FOR,
TokenTypes.LITERAL_RETURN, TokenTypes.POST_DEC,
TokenTypes.LITERAL_WHILE, TokenTypes.POST_INC);

if (ListUtil.isNotEmpty(childDetailASTList)) {
continue;
}

List<DetailAST> assignDetailASTList = getAllChildTokens(
nextSiblingDetailAST, true, TokenTypes.ASSIGN);

for (DetailAST assignDetailAST : assignDetailASTList) {
parentDetailAST = assignDetailAST.getParent();

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

String name = getName(assignDetailAST);

if (name == null) {
continue outerLoop;
}

DetailAST variableDefinitionDetailAST =
getVariableDefinitionDetailAST(
assignDetailAST, name, false);

if ((variableDefinitionDetailAST == null) ||
(variableDefinitionDetailAST.getLineNo() <
forEachClauseDetailAST.getLineNo())) {

continue outerLoop;
}
}

List<DetailAST> methodCallDetailASTList = getAllChildTokens(
nextSiblingDetailAST, true, TokenTypes.METHOD_CALL);

for (DetailAST methodCallDetailAST : methodCallDetailASTList) {
DetailAST dotDetailAST = methodCallDetailAST.findFirstToken(
TokenTypes.DOT);

if (dotDetailAST == null) {
continue;
}

List<String> names = getNames(dotDetailAST, false);

if (names.size() != 2) {
continue;
}

String methodCallClassName = names.get(0);

if (methodCallClassName.equals(returnVariableName)) {
continue;
}

DetailAST variableDefinitionDetailAST =
getVariableDefinitionDetailAST(
dotDetailAST, methodCallClassName, true);

if (variableDefinitionDetailAST == null) {
continue;
}

if (variableDefinitionDetailAST.getLineNo() <
forEachClauseDetailAST.getLineNo()) {

String methodCallMethodName = names.get(1);

if (methodCallMethodName.startsWith("add") ||
methodCallMethodName.startsWith("put") ||
methodCallMethodName.startsWith("set")) {

continue outerLoop;
}
}
}

String absolutePath = getAbsolutePath();

if (absolutePath.endsWith("ResourceImpl.java") &&
absolutePath.matches(".+/internal/resource/v\\d*(_\\d+)+/.+")) {

log(forEachClauseDetailAST, _MSG_USE_TRANSFORM);
}
else {
log(forEachClauseDetailAST, _MSG_USE_TRANSFORM_UTIL_TRANSFORM);
}
}
}

private boolean _isAddMethodCall(DetailAST detailAST, String variableName) {
DetailAST parentDetailAST = detailAST.getParent();

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

parentDetailAST = parentDetailAST.getParent();

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

List<String> names = getNames(detailAST.getParent(), false);

if ((names.size() == 2) &&
StringUtil.equals(variableName, names.get(0)) &&
StringUtil.equals(names.get(1), "add")) {

return true;
}

return false;
}

private static final String _MSG_USE_TRANSFORM = "transform.use";

private static final String _MSG_USE_TRANSFORM_UTIL_TRANSFORM =
"transform.util.transform.use";

}
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,12 @@
<property name="description" value="Finds usage of `TransactionalTestRule` in `*StagedModelDataHandlerTest`." />
<message key="import.invalid" value="Avoid using import TransactionalTestRule in *StagedModelDataHandlerTest, see LPS-68908" />
</module>
<module name="com.liferay.source.formatter.checkstyle.check.TransformUtilCheck">
<property name="category" value="Styling" />
<property name="description" value="Checks for utilization of class `Transform`." />
<message key="transform.use" value="Use &quot;transform&quot; to simplify code" />
<message key="transform.util.transform.use" value="Use &quot;TransformUtil.transform&quot; to simplify code" />
</module>
<module name="com.liferay.source.formatter.checkstyle.check.TryWithResourcesCheck">
<property name="category" value="Performance" />
<property name="description" value="Ensures using Try-With-Resources statement to properly close the resource." />
Expand Down