Skip to content

Commit

Permalink
Merge branch '__rultor'
Browse files Browse the repository at this point in the history
  • Loading branch information
rultor committed Jan 25, 2022
2 parents e62bcb5 + d43689e commit cbdcd34
Show file tree
Hide file tree
Showing 5 changed files with 329 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<!-- @todo #/DEV Write an instruction how to add arch4u rules to your gradle and maven projects -->
<artifactId>arch4u-pmd</artifactId>
<!-- @todo #/DEV Write minimalistic/laconic project overview in readme.md -->
<version>0.3.0</version>
<version>0.0.0</version>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description></description>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* MIT License
*
* Copyright (c) 2019-2022 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.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.rule.AbstractPoorMethodCall;
import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
import net.sourceforge.pmd.lang.java.xpath.TypeIsExactlyFunction;
import net.sourceforge.pmd.lang.java.xpath.TypeIsFunction;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;
import org.apache.commons.lang3.StringUtils;

/**
* A rule that prohibits the using methods of a particular class.
*
* @see <a href="https://github.com/dgroup/arch4u-pmd/issues/22">
* https://github.com/dgroup/arch4u-pmd/issues/22</a>
* @since 0.4.0
*/
@SuppressWarnings("PMD.StaticAccessToStaticFields")
public final class AvoidProhibitedMethodsUsage extends AbstractPoorMethodCall {

/**
* Property descriptor with test class suffix.
*/
private static final PropertyDescriptor<String> CLASS =
PropertyFactory.stringProperty("class")
.desc("The fully qualified name of the class")
.defaultValue(StringUtils.EMPTY)
.build();

/**
* Property descriptor with the list of the prohibited methods.
*/
private static final PropertyDescriptor<List<String>> METHODS =
PropertyFactory.stringListProperty("methods")
.desc("List of prohibited methods")
.emptyDefaultValue()
.build();

/**
* A property descriptor with the property that is responsible for
* whether subtypes should be checked.
*/
private static final PropertyDescriptor<Boolean> CHECK_SUBTYPES =
PropertyFactory.booleanProperty("checkSubtypes")
.desc("The property matches whether the subtypes should be checked")
.defaultValue(false)
.build();

/**
* Constructor for defining property descriptor.
*/
@SuppressWarnings("PMD.ConstructorOnlyInitializesOrCallOtherConstructors")
public AvoidProhibitedMethodsUsage() {
this.definePropertyDescriptor(CLASS);
this.definePropertyDescriptor(METHODS);
this.definePropertyDescriptor(CHECK_SUBTYPES);
}

@Override
public Object visit(final ASTVariableDeclaratorId node, final Object data) {
if (node.getNameDeclaration() != null && this.hasNotedClass(node)) {
for (final NameOccurrence usage : node.getUsages()) {
final JavaNameOccurrence occurrence = (JavaNameOccurrence) usage;
if (this.isNotedMethod(occurrence.getNameForWhichThisIsAQualifier())) {
this.addViolation(
data, occurrence.getLocation(), new String[]{
this.targetTypename(),
occurrence.getNameForWhichThisIsAQualifier().getImage(),
}
);
}
}
}
return data;
}

@Override
public String targetTypename() {
return this.getProperty(CLASS);
}

@Override
public String[] methodNames() {
return this.getProperty(METHODS).toArray(new String[0]);
}

@Override
public boolean isViolationArgument(final Node node) {
throw new UnsupportedOperationException();
}

/**
* Checks if the class of the variable is specified in the rule properties.
* @param node Variable declarator node.
* @return True if the node class is specified.
*/
private boolean hasNotedClass(final ASTVariableDeclaratorId node) {
final boolean noted;
if (this.getProperty(CHECK_SUBTYPES)) {
noted = TypeIsFunction.typeIs(node.getTypeNode(), this.targetTypename());
} else {
noted = TypeIsExactlyFunction.typeIsExactly(node.getTypeNode(), this.targetTypename());
}
return noted;
}

/**
* Checks if the variable occurrence contains prohibited method.
* @param occurrence Variable occurrence.
* @return True if the occurrence contains prohibited method.
*/
private boolean isNotedMethod(final NameOccurrence occurrence) {
boolean noted = false;
if (occurrence != null) {
final String invocation = occurrence.getImage();
noted = this.getProperty(METHODS).contains(invocation);
}
return noted;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
class="net.sourceforge.pmd.lang.rule.XPathRule">
<description>
Avoid to use prohibited classes.
See discussion about tips/tricks implementation on Github: https://github.com/pmd/pmd/discussions/3705
See discussion about tips/tricks implementation on Github:
https://github.com/pmd/pmd/discussions/3705
</description>
<priority>3</priority>
<properties>
Expand Down Expand Up @@ -77,4 +78,32 @@
]]>
</example>
</rule>

<rule name="AvoidProhibitedMethodsUsage"
since="0.4.0"
language="java"
message="The {0}#{1} invocation is prohibited to use."
class="io.github.dgroup.arch4u.pmd.AvoidProhibitedMethodsUsage">
<description>
Avoid using the prohibited method(s).
See the discussion about implementation tips/tricks on Github: https://github.com/dgroup/arch4u-pmd/discussions/40
</description>
<priority>3</priority>
<properties>
<property name="class" description="The fully qualified name of the class"
value="java.lang.Object"/>
<property name="methods" description="List of prohibited methods" value="toString"/>
<property name="checkSubtypes" value="false"
description="The property matches whether the subtypes should be checked"/>
</properties>
<example>
<![CDATA[
class Foo {
void bar(Object obj) {
String s = obj.toString();
}
}
]]>
</example>
</rule>
</ruleset>
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* MIT License
*
* Copyright (c) 2019-2022 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 net.sourceforge.pmd.testframework.SimpleAggregatorTst;

/**
* Test case for {@link AvoidProhibitedMethodsUsage} rule.
*
* @since 0.4.0
*/
@SuppressWarnings({"PMD.TestClassWithoutTestCases", "PMD.JUnit4TestShouldUseBeforeAnnotation"})
public final class AvoidProhibitedMethodsUsageTest extends SimpleAggregatorTst {

@Override
public void setUp() {
addRule(
"io/github/dgroup/arch4u/pmd/arch4u-template-ruleset.xml",
"AvoidProhibitedMethodsUsage"
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ MIT License
~
~ Copyright (c) 2019-2022 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.
-->

<test-data
xmlns="http://pmd.sourceforge.net/rule-tests"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd">

<test-code>
<description>[BAD]: prohibited method invocation</description>
<rule-property name="class">java.lang.Object</rule-property>
<rule-property name="methods">toString</rule-property>
<rule-property name="checkSubtypes">false</rule-property>
<expected-problems>1</expected-problems>
<expected-linenumbers>3</expected-linenumbers>
<expected-messages>
<message>The java.lang.Object#toString invocation is prohibited to use.</message>
</expected-messages>
<code><![CDATA[
class Foo {
void bar(Object obj) {
String s = obj.toString(); //violation
}
}
]]></code>
</test-code>

<test-code>
<description>[BAD]: prohibited method invocation, check subtypes</description>
<rule-property name="class">java.lang.Object</rule-property>
<rule-property name="methods">toString</rule-property>
<rule-property name="checkSubtypes">true</rule-property>
<expected-problems>1</expected-problems>
<expected-linenumbers>3</expected-linenumbers>
<expected-messages>
<message>The java.lang.Object#toString invocation is prohibited to use.</message>
</expected-messages>
<code><![CDATA[
class Foo {
void bar(Integer obj) {
String s = obj.toString(); //violation
}
}
]]></code>
</test-code>

<test-code>
<description>[BAD]: prohibited method invocation on field</description>
<rule-property name="class">java.lang.Object</rule-property>
<rule-property name="methods">toString</rule-property>
<rule-property name="checkSubtypes">true</rule-property>
<expected-problems>1</expected-problems>
<expected-linenumbers>6</expected-linenumbers>
<code><![CDATA[
import java.math.BigDecimal;
class Foo {
private BigDecimal field;
void bar() {
String s = field.toString(); //violation
}
}
]]></code>
</test-code>

<test-code>
<description>[OK]: prohibited method invocation on unchecked subclass instance</description>
<rule-property name="class">java.lang.Object</rule-property>
<rule-property name="methods">toString</rule-property>
<rule-property name="checkSubtypes">false</rule-property>
<expected-problems>0</expected-problems>
<code><![CDATA[
import java.math.BigDecimal;
class Foo {
private BigDecimal field;
void bar() {
String s = field.toString();
}
}
]]></code>
</test-code>

</test-data>

0 comments on commit cbdcd34

Please sign in to comment.