Skip to content

Commit

Permalink
Merge pull request #182 from dykov/168-wip-pmd-7.x
Browse files Browse the repository at this point in the history
fix checkstyle
  • Loading branch information
dykov authored Oct 13, 2024
2 parents e8daa6b + 94f3029 commit 5b99268
Show file tree
Hide file tree
Showing 14 changed files with 314 additions and 82 deletions.
1 change: 0 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,6 @@
<exclude>checkstyle:/src/test/java/io/github/dgroup/arch4u/pmd/test_entity/.*</exclude>
<!-- @todo #/DEV Fix Checkstyle step by step -->
<exclude>checkstyle:/src/test/java/io/github/dgroup/arch4u/pmd/.*</exclude>
<exclude>checkstyle:/src/main/java/io/github/dgroup/arch4u/pmd/.*</exclude>
<exclude>checkstyle:/src/main/java/io/github/dgroup/arch4u/pmd/test_entity/.*</exclude>
<exclude>dependencies:org.cactoos:cactoos</exclude>
<exclude>dependencies:org.llorllale:cactoos-matchers</exclude>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

package io.github.dgroup.arch4u.pmd;

import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTFinallyClause;
import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
Expand All @@ -32,8 +33,6 @@
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;
import java.util.List;


/**
* A PMD rule that prohibits the invocation of specified methods from a given class.
Expand All @@ -49,54 +48,85 @@
})
public final class AvoidMdcOutsideTryStatement extends AbstractJavaRule {

/**
* Property Descriptor for MDC classes.
*/
private static final PropertyDescriptor<List<String>> CLASSES =
PropertyFactory.stringListProperty("mdcClasses")
.desc("Full name of the MDC classes. Use a comma (,) as a delimiter.")
.defaultValues("org.slf4j.MDC")
.build();

/**
* Property Descriptor for method names.
*/
private static final PropertyDescriptor<List<String>> TRY =
PropertyFactory.stringListProperty("tryMethodNames")
.desc("Method names that should be within a Try statement.")
.defaultValues("put")
.build();

/**
* Property Descriptor for method names.
*/
private static final PropertyDescriptor<List<String>> FINALLY =
PropertyFactory.stringListProperty("finallyMethodNames")
.desc("Method names that should be within a Finally clause.")
.defaultValues("remove", "clear")
.build();

/**
* List of MDC classes.
*/
private final List<String> mdc;

/**
* Constructor.
*/
public AvoidMdcOutsideTryStatement() {
definePropertyDescriptor(CLASSES);
definePropertyDescriptor(TRY);
definePropertyDescriptor(FINALLY);
this.mdc = getProperty(CLASSES);
}

@Override
public Object visit(final ASTMethodCall node, final Object data) {
if (this.isMdc(node.getQualifier()) && (inTry(node) || inFinally(node))) {
if (this.isMdc(node.getQualifier()) && (this.inTry(node) || this.inFinally(node))) {
asCtx(data).addViolation(node);
}
return data;
}

/**
* Checks if the provided expression is an invocation of an MDC class.
* @param qualifier An expression.
* @return Result if the expression is an MDC invocation.
* @todo: move to an util class as a duplicated code.
*/
@SuppressWarnings("AvoidInlineConditionals")
private boolean isMdc(final ASTExpression qualifier) {
if (qualifier == null) {
return false;
}
return this.getProperty(CLASSES)
.stream()
.anyMatch(mdc -> TypeTestUtil.isA(mdc, qualifier.getTypeMirror()));
return qualifier != null && this.mdc.stream()
.anyMatch(mdcClass -> TypeTestUtil.isA(mdcClass, qualifier.getTypeMirror()));
}

/**
* Checks if the method invocation located inside a try-statement.
* @param node Method invocation node.
* @return True if is inside a try-statement.
*/
private boolean inTry(final ASTMethodCall node) {
return this.getProperty(TRY).contains(node.getMethodName())
&& node.ancestors(ASTTryStatement.class).isEmpty();
&& node.ancestors(ASTTryStatement.class).isEmpty();
}

/**
* Checks if the method invocation located inside a finally-statement.
* @param node Method invocation node.
* @return True if is inside a finally-statement.
*/
private boolean inFinally(final ASTMethodCall node) {
return this.getProperty(FINALLY).contains(node.getMethodName())
&& node.ancestors(ASTFinallyClause.class).isEmpty();
&& node.ancestors(ASTFinallyClause.class).isEmpty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@

package io.github.dgroup.arch4u.pmd;

import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTClassType;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;
import java.util.List;

/**
* A PMD rule that prohibits the usage of specified classes.
Expand Down Expand Up @@ -60,6 +60,9 @@ public final class AvoidProhibitedClasses extends AbstractJavaRule {
.defaultValue(false)
.build();

/**
* Constructor.
*/
public AvoidProhibitedClasses() {
definePropertyDescriptor(CLASSES);
definePropertyDescriptor(SUBTYPES);
Expand All @@ -70,8 +73,8 @@ public Object visit(final ASTClassType node, final Object data) {
this.getProperty(CLASSES)
.stream()
.filter(this.getProperty(SUBTYPES)
? name -> TypeTestUtil.isA(name, node)
: name -> TypeTestUtil.isExactlyA(name, node))
? name -> TypeTestUtil.isA(name, node)
: name -> TypeTestUtil.isExactlyA(name, node))
.findFirst()
.ifPresent(className -> asCtx(data).addViolation(node, className));
return data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,20 @@

package io.github.dgroup.arch4u.pmd;

import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;
import java.util.List;

/**
* A PMD rule that prohibits the invocation of specified methods from a given class.
*
* @see <a href="https://github.com/dgroup/arch4u-pmd/issues/22">https://github.com/dgroup/arch4u-pmd/issues/22</a>
* @since 0.1.0
* @checkstyle ReturnCountCheck (150 lines)
*/
@SuppressWarnings({
"PMD.StaticAccessToStaticFields",
Expand Down Expand Up @@ -71,6 +72,9 @@ public final class AvoidProhibitedMethodsUsage extends AbstractJavaRule {
.defaultValue(false)
.build();

/**
* Constructor.
*/
public AvoidProhibitedMethodsUsage() {
definePropertyDescriptor(CLASS);
definePropertyDescriptor(METHODS);
Expand All @@ -83,25 +87,38 @@ public Object visit(final ASTMethodCall node, final Object data) {
if (node.getMethodType() == null || node.getMethodType().getDeclaringType() == null) {
return data;
}
if (getProperty(METHODS).contains(node.getMethodType().getName())) {
if (getProperty(SUBTYPES) && isSubtype(node.getMethodType().getDeclaringType())) {
if (this.getProperty(METHODS).contains(node.getMethodType().getName())) {
if (this.getProperty(SUBTYPES)
&& this.isSubtype(node.getMethodType().getDeclaringType())) {
asCtx(data).addViolation(
node, getProperty(CLASS), node.getMethodType().getName()
node, this.getProperty(CLASS), node.getMethodType().getName()
);
}
if (isExactClass(node.getMethodType().getDeclaringType().toString())) {
if (this.isExactClass(node.getMethodType().getDeclaringType().toString())) {
asCtx(data).addViolation(
node, getProperty(CLASS), node.getMethodType().getName()
node, this.getProperty(CLASS), node.getMethodType().getName()
);
}
}
return data;
}

/**
* Checks if the class is prohibited.
*
* @param classname Class name.
* @return True if the class is prohibited.
*/
private boolean isExactClass(final String classname) {
return this.getProperty(CLASS).equals(classname);
}

/**
* Checks if the provided class node is a subtype of a prohibited class.
*
* @param type A class node.
* @return True if this is a prohibited class.
*/
private boolean isSubtype(final JTypeMirror type) {
return TypeTestUtil.isA(this.getProperty(CLASS), type);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,69 @@
/*
* MIT License
*
* Copyright (c) 2019-2024 Yurii Dubinka
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*/

package io.github.dgroup.arch4u.pmd;

import java.util.List;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.*;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
import net.sourceforge.pmd.lang.java.ast.ASTInitializer;
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.TypeNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;
import java.util.List;

/**
* The rule is designed to find a local variables that should be used
* as a class fields such as {@link com.fasterxml.jackson.databind.ObjectMapper}.
* @since 0.1.0
*/
@SuppressWarnings({
"PMD.StaticAccessToStaticFields",
"PMD.ConstructorOnlyInitializesOrCallOtherConstructors"
})
public class AvoidTypeAsLocalVariable extends AbstractJavaRule {
public final class AvoidTypeAsLocalVariable extends AbstractJavaRule {

/**
* Property Descriptor for list of classes to find.
*/
private static final PropertyDescriptor<List<String>> CLASSES =
PropertyFactory.stringListProperty("classes")
.desc("Full names of the classes")
// @todo #/DEV Remove default value for classes, use *.xml configuration instead
.defaultValues("com.fasterxml.jackson.databind.ObjectMapper")
.build();

/**
* Property Descriptor for list of annotations that allows to use the objects
* as a local variables.
*/
private static final PropertyDescriptor<List<String>> ANNOTATIONS =
PropertyFactory.stringListProperty("annotations")
.desc("Full name of the method annotations in which it's allowed to use objects")
Expand All @@ -31,19 +74,32 @@ public class AvoidTypeAsLocalVariable extends AbstractJavaRule {
)
.build();

/**
* The property matches whether the classes subtypes should be checked.
*/
private static final PropertyDescriptor<Boolean> SUBTYPES =
PropertyFactory.booleanProperty("checkSubtypes")
.desc("The property matches whether the classes subtypes should be checked")
.defaultValue(true)
.build();

/**
* List of classes to find.
*/
private final List<String> classes;

/**
* List of annotations that allows to use the objects as a local variables.
*/
private final List<String> annotations;

/**
* Constructor.
*/
public AvoidTypeAsLocalVariable() {
definePropertyDescriptor(CLASSES);
definePropertyDescriptor(ANNOTATIONS);
definePropertyDescriptor(SUBTYPES);
this.definePropertyDescriptor(CLASSES);
this.definePropertyDescriptor(ANNOTATIONS);
this.definePropertyDescriptor(SUBTYPES);
this.classes = getProperty(CLASSES);
this.annotations = getProperty(ANNOTATIONS);
}
Expand Down Expand Up @@ -74,35 +130,52 @@ public Object visit(final ASTConstructorCall ctor, final Object data) {
return super.visit(ctor, data);
}

/**
* Checks if the provided type is an illegal type.
* @param type A variable type.
* @return True if the type is illegal.
*/
private boolean illegalType(final TypeNode type) {
boolean found = false;
if (type != null) {
found = this.classes.stream().anyMatch(className -> this.isTypeMatches(type, className));
found = this.classes.stream()
.anyMatch(className -> this.isTypeMatches(type, className));
}
return found;
}

/**
* Compares the type node with the class name.
* @param type Type node.
* @param classname Class name.
* @return True if matches.
*/
private boolean isTypeMatches(final TypeNode type, final String classname) {
return getProperty(SUBTYPES)
return this.getProperty(SUBTYPES)
? TypeTestUtil.isA(classname, type)
: TypeTestUtil.isExactlyA(classname, type);
}

/**
* Checks if an allowed annotation is not presented and
* if type is not declared in fields, constructors, and initialization blocks.
* @param node A node to check.
* @return True if the node is in a prohibited context.
*/
private boolean isInNotAllowedContext(final Node node) {
return node.ancestors(ASTMethodDeclaration.class).toStream().noneMatch(this::hasAllowedAnnotations)
return node.ancestors(ASTMethodDeclaration.class).toStream()
.noneMatch(this::hasAllowedAnnotations)
&& node.ancestors(ASTFieldDeclaration.class).isEmpty()
&& node.ancestors(ASTConstructorDeclaration.class).isEmpty()
&& node.ancestors(ASTInitializer.class).isEmpty();
}

/**
* Check if the type is used in a method with specific annotations.
* @param method A method declaration node.
* @return True if an allowed annotation is presented.
*/
private boolean hasAllowedAnnotations(final ASTMethodDeclaration method) {
return method.isAnyAnnotationPresent(annotations);
return method.isAnyAnnotationPresent(this.annotations);
}
}
Loading

0 comments on commit 5b99268

Please sign in to comment.