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

jp.skypencil.pmd.slf4j.BracketWithoutArgument Maven / Gradle / Ivy

package jp.skypencil.pmd.slf4j;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sourceforge.pmd.AbstractJavaRule;
import net.sourceforge.pmd.ast.ASTArgumentList;
import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.ast.ASTExpression;
import net.sourceforge.pmd.ast.ASTFieldDeclaration;
import net.sourceforge.pmd.ast.ASTLiteral;
import net.sourceforge.pmd.ast.ASTName;
import net.sourceforge.pmd.ast.ASTPrimaryExpression;
import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
import net.sourceforge.pmd.ast.ASTPrimarySuffix;
import net.sourceforge.pmd.ast.ASTType;
import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;

import org.slf4j.Logger;

public class BracketWithoutArgument extends AbstractJavaRule {
	private Set loggerFields = new HashSet();

	@Override
	public Object visit(ASTFieldDeclaration node, Object data) {
		ASTType fieldType = node.getFirstChildOfType(ASTType.class);
		if (fieldType == null) {
			return super.visit(node, data);
		}
		ASTClassOrInterfaceType fieldClass = fieldType.getFirstChildOfType(ASTClassOrInterfaceType.class);
		if (fieldClass != null && Logger.class.equals(fieldClass.getType())) {
			String fieldName = node.getFirstChildOfType(ASTVariableDeclaratorId.class).getNameDeclaration().getImage();
			loggerFields.add(fieldName);
		}
		return super.visit(node, data);
	}

	@Override
	public Object visit(ASTPrimaryExpression node, Object data) {
		ASTPrimaryPrefix prefix = node.getFirstChildOfType(ASTPrimaryPrefix.class);
		ASTPrimarySuffix suffix = node.getFirstChildOfType(ASTPrimarySuffix.class);
		if (prefix == null || suffix == null) {
			return super.visit(node, data);
		}
		String expressionName = prefix.getFirstChildOfType(ASTName.class).getImage();
		ASTArgumentList argumentList = suffix.getFirstChildOfType(ASTArgumentList.class);
		if (!isLogging(expressionName) || argumentList == null) {
			return super.visit(node, data);
		}

		List arguments = argumentList.findChildrenOfType(ASTExpression.class);
		if (arguments.size() > 0) {
			ASTLiteral literal = arguments.get(0).getFirstChildOfType(ASTLiteral.class);
			if (literal != null) {
				String format = literal.getImage();
				int expectedArguments = countDelimiter(format);
				ASTExpression lastArgument = arguments.get(arguments.size() - 1);
				int givenArguments = arguments.size() - 1;	// removing count of message
				if (isThrowable(lastArgument.getType())) {
					--givenArguments;
				}
				if (expectedArguments != givenArguments) {
					addViolation(data, node);
				}
			}
		}
		return super.visit(node, data);
	}

	boolean isThrowable(Class clazz) {
		Class superClass = clazz.getSuperclass();
		if (superClass == null || superClass == Object.class) {
			return clazz.equals(Throwable.class);
		} else {
			return isThrowable(superClass);
		}
	}

	private boolean isLogging(String expressionName) {
		for (String fieldName : loggerFields) {
			for (String methodName : new String[]{"trace", "debug", "info", "warn", "error"}) {
				String loggingMethodName = fieldName + "." + methodName;
				if (expressionName.equals(loggingMethodName)) {
					return true;
				}
			}
		}
		return false;
	}

	int countDelimiter(String format) {
		Matcher matcher = Pattern.compile("(.?)(\\\\\\\\)*\\{\\}").matcher(format);
		int count = 0;
		while (matcher.find()) {
			if (!"\\".equals(matcher.group(1))) {
				++count;
			}
		}
		return count;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy