UseStringIsEmptyRule.java
/*
* SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
* SPDX-License-Identifier: MIT
*/
package com.qulice.pmd.rules;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTInfixExpression;
import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
import net.sourceforge.pmd.lang.java.ast.ASTNumericLiteral;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
/**
* Rule to prohibit use of String.length() when checking for empty string.
* String.isEmpty() should be used instead.
*
* @since 0.18
*/
public final class UseStringIsEmptyRule extends AbstractJavaRulechainRule {
public UseStringIsEmptyRule() {
super(ASTInfixExpression.class);
}
@Override
public Object visit(final ASTInfixExpression expr, final Object data) {
if (isComparison(expr) && (
matchesLengthCheck(
expr.getLeftOperand(),
expr.getRightOperand()
)
|| matchesLengthCheck(
expr.getRightOperand(),
expr.getLeftOperand()
)
)
) {
asCtx(data).addViolation(expr);
}
return data;
}
private static boolean isComparison(final ASTInfixExpression expr) {
final boolean result;
switch (expr.getOperator()) {
case EQ:
case NE:
case GT:
case LT:
case GE:
case LE:
result = true;
break;
default:
result = false;
break;
}
return result;
}
/**
* Checks if length is length() or literal is 0 or 1.
*
* @param length The method
* @param literal The number
* @return True if matches, false otherwise
* @checkstyle BooleanExpressionComplexityCheck (20 lines)
*/
private static boolean matchesLengthCheck(
final ASTExpression length,
final ASTExpression literal
) {
boolean result = false;
if (length != null && literal != null && isZeroOrOneLiteral(literal)
&& length instanceof ASTMethodCall) {
final ASTMethodCall call = (ASTMethodCall) length;
result = "length".equals(call.getMethodName())
&& call.getArguments().isEmpty()
&& call.getQualifier() != null
&& isStringExpression(call.getQualifier());
}
return result;
}
private static boolean isZeroOrOneLiteral(final ASTExpression expr) {
boolean matches = false;
if (expr instanceof ASTNumericLiteral) {
final ASTNumericLiteral lit = (ASTNumericLiteral) expr;
final String image = lit.getImage();
matches = "0".equals(image) || "1".equals(image);
}
return matches;
}
private static boolean isStringExpression(final ASTExpression expr) {
final JTypeMirror type = expr.getTypeMirror();
return type.isClassOrInterface()
&& "java.lang.String".equals(type.toString());
}
}