From 3abb8339801a5ac9bc04c636c40134ddfe4ab798 Mon Sep 17 00:00:00 2001 From: rajeshggwp Date: Sat, 13 Oct 2018 22:02:51 +0530 Subject: [PATCH 001/139] added new rule - NumericLiteralCovention --- docs/pages/pmd/rules/java.md | 1 + docs/pages/pmd/rules/java/codestyle.md | 32 +++++++- .../resources/category/java/codestyle.xml | 32 ++++++++ .../rule/codestyle/CodeStyleRulesTest.java | 1 + .../xml/NumericLiteralConvention.xml | 76 +++++++++++++++++++ 5 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml diff --git a/docs/pages/pmd/rules/java.md b/docs/pages/pmd/rules/java.md index 516e0ddd7a..386d9f6ecb 100644 --- a/docs/pages/pmd/rules/java.md +++ b/docs/pages/pmd/rules/java.md @@ -98,6 +98,7 @@ folder: pmd/rules * [MethodNamingConventions](pmd_rules_java_codestyle.html#methodnamingconventions): Configurable naming conventions for method declarations. This rule reports method decl... * [MIsLeadingVariableName](pmd_rules_java_codestyle.html#misleadingvariablename): Deprecated Detects when a non-field has a name starting with 'm_'. This usually denotes a field and could b... * [NoPackage](pmd_rules_java_codestyle.html#nopackage): Detects when a class or interface does not have a package definition. +* [NumericLiteralConvention](pmd_rules_java_codestyle.html#numericliteralconvention): Numeric literals with more than 3 digits must use '_' as a separator. * [OnlyOneReturn](pmd_rules_java_codestyle.html#onlyonereturn): A method should have only one exit point, and that should be the last statement in the method. * [PackageCase](pmd_rules_java_codestyle.html#packagecase): Detects when a package definition contains uppercase characters. * [PrematureDeclaration](pmd_rules_java_codestyle.html#prematuredeclaration): Checks for variables that are defined before they might be used. A reference is deemed to be prem... diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index 091987c4e1..1b23f7732b 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -5,7 +5,7 @@ permalink: pmd_rules_java_codestyle.html folder: pmd/rules/java sidebaractiveurl: /pmd_rules_java.html editmepath: ../pmd-java/src/main/resources/category/java/codestyle.xml -keywords: Code Style, AbstractNaming, AtLeastOneConstructor, AvoidDollarSigns, AvoidFinalLocalVariable, AvoidPrefixingMethodParameters, AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending, AvoidUsingNativeCode, BooleanGetMethodName, CallSuperInConstructor, ClassNamingConventions, CommentDefaultAccessModifier, ConfusingTernary, ControlStatementBraces, DefaultPackage, DontImportJavaLang, DuplicateImports, EmptyMethodInAbstractClassShouldBeAbstract, ExtendsObject, FieldDeclarationsShouldBeAtStartOfClass, FieldNamingConventions, ForLoopShouldBeWhileLoop, ForLoopsMustUseBraces, FormalParameterNamingConventions, GenericsNaming, IdenticalCatchBranches, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, LinguisticNaming, LocalHomeNamingConvention, LocalInterfaceSessionNamingConvention, LocalVariableCouldBeFinal, LocalVariableNamingConventions, LongVariable, MDBAndSessionBeanNamingConvention, MethodArgumentCouldBeFinal, MethodNamingConventions, MIsLeadingVariableName, NoPackage, OnlyOneReturn, PackageCase, PrematureDeclaration, RemoteInterfaceNamingConvention, RemoteSessionInterfaceNamingConvention, ShortClassName, ShortMethodName, ShortVariable, SuspiciousConstantFieldName, TooManyStaticImports, UnnecessaryAnnotationValueElement, UnnecessaryConstructor, UnnecessaryFullyQualifiedName, UnnecessaryLocalBeforeReturn, UnnecessaryModifier, UnnecessaryReturn, UselessParentheses, UselessQualifiedThis, VariableNamingConventions, WhileLoopsMustUseBraces +keywords: Code Style, AbstractNaming, AtLeastOneConstructor, AvoidDollarSigns, AvoidFinalLocalVariable, AvoidPrefixingMethodParameters, AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending, AvoidUsingNativeCode, BooleanGetMethodName, CallSuperInConstructor, ClassNamingConventions, CommentDefaultAccessModifier, ConfusingTernary, ControlStatementBraces, DefaultPackage, DontImportJavaLang, DuplicateImports, EmptyMethodInAbstractClassShouldBeAbstract, ExtendsObject, FieldDeclarationsShouldBeAtStartOfClass, FieldNamingConventions, ForLoopShouldBeWhileLoop, ForLoopsMustUseBraces, FormalParameterNamingConventions, GenericsNaming, IdenticalCatchBranches, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, LinguisticNaming, LocalHomeNamingConvention, LocalInterfaceSessionNamingConvention, LocalVariableCouldBeFinal, LocalVariableNamingConventions, LongVariable, MDBAndSessionBeanNamingConvention, MethodArgumentCouldBeFinal, MethodNamingConventions, MIsLeadingVariableName, NoPackage, NumericLiteralConvention, OnlyOneReturn, PackageCase, PrematureDeclaration, RemoteInterfaceNamingConvention, RemoteSessionInterfaceNamingConvention, ShortClassName, ShortMethodName, ShortVariable, SuspiciousConstantFieldName, TooManyStaticImports, UnnecessaryAnnotationValueElement, UnnecessaryConstructor, UnnecessaryFullyQualifiedName, UnnecessaryLocalBeforeReturn, UnnecessaryModifier, UnnecessaryReturn, UselessParentheses, UselessQualifiedThis, VariableNamingConventions, WhileLoopsMustUseBraces language: Java --- ## AbstractNaming @@ -1505,6 +1505,36 @@ public class ClassInDefaultPackage { ``` +## NumericLiteralConvention + +**Since:** PMD 6.9 + +**Priority:** Medium (3) + +Numeric literals with more than 3 digits must use '_' as a separator. + +**This rule is defined by the following XPath expression:** +``` xpath +//Literal[@IntLiteral = true() or + @LongLiteral = true() or + @DoubleLiteral = true() or + @FloatLiteral = true()] + [not(matches(@Image, "^[0-9]{1,3}(_[0-9]{3})*(l|L)?(\.[0-9]+)?(d|D|f|F)?$"))] +``` + +**Example(s):** + +``` java +public class Foo { + private int num = 1000000; // should be 1_000_000 +} +``` + +**Use this rule by referencing it:** +``` xml + +``` + ## OnlyOneReturn **Since:** PMD 1.0 diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 9a9138a4f0..08c7baa296 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1351,6 +1351,38 @@ public class ClassInDefaultPackage { + + + Numeric literals with more than 3 digits must use '_' as a separator. + + 3 + + + + + + + + + + + + + + + + 0 + + + + + 1 + + + + + 1 + + + + + 0 + + + + + 1 + + + + + 0 + + + From 8f1a44063d031b5157b17774ab03a62a10527ad7 Mon Sep 17 00:00:00 2001 From: rajeshggwp Date: Sun, 14 Oct 2018 12:17:17 +0530 Subject: [PATCH 002/139] minor changes and more test cases --- docs/pages/pmd/rules/java/codestyle.md | 6 +- .../resources/category/java/codestyle.xml | 5 +- .../xml/NumericLiteralConvention.xml | 72 +++++++++++++++++++ 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index 1b23f7732b..4cd706857c 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -1507,10 +1507,12 @@ public class ClassInDefaultPackage { ## NumericLiteralConvention -**Since:** PMD 6.9 +**Since:** PMD 6.9.0 **Priority:** Medium (3) +**Minimum Language Version:** Java 1.7 + Numeric literals with more than 3 digits must use '_' as a separator. **This rule is defined by the following XPath expression:** @@ -1519,7 +1521,7 @@ Numeric literals with more than 3 digits must use '_' as a separator. @LongLiteral = true() or @DoubleLiteral = true() or @FloatLiteral = true()] - [not(matches(@Image, "^[0-9]{1,3}(_[0-9]{3})*(l|L)?(\.[0-9]+)?(d|D|f|F)?$"))] + [not(matches(@Image, "^[0-9]{1,3}(_[0-9]{3})*(l|L|\.[0-9]+)?(d|D|f|F)?$"))] ``` **Example(s):** diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 08c7baa296..82d2aa9f96 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1353,7 +1353,8 @@ public class ClassInDefaultPackage { @@ -1369,7 +1370,7 @@ public class ClassInDefaultPackage { @LongLiteral = true() or @DoubleLiteral = true() or @FloatLiteral = true()] - [not(matches(@Image, "^[0-9]{1,3}(_[0-9]{3})*(l|L)?(\.[0-9]+)?(d|D|f|F)?$"))] + [not(matches(@Image, "^[0-9]{1,3}(_[0-9]{3})*(l|L|\.[0-9]+)?(d|D|f|F)?$"))] ]]> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml index 2f2dbd74dd..f51d60d38c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml @@ -70,6 +70,78 @@ public class Foo { private callBar() { bar(314_159_265.359); } +} + ]]> + + + + 0 + + + + + 1 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + From 6cdb4a1002cdaf355502d089d652437770364340 Mon Sep 17 00:00:00 2001 From: rajeshggwp Date: Sun, 14 Oct 2018 23:41:41 +0530 Subject: [PATCH 003/139] #1232 changes required after merging with master --- .../rule/codestyle/NumericLiteralConventionTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/NumericLiteralConventionTest.java diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/NumericLiteralConventionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/NumericLiteralConventionTest.java new file mode 100644 index 0000000000..b753bad7d9 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/NumericLiteralConventionTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codestyle; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class NumericLiteralConventionTest extends PmdRuleTst { + // no additional unit tests +} From d1a41ffd351cefb80eafd8ff483d4238c681f607 Mon Sep 17 00:00:00 2001 From: rajeshggwp Date: Mon, 15 Oct 2018 01:46:47 +0530 Subject: [PATCH 004/139] #1232 added xpath version property and more test cases --- .../resources/category/java/codestyle.xml | 1 + .../xml/NumericLiteralConvention.xml | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 82d2aa9f96..d31da8bdad 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1363,6 +1363,7 @@ public class ClassInDefaultPackage { 3 + + + + + 0 + + + + + 0 + From 6e3ee3c85740cb51ee59b454463f0a7ab8788a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 28 Oct 2018 00:02:27 +0200 Subject: [PATCH 005/139] Tag XPath implementation as private API --- .../pmd/lang/ast/xpath/AbstractASTXPathHandler.java | 4 ++++ .../pmd/lang/ast/xpath/AttributeAxisIterator.java | 5 +++++ .../pmd/lang/ast/xpath/DefaultASTXPathHandler.java | 5 +++++ .../sourceforge/pmd/lang/ast/xpath/DocumentNavigator.java | 3 +++ .../net/sourceforge/pmd/lang/ast/xpath/NodeIterator.java | 3 +++ .../pmd/lang/ast/xpath/saxon/AbstractNodeInfo.java | 4 ++++ .../pmd/lang/ast/xpath/saxon/AttributeAxisIterator.java | 3 +++ .../sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java | 3 +++ .../sourceforge/pmd/lang/ast/xpath/saxon/DocumentNode.java | 3 +++ .../sourceforge/pmd/lang/ast/xpath/saxon/ElementNode.java | 3 +++ .../sourceforge/pmd/lang/ast/xpath/saxon/IdGenerator.java | 5 +++++ 11 files changed, 41 insertions(+) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AbstractASTXPathHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AbstractASTXPathHandler.java index 4c9fad1fdf..f4c1e8ddbe 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AbstractASTXPathHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AbstractASTXPathHandler.java @@ -6,11 +6,15 @@ package net.sourceforge.pmd.lang.ast.xpath; import org.jaxen.Navigator; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.XPathHandler; import net.sf.saxon.sxpath.IndependentContext; + +@Deprecated +@InternalApi public abstract class AbstractASTXPathHandler implements XPathHandler { @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java index 2a93c13ba5..75807ecd71 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java @@ -14,6 +14,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; @@ -22,7 +23,11 @@ import net.sourceforge.pmd.lang.ast.Node; * attributes. This is the default way the attributes of a node * are made accessible to XPath rules, and defines an important * piece of PMD's XPath support. + * + * @deprecated Use {@link Node#getXPathAttributesIterator()} */ +@Deprecated +@InternalApi public class AttributeAxisIterator implements Iterator { /** Caches the precomputed attribute accessors of a given class. */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DefaultASTXPathHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DefaultASTXPathHandler.java index 4bf033c437..974d426e80 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DefaultASTXPathHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DefaultASTXPathHandler.java @@ -4,8 +4,13 @@ package net.sourceforge.pmd.lang.ast.xpath; +import net.sourceforge.pmd.annotation.InternalApi; + import net.sf.saxon.sxpath.IndependentContext; + +@Deprecated +@InternalApi public class DefaultASTXPathHandler extends AbstractASTXPathHandler { @Override public void initialize() { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DocumentNavigator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DocumentNavigator.java index 9fcdcf2163..4f90c2cac7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DocumentNavigator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DocumentNavigator.java @@ -11,12 +11,15 @@ import org.jaxen.DefaultNavigator; import org.jaxen.XPath; import org.jaxen.util.SingleObjectIterator; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.RootNode; /** * @author daniels */ +@Deprecated +@InternalApi public class DocumentNavigator extends DefaultNavigator { private static final Iterator EMPTY_ITERATOR = new ArrayList().iterator(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NodeIterator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NodeIterator.java index 2d189cfcef..c442baa8ed 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NodeIterator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NodeIterator.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.ast.xpath; import java.util.Iterator; import java.util.NoSuchElementException; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; /** @@ -15,6 +16,8 @@ import net.sourceforge.pmd.lang.ast.Node; * * @author daniels */ +@Deprecated +@InternalApi public abstract class NodeIterator implements Iterator { private Node node; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AbstractNodeInfo.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AbstractNodeInfo.java index d309e65b68..1e7c8e0825 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AbstractNodeInfo.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AbstractNodeInfo.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.ast.xpath.saxon; +import net.sourceforge.pmd.annotation.InternalApi; + import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.om.Axis; @@ -27,6 +29,8 @@ import net.sf.saxon.value.Value; * useful implementations, such as {@link #iterateAxis(byte, NodeTest)} and * {@link #isSameNodeInfo(NodeInfo)}. */ +@Deprecated +@InternalApi public class AbstractNodeInfo implements VirtualNode, SiblingCountingNode { @Override public String getSystemId() { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeAxisIterator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeAxisIterator.java index ada6ed8a78..9a0e23baf1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeAxisIterator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeAxisIterator.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.ast.xpath.saxon; import java.util.Iterator; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.xpath.Attribute; import net.sf.saxon.om.Navigator; @@ -15,6 +16,8 @@ import net.sf.saxon.om.SequenceIterator; * An adapter over our {@link net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator} * for the Saxon model. */ +@Deprecated +@InternalApi public class AttributeAxisIterator extends Navigator.BaseEnumeration { protected final ElementNode startNodeInfo; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java index 69e93cddb4..fc36cf6b24 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.ast.xpath.saxon; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.xpath.Attribute; import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery; @@ -18,6 +19,8 @@ import net.sf.saxon.value.Value; * Belongs to an {@link ElementNode}, and wraps an * {@link Attribute}. */ +@Deprecated +@InternalApi public class AttributeNode extends AbstractNodeInfo { protected final Attribute attribute; protected final int id; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/DocumentNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/DocumentNode.java index d3aa3bfb5d..f91718c816 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/DocumentNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/DocumentNode.java @@ -8,6 +8,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sf.saxon.om.Axis; @@ -21,6 +22,8 @@ import net.sf.saxon.type.Type; /** * A Saxon OM Document node for an AST Node. */ +@Deprecated +@InternalApi public class DocumentNode extends AbstractNodeInfo implements DocumentInfo { /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/ElementNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/ElementNode.java index 73b4dbf606..60960f4f4b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/ElementNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/ElementNode.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.ast.xpath.saxon; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sf.saxon.om.Axis; @@ -19,6 +20,8 @@ import net.sf.saxon.type.Type; /** * A Saxon OM Element type node for an AST Node. */ +@Deprecated +@InternalApi public class ElementNode extends AbstractNodeInfo { protected final DocumentNode document; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/IdGenerator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/IdGenerator.java index a014729421..afb0886811 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/IdGenerator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/IdGenerator.java @@ -4,9 +4,14 @@ package net.sourceforge.pmd.lang.ast.xpath.saxon; +import net.sourceforge.pmd.annotation.InternalApi; + + /** * This class is used to generate unique IDs for nodes. */ +@Deprecated +@InternalApi public class IdGenerator { private int id; From c3113894cf9335d9d41f79365db88d3075edeb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 29 Oct 2018 23:20:24 +0100 Subject: [PATCH 006/139] Tweak RulesetWriter to recognize himself externally defined descriptors --- .../java/net/sourceforge/pmd/RuleSetWriter.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java index 70f6f23b41..0fba770e94 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java @@ -248,7 +248,7 @@ public class RuleSetWriter { Element priorityElement = createPriorityElement(priority); ruleElement.appendChild(priorityElement); } - Element propertiesElement = createPropertiesElement(propertyDescriptors, propertiesByPropertyDescriptor); + Element propertiesElement = createPropertiesElement(propertyDescriptors, propertiesByPropertyDescriptor, XPathRule.class.getName().equals(clazz)); if (propertiesElement != null) { ruleElement.appendChild(propertiesElement); } @@ -271,9 +271,18 @@ public class RuleSetWriter { return ruleSetReferenceElement; } + // We consider that any descriptor defined on something else than an XPath rule + // declaration is an error and don't care if it's output or not + private static boolean isExternallyDefined(boolean isXPathRule, PropertyDescriptor descriptor) { + return isXPathRule && !(descriptor.equals(XPathRule.XPATH_DESCRIPTOR) + || descriptor.equals(XPathRule.VERSION_DESCRIPTOR) + || descriptor.equals(XPathRule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR) + || descriptor.equals(XPathRule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR)); + } + @SuppressWarnings("PMD.CompareObjectsWithEquals") private Element createPropertiesElement(List> propertyDescriptors, - Map, Object> propertiesByPropertyDescriptor) { + Map, Object> propertiesByPropertyDescriptor, boolean isXPathRule) { Element propertiesElement = null; if (propertyDescriptors != null) { @@ -281,7 +290,7 @@ public class RuleSetWriter { for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { // For each provided PropertyDescriptor - if (propertyDescriptor.isDefinedExternally()) { + if (isExternallyDefined(isXPathRule, propertyDescriptor)) { // Any externally defined property needs to go out as a definition. if (propertiesElement == null) { propertiesElement = createPropertiesElement(); From 9d954fff0a21a35c59f160504e49497dbe941128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 30 Oct 2018 00:01:01 +0100 Subject: [PATCH 007/139] Deprecate isDefinedExternally --- .../net/sourceforge/pmd/properties/PropertyDescriptor.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index 09d501e01c..bda1597bd7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -154,8 +154,14 @@ public interface PropertyDescriptor extends Comparable> * to write out the property correctly: if it was defined externally, then its definition must be written out, * otherwise only its value. * + * @deprecated Not supported anymore. Behaviour may be wrong. + * Property descriptors should only be defined in the XML when defining an XPath rule. + * Other uses are unspecified, but should cause an error. That means, PropertyDescriptors + * don't need to carry this value around, and since this has proven to add very much + * boilerplate, we're removing it. * @return True if the descriptor was defined in xml */ + @Deprecated boolean isDefinedExternally(); } From 994c8462d09e8417a4da87f5e963dfb689249f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 30 Oct 2018 00:12:00 +0100 Subject: [PATCH 008/139] Deprecate preferredRowCount --- .../java/net/sourceforge/pmd/properties/PropertyDescriptor.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index bda1597bd7..adcdd6d14a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -136,8 +136,10 @@ public interface PropertyDescriptor extends Comparable> * If the datatype is a String then return the preferred number of rows to allocate in the text widget, returns a * value of one for all other types. Useful for multi-line XPATH editors. * + * @deprecated Was never implemented, and is none of the descriptor's concern * @return int */ + @Deprecated int preferredRowCount(); From 8563c802c461173bc1810bab3ac9b097203734f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 30 Oct 2018 00:17:00 +0100 Subject: [PATCH 009/139] update release notes --- docs/pages/release_notes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index b8f8783555..97ed71baa1 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -18,6 +18,9 @@ This is a {{ site.pmd.release_type }} release. ### API Changes +* The implementation of the adapters for the XPath engines Saxon and Jaxen (package net.sourceforge.pmd.lang.ast.xpath) + are now deprecated. They'll be moved to an internal package come 7.0.0. Only Attribute remains public API. + ### External Contributions {% endtocmaker %} From d4b0d79cea6a9fdc301f81f9480a965c176734ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 30 Oct 2018 08:33:03 +0100 Subject: [PATCH 010/139] Revert --- .../java/net/sourceforge/pmd/RuleSetWriter.java | 15 +++------------ .../pmd/properties/PropertyDescriptor.java | 8 ++------ 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java index 0fba770e94..70f6f23b41 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java @@ -248,7 +248,7 @@ public class RuleSetWriter { Element priorityElement = createPriorityElement(priority); ruleElement.appendChild(priorityElement); } - Element propertiesElement = createPropertiesElement(propertyDescriptors, propertiesByPropertyDescriptor, XPathRule.class.getName().equals(clazz)); + Element propertiesElement = createPropertiesElement(propertyDescriptors, propertiesByPropertyDescriptor); if (propertiesElement != null) { ruleElement.appendChild(propertiesElement); } @@ -271,18 +271,9 @@ public class RuleSetWriter { return ruleSetReferenceElement; } - // We consider that any descriptor defined on something else than an XPath rule - // declaration is an error and don't care if it's output or not - private static boolean isExternallyDefined(boolean isXPathRule, PropertyDescriptor descriptor) { - return isXPathRule && !(descriptor.equals(XPathRule.XPATH_DESCRIPTOR) - || descriptor.equals(XPathRule.VERSION_DESCRIPTOR) - || descriptor.equals(XPathRule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR) - || descriptor.equals(XPathRule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR)); - } - @SuppressWarnings("PMD.CompareObjectsWithEquals") private Element createPropertiesElement(List> propertyDescriptors, - Map, Object> propertiesByPropertyDescriptor, boolean isXPathRule) { + Map, Object> propertiesByPropertyDescriptor) { Element propertiesElement = null; if (propertyDescriptors != null) { @@ -290,7 +281,7 @@ public class RuleSetWriter { for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { // For each provided PropertyDescriptor - if (isExternallyDefined(isXPathRule, propertyDescriptor)) { + if (propertyDescriptor.isDefinedExternally()) { // Any externally defined property needs to go out as a definition. if (propertiesElement == null) { propertiesElement = createPropertiesElement(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index adcdd6d14a..98adff86fd 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -136,7 +136,7 @@ public interface PropertyDescriptor extends Comparable> * If the datatype is a String then return the preferred number of rows to allocate in the text widget, returns a * value of one for all other types. Useful for multi-line XPATH editors. * - * @deprecated Was never implemented, and is none of the descriptor's concern + * @deprecated Was never implemented, and is none of the descriptor's concern. Will be removed with 7.0.0 * @return int */ @Deprecated @@ -156,11 +156,7 @@ public interface PropertyDescriptor extends Comparable> * to write out the property correctly: if it was defined externally, then its definition must be written out, * otherwise only its value. * - * @deprecated Not supported anymore. Behaviour may be wrong. - * Property descriptors should only be defined in the XML when defining an XPath rule. - * Other uses are unspecified, but should cause an error. That means, PropertyDescriptors - * don't need to carry this value around, and since this has proven to add very much - * boilerplate, we're removing it. + * @deprecated May be removed with 7.0.0 * @return True if the descriptor was defined in xml */ @Deprecated From d5d51469c42c5ba0387487ee5de111c5969f1edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 30 Oct 2018 08:50:14 +0100 Subject: [PATCH 011/139] Deprecate some other stuff --- .../pmd/properties/AbstractMultiNumericProperty.java | 1 + .../pmd/properties/AbstractMultiPackagedProperty.java | 1 + .../pmd/properties/AbstractNumericProperty.java | 1 + .../pmd/properties/AbstractPackagedProperty.java | 1 + .../pmd/properties/EnumeratedPropertyDescriptor.java | 1 + .../sourceforge/pmd/properties/FloatMultiProperty.java | 2 ++ .../net/sourceforge/pmd/properties/FloatProperty.java | 3 ++- .../sourceforge/pmd/properties/MethodMultiProperty.java | 1 + .../net/sourceforge/pmd/properties/MethodProperty.java | 2 ++ .../pmd/properties/NumericPropertyDescriptor.java | 1 + .../pmd/properties/PackagedPropertyDescriptor.java | 1 + .../sourceforge/pmd/properties/PropertyDescriptor.java | 4 ++++ .../pmd/properties/PropertyDescriptorField.java | 2 ++ .../net/sourceforge/pmd/properties/PropertyTypeId.java | 8 +++++++- .../net/sourceforge/pmd/properties/TypeMultiProperty.java | 3 ++- .../java/net/sourceforge/pmd/properties/TypeProperty.java | 2 ++ .../sourceforge/pmd/properties/ValueParserConstants.java | 4 ++++ .../properties/builders/MultiNumericPropertyBuilder.java | 1 + .../properties/builders/MultiPackagedPropertyBuilder.java | 1 + .../PropertyDescriptorBuilderConversionWrapper.java | 1 + .../builders/PropertyDescriptorExternalBuilder.java | 1 + .../properties/builders/SingleNumericPropertyBuilder.java | 1 + .../builders/SinglePackagedPropertyBuilder.java | 1 + .../pmd/properties/modules/EnumeratedPropertyModule.java | 1 + .../pmd/properties/modules/MethodPropertyModule.java | 1 + .../pmd/properties/modules/NumericPropertyModule.java | 1 + .../pmd/properties/modules/PackagedPropertyModule.java | 1 + .../pmd/properties/modules/TypePropertyModule.java | 1 + 28 files changed, 46 insertions(+), 3 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiNumericProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiNumericProperty.java index b72bb6b4cd..2f2d212aff 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiNumericProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiNumericProperty.java @@ -19,6 +19,7 @@ import net.sourceforge.pmd.properties.modules.NumericPropertyModule; * @author Clément Fournier * @version Refactored June 2017 (6.0.0) */ +@Deprecated /* default */ abstract class AbstractMultiNumericProperty extends AbstractMultiValueProperty implements NumericPropertyDescriptor> { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiPackagedProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiPackagedProperty.java index a9183adcae..31882c325e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiPackagedProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiPackagedProperty.java @@ -19,6 +19,7 @@ import net.sourceforge.pmd.properties.modules.PackagedPropertyModule; * @author Clément Fournier * @version Refactored June 2017 (6.0.0) */ +@Deprecated /* default */ abstract class AbstractMultiPackagedProperty extends AbstractMultiValueProperty implements PackagedPropertyDescriptor> { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractNumericProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractNumericProperty.java index 9c6c42f9d3..866d88fcca 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractNumericProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractNumericProperty.java @@ -18,6 +18,7 @@ import net.sourceforge.pmd.properties.modules.NumericPropertyModule; * @author Clément Fournier * @version Refactored June 2017 (6.0.0) */ +@Deprecated /* default */ abstract class AbstractNumericProperty extends AbstractSingleValueProperty implements NumericPropertyDescriptor { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPackagedProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPackagedProperty.java index 3d498026a1..94921e7eae 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPackagedProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPackagedProperty.java @@ -19,6 +19,7 @@ import net.sourceforge.pmd.properties.modules.PackagedPropertyModule; * @author Clément Fournier * @version Refactored June 2017 (6.0.0) */ +@Deprecated /* default */ abstract class AbstractPackagedProperty extends AbstractSingleValueProperty implements PackagedPropertyDescriptor { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/EnumeratedPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/EnumeratedPropertyDescriptor.java index 0736db2c4d..c069542aac 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/EnumeratedPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/EnumeratedPropertyDescriptor.java @@ -16,6 +16,7 @@ import java.util.Map; * @author Clément Fournier * @since 6.0.0 */ +@Deprecated public interface EnumeratedPropertyDescriptor extends PropertyDescriptor { /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatMultiProperty.java index 4c06a0f107..ef8c60ac6b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatMultiProperty.java @@ -16,7 +16,9 @@ import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilderConversi * * @author Brian Remedios * @version Refactored June 2017 (6.0.0) + * @deprecated Use {@link DoubleMultiProperty} */ +@Deprecated public final class FloatMultiProperty extends AbstractMultiNumericProperty { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatProperty.java index a3ce5de9a1..19ced229aa 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatProperty.java @@ -12,9 +12,10 @@ import net.sourceforge.pmd.properties.builders.SingleNumericPropertyBuilder; /** * Defines a property type that supports single float property values within an upper and lower boundary. - * + * @deprecated Use {@link DoubleProperty} * @author Brian Remedios */ +@Deprecated public final class FloatProperty extends AbstractNumericProperty { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodMultiProperty.java index bac24a7efb..1a0248a07d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodMultiProperty.java @@ -24,6 +24,7 @@ import net.sourceforge.pmd.properties.modules.MethodPropertyModule; * @author Brian Remedios * @version Refactored June 2017 (6.0.0) */ +@Deprecated public final class MethodMultiProperty extends AbstractMultiPackagedProperty { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodProperty.java index 66cc0bed81..697f4eadb3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodProperty.java @@ -21,9 +21,11 @@ import net.sourceforge.pmd.properties.modules.MethodPropertyModule; *

Rule developers can limit the rules to those within designated packages per the 'legalPackages' argument in the * constructor which can be an array of partial package names, i.e., ["java.lang", "com.mycompany" ].

* + * @deprecated Not useful, will be remove by 7.0.0 * @author Brian Remedios * @version Refactored June 2017 (6.0.0) */ +@Deprecated public final class MethodProperty extends AbstractPackagedProperty { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/NumericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/NumericPropertyDescriptor.java index 99959662a9..1fdb507fa9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/NumericPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/NumericPropertyDescriptor.java @@ -12,6 +12,7 @@ package net.sourceforge.pmd.properties; * @author Brian Remedios * @author Clément Fournier */ +@Deprecated public interface NumericPropertyDescriptor extends PropertyDescriptor { /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PackagedPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PackagedPropertyDescriptor.java index bfc42fc402..e650d9a9b9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PackagedPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PackagedPropertyDescriptor.java @@ -12,6 +12,7 @@ package net.sourceforge.pmd.properties; * * @author Clément Fournier */ +@Deprecated public interface PackagedPropertyDescriptor extends PropertyDescriptor { /** Delimiter used to separate package names. */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index 98adff86fd..a7e7a01552 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -8,6 +8,7 @@ import java.util.Map; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleSetWriter; +import net.sourceforge.pmd.annotation.InternalApi; /** @@ -146,8 +147,10 @@ public interface PropertyDescriptor extends Comparable> /** * Returns a map representing all the property attributes of the receiver in string form. * + * @deprecated Will be removed with 7.0.0 * @return map */ + @Deprecated Map attributeValuesById(); @@ -160,6 +163,7 @@ public interface PropertyDescriptor extends Comparable> * @return True if the descriptor was defined in xml */ @Deprecated + @InternalApi boolean isDefinedExternally(); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptorField.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptorField.java index e1d3f1dd09..8a01f07572 100755 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptorField.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptorField.java @@ -16,7 +16,9 @@ import net.sourceforge.pmd.RuleSetFactory; * @author Brian Remedios * @see RuleSetFactory * @see PropertyTypeId + * @deprecated Will be removed with 7.0.0 */ +@Deprecated public enum PropertyDescriptorField { /** The type of the property. */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyTypeId.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyTypeId.java index dfe151fead..21b848fde8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyTypeId.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyTypeId.java @@ -37,14 +37,17 @@ public enum PropertyTypeId { INTEGER_LIST("List[Integer]", IntegerMultiProperty.extractor(), ValueParserConstants.INTEGER_PARSER), LONG("Long", LongProperty.extractor(), ValueParserConstants.LONG_PARSER), LONG_LIST("List[Long]", LongMultiProperty.extractor(), ValueParserConstants.LONG_PARSER), + @Deprecated FLOAT("Float", FloatProperty.extractor(), ValueParserConstants.FLOAT_PARSER), + @Deprecated FLOAT_LIST("List[Float]", FloatMultiProperty.extractor(), ValueParserConstants.FLOAT_PARSER), DOUBLE("Double", DoubleProperty.extractor(), ValueParserConstants.DOUBLE_PARSER), DOUBLE_LIST("List[Double]", DoubleMultiProperty.extractor(), ValueParserConstants.DOUBLE_PARSER), // ENUM("Enum", EnumeratedProperty.FACTORY), // TODO:cf we need new syntax in the xml to support that // ENUM_LIST("List[Enum]", EnumeratedMultiProperty.FACTORY), - + @Deprecated CLASS("Class", TypeProperty.extractor(), ValueParserConstants.CLASS_PARSER), + @Deprecated CLASS_LIST("List[Class]", TypeMultiProperty.extractor(), ValueParserConstants.CLASS_PARSER); @@ -85,6 +88,7 @@ public enum PropertyTypeId { * * @return The factory */ + @Deprecated public PropertyDescriptorExternalBuilder getFactory() { return factory; } @@ -96,6 +100,7 @@ public enum PropertyTypeId { * * @return whether the property is numeric */ + @Deprecated public boolean isPropertyNumeric() { return factory instanceof PropertyDescriptorBuilderConversionWrapper.SingleValue.Numeric || factory instanceof PropertyDescriptorBuilderConversionWrapper.MultiValue.Numeric; @@ -108,6 +113,7 @@ public enum PropertyTypeId { * * @return whether the property is packaged */ + @Deprecated public boolean isPropertyPackaged() { return factory instanceof PropertyDescriptorBuilderConversionWrapper.SingleValue.Packaged || factory instanceof PropertyDescriptorBuilderConversionWrapper.MultiValue.Packaged; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeMultiProperty.java index 5e53397e4a..f38dbbbf0f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeMultiProperty.java @@ -15,9 +15,10 @@ import net.sourceforge.pmd.properties.modules.TypePropertyModule; * Defines a property that supports multiple class types, even for primitive values! * * TODO - untested for array types - * + * @deprecated Not useful, will be removed by 7.0.0 * @author Brian Remedios */ +@Deprecated public final class TypeMultiProperty extends AbstractMultiPackagedProperty { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeProperty.java index a7d2ef2898..ed3f5ca3b8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeProperty.java @@ -17,7 +17,9 @@ import net.sourceforge.pmd.properties.modules.TypePropertyModule; * TODO - untested for array types * * @author Brian Remedios + * @deprecated Not useful, will be removed by 7.0.0 */ +@Deprecated public final class TypeProperty extends AbstractPackagedProperty { /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java index b4f60a7f6e..b452499082 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java @@ -18,13 +18,17 @@ import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.util.ClassUtil; /** + * @deprecated Was internal API * @author Clément Fournier * @since 6.0.0 */ +@Deprecated +@InternalApi public final class ValueParserConstants { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiNumericPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiNumericPropertyBuilder.java index 8bcc2340c3..8769731240 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiNumericPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiNumericPropertyBuilder.java @@ -13,6 +13,7 @@ import net.sourceforge.pmd.properties.MultiValuePropertyDescriptor; * @param Element type of the list * @param Concrete type of the underlying builder */ +@Deprecated public abstract class MultiNumericPropertyBuilder> extends MultiValuePropertyBuilder { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiPackagedPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiPackagedPropertyBuilder.java index aad9f61895..9ce2836929 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiPackagedPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiPackagedPropertyBuilder.java @@ -11,6 +11,7 @@ import java.util.Arrays; * @author Clément Fournier * @since 6.0.0 */ +@Deprecated public abstract class MultiPackagedPropertyBuilder> extends MultiValuePropertyBuilder { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilderConversionWrapper.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilderConversionWrapper.java index caf9beb9d6..0e8cfa3fd1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilderConversionWrapper.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilderConversionWrapper.java @@ -29,6 +29,7 @@ import net.sourceforge.pmd.properties.ValueParserConstants; * @author Clément Fournier * @since 6.0.0 */ +@Deprecated public abstract class PropertyDescriptorBuilderConversionWrapper> implements PropertyDescriptorExternalBuilder { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java index 16ded67141..e45be1e5e0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java @@ -18,6 +18,7 @@ import net.sourceforge.pmd.properties.PropertyDescriptorField; * @author Clément Fournier * @since 6.0.0 */ +@Deprecated public interface PropertyDescriptorExternalBuilder { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleNumericPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleNumericPropertyBuilder.java index 4e4d450aed..78832baf3e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleNumericPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleNumericPropertyBuilder.java @@ -8,6 +8,7 @@ package net.sourceforge.pmd.properties.builders; * @author Clément Fournier * @since 6.0.0 */ +@Deprecated public abstract class SingleNumericPropertyBuilder> extends SingleValuePropertyBuilder { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SinglePackagedPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SinglePackagedPropertyBuilder.java index 2f7219d14c..85e8e3a272 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SinglePackagedPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SinglePackagedPropertyBuilder.java @@ -12,6 +12,7 @@ import java.util.Collection; * @author Clément Fournier * @since 6.0.0 */ +@Deprecated public abstract class SinglePackagedPropertyBuilder> extends SingleValuePropertyBuilder { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/EnumeratedPropertyModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/EnumeratedPropertyModule.java index ff78fa232b..9836ceecb6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/EnumeratedPropertyModule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/EnumeratedPropertyModule.java @@ -15,6 +15,7 @@ import net.sourceforge.pmd.util.CollectionUtil; * * @author Clément Fournier */ +@Deprecated public class EnumeratedPropertyModule { private final Map choicesByLabel; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/MethodPropertyModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/MethodPropertyModule.java index c2b1019055..bbca8d8a02 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/MethodPropertyModule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/MethodPropertyModule.java @@ -16,6 +16,7 @@ import net.sourceforge.pmd.util.ClassUtil; * * @author Clément Fournier */ +@Deprecated public class MethodPropertyModule extends PackagedPropertyModule { public static final char CLASS_METHOD_DELIMITER = '#'; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/NumericPropertyModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/NumericPropertyModule.java index e37286f9a1..0b8a26c988 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/NumericPropertyModule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/NumericPropertyModule.java @@ -17,6 +17,7 @@ import net.sourceforge.pmd.properties.PropertyDescriptorField; * * @author Clément Fournier */ +@Deprecated public class NumericPropertyModule { private final T lowerLimit; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/PackagedPropertyModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/PackagedPropertyModule.java index a9c29a0ea6..5e90f6f4cc 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/PackagedPropertyModule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/PackagedPropertyModule.java @@ -24,6 +24,7 @@ import net.sourceforge.pmd.properties.PropertyDescriptorField; * * @author Clément Fournier */ +@Deprecated public abstract class PackagedPropertyModule { private static final Pattern PACKAGE_NAME_PATTERN = Pattern.compile("(\\w+)(\\.\\w+)*"); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/TypePropertyModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/TypePropertyModule.java index 183357552e..52e4f5d87f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/TypePropertyModule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/TypePropertyModule.java @@ -12,6 +12,7 @@ import java.util.List; * * @author Clément Fournier */ +@Deprecated public class TypePropertyModule extends PackagedPropertyModule { public TypePropertyModule(String[] legalPackageNames, List defaults) { From 5c398b825ed44f7aedd1aa8c994d3b27b88e15c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 30 Oct 2018 09:18:58 +0100 Subject: [PATCH 012/139] Add comments, update release notes --- docs/pages/release_notes.md | 19 +++++++++++++++++++ .../EnumeratedPropertyDescriptor.java | 2 ++ .../pmd/properties/FileProperty.java | 2 ++ .../pmd/properties/FloatMultiProperty.java | 2 +- .../pmd/properties/FloatProperty.java | 4 +++- .../pmd/properties/MethodMultiProperty.java | 1 + .../pmd/properties/MethodProperty.java | 1 + .../properties/NumericPropertyDescriptor.java | 2 ++ .../pmd/properties/PropertyDescriptor.java | 2 ++ .../pmd/properties/TypeMultiProperty.java | 2 +- .../pmd/properties/TypeProperty.java | 2 +- 11 files changed, 35 insertions(+), 4 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 89a879949a..4e9f375bc3 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -21,6 +21,25 @@ This is a {{ site.pmd.release_type }} release. ### API Changes +* Several classes and interfaces from the properties framework are now deprecated and will be removed with 7.0.0. + * MethodProperty, FloatProperty, FileProperty, TypeProperty and their multi-valued counterparts + are discontinued for lack of a use-case, and will probably not be replaced with 7.0.0. + Users of FloatProperty should consider using a DoubleProperty. + * EnumeratedPropertyDescriptor, NumericPropertyDescriptor, PackagedPropertyDescriptor, and the related builders + (in net.sourceforge.pmd.properties.builders) will be removed. In the future, these interfaces won't be around + but their functionality will, under another form. The related methods `PropertyTypeId#isPropertyNumeric` and + `PropertyTypeId#isPropertyPackaged` are also deprecated. + * All classes of net.sourceforge.pmd.properties.modules are deprecated and will be removed. They were + never intended as public api. + * The classes PropertyDescriptorField, PropertyDescriptorBuilderConversionWrapper, and the methods + `PropertyDescriptor#attributeValuesById`, `PropertyDescriptor#isDefinedExternally` and `PropertyTypeId#getFactory` are deprecated with no + intended replacement. These were used to read and write properties to and from XML, and were never + intended as public API. + * The class ValueParserConstants is deprecated with no intended replacement, it was not intended as + public API. + * The method `PropertyDescriptor#preferredRowCount` is deprecated with no intended replacement. It was + never implemented, and does not belong in this interface. + ### External Contributions {% endtocmaker %} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/EnumeratedPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/EnumeratedPropertyDescriptor.java index c069542aac..b8d17f99bd 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/EnumeratedPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/EnumeratedPropertyDescriptor.java @@ -15,6 +15,8 @@ import java.util.Map; * * @author Clément Fournier * @since 6.0.0 + * @deprecated Will be removed with 7.0.0. In the future this interface won't exist, + * but enumerated properties will still be around */ @Deprecated public interface EnumeratedPropertyDescriptor extends PropertyDescriptor { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/FileProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/FileProperty.java index 5720929625..7fc043e613 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/FileProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/FileProperty.java @@ -17,7 +17,9 @@ import net.sourceforge.pmd.properties.builders.SinglePackagedPropertyBuilder; * * @author Brian Remedios * @version Refactored June 2017 (6.0.0) + * @deprecated Will be removed with 7.0.0 with no scheduled replacement */ +@Deprecated public final class FileProperty extends AbstractSingleValueProperty { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatMultiProperty.java index ef8c60ac6b..9a166dc60d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatMultiProperty.java @@ -16,7 +16,7 @@ import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilderConversi * * @author Brian Remedios * @version Refactored June 2017 (6.0.0) - * @deprecated Use {@link DoubleMultiProperty} + * @deprecated Will be removed with 7.0.0 with no scheduled replacement. Users should use {@link DoubleMultiProperty} instead */ @Deprecated public final class FloatMultiProperty extends AbstractMultiNumericProperty { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatProperty.java index 19ced229aa..9f0990e24f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/FloatProperty.java @@ -12,7 +12,9 @@ import net.sourceforge.pmd.properties.builders.SingleNumericPropertyBuilder; /** * Defines a property type that supports single float property values within an upper and lower boundary. - * @deprecated Use {@link DoubleProperty} + * + * + * @deprecated Will be removed with 7.0.0 with no scheduled replacement. Users should use {@link DoubleProperty} instead * @author Brian Remedios */ @Deprecated diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodMultiProperty.java index 1a0248a07d..8c2c3d2a6e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodMultiProperty.java @@ -23,6 +23,7 @@ import net.sourceforge.pmd.properties.modules.MethodPropertyModule; * * @author Brian Remedios * @version Refactored June 2017 (6.0.0) + * @deprecated Will be removed with 7.0.0 with no scheduled replacement */ @Deprecated public final class MethodMultiProperty extends AbstractMultiPackagedProperty { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodProperty.java index 697f4eadb3..f42768eedb 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodProperty.java @@ -24,6 +24,7 @@ import net.sourceforge.pmd.properties.modules.MethodPropertyModule; * @deprecated Not useful, will be remove by 7.0.0 * @author Brian Remedios * @version Refactored June 2017 (6.0.0) + * @deprecated Will be removed with 7.0.0 with no scheduled replacement */ @Deprecated public final class MethodProperty extends AbstractPackagedProperty { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/NumericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/NumericPropertyDescriptor.java index 1fdb507fa9..d8b75e4089 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/NumericPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/NumericPropertyDescriptor.java @@ -9,6 +9,8 @@ package net.sourceforge.pmd.properties; * * @param type of the property value * + * @deprecated Will be removed with 7.0.0. In the future this interface won't exist, + * but numeric properties will still be around * @author Brian Remedios * @author Clément Fournier */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index a7e7a01552..aa93fb9da3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -22,6 +22,8 @@ import net.sourceforge.pmd.annotation.InternalApi; *

Several interfaces further specialize the behaviour of descriptors to accommodate specific types of descriptors, * see {@link NumericPropertyDescriptor} and {@link EnumeratedPropertyDescriptor}. * + *

Upcoming API changes to the properties framework: see https://github.com/pmd/pmd/issues/1415

+ * * @param type of the property's value. This is a list type for multi-valued properties. * * @author Brian Remedios diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeMultiProperty.java index f38dbbbf0f..9899e00538 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeMultiProperty.java @@ -15,7 +15,7 @@ import net.sourceforge.pmd.properties.modules.TypePropertyModule; * Defines a property that supports multiple class types, even for primitive values! * * TODO - untested for array types - * @deprecated Not useful, will be removed by 7.0.0 + * @deprecated Will be removed with 7.0.0 with no scheduled replacement yet * @author Brian Remedios */ @Deprecated diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeProperty.java index ed3f5ca3b8..9b6cfc1113 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeProperty.java @@ -17,7 +17,7 @@ import net.sourceforge.pmd.properties.modules.TypePropertyModule; * TODO - untested for array types * * @author Brian Remedios - * @deprecated Not useful, will be removed by 7.0.0 + * @deprecated Will be removed with 7.0.0 with no scheduled replacement yet */ @Deprecated public final class TypeProperty extends AbstractPackagedProperty { From a033b27e2e39a82136be893934bddab2890a143a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 29 Oct 2018 03:31:06 +0100 Subject: [PATCH 013/139] Add pmd 7.0.0 dev page to docs --- docs/_data/sidebars/pmd_sidebar.yml | 3 + docs/pages/next_major_development.md | 206 +++++++++++++++++++++++++++ docs/pages/release_notes.md | 2 + docs/pages/release_notes_old.md | 3 +- 4 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 docs/pages/next_major_development.md diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index 7e01f5c0c4..593dc5e9a1 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -25,6 +25,9 @@ entries: - title: Release notes url: /pmd_release_notes.html output: web, pdf + - title: PMD 7.0.0 development + url: /pmd_next_major_development.html + output: web, pdf - title: Getting help url: /pmd_about_help.html output: web, pdf diff --git a/docs/pages/next_major_development.md b/docs/pages/next_major_development.md new file mode 100644 index 0000000000..c7abcaa68c --- /dev/null +++ b/docs/pages/next_major_development.md @@ -0,0 +1,206 @@ +--- +title: PMD 7.0.0 development +permalink: pmd_next_major_development.html +keywords: changelog, release notes, deprecation, api changes +--- + +We're excited to bring you the next major version of PMD! Here are the major features and changes we're working on. +To give us feedback or to suggest a new feature, drop us a line on [Gitter](https://gitter.im/pmd/pmd)! + +## New Features + +TODO + +## Java grammar changes + +{% include note.html content="Current plans are listed [here](https://github.com/pmd/pmd/labels/in%3Aast) and in particular [here](https://github.com/pmd/pmd/issues/1019)" %} + + + +## New API support guidelines + +### What's new + +Until now, all released public members and types were implicitly considered part +of PMD's public API, including inheritance-specific members (protected members, abstract methods). +We have maintained those APIs with the goal to preserve full binary compatibility between minor releases, +only breaking those APIs infrequently, for major releases. + +In order to allow PMD to move forward at a faster pace, this implicit contract will +be invalidated with PMD 7.0.0. We now introduce more fine-grained distinctions between +the type of compatibility support we guarantee for our libraries, and ways to make +them explicit to clients of PMD. + +#### `.internal` packages and `@InternalApi` annotation + +*Internal API* is meant for use *only* by the main PMD codebase. Internal types and methods +may be modified in any way, or even removed, at any time. + +Any API in a package that contains an `.internal` segment is considered internal. +The `@InternalApi` annotation will be used for APIs that have to live outside of +these packages, e.g. methods of a public type that shouldn't be used outside of PMD (again, +these can be removed anytime). + +#### `@ReservedSubclassing` + +Types marked with the `@ReservedSubclassing` annotation are only meant to be subclassed +by classes within PMD. As such, we may add new abstract methods, or remove protected methods, +at any time. All published public members remain supported. The annotation is *not* inherited, which +means a reserved interface doesn't prevent its implementors to be subclassed. + +#### `@Experimental` + +APIs marked with the `@Experimental` annotation at the class or method level are subject to change. +They can be modified in any way, or even removed, at any time. You should not use or rely + on them in any production code. They are purely to allow broad testing and feedback. + +#### `@Deprecated` + +APIs marked with the `@Deprecated` annotation at the class or method level will remain supported +until the next major release but it is recommended to stop using them. + +### The transition + +*All currently supported APIs will remain so until 7.0.0*. All APIs that are to be moved to +`.internal` packages or hidden will be tagged `@InternalApi` before that major release, and +the breaking API changes will be performed in 7.0.0. + +## Planned API removals + +### List of currently deprecated APIs + +{% include warning.html content="This list is not exhaustive. The ultimate reference is whether +an API is tagged as `@Deprecated` or not in the latest minor release. During the development of 7.0.0, +we may decide to remove some APIs that were not tagged as deprecated, though we'll try to avoid it." %} + +#### 6.8.0 + +* A couple of methods and fields in `net.sourceforge.pmd.properties.AbstractPropertySource` have been + deprecated, as they are replaced by already existing functionality or expose internal implementation + details: `propertyDescriptors`, `propertyValuesByDescriptor`, + `copyPropertyDescriptors()`, `copyPropertyValues()`, `ignoredProperties()`, `usesDefaultValues()`, + `useDefaultValueFor()`. + +* Some methods in `net.sourceforge.pmd.properties.PropertySource` have been deprecated as well: + `usesDefaultValues()`, `useDefaultValueFor()`, `ignoredProperties()`. + +* The class `net.sourceforge.pmd.lang.rule.AbstractDelegateRule` has been deprecated and will + be removed with PMD 7.0.0. It is internally only in use by RuleReference. + +* The default constructor of `net.sourceforge.pmd.lang.rule.RuleReference` has been deprecated + and will be removed with PMD 7.0.0. RuleReferences should only be created by providing a Rule and + a RuleSetReference. Furthermore the following methods are deprecated: `setRuleReference()`, + `hasOverriddenProperty()`, `usesDefaultValues()`, `useDefaultValueFor()`. + +#### 6.7.0 + +* All classes in the package `net.sourceforge.pmd.lang.dfa.report` have been deprecated and will be removed + with PMD 7.0.0. This includes the class `net.sourceforge.pmd.lang.dfa.report.ReportTree`. The reason is, + that this class is very specific to Java and not suitable for other languages. It has only been used for + `YAHTMLRenderer`, which has been rewritten to work without these classes. + +* The nodes RUNSIGNEDSHIFT and RSIGNEDSHIFT are deprecated and will be removed from the AST with PMD 7.0.0. + These represented the operator of ShiftExpression in two cases out of three, but they're not needed and + make ShiftExpression inconsistent. The operator of a ShiftExpression is now accessible through + ShiftExpression#getOperator. + +#### 6.5.0 + +* The utility class `net.sourceforge.pmd.lang.java.ast.CommentUtil` has been deprecated and will be removed + with PMD 7.0.0. Its methods have been intended to parse javadoc tags. A more useful solution will be added + around the AST node `FormalComment`, which contains as children `JavadocElement` nodes, which in + turn provide access to the `JavadocTag`. + + All comment AST nodes (`FormalComment`, `MultiLineComment`, `SingleLineComment`) have a new method + `getFilteredComment()` which provide access to the comment text without the leading `/*` markers. + +* The method `AbstractCommentRule.tagsIndicesIn()` has been deprecated and will be removed with + PMD 7.0.0. It is not very useful, since it doesn't extract the information + in a useful way. You would still need check, which tags have been found, and with which + data they might be accompanied. + +#### 6.4.0 + +* The following classes in package `net.sourceforge.pmd.benchmark` have been deprecated: `Benchmark`, `Benchmarker`, + `BenchmarkReport`, `BenchmarkResult`, `RuleDuration`, `StringBuilderCR` and `TextReport`. Their API is not supported anymore + and is disconnected from the internals of PMD. Use the newer API based around `TimeTracker` instead, which can be found + in the same package. +* The class `net.sourceforge.pmd.lang.java.xpath.TypeOfFunction` has been deprecated. Use the newer `TypeIsFunction` in the same package. +* The `typeof` methods in `net.sourceforge.pmd.lang.java.xpath.JavaFunctions` have been deprecated. + Use the newer `typeIs` method in the same class instead.. +* The methods `isA`, `isEither` and `isNeither` of `net.sourceforge.pmd.lang.java.typeresolution.TypeHelper`. + Use the new `isExactlyAny` and `isExactlyNone` methods in the same class instead. + +#### 6.2.0 + +* The static method `PMDParameters.transformParametersIntoConfiguration(PMDParameters)` is now deprecated, + for removal in 7.0.0. The new instance method `PMDParameters.toConfiguration()` replaces it. + +* The method `ASTConstructorDeclaration.getParameters()` has been deprecated in favor of the new method + `getFormalParameters()`. This method is available for both `ASTConstructorDeclaration` and + `ASTMethodDeclaration`. + +#### 6.1.0 + +* The method `getXPathNodeName` is added to the `Node` interface, which removes the +use of the `toString` of a node to get its XPath element name (see [#569](https://github.com/pmd/pmd/issues/569)). + * The default implementation provided in `AbstractNode`, will + be removed with 7.0.0 + * With 7.0.0, the `Node.toString` method will not necessarily provide its XPath node + name anymore. + +* The interface `net.sourceforge.pmd.cpd.Renderer` has been deprecated. A new interface +`net.sourceforge.pmd.cpd.renderer.CPDRenderer` has been introduced to replace it. The main +difference is that the new interface is meant to render directly to a `java.io.Writer` +rather than to a String. This allows to greatly reduce the memory footprint of CPD, as on +large projects, with many duplications, it was causing `OutOfMemoryError`s (see [#795](https://github.com/pmd/pmd/issues/795)). + + `net.sourceforge.pmd.cpd.FileReporter` has also been deprecated as part of this change, as it's no longer needed. + +#### 6.0.1 + +* The constant `net.sourceforge.pmd.PMD.VERSION` has been deprecated and will be removed with PMD 7.0.0. + Please use `net.sourceforge.pmd.PMDVersion.VERSION` instead. + +### List of currently deprecated rules + +* The Java rules {% rule java/codestyle/VariableNamingConventions %}, {% rule java/codestyle/MIsLeadingVariableName %}, + {% rule java/codestyle/SuspiciousConstantFieldName %}, and {% rule java/codestyle/AvoidPrefixingMethodParameters %} are + now deprecated, and will be removed with version 7.0.0. They are replaced by the more general + {% rule java/codestyle/FieldNamingConventions %}, {% rule java/codestyle/FormalParameterNamingConventions %}, and + {% rule java/codestyle/LocalVariableNamingConventions %}. + +* The Java rule {% rule java/codestyle/AbstractNaming %} is deprecated + in favour of {% rule java/codestyle/ClassNamingConventions %}. + +* The Java rules {% rule java/codestyle/WhileLoopsMustUseBraces %}, {% rule java/codestyle/ForLoopMustUseBraces %}, {% rule java/codestyle/IfStmtMustUseBraces %}, and {% rule java/codestyle/IfElseStmtMustUseBraces %} + are deprecated. They will be replaced by the new rule {% rule java/codestyle/ControlStatementBraces %} + +* The Java rules {% rule java/codestyle/NcssConstructorCount %}, {% rule java/codestyle/NcssMethodCount %}, and {% rule java/codestyle/NcssTypeCount %} have been + deprecated. They will be replaced by the new rule {% rule java/design/NcssCount %} in the category `design`. + +* The Java rule `LooseCoupling` in ruleset `java-typeresolution` is deprecated. Use the rule with the same name from category `bestpractices` instead. + +* The Java rule `CloneMethodMustImplementCloneable` in ruleset `java-typeresolution` is deprecated. Use the rule with the same name from category `errorprone` instead. + +* The Java rule `UnusedImports` in ruleset `java-typeresolution` is deprecated. Use the rule with + the same name from category `bestpractices` instead. + +* The Java rule `SignatureDeclareThrowsException` in ruleset `java-typeresolution` is deprecated. Use the rule with the same name from category `design` instead. + +* The Java rule `EmptyStaticInitializer` in ruleset `java-empty` is deprecated. Use the rule {% rule java/errorprone/EmptyInitializer %}, which covers both static and non-static empty initializers.` + +* The Java rules `GuardDebugLogging` (ruleset `java-logging-jakarta-commons`) and `GuardLogStatementJavaUtil` + (ruleset `java-logging-java`) have been deprecated. Use the rule {% rule java/bestpractices/GuardLogStatement %}, which covers all cases regardless of the logging framework. + + + + + + + + + + + + diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index b8f8783555..8c5a72c673 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -22,3 +22,5 @@ This is a {{ site.pmd.release_type }} release. {% endtocmaker %} +{% include note.html content="The release notes of previous versions are available [here](pmd_release_notes_old.html)" %} + diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index 3fff802bb5..d7110b6473 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -3,8 +3,7 @@ title: Old Release Notes permalink: pmd_release_notes_old.html --- -Previous versions of PMD can be downloaded here: -http://sourceforge.net/projects/pmd/files/pmd/ +Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/releases ## 28-October-2018 - 6.9.0 From 679eaeb4e5786cb60b61e7e1890ff71e69f7c85e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 2 Nov 2018 08:11:26 +0100 Subject: [PATCH 014/139] Deprecate Initializer and functions --- .../main/java/net/sourceforge/pmd/lang/XPathHandler.java | 6 ++++++ .../java/net/sourceforge/pmd/lang/xpath/Initializer.java | 5 +++++ .../net/sourceforge/pmd/lang/xpath/MatchesFunction.java | 3 +++ .../java/net/sourceforge/pmd/lang/xpath/PMDFunctions.java | 5 +++++ .../pmd/lang/java/xpath/GetCommentOnFunction.java | 3 +++ .../net/sourceforge/pmd/lang/java/xpath/JavaFunctions.java | 3 +++ .../net/sourceforge/pmd/lang/java/xpath/MetricFunction.java | 3 +++ .../pmd/lang/java/xpath/TypeIsExactlyFunction.java | 4 ++++ .../net/sourceforge/pmd/lang/java/xpath/TypeIsFunction.java | 4 ++++ 9 files changed, 36 insertions(+) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/XPathHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/XPathHandler.java index d3d7ca82b6..95728185d7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/XPathHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/XPathHandler.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang; import org.jaxen.Navigator; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.xpath.Initializer; import net.sf.saxon.sxpath.IndependentContext; @@ -14,6 +15,8 @@ import net.sf.saxon.sxpath.IndependentContext; * Interface for performing Language specific XPath handling, such as * initialization and navigation. */ +@InternalApi +@Deprecated public interface XPathHandler { XPathHandler DUMMY = new XPathHandler() { @@ -48,6 +51,9 @@ public interface XPathHandler { /** * Get a Jaxen Navigator for this Language. May return null if * there is no Jaxen Navigation for this language. + * + * @deprecated Support for Jaxen will be removed come 7.0.0 */ + @Deprecated Navigator getNavigator(); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/Initializer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/Initializer.java index 54d28699c6..c73ef828a7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/Initializer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/Initializer.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.xpath; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; @@ -16,7 +17,11 @@ import net.sf.saxon.sxpath.IndependentContext; * initialization. For example, initializing custom Jaxen Functions. * Initialization should be performed before any XPath related operations are * performed. + * + * @deprecated Is internal API */ +@InternalApi +@Deprecated public final class Initializer { private Initializer() { } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/MatchesFunction.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/MatchesFunction.java index 67493ca9c5..252ed9bdec 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/MatchesFunction.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/MatchesFunction.java @@ -14,9 +14,12 @@ import org.jaxen.FunctionCallException; import org.jaxen.SimpleFunctionContext; import org.jaxen.XPathFunctionContext; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.xpath.Attribute; // FIXME Can this function be extended to work on non-AST attributes? +@InternalApi +@Deprecated public class MatchesFunction implements Function { public static void registerSelfInSimpleContext() { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/PMDFunctions.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/PMDFunctions.java index 394bd230d1..5a26e7b75c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/PMDFunctions.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/PMDFunctions.java @@ -4,6 +4,11 @@ package net.sourceforge.pmd.lang.xpath; +import net.sourceforge.pmd.annotation.InternalApi; + + +@InternalApi +@Deprecated public final class PMDFunctions { private PMDFunctions() { } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/GetCommentOnFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/GetCommentOnFunction.java index 386798653b..9e79e5328f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/GetCommentOnFunction.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/GetCommentOnFunction.java @@ -12,6 +12,7 @@ import org.jaxen.FunctionCallException; import org.jaxen.SimpleFunctionContext; import org.jaxen.XPathFunctionContext; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.AbstractNode; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; @@ -24,6 +25,8 @@ import net.sourceforge.pmd.lang.java.ast.Comment; * * @author Andy Throgmorton */ +@InternalApi +@Deprecated public class GetCommentOnFunction implements Function { public static void registerSelfInSimpleContext() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/JavaFunctions.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/JavaFunctions.java index 35f43e830b..d4242f26e6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/JavaFunctions.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/JavaFunctions.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.xpath; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.xpath.saxon.ElementNode; @@ -12,6 +13,8 @@ import net.sf.saxon.expr.XPathContext; /** * Exposes all Java Language specific functions for Saxon use. */ +@InternalApi +@Deprecated public final class JavaFunctions { private JavaFunctions() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java index 24a1f0a030..29e9c2bb69 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java @@ -15,6 +15,7 @@ import org.jaxen.FunctionCallException; import org.jaxen.SimpleFunctionContext; import org.jaxen.XPathFunctionContext; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; @@ -32,6 +33,8 @@ import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey; * @author Clément Fournier * @since 6.0.0 */ +@InternalApi +@Deprecated public class MetricFunction implements Function { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeIsExactlyFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeIsExactlyFunction.java index e6437fcce3..811afd1525 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeIsExactlyFunction.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeIsExactlyFunction.java @@ -12,10 +12,14 @@ import org.jaxen.FunctionCallException; import org.jaxen.SimpleFunctionContext; import org.jaxen.XPathFunctionContext; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.TypeNode; import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; + +@InternalApi +@Deprecated public class TypeIsExactlyFunction implements Function { public static void registerSelfInSimpleContext() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeIsFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeIsFunction.java index 0c5ecb3c3f..41ac55d5b0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeIsFunction.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeIsFunction.java @@ -12,10 +12,14 @@ import org.jaxen.FunctionCallException; import org.jaxen.SimpleFunctionContext; import org.jaxen.XPathFunctionContext; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.TypeNode; import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; + +@InternalApi +@Deprecated public class TypeIsFunction implements Function { public static void registerSelfInSimpleContext() { From e1b5717675646779553cebdfa510dbca17e2a30f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 2 Nov 2018 09:09:13 +0100 Subject: [PATCH 015/139] Fix #1372 --- .../resources/category/java/codestyle.xml | 6 +++-- .../codestyle/xml/UselessQualifiedThis.xml | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 3329ce7284..483d2e3a05 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1950,7 +1950,9 @@ public class Foo { message="Useless qualified this usage in the same class." class="net.sourceforge.pmd.lang.rule.XPathRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#uselessqualifiedthis"> - Look for qualified this usages in the same class. + + Reports qualified this usages in the same class. + 3 @@ -1958,7 +1960,7 @@ public class Foo { + + + False positive for UselessQualifiedThis #1372 + 0 + + + + \ No newline at end of file From 08950c9fbed7f1d365e33eb650b26ae53868f26f Mon Sep 17 00:00:00 2001 From: Will Herrmann Date: Fri, 2 Nov 2018 16:04:21 -0500 Subject: [PATCH 016/139] Upgrading JCommander from 1.48 to 1.72 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9f8f1d3050..52722c32d2 100644 --- a/pom.xml +++ b/pom.xml @@ -842,7 +842,7 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code com.beust jcommander - 1.48 + 1.72 org.ow2.asm From ddf1347782fd8526dcb4796a17acf35e7d22a0f8 Mon Sep 17 00:00:00 2001 From: Dem Pilafian Date: Sat, 3 Nov 2018 20:07:34 -0700 Subject: [PATCH 017/139] Who really knows regex? --- docs/pages/pmd/userdocs/suppressing_warnings.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/pmd/userdocs/suppressing_warnings.md b/docs/pages/pmd/userdocs/suppressing_warnings.md index 6f59675085..5b19ccab1c 100644 --- a/docs/pages/pmd/userdocs/suppressing_warnings.md +++ b/docs/pages/pmd/userdocs/suppressing_warnings.md @@ -175,7 +175,7 @@ are unused:
``` -Note for message based suppression to work, you must know who to write +Note for message based suppression to work, you must know how to write a regular expression that matches the message of violations you wish to suppress. Regular expressions are explained in the JavaDoc for standard Java class java.util.regex.Pattern. @@ -203,4 +203,4 @@ For example, to suppress reporting specifically typed parameters which are unuse Note for XPath based suppression to work, you must know how to write an XPath query that matches the AST structure of the nodes of the violations you wish to suppress. XPath queries are explained in -[XPath Rule tutorial](pmd_userdocs_extending_writing_xpath_rules.html). \ No newline at end of file +[XPath Rule tutorial](pmd_userdocs_extending_writing_xpath_rules.html). From 39d340f431c1101dd6836b3968a2e81196c07cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 4 Nov 2018 14:48:35 +0100 Subject: [PATCH 018/139] Update release notes, refs #1430 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 62caa38f96..bc060c9b9d 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -25,6 +25,7 @@ This is a {{ site.pmd.release_type }} release. ### External Contributions * [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007) +* [#1430](https://github.com/pmd/pmd/pull/1430): \[doc] Who really knows regex? - [Dem Pilafian](https://github.com/dpilafian) {% endtocmaker %} From 8823ef5356a09c46ba89c30a7199c6371f7cbb56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 5 Nov 2018 00:32:18 +0100 Subject: [PATCH 019/139] More deprecations on PropertyDescriptor, relates to #1432 --- .../AbstractMultiValueProperty.java | 1 + .../pmd/properties/AbstractProperty.java | 1 + .../AbstractSingleValueProperty.java | 1 + .../MultiValuePropertyDescriptor.java | 7 ++++ .../pmd/properties/PropertyDescriptor.java | 39 +++++++++++++------ .../pmd/properties/PropertyTypeId.java | 25 ++++++++++++ .../SingleValuePropertyDescriptor.java | 4 ++ .../builders/MultiValuePropertyBuilder.java | 3 ++ .../builders/PropertyDescriptorBuilder.java | 2 + .../PropertyDescriptorExternalBuilder.java | 1 + .../builders/SingleValuePropertyBuilder.java | 3 ++ 11 files changed, 76 insertions(+), 11 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiValueProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiValueProperty.java index 514ed20003..339a6554c6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiValueProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiValueProperty.java @@ -23,6 +23,7 @@ import net.sourceforge.pmd.Rule; * @author Clément Fournier * @version 6.0.0 */ +@Deprecated /* default */ abstract class AbstractMultiValueProperty extends AbstractProperty> implements MultiValuePropertyDescriptor { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractProperty.java index ab1815ddef..f6946437ea 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractProperty.java @@ -23,6 +23,7 @@ import org.apache.commons.lang3.StringUtils; * @author Clément Fournier * @version Refactored June 2017 (6.0.0) */ +// @Deprecated // will be replaced by another base class in the next PR /* default */ abstract class AbstractProperty implements PropertyDescriptor { private final String name; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractSingleValueProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractSingleValueProperty.java index 0864cbaf17..d3908f6c4d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractSingleValueProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractSingleValueProperty.java @@ -14,6 +14,7 @@ import net.sourceforge.pmd.Rule; * * @author Clément Fournier */ +@Deprecated /* default */ abstract class AbstractSingleValueProperty extends AbstractProperty implements SingleValuePropertyDescriptor { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MultiValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/MultiValuePropertyDescriptor.java index 6d70fd44a7..49d710b40c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MultiValuePropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/MultiValuePropertyDescriptor.java @@ -17,13 +17,18 @@ import java.util.List; * * @author Clément Fournier * @since 6.0.0 + * + * @deprecated The hard divide between multi- and single-value properties will be removed with 7.0.0 */ +@Deprecated public interface MultiValuePropertyDescriptor extends PropertyDescriptor> { /** Default delimiter for multi-valued properties other than numeric ones. */ + @Deprecated char DEFAULT_DELIMITER = '|'; /** Default delimiter for numeric multi-valued properties. */ + @Deprecated char DEFAULT_NUMERIC_DELIMITER = ','; @@ -33,9 +38,11 @@ public interface MultiValuePropertyDescriptor extends PropertyDescriptor type(); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index aa93fb9da3..d25bcba046 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -22,7 +22,7 @@ import net.sourceforge.pmd.annotation.InternalApi; *

Several interfaces further specialize the behaviour of descriptors to accommodate specific types of descriptors, * see {@link NumericPropertyDescriptor} and {@link EnumeratedPropertyDescriptor}. * - *

Upcoming API changes to the properties framework: see https://github.com/pmd/pmd/issues/1415

+ *

Upcoming API changes to the properties framework: see wiki

* * @param type of the property's value. This is a list type for multi-valued properties. * @@ -53,7 +53,11 @@ public interface PropertyDescriptor extends Comparable> * class. * * @return Class literal of the value type + * + * @deprecated This method is mainly used for documentation, but will not prove general enough + * to support PMD 7.0.0's improved property types. */ + @Deprecated Class type(); @@ -65,7 +69,10 @@ public interface PropertyDescriptor extends Comparable> * must be used.

* * @return boolean + * + * @deprecated The hard divide between multi- and single-value properties will be removed with 7.0.0 */ + @Deprecated boolean isMultiValue(); @@ -85,7 +92,7 @@ public interface PropertyDescriptor extends Comparable> * * @return A diagnostic message. */ - String errorFor(T value); + String errorFor(T value); // TODO Java 1.8 make optional /** @@ -93,12 +100,7 @@ public interface PropertyDescriptor extends Comparable> * edit property values. If the value returned has a non-zero fractional part then this is can be used to place * adjacent fields on the same row. * - *

Example:
name -> 0.0 description 1.0 minValue -> 2.0 maxValue -> 2.1

..would have their - * fields placed like:
- * - * name: [ ] description: [ ] minimum: [ ] maximum: [ ] - * - * @return float + * @return The relative order compared to other properties of the same rule */ float uiOrder(); @@ -109,8 +111,12 @@ public interface PropertyDescriptor extends Comparable> * @param propertyString The string to parse * * @return The value represented by the string + * * @throws IllegalArgumentException if the given string cannot be parsed + * @deprecated PMD 7.0.0 will use a more powerful scheme to represent values than + * simple strings, this method won't be general enough */ + @Deprecated T valueFrom(String propertyString) throws IllegalArgumentException; @@ -120,7 +126,11 @@ public interface PropertyDescriptor extends Comparable> * @param value Object * * @return String + * + * @deprecated PMD 7.0.0 will use a more powerful scheme to represent values than + * simple strings, this method won't be general enough */ + @Deprecated String asDelimitedString(T value); @@ -131,7 +141,11 @@ public interface PropertyDescriptor extends Comparable> * @param rule Rule * * @return String + * + * @deprecated Used nowhere, and fails if the rule doesn't define the property descriptor + * A better solution will be added on property source */ + @Deprecated String propertyErrorFor(Rule rule); @@ -139,8 +153,9 @@ public interface PropertyDescriptor extends Comparable> * If the datatype is a String then return the preferred number of rows to allocate in the text widget, returns a * value of one for all other types. Useful for multi-line XPATH editors. * - * @deprecated Was never implemented, and is none of the descriptor's concern. Will be removed with 7.0.0 * @return int + * + * @deprecated Was never implemented, and is none of the descriptor's concern. Will be removed with 7.0.0 */ @Deprecated int preferredRowCount(); @@ -149,8 +164,9 @@ public interface PropertyDescriptor extends Comparable> /** * Returns a map representing all the property attributes of the receiver in string form. * - * @deprecated Will be removed with 7.0.0 * @return map + * + * @deprecated Will be removed with 7.0.0 */ @Deprecated Map attributeValuesById(); @@ -161,8 +177,9 @@ public interface PropertyDescriptor extends Comparable> * to write out the property correctly: if it was defined externally, then its definition must be written out, * otherwise only its value. * - * @deprecated May be removed with 7.0.0 * @return True if the descriptor was defined in xml + * + * @deprecated May be removed with 7.0.0 */ @Deprecated @InternalApi diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyTypeId.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyTypeId.java index 21b848fde8..4e78fc04c2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyTypeId.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyTypeId.java @@ -18,11 +18,21 @@ import net.sourceforge.pmd.properties.builders.PropertyDescriptorExternalBuilder * of the property that should be built. The mapping between the values of this attribute * and the concrete property that is built is encoded in the constants of this enum. * + *

Properties API changes

This class' API is mainly provided to build GUIs for XPath rules + * like the rule designer, so that they have info about the available properties from XML. As such, + * the number of clients are probably low. Nevertheless, a bunch of members have been deprecated to + * warn about probable upcoming API changes with 7.0.0, but the amount of change may be greater. + * See {@link PropertyDescriptor} for more info about property framework changes with 7.0.0. + * * @author Clément Fournier * @see PropertyDescriptorExternalBuilder * @since 6.0.0 */ public enum PropertyTypeId { + // These are exclusively used for XPath rules. It would make more sense to model the supported + // property types around XML Schema Datatypes (XSD) 1.0 or 1.1 instead of Java datatypes (save for + // e.g. the Class type), including the mnemonics (eg. xs:integer instead of Integer) + BOOLEAN("Boolean", BooleanProperty.extractor(), ValueParserConstants.BOOLEAN_PARSER), BOOLEAN_LIST("List[Boolean]", BooleanMultiProperty.extractor(), ValueParserConstants.BOOLEAN_PARSER), @@ -125,7 +135,10 @@ public enum PropertyTypeId { * lists of values as its value. * * @return whether the property is multivalue + * + * @deprecated see {@link PropertyDescriptor#isMultiValue()} */ + @Deprecated public boolean isPropertyMultivalue() { return factory.isMultiValue(); } @@ -136,7 +149,10 @@ public enum PropertyTypeId { * This is the component type of the list if the property is multivalued. * * @return The value type of the property + * + * @deprecated see {@link PropertyDescriptor#type()} */ + @Deprecated public Class propertyValueType() { return factory.valueType(); } @@ -148,7 +164,10 @@ public enum PropertyTypeId { * of the list. A list parser can be obtained with {@link ValueParserConstants#multi(ValueParser, char)}. * * @return The value parser + * + * @deprecated see {@link PropertyDescriptor#valueFrom(String)} */ + @Deprecated public ValueParser getValueParser() { return valueParser; } @@ -170,7 +189,10 @@ public enum PropertyTypeId { * @param stringId The identifier of the type * * @return The factory used to build new instances of a descriptor + * + * @deprecated See {@link PropertyDescriptorExternalBuilder} */ + @Deprecated public static PropertyDescriptorExternalBuilder factoryFor(String stringId) { PropertyTypeId cons = CONSTANTS_BY_MNEMONIC.get(stringId); return cons == null ? null : cons.factory; @@ -197,7 +219,10 @@ public enum PropertyTypeId { * @param multiValue Whether the descriptor is multivalued or not * * @return The string id + * + * @deprecated The signature will probably be altered in 7.0.0 but a similar functionality will be available */ + @Deprecated public static String typeIdFor(Class valueType, boolean multiValue) { for (Map.Entry entry : CONSTANTS_BY_MNEMONIC.entrySet()) { if (entry.getValue().propertyValueType() == valueType diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/SingleValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/SingleValuePropertyDescriptor.java index e79c28d46c..4ca0ac6337 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/SingleValuePropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/SingleValuePropertyDescriptor.java @@ -12,9 +12,13 @@ package net.sourceforge.pmd.properties; * * @author Clément Fournier * @since 6.0.0 + * + * @deprecated The hard divide between multi- and single-value properties will be removed with 7.0.0 */ +@Deprecated public interface SingleValuePropertyDescriptor extends PropertyDescriptor { @Override + @Deprecated Class type(); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiValuePropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiValuePropertyBuilder.java index 6405dd5770..da8f9009a7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiValuePropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiValuePropertyBuilder.java @@ -17,7 +17,10 @@ import net.sourceforge.pmd.properties.MultiValuePropertyDescriptor; * * @param Element type of the list * @param Concrete type of the underlying builder + * */ +// @Deprecated // will be rewritten in the next PR and placed in the properties package, +// since there will be no need for a separate package public abstract class MultiValuePropertyBuilder> extends PropertyDescriptorBuilder, T> { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java index 784fe1ff0f..5aa1ef3959 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java @@ -19,6 +19,8 @@ import net.sourceforge.pmd.properties.PropertyDescriptor; * @author Clément Fournier * @since 6.0.0 */ +// @Deprecated // will be rewritten in the next PR and placed in the properties package, +// since there will be no need for a separate package public abstract class PropertyDescriptorBuilder> { protected String name; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java index e45be1e5e0..9f63bdd3b7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java @@ -17,6 +17,7 @@ import net.sourceforge.pmd.properties.PropertyDescriptorField; * * @author Clément Fournier * @since 6.0.0 + * @deprecated The property XML API will not need this anymore */ @Deprecated public interface PropertyDescriptorExternalBuilder { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleValuePropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleValuePropertyBuilder.java index 4c8edbf11b..cce7692506 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleValuePropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleValuePropertyBuilder.java @@ -9,7 +9,10 @@ package net.sourceforge.pmd.properties.builders; * * @param Value type of the built descriptor * @param Concrete type of this builder instance. + * */ +// @Deprecated // will be rewritten in the next PR and placed in the properties package, +// since there will be no need for a separate package public abstract class SingleValuePropertyBuilder> extends PropertyDescriptorBuilder { From 972a991cb0cdaffc17ffb92708fa3a698f8296b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 29 Oct 2018 19:36:56 +0100 Subject: [PATCH 020/139] WIP --- .../AbstractMultiValuePropertyBuilder.java | 76 ++++++++++++ .../newframework/AbstractPropertyBuilder.java | 91 ++++++++++++++ .../AbstractPropertyDescriptor.java | 76 ++++++++++++ .../AbstractSingleValuePropertyBuilder.java | 65 ++++++++++ .../MultiValuePropertyDescriptor.java | 67 ++++++++++ .../newframework/PropertyDescriptor.java | 116 ++++++++++++++++++ .../newframework/PropertyFactory.java | 59 +++++++++ .../newframework/PropertyValidator.java | 26 ++++ .../SingleValuePropertyDescriptor.java | 54 ++++++++ 9 files changed, 630 insertions(+) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractMultiValuePropertyBuilder.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyDescriptor.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractSingleValuePropertyBuilder.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/MultiValuePropertyDescriptor.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyDescriptor.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/SingleValuePropertyDescriptor.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractMultiValuePropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractMultiValuePropertyBuilder.java new file mode 100644 index 0000000000..e94f87b448 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractMultiValuePropertyBuilder.java @@ -0,0 +1,76 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + + +/** + * @author Clément Fournier + * @since 6.7.0 + */ +public abstract class AbstractMultiValuePropertyBuilder>, V> extends AbstractPropertyBuilder> { + private final Set> componentValidators = new LinkedHashSet<>(); + private final Function parser; + private final Class type; + + private List defaultValues; + + + AbstractMultiValuePropertyBuilder(String name, Function parser, Class type) { + super(name); + this.parser = parser; + this.type = type; + } + + + /** + * Specify a default value. + * + * @param val List of values + * + * @return The same builder + */ + @SuppressWarnings("unchecked") + public B defaultValues(Collection val) { + this.defaultValues = new ArrayList<>(val); + return (B) this; + } + + + /** + * Specify default values. + * + * @param val List of values + * + * @return The same builder + */ + @SuppressWarnings("unchecked") + public B defaultValues(V... val) { + this.defaultValues = Arrays.asList(val); + return (B) this; + } + + + @Override + public PropertyDescriptor> build() { + return new MultiValuePropertyDescriptor<>( + name, + description, + uiOrder, + defaultValues, + validators, + componentValidators, + parser, + type + ); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java new file mode 100644 index 0000000000..e31bdb73e3 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java @@ -0,0 +1,91 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; + + +/** + * @author Clément Fournier + * @since 6.7.0 + */ +public abstract class AbstractPropertyBuilder, T> { + private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z][\\w-]*"); + protected final Set> validators = new LinkedHashSet<>(); + protected String name; + protected String description; + protected float uiOrder = 0f; + + + public AbstractPropertyBuilder(String name) { + if (StringUtils.isBlank(name)) { + throw new IllegalArgumentException("Name must be provided"); + } else if (!NAME_PATTERN.matcher(name).matches()) { + throw new IllegalArgumentException("Invalid name '" + name + "'"); + } + this.name = name; + } + + + /** + * Specify the description of the property. + * + * @param desc The description + * + * @return The same builder + */ + @SuppressWarnings("unchecked") + public B desc(String desc) { + if (StringUtils.isBlank(desc)) { + throw new IllegalArgumentException("Description must be provided"); + } + this.description = desc; + return (B) this; + } + + + /** + * Specify the UI order of the property. + * + * @param f The UI order + * + * @return The same builder + */ + @SuppressWarnings("unchecked") + public B uiOrder(float f) { + this.uiOrder = f; + return (B) this; + } + + + @SuppressWarnings("unchecked") + protected B addValidator(Predicate pred, String errorMessage) { + validators.add(PropertyValidator.fromPredicate(pred, errorMessage)); + return (B) this; + } + + + /** + * Builds the descriptor and returns it. + * + * @return The built descriptor + * + * @throws IllegalArgumentException if parameters are incorrect + */ + public abstract PropertyDescriptor build(); + + + /** + * Returns the name of the property to be built. + */ + public String getName() { + return name; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyDescriptor.java new file mode 100644 index 0000000000..96e44ca073 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyDescriptor.java @@ -0,0 +1,76 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + + +/** + * @author Clément Fournier + * @since 6.7.0 + */ +public abstract class AbstractPropertyDescriptor implements PropertyDescriptor { + + private final String name; + private final String description; + private final float uiOrder; + private final Set> validators; + private final Class type; + + + protected AbstractPropertyDescriptor(String name, + String description, + float uiOrder, + Set> validators, Class type) { + this.name = name; + this.description = description; + this.uiOrder = uiOrder; + this.validators = validators; + this.type = type; + } + + + @Override + public final String getName() { + return name; + } + + + @Override + public final String getDescription() { + return description; + } + + + @Override + public final Class getType() { + return type; + } + + + @Override + public List getErrorMessagesFor(T value) { + return validators.stream() + .map(validator -> validator.validate(value)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + } + + + @Override + public final float getUiOrder() { + return uiOrder; + } + + + @Override + public final int compareTo(PropertyDescriptor o) { + return Float.compare(getUiOrder(), o.getUiOrder()); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractSingleValuePropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractSingleValuePropertyBuilder.java new file mode 100644 index 0000000000..5d90a8fbc3 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractSingleValuePropertyBuilder.java @@ -0,0 +1,65 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.function.Function; + + +/** + * @author Clément Fournier + * @since 6.7.0 + */ +public abstract class AbstractSingleValuePropertyBuilder, T> extends AbstractPropertyBuilder { + + + private final Function parser; + private final Class type; + + private T defaultValue; + + + AbstractSingleValuePropertyBuilder(String name, Function parser, Class type) { + super(name); + this.parser = parser; + this.type = type; + } + + + @Override + public PropertyDescriptor build() { + return new SingleValuePropertyDescriptor<>( + name, + description, + uiOrder, + defaultValue, + validators, + parser, + type + ); + } + + + /** + * Specify a default value. + * + * @param val Value + * + * @return The same builder + */ + @SuppressWarnings("unchecked") + public B defaultValue(T val) { + this.defaultValue = val; + return (B) this; + } + + + /** + * Returns the name of the property to be built. + */ + @Override + public String getName() { + return name; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/MultiValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/MultiValuePropertyDescriptor.java new file mode 100644 index 0000000000..440f7ae762 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/MultiValuePropertyDescriptor.java @@ -0,0 +1,67 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + + +/** + * @author Clément Fournier + * @since 6.7.0 + */ +final class MultiValuePropertyDescriptor extends AbstractPropertyDescriptor> { + + + private final List defaultValue; + private final Set> componentValidators; + private final Function parser; + + + MultiValuePropertyDescriptor(String name, String description, float uiOrder, + List defaultValue, + Set>> listValidators, + Set> componentValidators, + Function parser, + Class type) { + super(name, description, uiOrder, listValidators, type); + this.defaultValue = defaultValue; + this.componentValidators = componentValidators; + this.parser = parser; + } + + + @Override + public boolean isMultiValue() { + return true; + } + + + @Override + public List getDefaultValue() { + return defaultValue; + } + + + @Override + public List valueFrom(List propertyString) throws IllegalArgumentException { + return propertyString.stream().map(parser).collect(Collectors.toList()); + } + + + @Override + public List getErrorMessagesFor(List value) { + List listErrorMessages = super.getErrorMessagesFor(value); + return listErrorMessages.isEmpty() ? listErrorMessages + : componentValidators.stream() + .flatMap(validator -> value.stream().map(validator::validate)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyDescriptor.java new file mode 100644 index 0000000000..4af7654f1f --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyDescriptor.java @@ -0,0 +1,116 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.List; + +import net.sourceforge.pmd.properties.EnumeratedPropertyDescriptor; +import net.sourceforge.pmd.properties.MultiValuePropertyDescriptor; +import net.sourceforge.pmd.properties.NumericPropertyDescriptor; +import net.sourceforge.pmd.properties.SingleValuePropertyDescriptor; + + +/** + * Property value descriptor that defines the use & requirements for setting property values for use within PMD and + * any associated GUIs. While concrete descriptor instances are static and immutable they provide validation, + * serialization, and default values for any specific datatypes. + * + *

This interface is primarily specialized according to whether the property is multi-valued or single-valued, see + * {@link SingleValuePropertyDescriptor} and {@link MultiValuePropertyDescriptor}. + * + *

Several interfaces further specialize the behaviour of descriptors to accommodate specific types of descriptors, + * see {@link NumericPropertyDescriptor} and {@link EnumeratedPropertyDescriptor}. + * + * @param type of the property's value. This is a list type for multi-valued properties. + * + * @author Brian Remedios + * @author Clément Fournier + * @version Refactored June 2017 (6.0.0) + */ +public interface PropertyDescriptor extends Comparable> { + + /** + * The name of the property without spaces as it serves as the key into the property map. + * + * @return String + */ + String getName(); + + + /** + * Describes the property and the role it plays within the rule it is specified for. Could be used in a tooltip. + * + * @return String + */ + String getDescription(); + + + /** + * Returns whether the property is multi-valued, i.e. an array of strings, + * + *

As unary property rule properties will return a value of one, you must use the get/setProperty accessors when + * working with the actual values. When working with multi-value properties then the get/setProperties accessors + * must be used.

+ * + * @return boolean + */ + boolean isMultiValue(); + + + /** + * Default value to use when the user hasn't specified one or when they wish to revert to a known-good state. + * + * @return Object + */ + T getDefaultValue(); + + + /** + * Denotes the value datatype. For multi-value properties, this is not the List class but the + * list's component class. + * + * @return Class literal of the value type + */ + Class getType(); + + /** + * Validation function that returns a diagnostic error message for a sample property value. Returns null if the + * value is acceptable. + * + * @param value The value to check. + * + * @return A diagnostic message. + */ + List getErrorMessagesFor(T value); + + + /** + * Denotes the relative order the property field should occupy if we are using an auto-generated UI to display and + * edit property values. If the value returned has a non-zero fractional part then this is can be used to place + * adjacent fields on the same row. + * + *

Example:
name -> 0.0 description 1.0 minValue -> 2.0 maxValue -> 2.1

..would have their + * fields placed like:
+ * + * {@code name: [ ] description: [ ] minimum: [ ] maximum: [ ]} + * + * @return float + */ + float getUiOrder(); + + + /** + * Returns the value represented by this string. + * + * @param propertyString The string to parse + * + * @return The value represented by the string + * + * @throws IllegalArgumentException if the given string cannot be parsed + */ + T valueFrom(List propertyString) throws IllegalArgumentException; + + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java new file mode 100644 index 0000000000..0f41476d16 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java @@ -0,0 +1,59 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.function.Function; + +import org.apache.commons.lang3.EnumUtils; + + +/** + * @author Clément Fournier + * @since 6.7.0 + */ +public final class PropertyFactory { + + private PropertyFactory() { + + } + + + public static NumericPropertyBuilder intProperty(String name) { + return new NumericPropertyBuilder<>(name, Integer::valueOf, Integer.class); + } + + // TODO need a way to document the possible values + public static > GenericPBuilder enumProperty(String name, Class enumClass) { + return new GenericPBuilder<>(name, s -> + EnumUtils.getEnumList(enumClass).stream() + .filter(e -> e.name().equalsIgnoreCase(s)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("The name '" + s + "' doesn't correspond to any constant in the enum '" + enumClass.getName() + "'")) + , enumClass); + } + + + // removes the other type parameter + public static class GenericPBuilder extends AbstractSingleValuePropertyBuilder, T> { + + GenericPBuilder(String name, Function parser, Class type) { + super(name, parser, type); + } + } + + public static class NumericPropertyBuilder extends AbstractSingleValuePropertyBuilder, N> { + + NumericPropertyBuilder(String name, Function parser, Class type) { + super(name, parser, type); + } + + + public NumericPropertyBuilder requirePositive() { + return addValidator(n -> n.intValue() > 0, "Expected a positive number"); + } + } + + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java new file mode 100644 index 0000000000..f97bb3d8fb --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java @@ -0,0 +1,26 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.Optional; +import java.util.function.Predicate; + + +/** + * @author Clément Fournier + * @since 6.7.0 + */ +@FunctionalInterface +public interface PropertyValidator { + + Optional validate(T value); + + + static PropertyValidator fromPredicate(Predicate pred, String failureMessage) { + return u -> pred.test(u) ? Optional.empty() : Optional.of(failureMessage); + } + + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/SingleValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/SingleValuePropertyDescriptor.java new file mode 100644 index 0000000000..12eebe7acd --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/SingleValuePropertyDescriptor.java @@ -0,0 +1,54 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.List; +import java.util.Set; +import java.util.function.Function; + + +/** + * @author Clément Fournier + * @since 6.7.0 + */ +final class SingleValuePropertyDescriptor extends AbstractPropertyDescriptor { + + + private final T defaultValue; + private final Function parser; + + + SingleValuePropertyDescriptor(String name, String description, float uiOrder, + T defaultValue, + Set> validators, + Function parser, + Class type) { + super(name, description, uiOrder, validators, type); + this.defaultValue = defaultValue; + this.parser = parser; + } + + + @Override + public boolean isMultiValue() { + return false; + } + + + @Override + public T getDefaultValue() { + return defaultValue; + } + + + @Override + public T valueFrom(List valuesList) throws IllegalArgumentException { + if (valuesList.size() != 1) { + throw new IllegalArgumentException("This property can only handle a single value, but " + valuesList.size() + " was supplied"); + } + + return parser.apply(valuesList.get(0)); + } +} From b9a15b405a73e2501501dfa4d92e9878f73c66a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 29 Oct 2018 22:49:37 +0100 Subject: [PATCH 021/139] Move towards java7 compat --- .../rule/design/CyclomaticComplexityRule.java | 6 +- ...=> AbstractGenericPropertyDescriptor.java} | 20 +- .../AbstractMultiValuePropertyBuilder.java | 76 -------- .../newframework/AbstractPropertyBuilder.java | 176 +++++++++++++++++- .../AbstractSingleValuePropertyBuilder.java | 65 ------- ... GenericMultiValuePropertyDescriptor.java} | 21 +-- .../GenericPropertyDescriptor.java | 49 +++++ .../newframework/PropertyFactory.java | 35 ++-- .../newframework/PropertyValidator.java | 30 ++- .../SingleValuePropertyDescriptor.java | 54 ------ .../properties/newframework/Validators.java | 70 +++++++ 11 files changed, 361 insertions(+), 241 deletions(-) rename pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/{AbstractPropertyDescriptor.java => AbstractGenericPropertyDescriptor.java} (70%) delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractMultiValuePropertyBuilder.java delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractSingleValuePropertyBuilder.java rename pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/{MultiValuePropertyDescriptor.java => GenericMultiValuePropertyDescriptor.java} (68%) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericPropertyDescriptor.java delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/SingleValuePropertyDescriptor.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/Validators.java diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java index 08b6c567c5..e8d6b6a450 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java @@ -16,6 +16,8 @@ import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; import net.sourceforge.pmd.lang.metrics.ResultOption; import net.sourceforge.pmd.properties.IntegerProperty; +import net.sourceforge.pmd.properties.newframework.PropertyDescriptor; +import net.sourceforge.pmd.properties.newframework.PropertyFactory; /** @@ -25,8 +27,8 @@ import net.sourceforge.pmd.properties.IntegerProperty; */ public class CyclomaticComplexityRule extends AbstractApexRule { - private static final IntegerProperty CLASS_LEVEL_DESCRIPTOR - = IntegerProperty.named("classReportLevel") + private static final PropertyDescriptor CLASS_LEVEL_DESCRIPTOR + = PropertyFactory.intProperty("classReportLevel") .desc("Total class complexity reporting threshold") .range(1, 200) .defaultValue(40) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractGenericPropertyDescriptor.java similarity index 70% rename from pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyDescriptor.java rename to pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractGenericPropertyDescriptor.java index 96e44ca073..947ad61145 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractGenericPropertyDescriptor.java @@ -14,8 +14,9 @@ import java.util.stream.Collectors; * @author Clément Fournier * @since 6.7.0 */ -public abstract class AbstractPropertyDescriptor implements PropertyDescriptor { +abstract class AbstractGenericPropertyDescriptor implements PropertyDescriptor { + protected final T defaultValue; private final String name; private final String description; private final float uiOrder; @@ -23,13 +24,16 @@ public abstract class AbstractPropertyDescriptor implements PropertyDescripto private final Class type; - protected AbstractPropertyDescriptor(String name, - String description, - float uiOrder, - Set> validators, Class type) { + protected AbstractGenericPropertyDescriptor(String name, + String description, + float uiOrder, + T defaultValue, + Set> validators, + Class type) { this.name = name; this.description = description; this.uiOrder = uiOrder; + this.defaultValue = defaultValue; this.validators = validators; this.type = type; } @@ -53,6 +57,12 @@ public abstract class AbstractPropertyDescriptor implements PropertyDescripto } + @Override + public T getDefaultValue() { + return defaultValue; + } + + @Override public List getErrorMessagesFor(T value) { return validators.stream() diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractMultiValuePropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractMultiValuePropertyBuilder.java deleted file mode 100644 index e94f87b448..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractMultiValuePropertyBuilder.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.newframework; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Function; - - -/** - * @author Clément Fournier - * @since 6.7.0 - */ -public abstract class AbstractMultiValuePropertyBuilder>, V> extends AbstractPropertyBuilder> { - private final Set> componentValidators = new LinkedHashSet<>(); - private final Function parser; - private final Class type; - - private List defaultValues; - - - AbstractMultiValuePropertyBuilder(String name, Function parser, Class type) { - super(name); - this.parser = parser; - this.type = type; - } - - - /** - * Specify a default value. - * - * @param val List of values - * - * @return The same builder - */ - @SuppressWarnings("unchecked") - public B defaultValues(Collection val) { - this.defaultValues = new ArrayList<>(val); - return (B) this; - } - - - /** - * Specify default values. - * - * @param val List of values - * - * @return The same builder - */ - @SuppressWarnings("unchecked") - public B defaultValues(V... val) { - this.defaultValues = Arrays.asList(val); - return (B) this; - } - - - @Override - public PropertyDescriptor> build() { - return new MultiValuePropertyDescriptor<>( - name, - description, - uiOrder, - defaultValues, - validators, - componentValidators, - parser, - type - ); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java index e31bdb73e3..4010bfaeec 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java @@ -4,27 +4,40 @@ package net.sourceforge.pmd.properties.newframework; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; -import java.util.function.Predicate; +import java.util.function.Function; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; +import net.sourceforge.pmd.properties.ValueParser; + /** + * Base class for generic property builders. + * + * @param Concrete type of this builder instance + * @param Type of values the property handles + * * @author Clément Fournier * @since 6.7.0 */ public abstract class AbstractPropertyBuilder, T> { private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z][\\w-]*"); - protected final Set> validators = new LinkedHashSet<>(); - protected String name; - protected String description; - protected float uiOrder = 0f; + private final Set> validators = new LinkedHashSet<>(); + private String name; + private String description; + private float uiOrder = 0f; + private T defaultValue; - public AbstractPropertyBuilder(String name) { + AbstractPropertyBuilder(String name) { + if (StringUtils.isBlank(name)) { throw new IllegalArgumentException("Name must be provided"); } else if (!NAME_PATTERN.matcher(name).matches()) { @@ -34,6 +47,26 @@ public abstract class AbstractPropertyBuilder> getValidators() { + return validators; + } + + + String getDescription() { + return description; + } + + + float getUiOrder() { + return uiOrder; + } + + + T getDefaultValue() { + return defaultValue; + } + + /** * Specify the description of the property. * @@ -66,8 +99,22 @@ public abstract class AbstractPropertyBuilder pred, String errorMessage) { - validators.add(PropertyValidator.fromPredicate(pred, errorMessage)); + B addValidator(PropertyValidator validator) { + validators.add(validator); + return (B) this; + } + + + /** + * Specify a default value. + * + * @param val Value + * + * @return The same builder + */ + @SuppressWarnings("unchecked") + public B defaultValue(T val) { + this.defaultValue = val; return (B) this; } @@ -88,4 +135,117 @@ public abstract class AbstractPropertyBuilderThis class is abstract because the B type parameter + * prevents it to be instantiated anyway. That type parameter + * is of use to more refined concrete subclasses. + * + * @param Concrete type of this builder instance + * @param Type of values the property handles + * + * @author Clément Fournier + * @since 6.7.0 + */ + public abstract static class GenericPropertyBuilder, T> extends AbstractPropertyBuilder { + + + private final ValueParser parser; + private final Class type; + + + GenericPropertyBuilder(String name, ValueParser parser, Class type) { + super(name); + this.parser = parser; + this.type = type; + } + + + @Override + public PropertyDescriptor build() { + return new GenericPropertyDescriptor<>( + getName(), + getDescription(), + getUiOrder(), + getDefaultValue(), + getValidators(), + parser, + type + ); + } + + + } + + /** + * Builder for a generic multi-value property. + * + *

This class is abstract because the B type parameter + * prevents it to be instantiated anyway. That type parameter + * is of use to more refined concrete subclasses. + * + * @param Concrete type of this builder instance + * @param Type of values the property handles. This is the component type of the list + * + * @author Clément Fournier + * @since 6.7.0 + */ + public abstract static class AbstractGenericMultiPropertyBuilder>, V> extends AbstractPropertyBuilder> { + private final Set> componentValidators = new LinkedHashSet<>(); + private final Function parser; + private final Class type; + + + AbstractGenericMultiPropertyBuilder(String name, Function parser, Class type) { + super(name); + this.parser = parser; + this.type = type; + } + + + /** + * Specify a default value. + * + * @param val List of values + * + * @return The same builder + */ + @SuppressWarnings("unchecked") + public B defaultValues(Collection val) { + super.defaultValue(new ArrayList<>(val)); + return (B) this; + } + + + /** + * Specify default values. + * + * @param val List of values + * + * @return The same builder + */ + @SuppressWarnings("unchecked") + public B defaultValues(V... val) { + super.defaultValue(Arrays.asList(val)); + return (B) this; + } + + + @Override + public PropertyDescriptor> build() { + return new GenericMultiValuePropertyDescriptor<>( + getName(), + getDescription(), + getUiOrder(), + getDefaultValue(), + getValidators(), + componentValidators, + parser, + type + ); + } + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractSingleValuePropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractSingleValuePropertyBuilder.java deleted file mode 100644 index 5d90a8fbc3..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractSingleValuePropertyBuilder.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.newframework; - -import java.util.function.Function; - - -/** - * @author Clément Fournier - * @since 6.7.0 - */ -public abstract class AbstractSingleValuePropertyBuilder, T> extends AbstractPropertyBuilder { - - - private final Function parser; - private final Class type; - - private T defaultValue; - - - AbstractSingleValuePropertyBuilder(String name, Function parser, Class type) { - super(name); - this.parser = parser; - this.type = type; - } - - - @Override - public PropertyDescriptor build() { - return new SingleValuePropertyDescriptor<>( - name, - description, - uiOrder, - defaultValue, - validators, - parser, - type - ); - } - - - /** - * Specify a default value. - * - * @param val Value - * - * @return The same builder - */ - @SuppressWarnings("unchecked") - public B defaultValue(T val) { - this.defaultValue = val; - return (B) this; - } - - - /** - * Returns the name of the property to be built. - */ - @Override - public String getName() { - return name; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/MultiValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericMultiValuePropertyDescriptor.java similarity index 68% rename from pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/MultiValuePropertyDescriptor.java rename to pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericMultiValuePropertyDescriptor.java index 440f7ae762..f90db3cdc3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/MultiValuePropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericMultiValuePropertyDescriptor.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.properties.newframework; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; @@ -15,22 +16,20 @@ import java.util.stream.Collectors; * @author Clément Fournier * @since 6.7.0 */ -final class MultiValuePropertyDescriptor extends AbstractPropertyDescriptor> { +final class GenericMultiValuePropertyDescriptor extends AbstractGenericPropertyDescriptor> { - private final List defaultValue; private final Set> componentValidators; private final Function parser; - MultiValuePropertyDescriptor(String name, String description, float uiOrder, - List defaultValue, - Set>> listValidators, - Set> componentValidators, - Function parser, - Class type) { - super(name, description, uiOrder, listValidators, type); - this.defaultValue = defaultValue; + GenericMultiValuePropertyDescriptor(String name, String description, float uiOrder, + List defaultValue, + Set>> listValidators, + Set> componentValidators, + Function parser, + Class type) { + super(name, description, uiOrder, defaultValue, listValidators, type); this.componentValidators = componentValidators; this.parser = parser; } @@ -44,7 +43,7 @@ final class MultiValuePropertyDescriptor extends AbstractPropertyDescriptor getDefaultValue() { - return defaultValue; + return Collections.unmodifiableList(defaultValue); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericPropertyDescriptor.java new file mode 100644 index 0000000000..6037ccf4ce --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericPropertyDescriptor.java @@ -0,0 +1,49 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.List; +import java.util.Set; + +import net.sourceforge.pmd.properties.ValueParser; + + +/** + * @author Clément Fournier + * @since 6.7.0 + */ +final class GenericPropertyDescriptor extends AbstractGenericPropertyDescriptor { + + + private final ValueParser parser; + + + GenericPropertyDescriptor(String name, + String description, + float uiOrder, + T defaultValue, + Set> validators, + ValueParser parser, + Class type) { + super(name, description, uiOrder, defaultValue, validators, type); + this.parser = parser; + } + + + @Override + public boolean isMultiValue() { + return false; + } + + + @Override + public T valueFrom(List valuesList) throws IllegalArgumentException { + if (valuesList.size() != 1) { + throw new IllegalArgumentException("This property can only handle a single value, but " + valuesList.size() + " was supplied"); + } + + return parser.valueOf(valuesList.get(0)); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java index 0f41476d16..85b70d5fed 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java @@ -4,10 +4,11 @@ package net.sourceforge.pmd.properties.newframework; -import java.util.function.Function; - import org.apache.commons.lang3.EnumUtils; +import net.sourceforge.pmd.properties.ValueParser; +import net.sourceforge.pmd.properties.newframework.AbstractPropertyBuilder.GenericPropertyBuilder; + /** * @author Clément Fournier @@ -20,38 +21,42 @@ public final class PropertyFactory { } + private static > T enumConstantFromEnum(Class enumClass, String name) { + return EnumUtils.getEnumList(enumClass).stream() + .filter(e -> e.name().equalsIgnoreCase(name)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("The name '" + name + "' doesn't correspond to any constant in the enum '" + enumClass.getName() + "'")); + } + + public static NumericPropertyBuilder intProperty(String name) { return new NumericPropertyBuilder<>(name, Integer::valueOf, Integer.class); } - // TODO need a way to document the possible values + public static > GenericPBuilder enumProperty(String name, Class enumClass) { - return new GenericPBuilder<>(name, s -> - EnumUtils.getEnumList(enumClass).stream() - .filter(e -> e.name().equalsIgnoreCase(s)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("The name '" + s + "' doesn't correspond to any constant in the enum '" + enumClass.getName() + "'")) - , enumClass); + return new GenericPBuilder<>(name, s -> enumConstantFromEnum(enumClass, s), enumClass); } // removes the other type parameter - public static class GenericPBuilder extends AbstractSingleValuePropertyBuilder, T> { + public static class GenericPBuilder extends GenericPropertyBuilder, T> { - GenericPBuilder(String name, Function parser, Class type) { + GenericPBuilder(String name, ValueParser parser, Class type) { super(name, parser, type); } } - public static class NumericPropertyBuilder extends AbstractSingleValuePropertyBuilder, N> { + public static class NumericPropertyBuilder extends GenericPropertyBuilder, N> { - NumericPropertyBuilder(String name, Function parser, Class type) { + NumericPropertyBuilder(String name, ValueParser parser, Class type) { super(name, parser, type); } - public NumericPropertyBuilder requirePositive() { - return addValidator(n -> n.intValue() > 0, "Expected a positive number"); + // TODO rename + public NumericPropertyBuilder range(N min, N max) { + return addValidator(Validators.rangeValidator(min, max)); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java index f97bb3d8fb..e42349b1d5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java @@ -5,22 +5,42 @@ package net.sourceforge.pmd.properties.newframework; import java.util.Optional; -import java.util.function.Predicate; /** + * Validates the value of a property. + * + * @param Type of value to handle + * * @author Clément Fournier * @since 6.7.0 */ -@FunctionalInterface public interface PropertyValidator { + /** + * Returns a diagnostic message if the value + * has a problem. Otherwise returns an empty + * optional. + * + * @param value The value to validate + * + * @return An optional diagnostic message + */ Optional validate(T value); - static PropertyValidator fromPredicate(Predicate pred, String failureMessage) { - return u -> pred.test(u) ? Optional.empty() : Optional.of(failureMessage); - } + /** + * Returns a description of the constraint + * imposed by this validator on the values. + * E.g. "The value should be positive", or + * "The value should be one of A | B | C." + * + * @return A description of the constraint + */ + String getConstraintDescription(); + + + // TODO Java 8 move PropertyFactory#fromPredicate here } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/SingleValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/SingleValuePropertyDescriptor.java deleted file mode 100644 index 12eebe7acd..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/SingleValuePropertyDescriptor.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.newframework; - -import java.util.List; -import java.util.Set; -import java.util.function.Function; - - -/** - * @author Clément Fournier - * @since 6.7.0 - */ -final class SingleValuePropertyDescriptor extends AbstractPropertyDescriptor { - - - private final T defaultValue; - private final Function parser; - - - SingleValuePropertyDescriptor(String name, String description, float uiOrder, - T defaultValue, - Set> validators, - Function parser, - Class type) { - super(name, description, uiOrder, validators, type); - this.defaultValue = defaultValue; - this.parser = parser; - } - - - @Override - public boolean isMultiValue() { - return false; - } - - - @Override - public T getDefaultValue() { - return defaultValue; - } - - - @Override - public T valueFrom(List valuesList) throws IllegalArgumentException { - if (valuesList.size() != 1) { - throw new IllegalArgumentException("This property can only handle a single value, but " + valuesList.size() + " was supplied"); - } - - return parser.apply(valuesList.get(0)); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/Validators.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/Validators.java new file mode 100644 index 0000000000..bfe5848a86 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/Validators.java @@ -0,0 +1,70 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.newframework; + +import java.util.Optional; + + +/** + * Transitional class to make up for the absence of lambdas until we move to Java 8. + * + * @author Clément Fournier + * @since 6.7.0 + */ +final class Validators { + + private Validators() { + + } + + + public static PropertyValidator rangeValidator(T min, T max) { + return fromPredicate(new Predicate() { + @Override + public boolean test(T t) { + return min.doubleValue() < t.doubleValue() && max.doubleValue() > t.doubleValue(); + } + }, + "Should be between " + min + " and " + max + ); + } + + + /** + * Builds a new validator from a predicate, + * and documentation messages. + * + * @param pred The predicate. If it returns + * false on a value, then the + * value is deemed to have a + * problem and the failureMessage + * will be transmitted. + * @param constraintDescription Description of the constraint, + * see {@link PropertyValidator#getConstraintDescription()}. + * @param Type of value to validate + * + * @return A new validator + */ + private static PropertyValidator fromPredicate(Predicate pred, String constraintDescription) { + return new PropertyValidator() { + @Override + public Optional validate(U value) { + return pred.test(value) ? Optional.empty() : Optional.of("Constraint violated on value '" + value + "' (" + constraintDescription + ")"); + } + + + @Override + public String getConstraintDescription() { + return constraintDescription; + } + }; + } + + + // Until we have Java 8 + interface Predicate { + boolean test(T t); + } +} From de176384f773996db15474f2672dcc1df850c06e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 29 Oct 2018 23:10:14 +0100 Subject: [PATCH 022/139] Try to integrate in current framework --- .../rule/design/CyclomaticComplexityRule.java | 2 +- .../AbstractPropertyBuilder.java | 23 ++-- .../GenericMultiValuePropertyDescriptor.java | 71 +++++++++++ .../properties/GenericPropertyDescriptor.java | 45 +++++++ .../{newframework => }/PropertyFactory.java | 20 ++- .../{newframework => }/PropertyValidator.java | 10 +- .../{newframework => }/Validators.java | 9 +- .../AbstractGenericPropertyDescriptor.java | 86 ------------- .../GenericMultiValuePropertyDescriptor.java | 66 ---------- .../GenericPropertyDescriptor.java | 49 -------- .../newframework/PropertyDescriptor.java | 116 ------------------ 11 files changed, 153 insertions(+), 344 deletions(-) rename pmd-core/src/main/java/net/sourceforge/pmd/properties/{newframework => }/AbstractPropertyBuilder.java (89%) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java rename pmd-core/src/main/java/net/sourceforge/pmd/properties/{newframework => }/PropertyFactory.java (68%) rename pmd-core/src/main/java/net/sourceforge/pmd/properties/{newframework => }/PropertyValidator.java (83%) rename pmd-core/src/main/java/net/sourceforge/pmd/properties/{newframework => }/Validators.java (86%) delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractGenericPropertyDescriptor.java delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericMultiValuePropertyDescriptor.java delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericPropertyDescriptor.java delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyDescriptor.java diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java index e8d6b6a450..f3fda24a87 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java @@ -17,7 +17,7 @@ import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; import net.sourceforge.pmd.lang.metrics.ResultOption; import net.sourceforge.pmd.properties.IntegerProperty; import net.sourceforge.pmd.properties.newframework.PropertyDescriptor; -import net.sourceforge.pmd.properties.newframework.PropertyFactory; +import net.sourceforge.pmd.properties.PropertyFactory; /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertyBuilder.java similarity index 89% rename from pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java rename to pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertyBuilder.java index 4010bfaeec..7ba53b4c08 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertyBuilder.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.properties.newframework; +package net.sourceforge.pmd.properties; import java.util.ArrayList; import java.util.Arrays; @@ -10,13 +10,10 @@ import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import java.util.function.Function; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; -import net.sourceforge.pmd.properties.ValueParser; - /** * Base class for generic property builders. @@ -155,12 +152,14 @@ public abstract class AbstractPropertyBuilder parser; private final Class type; + private final boolean isDefinedExternally; - GenericPropertyBuilder(String name, ValueParser parser, Class type) { + GenericPropertyBuilder(String name, ValueParser parser, Class type, boolean isDefinedExternally) { super(name); this.parser = parser; this.type = type; + this.isDefinedExternally = isDefinedExternally; } @@ -173,7 +172,8 @@ public abstract class AbstractPropertyBuilder>, V> extends AbstractPropertyBuilder> { private final Set> componentValidators = new LinkedHashSet<>(); - private final Function parser; + private final ValueParser parser; private final Class type; + private final boolean isDefinedExternally; - AbstractGenericMultiPropertyBuilder(String name, Function parser, Class type) { + AbstractGenericMultiPropertyBuilder(String name, ValueParser parser, Class type, boolean isDefinedExternally) { super(name); this.parser = parser; this.type = type; + this.isDefinedExternally = isDefinedExternally; } @@ -236,7 +238,7 @@ public abstract class AbstractPropertyBuilder> build() { - return new GenericMultiValuePropertyDescriptor<>( + return new GenericMultiValuePropertyDescriptor( getName(), getDescription(), getUiOrder(), @@ -244,7 +246,8 @@ public abstract class AbstractPropertyBuilder extends AbstractMultiValueProperty { + + + private final Set>> listValidators; + private final Set> componentValidators; + private final ValueParser parser; + private final Class type; + + + GenericMultiValuePropertyDescriptor(String name, String description, float uiOrder, + List defaultValue, + Set>> listValidators, + Set> componentValidators, + ValueParser parser, + Class type, + boolean isDefinedExternally) { + + super(name, description, defaultValue, uiOrder, isDefinedExternally); + this.listValidators = listValidators; + this.componentValidators = componentValidators; + this.parser = parser; + this.type = type; + } + + + @Override + public String errorFor(List values) { + for (PropertyValidator> lv : listValidators) { + String error = lv.validate(values); + if (error != null) { + return error; + } + } + + for (PropertyValidator cv : componentValidators) { + for (V v : values) { + String error = cv.validate(v); + if (error != null) { + return error; + } + } + } + return null; + } + + + @Override + protected V createFrom(String toParse) { + return parser.valueOf(toParse); + } + + + @Override + public Class type() { + return type; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java new file mode 100644 index 0000000000..5cebefab5e --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java @@ -0,0 +1,45 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties; + +import java.util.Set; + + +/** + * @author Clément Fournier + * @since 6.7.0 + */ +final class GenericPropertyDescriptor extends AbstractSingleValueProperty { + + + private final ValueParser parser; + private final Class type; + + + GenericPropertyDescriptor(String name, + String description, + float uiOrder, + T defaultValue, + Set> validators, + ValueParser parser, + Class type, + boolean isDefinedExternally) { + super(name, description, defaultValue, uiOrder, isDefinedExternally); + this.parser = parser; + this.type = type; + } + + + @Override + protected T createFrom(String toParse) { + return parser.valueOf(toParse); + } + + + @Override + public Class type() { + return type; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java similarity index 68% rename from pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java rename to pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java index 85b70d5fed..ef758f4dda 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java @@ -2,12 +2,13 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.properties.newframework; +package net.sourceforge.pmd.properties; + +import java.util.function.Function; import org.apache.commons.lang3.EnumUtils; -import net.sourceforge.pmd.properties.ValueParser; -import net.sourceforge.pmd.properties.newframework.AbstractPropertyBuilder.GenericPropertyBuilder; +import net.sourceforge.pmd.properties.AbstractPropertyBuilder.GenericPropertyBuilder; /** @@ -30,7 +31,12 @@ public final class PropertyFactory { public static NumericPropertyBuilder intProperty(String name) { - return new NumericPropertyBuilder<>(name, Integer::valueOf, Integer.class); + return new NumericPropertyBuilder<>(name, ValueParserConstants.INTEGER_PARSER, Integer.class); + } + + + public static NumericPropertyBuilder doubleProperty(String name) { + return new NumericPropertyBuilder<>(name, ValueParserConstants.DOUBLE_PARSER, Double.class); } @@ -47,6 +53,7 @@ public final class PropertyFactory { } } + public static class NumericPropertyBuilder extends GenericPropertyBuilder, N> { NumericPropertyBuilder(String name, ValueParser parser, Class type) { @@ -60,5 +67,10 @@ public final class PropertyFactory { } } + public static class MultiNumericPropertyBuilder extends AbstractPropertyBuilder.AbstractGenericMultiPropertyBuilder, N> { + MultiNumericPropertyBuilder(String name, Function parser, Class type) { + super(name, parser, type); + } + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyValidator.java similarity index 83% rename from pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java rename to pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyValidator.java index e42349b1d5..5a18e562a4 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyValidator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyValidator.java @@ -2,10 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.properties.newframework; - -import java.util.Optional; - +package net.sourceforge.pmd.properties; /** * Validates the value of a property. @@ -15,7 +12,7 @@ import java.util.Optional; * @author Clément Fournier * @since 6.7.0 */ -public interface PropertyValidator { +interface PropertyValidator { /** * Returns a diagnostic message if the value @@ -26,7 +23,8 @@ public interface PropertyValidator { * * @return An optional diagnostic message */ - Optional validate(T value); + // TODO Java 8 use Optional + String validate(T value); /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/Validators.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java similarity index 86% rename from pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/Validators.java rename to pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java index bfe5848a86..4fdfeccbdb 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/Validators.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java @@ -2,10 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.properties.newframework; - -import java.util.Optional; - +package net.sourceforge.pmd.properties; /** * Transitional class to make up for the absence of lambdas until we move to Java 8. @@ -50,8 +47,8 @@ final class Validators { private static PropertyValidator fromPredicate(Predicate pred, String constraintDescription) { return new PropertyValidator() { @Override - public Optional validate(U value) { - return pred.test(value) ? Optional.empty() : Optional.of("Constraint violated on value '" + value + "' (" + constraintDescription + ")"); + public String validate(U value) { + return pred.test(value) ? null : "Constraint violated on value '" + value + "' (" + constraintDescription + ")"; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractGenericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractGenericPropertyDescriptor.java deleted file mode 100644 index 947ad61145..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/AbstractGenericPropertyDescriptor.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.newframework; - -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - - -/** - * @author Clément Fournier - * @since 6.7.0 - */ -abstract class AbstractGenericPropertyDescriptor implements PropertyDescriptor { - - protected final T defaultValue; - private final String name; - private final String description; - private final float uiOrder; - private final Set> validators; - private final Class type; - - - protected AbstractGenericPropertyDescriptor(String name, - String description, - float uiOrder, - T defaultValue, - Set> validators, - Class type) { - this.name = name; - this.description = description; - this.uiOrder = uiOrder; - this.defaultValue = defaultValue; - this.validators = validators; - this.type = type; - } - - - @Override - public final String getName() { - return name; - } - - - @Override - public final String getDescription() { - return description; - } - - - @Override - public final Class getType() { - return type; - } - - - @Override - public T getDefaultValue() { - return defaultValue; - } - - - @Override - public List getErrorMessagesFor(T value) { - return validators.stream() - .map(validator -> validator.validate(value)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toList()); - } - - - @Override - public final float getUiOrder() { - return uiOrder; - } - - - @Override - public final int compareTo(PropertyDescriptor o) { - return Float.compare(getUiOrder(), o.getUiOrder()); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericMultiValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericMultiValuePropertyDescriptor.java deleted file mode 100644 index f90db3cdc3..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericMultiValuePropertyDescriptor.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.newframework; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - - -/** - * @author Clément Fournier - * @since 6.7.0 - */ -final class GenericMultiValuePropertyDescriptor extends AbstractGenericPropertyDescriptor> { - - - private final Set> componentValidators; - private final Function parser; - - - GenericMultiValuePropertyDescriptor(String name, String description, float uiOrder, - List defaultValue, - Set>> listValidators, - Set> componentValidators, - Function parser, - Class type) { - super(name, description, uiOrder, defaultValue, listValidators, type); - this.componentValidators = componentValidators; - this.parser = parser; - } - - - @Override - public boolean isMultiValue() { - return true; - } - - - @Override - public List getDefaultValue() { - return Collections.unmodifiableList(defaultValue); - } - - - @Override - public List valueFrom(List propertyString) throws IllegalArgumentException { - return propertyString.stream().map(parser).collect(Collectors.toList()); - } - - - @Override - public List getErrorMessagesFor(List value) { - List listErrorMessages = super.getErrorMessagesFor(value); - return listErrorMessages.isEmpty() ? listErrorMessages - : componentValidators.stream() - .flatMap(validator -> value.stream().map(validator::validate)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(Collectors.toList()); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericPropertyDescriptor.java deleted file mode 100644 index 6037ccf4ce..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/GenericPropertyDescriptor.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.newframework; - -import java.util.List; -import java.util.Set; - -import net.sourceforge.pmd.properties.ValueParser; - - -/** - * @author Clément Fournier - * @since 6.7.0 - */ -final class GenericPropertyDescriptor extends AbstractGenericPropertyDescriptor { - - - private final ValueParser parser; - - - GenericPropertyDescriptor(String name, - String description, - float uiOrder, - T defaultValue, - Set> validators, - ValueParser parser, - Class type) { - super(name, description, uiOrder, defaultValue, validators, type); - this.parser = parser; - } - - - @Override - public boolean isMultiValue() { - return false; - } - - - @Override - public T valueFrom(List valuesList) throws IllegalArgumentException { - if (valuesList.size() != 1) { - throw new IllegalArgumentException("This property can only handle a single value, but " + valuesList.size() + " was supplied"); - } - - return parser.valueOf(valuesList.get(0)); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyDescriptor.java deleted file mode 100644 index 4af7654f1f..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/newframework/PropertyDescriptor.java +++ /dev/null @@ -1,116 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.newframework; - -import java.util.List; - -import net.sourceforge.pmd.properties.EnumeratedPropertyDescriptor; -import net.sourceforge.pmd.properties.MultiValuePropertyDescriptor; -import net.sourceforge.pmd.properties.NumericPropertyDescriptor; -import net.sourceforge.pmd.properties.SingleValuePropertyDescriptor; - - -/** - * Property value descriptor that defines the use & requirements for setting property values for use within PMD and - * any associated GUIs. While concrete descriptor instances are static and immutable they provide validation, - * serialization, and default values for any specific datatypes. - * - *

This interface is primarily specialized according to whether the property is multi-valued or single-valued, see - * {@link SingleValuePropertyDescriptor} and {@link MultiValuePropertyDescriptor}. - * - *

Several interfaces further specialize the behaviour of descriptors to accommodate specific types of descriptors, - * see {@link NumericPropertyDescriptor} and {@link EnumeratedPropertyDescriptor}. - * - * @param type of the property's value. This is a list type for multi-valued properties. - * - * @author Brian Remedios - * @author Clément Fournier - * @version Refactored June 2017 (6.0.0) - */ -public interface PropertyDescriptor extends Comparable> { - - /** - * The name of the property without spaces as it serves as the key into the property map. - * - * @return String - */ - String getName(); - - - /** - * Describes the property and the role it plays within the rule it is specified for. Could be used in a tooltip. - * - * @return String - */ - String getDescription(); - - - /** - * Returns whether the property is multi-valued, i.e. an array of strings, - * - *

As unary property rule properties will return a value of one, you must use the get/setProperty accessors when - * working with the actual values. When working with multi-value properties then the get/setProperties accessors - * must be used.

- * - * @return boolean - */ - boolean isMultiValue(); - - - /** - * Default value to use when the user hasn't specified one or when they wish to revert to a known-good state. - * - * @return Object - */ - T getDefaultValue(); - - - /** - * Denotes the value datatype. For multi-value properties, this is not the List class but the - * list's component class. - * - * @return Class literal of the value type - */ - Class getType(); - - /** - * Validation function that returns a diagnostic error message for a sample property value. Returns null if the - * value is acceptable. - * - * @param value The value to check. - * - * @return A diagnostic message. - */ - List getErrorMessagesFor(T value); - - - /** - * Denotes the relative order the property field should occupy if we are using an auto-generated UI to display and - * edit property values. If the value returned has a non-zero fractional part then this is can be used to place - * adjacent fields on the same row. - * - *

Example:
name -> 0.0 description 1.0 minValue -> 2.0 maxValue -> 2.1

..would have their - * fields placed like:
- * - * {@code name: [ ] description: [ ] minimum: [ ] maximum: [ ]} - * - * @return float - */ - float getUiOrder(); - - - /** - * Returns the value represented by this string. - * - * @param propertyString The string to parse - * - * @return The value represented by the string - * - * @throws IllegalArgumentException if the given string cannot be parsed - */ - T valueFrom(List propertyString) throws IllegalArgumentException; - - -} From 993d80d2df9ea1ad6b6f65da47b32ccd0c1c489d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 29 Oct 2018 23:53:17 +0100 Subject: [PATCH 023/139] Fix compilation --- .../rule/design/CyclomaticComplexityRule.java | 2 +- .../properties/AbstractPropertyBuilder.java | 14 ++++--------- .../GenericMultiValuePropertyDescriptor.java | 5 ++--- .../properties/GenericPropertyDescriptor.java | 5 ++--- .../pmd/properties/PropertyFactory.java | 20 +++++++++---------- .../pmd/properties/Validators.java | 4 ++-- .../net/sourceforge/pmd/TestRuleset1.xml | 2 +- 7 files changed, 22 insertions(+), 30 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java index f3fda24a87..fef4a5d0c2 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java @@ -16,7 +16,7 @@ import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; import net.sourceforge.pmd.lang.metrics.ResultOption; import net.sourceforge.pmd.properties.IntegerProperty; -import net.sourceforge.pmd.properties.newframework.PropertyDescriptor; +import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertyBuilder.java index 7ba53b4c08..ba95e5a6b5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertyBuilder.java @@ -152,14 +152,12 @@ public abstract class AbstractPropertyBuilder parser; private final Class type; - private final boolean isDefinedExternally; - GenericPropertyBuilder(String name, ValueParser parser, Class type, boolean isDefinedExternally) { + GenericPropertyBuilder(String name, ValueParser parser, Class type) { super(name); this.parser = parser; this.type = type; - this.isDefinedExternally = isDefinedExternally; } @@ -172,8 +170,7 @@ public abstract class AbstractPropertyBuilder> componentValidators = new LinkedHashSet<>(); private final ValueParser parser; private final Class type; - private final boolean isDefinedExternally; - AbstractGenericMultiPropertyBuilder(String name, ValueParser parser, Class type, boolean isDefinedExternally) { + AbstractGenericMultiPropertyBuilder(String name, ValueParser parser, Class type) { super(name); this.parser = parser; this.type = type; - this.isDefinedExternally = isDefinedExternally; } @@ -246,8 +241,7 @@ public abstract class AbstractPropertyBuilder extends AbstractMultiValuePro Set>> listValidators, Set> componentValidators, ValueParser parser, - Class type, - boolean isDefinedExternally) { + Class type) { - super(name, description, defaultValue, uiOrder, isDefinedExternally); + super(name, description, defaultValue, uiOrder, false); this.listValidators = listValidators; this.componentValidators = componentValidators; this.parser = parser; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java index 5cebefab5e..4bd5a18225 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java @@ -24,9 +24,8 @@ final class GenericPropertyDescriptor extends AbstractSingleValueProperty T defaultValue, Set> validators, ValueParser parser, - Class type, - boolean isDefinedExternally) { - super(name, description, defaultValue, uiOrder, isDefinedExternally); + Class type) { + super(name, description, defaultValue, uiOrder, false); this.parser = parser; this.type = type; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java index ef758f4dda..268a8ed2e3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java @@ -22,12 +22,12 @@ public final class PropertyFactory { } - private static > T enumConstantFromEnum(Class enumClass, String name) { - return EnumUtils.getEnumList(enumClass).stream() - .filter(e -> e.name().equalsIgnoreCase(name)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("The name '" + name + "' doesn't correspond to any constant in the enum '" + enumClass.getName() + "'")); - } +// private static > T enumConstantFromEnum(Class enumClass, String name) { +// return EnumUtils.getEnumList(enumClass).stream() +// .filter(e -> e.name().equalsIgnoreCase(name)) +// .findFirst() +// .orElseThrow(() -> new IllegalArgumentException("The name '" + name + "' doesn't correspond to any constant in the enum '" + enumClass.getName() + "'")); +// } public static NumericPropertyBuilder intProperty(String name) { @@ -40,9 +40,9 @@ public final class PropertyFactory { } - public static > GenericPBuilder enumProperty(String name, Class enumClass) { - return new GenericPBuilder<>(name, s -> enumConstantFromEnum(enumClass, s), enumClass); - } +// public static > GenericPBuilder enumProperty(String name, Class enumClass) { +// return new GenericPBuilder<>(name, s -> enumConstantFromEnum(enumClass, s), enumClass); +// } // removes the other type parameter @@ -68,7 +68,7 @@ public final class PropertyFactory { } public static class MultiNumericPropertyBuilder extends AbstractPropertyBuilder.AbstractGenericMultiPropertyBuilder, N> { - MultiNumericPropertyBuilder(String name, Function parser, Class type) { + MultiNumericPropertyBuilder(String name, ValueParser parser, Class type) { super(name, parser, type); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java index 4fdfeccbdb..158ab7a652 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java @@ -17,7 +17,7 @@ final class Validators { } - public static PropertyValidator rangeValidator(T min, T max) { + public static PropertyValidator rangeValidator(final T min, final T max) { return fromPredicate(new Predicate() { @Override public boolean test(T t) { @@ -44,7 +44,7 @@ final class Validators { * * @return A new validator */ - private static PropertyValidator fromPredicate(Predicate pred, String constraintDescription) { + private static PropertyValidator fromPredicate(final Predicate pred, final String constraintDescription) { return new PropertyValidator() { @Override public String validate(U value) { diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/TestRuleset1.xml b/pmd-core/src/test/resources/net/sourceforge/pmd/TestRuleset1.xml index aaee1b98f0..628f1b0761 100644 --- a/pmd-core/src/test/resources/net/sourceforge/pmd/TestRuleset1.xml +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/TestRuleset1.xml @@ -33,7 +33,7 @@ Just for test Just for test From c4bf37325516d3cf7dc7eba62073ba36fc424be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 1 Nov 2018 00:23:13 +0100 Subject: [PATCH 024/139] WIP --- .../GenericMultiValuePropertyDescriptor.java | 23 ++-- .../properties/GenericPropertyDescriptor.java | 27 +++- ...pertyBuilder.java => PropertyBuilder.java} | 117 +++++++++++++++--- .../pmd/properties/PropertyFactory.java | 82 ++++++------ .../pmd/properties/Validators.java | 67 ---------- .../pmd/properties/ValueParserConstants.java | 16 ++- .../validators/NumericValidators.java | 37 ++++++ .../{ => validators}/PropertyValidator.java | 21 +++- .../validators/ValidatorFactory.java | 88 +++++++++++++ 9 files changed, 332 insertions(+), 146 deletions(-) rename pmd-core/src/main/java/net/sourceforge/pmd/properties/{AbstractPropertyBuilder.java => PropertyBuilder.java} (62%) delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/NumericValidators.java rename pmd-core/src/main/java/net/sourceforge/pmd/properties/{ => validators}/PropertyValidator.java (64%) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/ValidatorFactory.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java index 672e195f52..403a70da42 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java @@ -7,6 +7,8 @@ package net.sourceforge.pmd.properties; import java.util.List; import java.util.Set; +import net.sourceforge.pmd.properties.validators.PropertyValidator; + /** * @author Clément Fournier @@ -15,22 +17,20 @@ import java.util.Set; final class GenericMultiValuePropertyDescriptor extends AbstractMultiValueProperty { - private final Set>> listValidators; - private final Set> componentValidators; + private final Set>> listValidators; private final ValueParser parser; private final Class type; GenericMultiValuePropertyDescriptor(String name, String description, float uiOrder, List defaultValue, - Set>> listValidators, - Set> componentValidators, + Set>> listValidators, ValueParser parser, + char delim, Class type) { - super(name, description, defaultValue, uiOrder, false); + super(name, description, defaultValue, uiOrder, delim, false); this.listValidators = listValidators; - this.componentValidators = componentValidators; this.parser = parser; this.type = type; } @@ -38,21 +38,12 @@ final class GenericMultiValuePropertyDescriptor extends AbstractMultiValuePro @Override public String errorFor(List values) { - for (PropertyValidator> lv : listValidators) { + for (PropertyValidator> lv : listValidators) { String error = lv.validate(values); if (error != null) { return error; } } - - for (PropertyValidator cv : componentValidators) { - for (V v : values) { - String error = cv.validate(v); - if (error != null) { - return error; - } - } - } return null; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java index 4bd5a18225..c963c4e56c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java @@ -6,6 +6,8 @@ package net.sourceforge.pmd.properties; import java.util.Set; +import net.sourceforge.pmd.properties.validators.PropertyValidator; + /** * @author Clément Fournier @@ -16,24 +18,35 @@ final class GenericPropertyDescriptor extends AbstractSingleValueProperty private final ValueParser parser; private final Class type; + private final Set> validators; GenericPropertyDescriptor(String name, String description, float uiOrder, T defaultValue, - Set> validators, + Set> validators, ValueParser parser, + boolean isDefinedExternally, Class type) { - super(name, description, defaultValue, uiOrder, false); + + super(name, description, defaultValue, uiOrder, isDefinedExternally); + this.validators = validators; this.parser = parser; this.type = type; } @Override - protected T createFrom(String toParse) { - return parser.valueOf(toParse); + public String errorFor(T value) { + for (PropertyValidator validator : validators) { + String error = validator.validate(value); + if (error != null) { + return error; + } + + } + return null; } @@ -41,4 +54,10 @@ final class GenericPropertyDescriptor extends AbstractSingleValueProperty public Class type() { return type; } + + + @Override + protected T createFrom(String toParse) { + return parser.valueOf(toParse); + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java similarity index 62% rename from pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertyBuilder.java rename to pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java index ba95e5a6b5..2281a4fa5f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java @@ -14,6 +14,10 @@ import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; +import net.sourceforge.pmd.annotation.Experimental; +import net.sourceforge.pmd.properties.PropertyFactory.GenericMultiPBuilder; +import net.sourceforge.pmd.properties.validators.PropertyValidator; + /** * Base class for generic property builders. @@ -24,16 +28,18 @@ import org.apache.commons.lang3.StringUtils; * @author Clément Fournier * @since 6.7.0 */ -public abstract class AbstractPropertyBuilder, T> { +@Experimental +public abstract class PropertyBuilder, T> { private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z][\\w-]*"); - private final Set> validators = new LinkedHashSet<>(); + private final Set> validators = new LinkedHashSet<>(); + protected boolean isDefinedExternally; private String name; private String description; private float uiOrder = 0f; private T defaultValue; - AbstractPropertyBuilder(String name) { + PropertyBuilder(String name) { if (StringUtils.isBlank(name)) { throw new IllegalArgumentException("Name must be provided"); @@ -44,7 +50,13 @@ public abstract class AbstractPropertyBuilder> getValidators() { + @Deprecated + void setDefinedExternally(boolean bool) { + this.isDefinedExternally = bool; + } + + + Set> getValidators() { return validators; } @@ -96,7 +108,7 @@ public abstract class AbstractPropertyBuilder validator) { + protected B addValidator(PropertyValidator validator) { validators.add(validator); return (B) this; } @@ -137,21 +149,22 @@ public abstract class AbstractPropertyBuilderThis class is abstract because the B type parameter - * prevents it to be instantiated anyway. That type parameter + *

This class is abstract because the B setType parameter + * prevents it to be instantiated anyway. That setType parameter * is of use to more refined concrete subclasses. * - * @param Concrete type of this builder instance + * @param Concrete setType of this builder instance * @param Type of values the property handles * * @author Clément Fournier * @since 6.7.0 */ - public abstract static class GenericPropertyBuilder, T> extends AbstractPropertyBuilder { + @Experimental + public static class GenericPropertyBuilder extends PropertyBuilder, T> { - private final ValueParser parser; - private final Class type; + private ValueParser parser; + private Class type; GenericPropertyBuilder(String name, ValueParser parser, Class type) { @@ -161,6 +174,47 @@ public abstract class AbstractPropertyBuilder parser) { + this.parser = parser; + } + + + protected ValueParser getParser() { + return parser; + } + + + protected Class getType() { + return type; + } + + @SuppressWarnings("unchecked") + protected B setType(Class type) { + this.type = type; + return (B) this; + } + + + public GenericMultiPBuilder toList() { + if (getDefaultValue() != null) { + throw new IllegalStateException("The default value is already set!"); + } + + GenericMultiPBuilder result = new GenericMultiPBuilder<>(getName(), getParser(), getType()); + + for (PropertyValidator validator : getValidators()) { + result.addValidator(validator.()); + } + + return result; + } + + @Override public PropertyDescriptor build() { return new GenericPropertyDescriptor<>( @@ -170,6 +224,7 @@ public abstract class AbstractPropertyBuilderThis class is abstract because the B type parameter - * prevents it to be instantiated anyway. That type parameter + *

This class is abstract because the B setType parameter + * prevents it to be instantiated anyway. That setType parameter * is of use to more refined concrete subclasses. * - * @param Concrete type of this builder instance - * @param Type of values the property handles. This is the component type of the list + * @param Concrete setType of this builder instance + * @param Type of values the property handles. This is the component setType of the list * * @author Clément Fournier * @since 6.7.0 */ - public abstract static class AbstractGenericMultiPropertyBuilder>, V> extends AbstractPropertyBuilder> { - private final Set> componentValidators = new LinkedHashSet<>(); + @Experimental + public abstract static class AbstractGenericMultiPropertyBuilder>, V> extends PropertyBuilder> { private final ValueParser parser; private final Class type; + protected char multiValueDelimiter; AbstractGenericMultiPropertyBuilder(String name, ValueParser parser, Class type) { @@ -203,6 +259,16 @@ public abstract class AbstractPropertyBuilder getParser() { + return parser; + } + + + protected Class getType() { + return type; + } + + /** * Specify a default value. * @@ -231,6 +297,21 @@ public abstract class AbstractPropertyBuilder> build() { return new GenericMultiValuePropertyDescriptor( @@ -239,8 +320,8 @@ public abstract class AbstractPropertyBuilder> T enumConstantFromEnum(Class enumClass, String name) { -// return EnumUtils.getEnumList(enumClass).stream() -// .filter(e -> e.name().equalsIgnoreCase(name)) -// .findFirst() -// .orElseThrow(() -> new IllegalArgumentException("The name '" + name + "' doesn't correspond to any constant in the enum '" + enumClass.getName() + "'")); -// } - - - public static NumericPropertyBuilder intProperty(String name) { - return new NumericPropertyBuilder<>(name, ValueParserConstants.INTEGER_PARSER, Integer.class); + public static GenericPBuilder intProperty(String name) { + return new GenericPBuilder<>(name, ValueParserConstants.INTEGER_PARSER, Integer.class); } - public static NumericPropertyBuilder doubleProperty(String name) { - return new NumericPropertyBuilder<>(name, ValueParserConstants.DOUBLE_PARSER, Double.class); + public static GenericMultiPBuilder intListProperty(String name) { + return new GenericMultiPBuilder<>(name, ValueParserConstants.INTEGER_PARSER, Integer.class); } -// public static > GenericPBuilder enumProperty(String name, Class enumClass) { -// return new GenericPBuilder<>(name, s -> enumConstantFromEnum(enumClass, s), enumClass); -// } + public static GenericPBuilder doubleProperty(String name) { + return new GenericPBuilder<>(name, ValueParserConstants.DOUBLE_PARSER, Double.class); + } - // removes the other type parameter + public static GenericMultiPBuilder doubleListProperty(String name) { + return new GenericMultiPBuilder<>(name, ValueParserConstants.DOUBLE_PARSER, Double.class); + } + + + public static GenericPBuilder enumProperty(String name, Map nameToValue) { + return new GenericPBuilder<>(name, ValueParserConstants.enumerationParser(nameToValue)) + .addValidator(documentConstraint("Should be in the set " + nameToValue.keySet())); + } + + + // FIXME this is a workaround to document a constraint that occurs while parsing + // With java 8 we could devise a better scheme + private static PropertyValidator documentConstraint(String description) { + return ValidatorFactory.fromPredicate(new Predicate() { + @Override + public boolean test(T t) { + return true; + } + }, description); + } + + // removes the other setType parameter public static class GenericPBuilder extends GenericPropertyBuilder, T> { + @SuppressWarnings("unchecked") + GenericPBuilder(String name, ValueParser parser) { + this(name, parser, (Class) Object.class); + } + + GenericPBuilder(String name, ValueParser parser, Class type) { super(name, parser, type); } + + } + // removes the other setType parameter + public static class GenericMultiPBuilder extends AbstractGenericMultiPropertyBuilder, T> { - public static class NumericPropertyBuilder extends GenericPropertyBuilder, N> { - - NumericPropertyBuilder(String name, ValueParser parser, Class type) { - super(name, parser, type); - } - - - // TODO rename - public NumericPropertyBuilder range(N min, N max) { - return addValidator(Validators.rangeValidator(min, max)); - } - } - - public static class MultiNumericPropertyBuilder extends AbstractPropertyBuilder.AbstractGenericMultiPropertyBuilder, N> { - MultiNumericPropertyBuilder(String name, ValueParser parser, Class type) { + GenericMultiPBuilder(String name, ValueParser parser, Class type) { super(name, parser, type); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java deleted file mode 100644 index 158ab7a652..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/Validators.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties; - -/** - * Transitional class to make up for the absence of lambdas until we move to Java 8. - * - * @author Clément Fournier - * @since 6.7.0 - */ -final class Validators { - - private Validators() { - - } - - - public static PropertyValidator rangeValidator(final T min, final T max) { - return fromPredicate(new Predicate() { - @Override - public boolean test(T t) { - return min.doubleValue() < t.doubleValue() && max.doubleValue() > t.doubleValue(); - } - }, - "Should be between " + min + " and " + max - ); - } - - - /** - * Builds a new validator from a predicate, - * and documentation messages. - * - * @param pred The predicate. If it returns - * false on a value, then the - * value is deemed to have a - * problem and the failureMessage - * will be transmitted. - * @param constraintDescription Description of the constraint, - * see {@link PropertyValidator#getConstraintDescription()}. - * @param Type of value to validate - * - * @return A new validator - */ - private static PropertyValidator fromPredicate(final Predicate pred, final String constraintDescription) { - return new PropertyValidator() { - @Override - public String validate(U value) { - return pred.test(value) ? null : "Constraint violated on value '" + value + "' (" + constraintDescription + ")"; - } - - - @Override - public String getConstraintDescription() { - return constraintDescription; - } - }; - } - - - // Until we have Java 8 - interface Predicate { - boolean test(T t); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java index b452499082..304c128300 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java @@ -14,6 +14,7 @@ import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; @@ -23,9 +24,9 @@ import net.sourceforge.pmd.util.ClassUtil; /** - * @deprecated Was internal API * @author Clément Fournier * @since 6.0.0 + * @deprecated Was internal API */ @Deprecated @InternalApi @@ -235,6 +236,19 @@ public final class ValueParserConstants { } + static ValueParser enumerationParser(final Map mappings) { + return new ValueParser() { + @Override + public T valueOf(String value) throws IllegalArgumentException { + if (!mappings.containsKey(value)) { + throw new IllegalArgumentException("Value was not in the set " + mappings.keySet()); + } + return mappings.get(value); + } + }; + } + + /** * Returns a value parser parsing lists of values of type U. * diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/NumericValidators.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/NumericValidators.java new file mode 100644 index 0000000000..eb697bf558 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/NumericValidators.java @@ -0,0 +1,37 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.validators; + + +import net.sourceforge.pmd.properties.validators.ValidatorFactory.Predicate; + + +/** + * Common validators for properties dealing with numbers. + * + * @author Clément Fournier + * @since 6.7.0 + */ +public class NumericValidators { + + private NumericValidators() { + + } + + + public static PropertyValidator inRange(final N min, final N max) { + return ValidatorFactory.fromPredicate(new Predicate() { + @Override + public boolean test(N t) { + return min.doubleValue() < t.doubleValue() && max.doubleValue() > t.doubleValue(); + } + }, + "Should be between " + min + " and " + max + ); + + } + + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyValidator.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/PropertyValidator.java similarity index 64% rename from pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyValidator.java rename to pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/PropertyValidator.java index 5a18e562a4..a167357815 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyValidator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/PropertyValidator.java @@ -2,7 +2,10 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.properties; +package net.sourceforge.pmd.properties.validators; + +import net.sourceforge.pmd.annotation.Experimental; + /** * Validates the value of a property. @@ -12,7 +15,13 @@ package net.sourceforge.pmd.properties; * @author Clément Fournier * @since 6.7.0 */ -interface PropertyValidator { +@Experimental +public interface PropertyValidator { + // TODO Java 8 extend Predicate + + + boolean test(T value); + /** * Returns a diagnostic message if the value @@ -24,20 +33,22 @@ interface PropertyValidator { * @return An optional diagnostic message */ // TODO Java 8 use Optional - String validate(T value); + String validate(T value); // Future make default /** * Returns a description of the constraint * imposed by this validator on the values. - * E.g. "The value should be positive", or - * "The value should be one of A | B | C." + * E.g. "Should be positive", or + * "Should be one of A | B | C." * * @return A description of the constraint */ String getConstraintDescription(); + PropertyValidator> toMulti(); + // TODO Java 8 move PropertyFactory#fromPredicate here diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/ValidatorFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/ValidatorFactory.java new file mode 100644 index 0000000000..feaff054e6 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/ValidatorFactory.java @@ -0,0 +1,88 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.validators; + +import org.apache.commons.lang3.StringUtils; + +import net.sourceforge.pmd.annotation.Experimental; + + +/** + * Transitional class until we move to Java 8. + * Used to build a validator until we move the static factory on the interface. Do not use + * + * @author Clément Fournier + * @since 6.7.0 + */ +@Deprecated +@Experimental +public final class ValidatorFactory { + + private ValidatorFactory() { + + } + + + /** + * Builds a new validator from a predicate, and description. + * + * @param pred The predicate. If it returns + * false on a value, then the + * value is deemed to have a + * problem + * @param constraintDescription Description of the constraint, + * see {@link PropertyValidator#getConstraintDescription()}. + * @param Type of value to validate + * + * @return A new validator + */ + public static PropertyValidator fromPredicate(final Predicate pred, final String constraintDescription) { + return new PropertyValidator() { + + @Override + public boolean test(U value) { + return pred.test(value); + } + + + @Override + public String validate(U value) { + return pred.test(value) ? null : "Constraint violated on value '" + value + "' (" + constraintDescription + ")"; + } + + + @Override + public String getConstraintDescription() { + return StringUtils.capitalize(constraintDescription); + } + + + @Override + public PropertyValidator> toMulti() { + final PropertyValidator thisValidator = this; + return fromPredicate(new Predicate>() { + @Override + public boolean test(Iterable us) { + for (U u : us) { + if (!thisValidator.test(u)) { + return false; + } + } + return true; + } + }, + "Components " + StringUtils.uncapitalize(thisValidator.getConstraintDescription()) + ); + } + }; + } + + + // Until we have Java 8 + @Deprecated + public interface Predicate { + boolean test(T t); + } +} From 356dfbfb4f35f1b95217045280f88f5c984b2194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 1 Nov 2018 01:18:44 +0100 Subject: [PATCH 025/139] Simplify builder hierarchy --- .../rule/design/CyclomaticComplexityRule.java | 11 +- .../GenericMultiValuePropertyDescriptor.java | 14 ++- .../properties/GenericPropertyDescriptor.java | 14 +-- .../pmd/properties/PropertyBuilder.java | 102 +++++++++--------- .../pmd/properties/PropertyDescriptor.java | 43 +++----- .../pmd/properties/PropertyFactory.java | 70 ++++-------- .../pmd/properties/ValueParserConstants.java | 3 + .../builders/MultiNumericPropertyBuilder.java | 1 + .../MultiPackagedPropertyBuilder.java | 2 + .../builders/MultiValuePropertyBuilder.java | 5 +- .../builders/PropertyDescriptorBuilder.java | 7 +- ...rtyDescriptorBuilderConversionWrapper.java | 1 + .../PropertyDescriptorExternalBuilder.java | 3 +- .../SingleNumericPropertyBuilder.java | 1 + .../SinglePackagedPropertyBuilder.java | 1 + .../builders/SingleValuePropertyBuilder.java | 5 +- .../ConstraintFactory.java} | 23 ++-- .../constraints/NumericConstraints.java | 67 ++++++++++++ .../PropertyConstraint.java} | 26 +++-- .../validators/NumericValidators.java | 37 ------- 20 files changed, 225 insertions(+), 211 deletions(-) rename pmd-core/src/main/java/net/sourceforge/pmd/properties/{validators/ValidatorFactory.java => constraints/ConstraintFactory.java} (79%) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java rename pmd-core/src/main/java/net/sourceforge/pmd/properties/{validators/PropertyValidator.java => constraints/PropertyConstraint.java} (54%) delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/NumericValidators.java diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java index fef4a5d0c2..d17b7d6b9c 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java @@ -5,6 +5,8 @@ package net.sourceforge.pmd.lang.apex.rule.design; +import static net.sourceforge.pmd.properties.constraints.NumericConstraints.positive; + import java.util.Stack; import net.sourceforge.pmd.lang.apex.ast.ASTMethod; @@ -15,7 +17,6 @@ import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey; import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; import net.sourceforge.pmd.lang.metrics.ResultOption; -import net.sourceforge.pmd.properties.IntegerProperty; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; @@ -30,14 +31,14 @@ public class CyclomaticComplexityRule extends AbstractApexRule { private static final PropertyDescriptor CLASS_LEVEL_DESCRIPTOR = PropertyFactory.intProperty("classReportLevel") .desc("Total class complexity reporting threshold") - .range(1, 200) + .require(positive()) .defaultValue(40) .uiOrder(1.0f).build(); - private static final IntegerProperty METHOD_LEVEL_DESCRIPTOR - = IntegerProperty.named("methodReportLevel") + private static final PropertyDescriptor METHOD_LEVEL_DESCRIPTOR + = PropertyFactory.intProperty("methodReportLevel") .desc("Cyclomatic complexity reporting threshold") - .range(1, 30) + .require(positive()) .defaultValue(10) .uiOrder(2.0f).build(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java index 403a70da42..9db9b6f360 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java @@ -7,24 +7,28 @@ package net.sourceforge.pmd.properties; import java.util.List; import java.util.Set; -import net.sourceforge.pmd.properties.validators.PropertyValidator; +import net.sourceforge.pmd.properties.constraints.PropertyConstraint; /** + * If we implement schema changes to properties, delimiter logic will probably be scrapped, + * and hence the divide between multi-value and single-value property descriptors. We can then + * use a single class for all property descriptors. + * * @author Clément Fournier - * @since 6.7.0 + * @since 6.10.0 */ final class GenericMultiValuePropertyDescriptor extends AbstractMultiValueProperty { - private final Set>> listValidators; + private final Set>> listValidators; private final ValueParser parser; private final Class type; GenericMultiValuePropertyDescriptor(String name, String description, float uiOrder, List defaultValue, - Set>> listValidators, + Set>> listValidators, ValueParser parser, char delim, Class type) { @@ -38,7 +42,7 @@ final class GenericMultiValuePropertyDescriptor extends AbstractMultiValuePro @Override public String errorFor(List values) { - for (PropertyValidator> lv : listValidators) { + for (PropertyConstraint> lv : listValidators) { String error = lv.validate(values); if (error != null) { return error; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java index c963c4e56c..95198119fd 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java @@ -6,32 +6,34 @@ package net.sourceforge.pmd.properties; import java.util.Set; -import net.sourceforge.pmd.properties.validators.PropertyValidator; +import net.sourceforge.pmd.properties.constraints.PropertyConstraint; /** + * Bound to be the single implementation for PropertyDescriptor in 7.0.0. + * * @author Clément Fournier - * @since 6.7.0 + * @since 6.10.0 */ final class GenericPropertyDescriptor extends AbstractSingleValueProperty { private final ValueParser parser; private final Class type; - private final Set> validators; + private final Set> constraints; GenericPropertyDescriptor(String name, String description, float uiOrder, T defaultValue, - Set> validators, + Set> constraints, ValueParser parser, boolean isDefinedExternally, Class type) { super(name, description, defaultValue, uiOrder, isDefinedExternally); - this.validators = validators; + this.constraints = constraints; this.parser = parser; this.type = type; } @@ -39,7 +41,7 @@ final class GenericPropertyDescriptor extends AbstractSingleValueProperty @Override public String errorFor(T value) { - for (PropertyValidator validator : validators) { + for (PropertyConstraint validator : constraints) { String error = validator.validate(value); if (error != null) { return error; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java index 2281a4fa5f..ea37944796 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java @@ -15,12 +15,14 @@ import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import net.sourceforge.pmd.annotation.Experimental; -import net.sourceforge.pmd.properties.PropertyFactory.GenericMultiPBuilder; -import net.sourceforge.pmd.properties.validators.PropertyValidator; +import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilder; +import net.sourceforge.pmd.properties.constraints.PropertyConstraint; /** * Base class for generic property builders. + * Note: from 7.0.0 on, all property builders will + * extend this class instead of {@link PropertyDescriptorBuilder}. * * @param Concrete type of this builder instance * @param Type of values the property handles @@ -31,8 +33,9 @@ import net.sourceforge.pmd.properties.validators.PropertyValidator; @Experimental public abstract class PropertyBuilder, T> { private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z][\\w-]*"); - private final Set> validators = new LinkedHashSet<>(); - protected boolean isDefinedExternally; + + boolean isDefinedExternally; + private final Set> validators = new LinkedHashSet<>(); private String name; private String description; private float uiOrder = 0f; @@ -56,7 +59,7 @@ public abstract class PropertyBuilder, T> { } - Set> getValidators() { + Set> getConstraints() { return validators; } @@ -107,9 +110,18 @@ public abstract class PropertyBuilder, T> { } + /** + * Add a constraint on the values that this property may take. + * The validity of values will be checked when constructing the XML + * and invalid values will be reported. + * + * @param constraint The constraint + * + * @return The same builder + */ @SuppressWarnings("unchecked") - protected B addValidator(PropertyValidator validator) { - validators.add(validator); + public B require(PropertyConstraint constraint) { + validators.add(constraint); return (B) this; } @@ -147,24 +159,19 @@ public abstract class PropertyBuilder, T> { /** - * Builder for a generic single-value property. + * Generic builder for a single-value property. * - *

This class is abstract because the B setType parameter - * prevents it to be instantiated anyway. That setType parameter - * is of use to more refined concrete subclasses. - * - * @param Concrete setType of this builder instance * @param Type of values the property handles * * @author Clément Fournier * @since 6.7.0 */ @Experimental - public static class GenericPropertyBuilder extends PropertyBuilder, T> { + public static final class GenericPropertyBuilder extends PropertyBuilder, T> { - private ValueParser parser; - private Class type; + private final ValueParser parser; + private final Class type; GenericPropertyBuilder(String name, ValueParser parser, Class type) { @@ -174,16 +181,6 @@ public abstract class PropertyBuilder, T> { } - GenericPropertyBuilder(String name) { - super(name); - } - - - protected void setParser(ValueParser parser) { - this.parser = parser; - } - - protected ValueParser getParser() { return parser; } @@ -193,22 +190,24 @@ public abstract class PropertyBuilder, T> { return type; } - @SuppressWarnings("unchecked") - protected B setType(Class type) { - this.type = type; - return (B) this; - } - - public GenericMultiPBuilder toList() { + /** + * Returns a new builder that can be used to build a property + * handling lists of Ts. The validators already added are + * converted to list validators. The default value cannot have + * previously been set. + * + * @return A new list property builder + */ + public GenericListPropertyBuilder toList() { if (getDefaultValue() != null) { throw new IllegalStateException("The default value is already set!"); } - GenericMultiPBuilder result = new GenericMultiPBuilder<>(getName(), getParser(), getType()); + GenericListPropertyBuilder result = new GenericListPropertyBuilder<>(getName(), getParser(), getType()); - for (PropertyValidator validator : getValidators()) { - result.addValidator(validator.()); + for (PropertyConstraint validator : getConstraints()) { + result.require(validator.toMulti()); } return result; @@ -222,7 +221,7 @@ public abstract class PropertyBuilder, T> { getDescription(), getUiOrder(), getDefaultValue(), - getValidators(), + getConstraints(), parser, isDefinedExternally, type @@ -233,26 +232,21 @@ public abstract class PropertyBuilder, T> { } /** - * Builder for a generic multi-value property. + * Generic builder for a multi-value property. * - *

This class is abstract because the B setType parameter - * prevents it to be instantiated anyway. That setType parameter - * is of use to more refined concrete subclasses. - * - * @param Concrete setType of this builder instance - * @param Type of values the property handles. This is the component setType of the list + * @param Component type of the list * * @author Clément Fournier * @since 6.7.0 */ @Experimental - public abstract static class AbstractGenericMultiPropertyBuilder>, V> extends PropertyBuilder> { + public static final class GenericListPropertyBuilder extends PropertyBuilder, List> { private final ValueParser parser; private final Class type; - protected char multiValueDelimiter; + private char multiValueDelimiter; - AbstractGenericMultiPropertyBuilder(String name, ValueParser parser, Class type) { + GenericListPropertyBuilder(String name, ValueParser parser, Class type) { super(name); this.parser = parser; this.type = type; @@ -277,9 +271,9 @@ public abstract class PropertyBuilder, T> { * @return The same builder */ @SuppressWarnings("unchecked") - public B defaultValues(Collection val) { + public GenericListPropertyBuilder defaultValues(Collection val) { super.defaultValue(new ArrayList<>(val)); - return (B) this; + return this; } @@ -291,9 +285,9 @@ public abstract class PropertyBuilder, T> { * @return The same builder */ @SuppressWarnings("unchecked") - public B defaultValues(V... val) { + public GenericListPropertyBuilder defaultValues(V... val) { super.defaultValue(Arrays.asList(val)); - return (B) this; + return this; } @@ -306,9 +300,9 @@ public abstract class PropertyBuilder, T> { * @return The same builder */ @SuppressWarnings("unchecked") - public B delim(char delim) { + public GenericListPropertyBuilder delim(char delim) { this.multiValueDelimiter = delim; - return (B) this; + return this; } @@ -319,7 +313,7 @@ public abstract class PropertyBuilder, T> { getDescription(), getUiOrder(), getDefaultValue(), - getValidators(), + getConstraints(), parser, multiValueDelimiter, type diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index d25bcba046..c122bedd3a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -22,7 +22,7 @@ import net.sourceforge.pmd.annotation.InternalApi; *

Several interfaces further specialize the behaviour of descriptors to accommodate specific types of descriptors, * see {@link NumericPropertyDescriptor} and {@link EnumeratedPropertyDescriptor}. * - *

Upcoming API changes to the properties framework: see wiki

+ *

Upcoming API changes to the properties framework: see https://github.com/pmd/pmd/issues/1415

* * @param type of the property's value. This is a list type for multi-valued properties. * @@ -53,11 +53,11 @@ public interface PropertyDescriptor extends Comparable> * class. * * @return Class literal of the value type - * - * @deprecated This method is mainly used for documentation, but will not prove general enough - * to support PMD 7.0.0's improved property types. */ - @Deprecated + // TODO Type is used only to document the expected value format, but generic arguments are erased. + // This will become a problem when we remove the divide between multi-/single-value properties and + // let users make properties out of any type they want. + // We'll probably have to remove this method and find another solution to document the expected format. Class type(); @@ -69,10 +69,7 @@ public interface PropertyDescriptor extends Comparable> * must be used.

* * @return boolean - * - * @deprecated The hard divide between multi- and single-value properties will be removed with 7.0.0 */ - @Deprecated boolean isMultiValue(); @@ -92,7 +89,7 @@ public interface PropertyDescriptor extends Comparable> * * @return A diagnostic message. */ - String errorFor(T value); // TODO Java 1.8 make optional + String errorFor(T value); /** @@ -100,7 +97,12 @@ public interface PropertyDescriptor extends Comparable> * edit property values. If the value returned has a non-zero fractional part then this is can be used to place * adjacent fields on the same row. * - * @return The relative order compared to other properties of the same rule + *

Example:
name -> 0.0 description 1.0 minValue -> 2.0 maxValue -> 2.1

..would have their + * fields placed like:
+ * + * name: [ ] description: [ ] minimum: [ ] maximum: [ ] + * + * @return float */ float uiOrder(); @@ -111,12 +113,8 @@ public interface PropertyDescriptor extends Comparable> * @param propertyString The string to parse * * @return The value represented by the string - * * @throws IllegalArgumentException if the given string cannot be parsed - * @deprecated PMD 7.0.0 will use a more powerful scheme to represent values than - * simple strings, this method won't be general enough */ - @Deprecated T valueFrom(String propertyString) throws IllegalArgumentException; @@ -126,11 +124,7 @@ public interface PropertyDescriptor extends Comparable> * @param value Object * * @return String - * - * @deprecated PMD 7.0.0 will use a more powerful scheme to represent values than - * simple strings, this method won't be general enough */ - @Deprecated String asDelimitedString(T value); @@ -141,11 +135,7 @@ public interface PropertyDescriptor extends Comparable> * @param rule Rule * * @return String - * - * @deprecated Used nowhere, and fails if the rule doesn't define the property descriptor - * A better solution will be added on property source */ - @Deprecated String propertyErrorFor(Rule rule); @@ -153,9 +143,8 @@ public interface PropertyDescriptor extends Comparable> * If the datatype is a String then return the preferred number of rows to allocate in the text widget, returns a * value of one for all other types. Useful for multi-line XPATH editors. * - * @return int - * * @deprecated Was never implemented, and is none of the descriptor's concern. Will be removed with 7.0.0 + * @return int */ @Deprecated int preferredRowCount(); @@ -164,9 +153,8 @@ public interface PropertyDescriptor extends Comparable> /** * Returns a map representing all the property attributes of the receiver in string form. * - * @return map - * * @deprecated Will be removed with 7.0.0 + * @return map */ @Deprecated Map attributeValuesById(); @@ -177,9 +165,8 @@ public interface PropertyDescriptor extends Comparable> * to write out the property correctly: if it was defined externally, then its definition must be written out, * otherwise only its value. * - * @return True if the descriptor was defined in xml - * * @deprecated May be removed with 7.0.0 + * @return True if the descriptor was defined in xml */ @Deprecated @InternalApi diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java index 7b7fa02b78..88e651f331 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java @@ -6,16 +6,17 @@ package net.sourceforge.pmd.properties; import java.util.Map; -import net.sourceforge.pmd.properties.PropertyBuilder.AbstractGenericMultiPropertyBuilder; +import net.sourceforge.pmd.properties.PropertyBuilder.GenericListPropertyBuilder; import net.sourceforge.pmd.properties.PropertyBuilder.GenericPropertyBuilder; -import net.sourceforge.pmd.properties.validators.PropertyValidator; -import net.sourceforge.pmd.properties.validators.ValidatorFactory; -import net.sourceforge.pmd.properties.validators.ValidatorFactory.Predicate; /** + * Provides factory methods for common property types. + * Note: from 7.0.0 on, this will be the only way to + * build property descriptors. + * * @author Clément Fournier - * @since 6.7.0 + * @since 6.10.0 */ public final class PropertyFactory { @@ -24,65 +25,38 @@ public final class PropertyFactory { } - public static GenericPBuilder intProperty(String name) { - return new GenericPBuilder<>(name, ValueParserConstants.INTEGER_PARSER, Integer.class); + public static GenericPropertyBuilder intProperty(String name) { + return new GenericPropertyBuilder<>(name, ValueParserConstants.INTEGER_PARSER, Integer.class); } - public static GenericMultiPBuilder intListProperty(String name) { - return new GenericMultiPBuilder<>(name, ValueParserConstants.INTEGER_PARSER, Integer.class); + public static GenericListPropertyBuilder intListProperty(String name) { + return intProperty(name).toList(); } - public static GenericPBuilder doubleProperty(String name) { - return new GenericPBuilder<>(name, ValueParserConstants.DOUBLE_PARSER, Double.class); + public static GenericPropertyBuilder doubleProperty(String name) { + return new GenericPropertyBuilder<>(name, ValueParserConstants.DOUBLE_PARSER, Double.class); } - public static GenericMultiPBuilder doubleListProperty(String name) { - return new GenericMultiPBuilder<>(name, ValueParserConstants.DOUBLE_PARSER, Double.class); + public static GenericListPropertyBuilder doubleListProperty(String name) { + return doubleProperty(name).toList(); } - public static GenericPBuilder enumProperty(String name, Map nameToValue) { - return new GenericPBuilder<>(name, ValueParserConstants.enumerationParser(nameToValue)) - .addValidator(documentConstraint("Should be in the set " + nameToValue.keySet())); + public static GenericPropertyBuilder enumProperty(String name, Map nameToValue) { + // TODO find solution to document the set of possible values + // At best, map that requirement to a constraint (eg make parser return null if not found, and + // add a non-null constraint with the right description. But if we disallow null values everywhere, + // this will get caught early on.) + return new GenericPropertyBuilder<>(name, ValueParserConstants.enumerationParser(nameToValue), (Class) Object.class); } - // FIXME this is a workaround to document a constraint that occurs while parsing - // With java 8 we could devise a better scheme - private static PropertyValidator documentConstraint(String description) { - return ValidatorFactory.fromPredicate(new Predicate() { - @Override - public boolean test(T t) { - return true; - } - }, description); + public static GenericListPropertyBuilder enumListProperty(String name, Map nameToValue) { + return enumProperty(name, nameToValue).toList(); } - // removes the other setType parameter - public static class GenericPBuilder extends GenericPropertyBuilder, T> { - - @SuppressWarnings("unchecked") - GenericPBuilder(String name, ValueParser parser) { - this(name, parser, (Class) Object.class); - } - - - GenericPBuilder(String name, ValueParser parser, Class type) { - super(name, parser, type); - } - - - } - - // removes the other setType parameter - public static class GenericMultiPBuilder extends AbstractGenericMultiPropertyBuilder, T> { - - GenericMultiPBuilder(String name, ValueParser parser, Class type) { - super(name, parser, type); - } - } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java index 304c128300..e5f623ffb3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParserConstants.java @@ -24,6 +24,9 @@ import net.sourceforge.pmd.util.ClassUtil; /** + * This class will be completely scrapped with 7.0.0. It only hid away the syntactic + * overhead caused by the lack of lambdas in Java 7. + * * @author Clément Fournier * @since 6.0.0 * @deprecated Was internal API diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiNumericPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiNumericPropertyBuilder.java index 8769731240..f63f41ecc7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiNumericPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiNumericPropertyBuilder.java @@ -12,6 +12,7 @@ import net.sourceforge.pmd.properties.MultiValuePropertyDescriptor; * * @param Element type of the list * @param Concrete type of the underlying builder + * @deprecated see {@link net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilder} */ @Deprecated public abstract class MultiNumericPropertyBuilder> diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiPackagedPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiPackagedPropertyBuilder.java index 9ce2836929..e6d1c298ee 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiPackagedPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiPackagedPropertyBuilder.java @@ -10,6 +10,8 @@ import java.util.Arrays; /** * @author Clément Fournier * @since 6.0.0 + * + * @deprecated see {@link net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilder} */ @Deprecated public abstract class MultiPackagedPropertyBuilder> diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiValuePropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiValuePropertyBuilder.java index da8f9009a7..d433d0ea9d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiValuePropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/MultiValuePropertyBuilder.java @@ -17,10 +17,9 @@ import net.sourceforge.pmd.properties.MultiValuePropertyDescriptor; * * @param Element type of the list * @param Concrete type of the underlying builder - * + * @deprecated see {@link net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilder} */ -// @Deprecated // will be rewritten in the next PR and placed in the properties package, -// since there will be no need for a separate package +@Deprecated public abstract class MultiValuePropertyBuilder> extends PropertyDescriptorBuilder, T> { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java index 5aa1ef3959..3f9206f10f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java @@ -6,7 +6,9 @@ package net.sourceforge.pmd.properties.builders; import org.apache.commons.lang3.StringUtils; +import net.sourceforge.pmd.properties.PropertyBuilder; import net.sourceforge.pmd.properties.PropertyDescriptor; +import net.sourceforge.pmd.properties.PropertyFactory; /** @@ -16,11 +18,12 @@ import net.sourceforge.pmd.properties.PropertyDescriptor; * @param Concrete type of this builder instance. Removes code duplication at the expense of a few unchecked casts. * Everything goes well if this parameter's value is correctly set. * + * @deprecated From 7.0.0 on, the only supported way to build properties will be through {@link PropertyFactory}. + * This class hierarchy is replaced by the newer {@link PropertyBuilder}. * @author Clément Fournier * @since 6.0.0 */ -// @Deprecated // will be rewritten in the next PR and placed in the properties package, -// since there will be no need for a separate package +@Deprecated public abstract class PropertyDescriptorBuilder> { protected String name; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilderConversionWrapper.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilderConversionWrapper.java index 0e8cfa3fd1..d7e0ca7ef0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilderConversionWrapper.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilderConversionWrapper.java @@ -26,6 +26,7 @@ import net.sourceforge.pmd.properties.ValueParserConstants; * @param Value type of the descriptor * @param Concrete type of the underlying builder * + * @deprecated This was not public API and will be removed by 7.0.0 * @author Clément Fournier * @since 6.0.0 */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java index 9f63bdd3b7..92885b4d5b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorExternalBuilder.java @@ -14,7 +14,8 @@ import net.sourceforge.pmd.properties.PropertyDescriptorField; * Builds properties from a map of key value pairs, eg extracted from an XML element. * * @param The type of values. - * + * @deprecated see {@link net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilder} + * @author Clément Fournier * @since 6.0.0 * @deprecated The property XML API will not need this anymore diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleNumericPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleNumericPropertyBuilder.java index 78832baf3e..8610c3ea8c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleNumericPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleNumericPropertyBuilder.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.properties.builders; /** * @author Clément Fournier * @since 6.0.0 + * @deprecated see {@link net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilder} */ @Deprecated public abstract class SingleNumericPropertyBuilder> diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SinglePackagedPropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SinglePackagedPropertyBuilder.java index 85e8e3a272..5f253e9cc3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SinglePackagedPropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SinglePackagedPropertyBuilder.java @@ -11,6 +11,7 @@ import java.util.Collection; /** * @author Clément Fournier * @since 6.0.0 + * @deprecated see {@link net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilder} */ @Deprecated public abstract class SinglePackagedPropertyBuilder> diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleValuePropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleValuePropertyBuilder.java index cce7692506..53e726509d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleValuePropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/SingleValuePropertyBuilder.java @@ -7,12 +7,11 @@ package net.sourceforge.pmd.properties.builders; /** * For single-value property descriptors. * + * @deprecated see {@link net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilder} * @param Value type of the built descriptor * @param Concrete type of this builder instance. - * */ -// @Deprecated // will be rewritten in the next PR and placed in the properties package, -// since there will be no need for a separate package +@Deprecated public abstract class SingleValuePropertyBuilder> extends PropertyDescriptorBuilder { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/ValidatorFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java similarity index 79% rename from pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/ValidatorFactory.java rename to pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java index feaff054e6..7218ca6c5c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/ValidatorFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.properties.validators; +package net.sourceforge.pmd.properties.constraints; import org.apache.commons.lang3.StringUtils; @@ -11,16 +11,15 @@ import net.sourceforge.pmd.annotation.Experimental; /** * Transitional class until we move to Java 8. - * Used to build a validator until we move the static factory on the interface. Do not use + * Used to build a validator until we move the static factory on the interface. Do not use. * * @author Clément Fournier - * @since 6.7.0 + * @since 6.10.0 */ -@Deprecated @Experimental -public final class ValidatorFactory { +final class ConstraintFactory { - private ValidatorFactory() { + private ConstraintFactory() { } @@ -33,13 +32,14 @@ public final class ValidatorFactory { * value is deemed to have a * problem * @param constraintDescription Description of the constraint, - * see {@link PropertyValidator#getConstraintDescription()}. + * see {@link PropertyConstraint#getConstraintDescription()}. * @param Type of value to validate * * @return A new validator */ - public static PropertyValidator fromPredicate(final Predicate pred, final String constraintDescription) { - return new PropertyValidator() { + @Experimental + public static PropertyConstraint fromPredicate(final Predicate pred, final String constraintDescription) { + return new PropertyConstraint() { @Override public boolean test(U value) { @@ -60,8 +60,8 @@ public final class ValidatorFactory { @Override - public PropertyValidator> toMulti() { - final PropertyValidator thisValidator = this; + public PropertyConstraint> toMulti() { + final PropertyConstraint thisValidator = this; return fromPredicate(new Predicate>() { @Override public boolean test(Iterable us) { @@ -81,7 +81,6 @@ public final class ValidatorFactory { // Until we have Java 8 - @Deprecated public interface Predicate { boolean test(T t); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java new file mode 100644 index 0000000000..70d4481b4c --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java @@ -0,0 +1,67 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.constraints; + + +import net.sourceforge.pmd.properties.constraints.ConstraintFactory.Predicate; + + +/** + * Common constraints for properties dealing with numbers. + * + * @author Clément Fournier + * @see PropertyConstraint + * @since 6.10.0 + */ +public class NumericConstraints { + + private NumericConstraints() { + + } + + // Methods are named as adjectives to mix well with the "require" syntax. + + + /** + * Requires the number to be inside a range. + * The int values of the numbers are used so there + * may be some unexpected behaviour with decimal numbers. + * + * @param Type of number + * + * @return A range constraint + */ + public static PropertyConstraint inRange(final N minInclusive, final N maxInclusive) { + return ConstraintFactory.fromPredicate(new Predicate() { + @Override + public boolean test(N t) { + return minInclusive.intValue() <= t.intValue() && maxInclusive.intValue() >= t.intValue(); + } + }, + "Should be between " + minInclusive + " and " + maxInclusive + ); + + } + + + /** + * Requires the number to be strictly positive. + * + * @param Type of number + * + * @return A positivity constraint + */ + public static PropertyConstraint positive() { + return ConstraintFactory.fromPredicate(new Predicate() { + @Override + public boolean test(N t) { + return t.intValue() > 0; + } + }, + "Should be positive" + ); + + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/PropertyValidator.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java similarity index 54% rename from pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/PropertyValidator.java rename to pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java index a167357815..e7cbfcfcfe 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/PropertyValidator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java @@ -2,7 +2,7 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.properties.validators; +package net.sourceforge.pmd.properties.constraints; import net.sourceforge.pmd.annotation.Experimental; @@ -10,13 +10,18 @@ import net.sourceforge.pmd.annotation.Experimental; /** * Validates the value of a property. * + *

This interface will change a lot with PMD 7.0.0, + * because of the introduction of Java 8. Please use + * only the ready-made validators in {@link NumericConstraints} + * for now. + * * @param Type of value to handle * * @author Clément Fournier - * @since 6.7.0 + * @since 6.10.0 */ @Experimental -public interface PropertyValidator { +public interface PropertyConstraint { // TODO Java 8 extend Predicate @@ -39,17 +44,24 @@ public interface PropertyValidator { /** * Returns a description of the constraint * imposed by this validator on the values. - * E.g. "Should be positive", or - * "Should be one of A | B | C." + * E.g. "Should be positive", or "Should be one of A | B | C." + * + *

This is used to generate documentation. * * @return A description of the constraint */ String getConstraintDescription(); - PropertyValidator> toMulti(); + /** + * Returns a constraint that validates a collection of Ts + * by checking each component conforms to this conforms. + * + * @return A collection validator + */ + PropertyConstraint> toMulti(); - // TODO Java 8 move PropertyFactory#fromPredicate here + // TODO Java 8 move ConstraintFactory#fromPredicate here } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/NumericValidators.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/NumericValidators.java deleted file mode 100644 index eb697bf558..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/validators/NumericValidators.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.validators; - - -import net.sourceforge.pmd.properties.validators.ValidatorFactory.Predicate; - - -/** - * Common validators for properties dealing with numbers. - * - * @author Clément Fournier - * @since 6.7.0 - */ -public class NumericValidators { - - private NumericValidators() { - - } - - - public static PropertyValidator inRange(final N min, final N max) { - return ValidatorFactory.fromPredicate(new Predicate() { - @Override - public boolean test(N t) { - return min.doubleValue() < t.doubleValue() && max.doubleValue() > t.doubleValue(); - } - }, - "Should be between " + min + " and " + max - ); - - } - - -} From a08c370da7598688facfcc7ac79a45184f33e6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 5 Nov 2018 01:29:21 +0100 Subject: [PATCH 026/139] Generalize list property builders --- .../GenericMultiValuePropertyDescriptor.java | 24 ++-- .../pmd/properties/PropertyBuilder.java | 108 ++++++++++++++---- .../pmd/properties/PropertyFactory.java | 19 ++- .../codestyle/FieldNamingConventionsRule.java | 12 +- 4 files changed, 122 insertions(+), 41 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java index 9db9b6f360..9ee69179ac 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.properties; +import java.util.Collection; import java.util.List; import java.util.Set; @@ -18,32 +19,41 @@ import net.sourceforge.pmd.properties.constraints.PropertyConstraint; * @author Clément Fournier * @since 6.10.0 */ -final class GenericMultiValuePropertyDescriptor extends AbstractMultiValueProperty { +final class GenericMultiValuePropertyDescriptor> extends AbstractMultiValueProperty { - private final Set>> listValidators; + private final Set> listValidators; private final ValueParser parser; private final Class type; GenericMultiValuePropertyDescriptor(String name, String description, float uiOrder, - List defaultValue, - Set>> listValidators, + Collection defaultValue, + Set> listValidators, ValueParser parser, char delim, Class type) { - super(name, description, defaultValue, uiOrder, delim, false); + super(name, description, (List) defaultValue, uiOrder, delim, false); this.listValidators = listValidators; this.parser = parser; this.type = type; } + @SuppressWarnings("unchecked") @Override public String errorFor(List values) { - for (PropertyConstraint> lv : listValidators) { - String error = lv.validate(values); + for (PropertyConstraint lv : listValidators) { + // Note: the unchecked cast is safe because pre-7.0.0, + // we only allow building property descriptors for lists. + // C is thus always List, and the cast doesn't fail + + // Post-7.0.0, the multi-value property classes will be removed + // and C will be the actual type parameter of the returned property + // descriptor + + String error = lv.validate((C) values); if (error != null) { return error; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java index ea37944796..4d2e67c7d2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java @@ -15,6 +15,7 @@ import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import net.sourceforge.pmd.annotation.Experimental; +import net.sourceforge.pmd.properties.PropertyBuilder.GenericCollectionPropertyBuilder.Supplier; import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilder; import net.sourceforge.pmd.properties.constraints.PropertyConstraint; @@ -32,10 +33,10 @@ import net.sourceforge.pmd.properties.constraints.PropertyConstraint; */ @Experimental public abstract class PropertyBuilder, T> { - private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z][\\w-]*"); - boolean isDefinedExternally; + private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z][\\w-]*"); private final Set> validators = new LinkedHashSet<>(); + protected boolean isDefinedExternally; private String name; private String description; private float uiOrder = 0f; @@ -166,7 +167,9 @@ public abstract class PropertyBuilder, T> { * @author Clément Fournier * @since 6.7.0 */ - @Experimental + // Note: we may keep some specialized property builders around to allow for some sugar, + // e.g. specifying the default value of a regex property as a string, or like the collection one, + // with varargs for collection types public static final class GenericPropertyBuilder extends PropertyBuilder, T> { @@ -198,19 +201,38 @@ public abstract class PropertyBuilder, T> { * previously been set. * * @return A new list property builder + * + * @throws IllegalStateException if the default value has already been set */ - public GenericListPropertyBuilder toList() { + /* package private */ GenericCollectionPropertyBuilder> toList() { + + Supplier> listSupplier = new Supplier>() { + @Override + public List get() { + return new ArrayList<>(); + } + }; + + return toCollection(listSupplier); + } + + + private > GenericCollectionPropertyBuilder toCollection(Supplier emptyCollSupplier) { if (getDefaultValue() != null) { throw new IllegalStateException("The default value is already set!"); } - GenericListPropertyBuilder result = new GenericListPropertyBuilder<>(getName(), getParser(), getType()); + GenericCollectionPropertyBuilder result = new GenericCollectionPropertyBuilder<>(getName(), + getParser(), + emptyCollSupplier, + getType()); for (PropertyConstraint validator : getConstraints()) { result.require(validator.toMulti()); } return result; + } @@ -232,34 +254,45 @@ public abstract class PropertyBuilder, T> { } /** - * Generic builder for a multi-value property. + * Generic builder for a collection-valued property. + * This builder allows some nice syntax to define + * the {@linkplain #defaultValues(Object[]) default value}. * - * @param Component type of the list + *

Note: this is meant to support arbitrary collections. + * Pre-7.0.0, the only collections available from the {@link PropertyFactory} + * are list types though. + * + * @param Component type of the collection + * @param Collection type for the property being built * * @author Clément Fournier * @since 6.7.0 */ - @Experimental - public static final class GenericListPropertyBuilder extends PropertyBuilder, List> { + public static final class GenericCollectionPropertyBuilder> extends PropertyBuilder, C> { private final ValueParser parser; + private final Supplier emptyCollSupplier; private final Class type; private char multiValueDelimiter; - GenericListPropertyBuilder(String name, ValueParser parser, Class type) { + /** + * Builds a new builder for a collection type. Package-private. + */ + GenericCollectionPropertyBuilder(String name, + ValueParser parser, + Supplier emptyCollSupplier, + Class type) { super(name); this.parser = parser; + this.emptyCollSupplier = emptyCollSupplier; this.type = type; } - protected ValueParser getParser() { - return parser; - } - - - protected Class getType() { - return type; + private C getDefaultValue(Collection list) { + C coll = emptyCollSupplier.get(); + coll.addAll(list); + return coll; } @@ -271,8 +304,8 @@ public abstract class PropertyBuilder, T> { * @return The same builder */ @SuppressWarnings("unchecked") - public GenericListPropertyBuilder defaultValues(Collection val) { - super.defaultValue(new ArrayList<>(val)); + public GenericCollectionPropertyBuilder defaultValue(Collection val) { + super.defaultValue(getDefaultValue(val)); return this; } @@ -285,8 +318,8 @@ public abstract class PropertyBuilder, T> { * @return The same builder */ @SuppressWarnings("unchecked") - public GenericListPropertyBuilder defaultValues(V... val) { - super.defaultValue(Arrays.asList(val)); + public GenericCollectionPropertyBuilder defaultValues(V... val) { + super.defaultValue(getDefaultValue(Arrays.asList(val))); return this; } @@ -298,17 +331,35 @@ public abstract class PropertyBuilder, T> { * @param delim Delimiter * * @return The same builder + * + * @deprecated PMD 7.0.0 will introduce a new XML syntax for multi-valued properties which will not rely on delimiters. + * This method is kept until this is implemented for compatibility reasons with the pre-7.0.0 framework, but + * it will be scrapped come 7.0.0. */ - @SuppressWarnings("unchecked") - public GenericListPropertyBuilder delim(char delim) { + @Deprecated + public GenericCollectionPropertyBuilder delim(char delim) { this.multiValueDelimiter = delim; return this; } + /** + * Builds a new property descriptor with the configuration held in this builder. + * + * @return A new property + */ + @SuppressWarnings("unchecked") @Override - public PropertyDescriptor> build() { - return new GenericMultiValuePropertyDescriptor( + public PropertyDescriptor build() { + // Note: the unchecked cast is safe because pre-7.0.0, + // we only allow building property descriptors for lists. + // C is thus always List, and the cast doesn't fail + + // Post-7.0.0, the multi-value property classes will be removed + // and C will be the actual type parameter of the returned property + // descriptor + + return (PropertyDescriptor) new GenericMultiValuePropertyDescriptor<>( getName(), getDescription(), getUiOrder(), @@ -319,5 +370,12 @@ public abstract class PropertyBuilder, T> { type ); } + + + // Until we have Java 8 + @Deprecated + interface Supplier { + T get(); + } } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java index 88e651f331..73c1801b71 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java @@ -4,9 +4,10 @@ package net.sourceforge.pmd.properties; +import java.util.List; import java.util.Map; -import net.sourceforge.pmd.properties.PropertyBuilder.GenericListPropertyBuilder; +import net.sourceforge.pmd.properties.PropertyBuilder.GenericCollectionPropertyBuilder; import net.sourceforge.pmd.properties.PropertyBuilder.GenericPropertyBuilder; @@ -30,7 +31,7 @@ public final class PropertyFactory { } - public static GenericListPropertyBuilder intListProperty(String name) { + public static GenericCollectionPropertyBuilder> intListProperty(String name) { return intProperty(name).toList(); } @@ -40,11 +41,21 @@ public final class PropertyFactory { } - public static GenericListPropertyBuilder doubleListProperty(String name) { + public static GenericCollectionPropertyBuilder> doubleListProperty(String name) { return doubleProperty(name).toList(); } + public static GenericPropertyBuilder stringProperty(String name) { + return new GenericPropertyBuilder<>(name, ValueParserConstants.STRING_PARSER, String.class); + } + + + public static GenericCollectionPropertyBuilder> stringListProperty(String name) { + return stringProperty(name).toList(); + } + + public static GenericPropertyBuilder enumProperty(String name, Map nameToValue) { // TODO find solution to document the set of possible values // At best, map that requirement to a constraint (eg make parser return null if not found, and @@ -54,7 +65,7 @@ public final class PropertyFactory { } - public static GenericListPropertyBuilder enumListProperty(String name, Map nameToValue) { + public static GenericCollectionPropertyBuilder> enumListProperty(String name, Map nameToValue) { return enumProperty(name, nameToValue).toList(); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldNamingConventionsRule.java index 0cfc4f2e5a..240e2dd647 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldNamingConventionsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldNamingConventionsRule.java @@ -4,14 +4,15 @@ package net.sourceforge.pmd.lang.java.rule.codestyle; +import java.util.List; import java.util.regex.Pattern; import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.properties.PropertyDescriptor; +import net.sourceforge.pmd.properties.PropertyFactory; import net.sourceforge.pmd.properties.RegexProperty; -import net.sourceforge.pmd.properties.StringMultiProperty; /** @@ -23,10 +24,11 @@ import net.sourceforge.pmd.properties.StringMultiProperty; public class FieldNamingConventionsRule extends AbstractNamingConventionRule { // TODO we need a more powerful scheme to match some fields, e.g. include modifiers/type // We could define a new property, but specifying property values as a single string doesn't scale - private static final StringMultiProperty EXCLUDED_NAMES = StringMultiProperty.named("exclusions") - .desc("Names of fields to whitelist.") - .defaultValues("serialVersionUID") - .build(); + private static final PropertyDescriptor> EXCLUDED_NAMES = + PropertyFactory.stringListProperty("exclusions") + .desc("Names of fields to whitelist.") + .defaultValues("serialVersionUID") + .build(); private final RegexProperty publicConstantFieldRegex = defaultProp("public constant").defaultValue("[A-Z][A-Z_0-9]*").build(); From 81e19a15ef7c42aa690fe14e6866563cee7c2cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 5 Nov 2018 00:00:20 -0300 Subject: [PATCH 027/139] Update changelog, refs #1427 --- docs/pages/release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 62caa38f96..d51c50d6b3 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -19,6 +19,8 @@ This is a {{ site.pmd.release_type }} release. * all * [#1318](https://github.com/pmd/pmd/issues/1318): \[test] Kotlin DSL to ease test writing * [#1341](https://github.com/pmd/pmd/issues/1341): \[doc] Documentation Error with Regex Properties +* java-codestyle + * [#1372](https://github.com/pmd/pmd/issues/1372): \[java] false positive for UselessQualifiedThis ### API Changes From 4180fe1c6d30ff0dc8634155c63996951942fb8f Mon Sep 17 00:00:00 2001 From: "Travis CI (pmd-bot)" Date: Mon, 5 Nov 2018 03:12:04 +0000 Subject: [PATCH 028/139] Update documentation TRAVIS_JOB_NUMBER=3007.1 TRAVIS_COMMIT_RANGE=39d340f431c1...1d9a412d59d5 --- docs/pages/pmd/rules/java.md | 2 +- docs/pages/pmd/rules/java/codestyle.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/pages/pmd/rules/java.md b/docs/pages/pmd/rules/java.md index 516e0ddd7a..964dc77003 100644 --- a/docs/pages/pmd/rules/java.md +++ b/docs/pages/pmd/rules/java.md @@ -115,7 +115,7 @@ folder: pmd/rules * [UnnecessaryModifier](pmd_rules_java_codestyle.html#unnecessarymodifier): Fields in interfaces and annotations are automatically 'public static final', and methods are 'pu... * [UnnecessaryReturn](pmd_rules_java_codestyle.html#unnecessaryreturn): Avoid the use of unnecessary return statements. * [UselessParentheses](pmd_rules_java_codestyle.html#uselessparentheses): Useless parentheses should be removed. -* [UselessQualifiedThis](pmd_rules_java_codestyle.html#uselessqualifiedthis): Look for qualified this usages in the same class. +* [UselessQualifiedThis](pmd_rules_java_codestyle.html#uselessqualifiedthis): Reports qualified this usages in the same class. * [VariableNamingConventions](pmd_rules_java_codestyle.html#variablenamingconventions): Deprecated A variable naming conventions rule - customize this to your liking. Currently, itchecks for fina... * [WhileLoopsMustUseBraces](pmd_rules_java_codestyle.html#whileloopsmustusebraces): Deprecated Avoid using 'while' statements without using braces to surround the code block. If the code forma... diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index a0e6b3f94f..af3fa16918 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -2157,13 +2157,13 @@ public class Foo { **Priority:** Medium (3) -Look for qualified this usages in the same class. +Reports qualified this usages in the same class. **This rule is defined by the following XPath expression:** ``` xpath //PrimaryExpression [PrimaryPrefix/Name[@Image]] -[PrimarySuffix[@Arguments='false']] +[PrimarySuffix[@Arguments='false' and @ArrayDereference = 'false']] [not(PrimarySuffix/MemberSelector)] [ancestor::ClassOrInterfaceBodyDeclaration[1][@AnonymousInnerClass='false']] /PrimaryPrefix/Name[@Image = ancestor::ClassOrInterfaceDeclaration[1]/@Image] From 9d9dc131de59fe7603a77f6544e12d1bfc016c7e Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 5 Nov 2018 22:19:53 +0100 Subject: [PATCH 029/139] Update release notes, refs #1428 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 62caa38f96..5446acb643 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -25,6 +25,7 @@ This is a {{ site.pmd.release_type }} release. ### External Contributions * [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007) +* [#1428](https://github.com/pmd/pmd/pull/1428): \[core] Upgrading JCommander from 1.48 to 1.72 - [Thunderforge](https://github.com/Thunderforge) {% endtocmaker %} From 010bdc2c4a3994a85b5d9534824f6e04af508588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Nov 2018 08:40:15 +0100 Subject: [PATCH 030/139] Deprecate Dimensionable & some methods from Field & LocalVar decls --- .../lang/java/ast/ASTArrayDimsAndInits.java | 3 ++ .../lang/java/ast/ASTFieldDeclaration.java | 31 +++++++++++++++++++ .../pmd/lang/java/ast/ASTFormalParameter.java | 2 ++ .../java/ast/ASTLocalVariableDeclaration.java | 9 ++++-- .../pmd/lang/java/ast/ASTPrimitiveType.java | 3 ++ .../pmd/lang/java/ast/ASTReferenceType.java | 3 ++ .../pmd/lang/java/ast/ASTResource.java | 3 ++ .../java/ast/ASTVariableDeclaratorId.java | 5 +-- .../pmd/lang/java/ast/Dimensionable.java | 6 ++++ .../pmd/lang/java/rule/JavaRuleViolation.java | 19 ++++++++++-- .../codestyle/PrematureDeclarationRule.java | 20 +++++++----- ...ingletonClassReturningNewInstanceRule.java | 11 ++++--- 12 files changed, 95 insertions(+), 20 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java index de1035272b..29425c8ddc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java @@ -24,16 +24,19 @@ public class ASTArrayDimsAndInits extends AbstractJavaNode implements Dimensiona return visitor.visit(this, data); } + @Deprecated public void bumpArrayDepth() { arrayDepth++; } @Override + @Deprecated public int getArrayDepth() { return arrayDepth; } @Override + @Deprecated public boolean isArray() { return arrayDepth > 0; // should always be true... } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java index 15e396118d..cc66f73be8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java @@ -9,6 +9,7 @@ import java.util.Iterator; import net.sourceforge.pmd.lang.ast.SignedNode; import net.sourceforge.pmd.lang.java.multifile.signature.JavaFieldSignature; +import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; /** @@ -128,11 +129,13 @@ public class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements D } @Override + @Deprecated public boolean isArray() { return checkType() + checkDecl() > 0; } @Override + @Deprecated public int getArrayDepth() { if (!isArray()) { return 0; @@ -159,8 +162,14 @@ public class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements D * VariableDeclartorId node and returns its image or null if * the child node is not found. * + * + * @deprecated FieldDeclaration may declare several variables, so this is not exhaustive + * Iterate on the {@linkplain ASTVariableDeclaratorId VariableDeclaratorIds} instead + * + * * @return a String representing the name of the variable */ + @Deprecated public String getVariableName() { ASTVariableDeclaratorId decl = getFirstDescendantOfType(ASTVariableDeclaratorId.class); if (decl != null) { @@ -189,4 +198,26 @@ public class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements D return ASTVariableDeclarator.iterateIds(this); } + + /** + * @deprecated FieldDeclaration may declare several variables with a different type + * It won't implement TypeNode anymore come 7.0.0 + */ + @Override + @Deprecated + public Class getType() { + return super.getType(); + } + + + /** + * + * @deprecated FieldDeclaration may declare several variables with a different type + * It won't implement TypeNode anymore come 7.0.0 + */ + @Override + @Deprecated + public JavaTypeDefinition getTypeDefinition() { + return super.getTypeDefinition(); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java index b2d5420c4c..7411d22922 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java @@ -103,6 +103,7 @@ public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Di * This includes varargs parameters. */ @Override + @Deprecated public boolean isArray() { return isVarargs() || getTypeNode() != null && getTypeNode().isArray() @@ -110,6 +111,7 @@ public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Di } @Override + @Deprecated public int getArrayDepth() { if (!isArray()) { return 0; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java index d0089bdb32..2c4fb0687f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java @@ -64,13 +64,13 @@ public class ASTLocalVariableDeclaration extends AbstractJavaAccessNode implemen } @Override - // TODO deprecate + @Deprecated public boolean isArray() { return getArrayDepth() > 0; } @Override - // TODO deprecate + @Deprecated public int getArrayDepth() { return getArrayDimensionOnType() + getArrayDimensionOnDeclaratorId(); } @@ -107,11 +107,14 @@ public class ASTLocalVariableDeclaration extends AbstractJavaAccessNode implemen * VariableDeclartorId node and returns it's image or null if * the child node is not found. * + * @deprecated LocalVariableDeclaration may declare several variables, so this is not exhaustive + * Iterate on the {@linkplain ASTVariableDeclaratorId VariableDeclaratorIds} instead + * * @return a String representing the name of the variable */ - // TODO deprecate. // It would be nice to have a way to inform XPath users of the intended replacement // for a deprecated attribute. We may use another annotation for that. + @Deprecated public String getVariableName() { ASTVariableDeclaratorId decl = getFirstDescendantOfType(ASTVariableDeclaratorId.class); if (decl != null) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimitiveType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimitiveType.java index c6eb62bd01..05766c53a3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimitiveType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimitiveType.java @@ -38,16 +38,19 @@ public class ASTPrimitiveType extends AbstractJavaTypeNode implements Dimensiona return visitor.visit(this, data); } + @Deprecated public void bumpArrayDepth() { arrayDepth++; } @Override + @Deprecated public int getArrayDepth() { return arrayDepth; } @Override + @Deprecated public boolean isArray() { return arrayDepth > 0; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReferenceType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReferenceType.java index b5f2714972..605f065186 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReferenceType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReferenceType.java @@ -37,16 +37,19 @@ public class ASTReferenceType extends AbstractJavaTypeNode implements Dimensiona return visitor.visit(this, data); } + @Deprecated public void bumpArrayDepth() { arrayDepth++; } @Override + @Deprecated public int getArrayDepth() { return arrayDepth; } @Override + @Deprecated public boolean isArray() { return arrayDepth > 0; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResource.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResource.java index dc4b381423..1c818e8a2f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResource.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResource.java @@ -20,6 +20,9 @@ public class ASTResource extends ASTFormalParameter { public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + // TODO Should we deprecate all methods from ASTFormalParameter? + } /* * JavaCC - OriginalChecksum=92734fc70bba91fd9422150dbf87d5c4 (do not edit this diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java index 5a549e5977..990f734be4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java @@ -65,18 +65,19 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim return getScope().getDeclarations(VariableNameDeclaration.class).get(nameDeclaration); } - // TODO Dimensionable will be deprecated - + @Deprecated public void bumpArrayDepth() { arrayDepth++; } @Override + @Deprecated public int getArrayDepth() { return arrayDepth; } @Override + @Deprecated public boolean isArray() { return arrayDepth > 0; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Dimensionable.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Dimensionable.java index 5c84e80580..fb0bbac437 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Dimensionable.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/Dimensionable.java @@ -4,8 +4,14 @@ package net.sourceforge.pmd.lang.java.ast; +/** + * @deprecated Will be removed with 7.0.0. See https://github.com/pmd/pmd/issues/997 and https://github.com/pmd/pmd/issues/910 + */ +@Deprecated public interface Dimensionable { + @Deprecated boolean isArray(); + @Deprecated int getArrayDepth(); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java index 35b7814209..4abba055de 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.rule; +import java.util.Iterator; import java.util.Set; import net.sourceforge.pmd.Rule; @@ -74,7 +75,7 @@ public class JavaRuleViolation extends ParametricRuleViolation { /** * Check for suppression on this node, on parents, and on contained types * for ASTCompilationUnit - * + * * @param node */ public static boolean isSupressed(Node node, Rule rule) { @@ -130,11 +131,23 @@ public class JavaRuleViolation extends ParametricRuleViolation { && ((CanSuppressWarnings) node).hasSuppressWarningsAnnotationFor(rule); } + private String getVariableNames(Iterable iterable) { + + Iterator it = iterable.iterator(); + StringBuilder builder = new StringBuilder(); + builder.append(it.next()); + + while (it.hasNext()) { + builder.append(", ").append(it.next()); + } + return builder.toString(); + } + private void setVariableNameIfExists(Node node) { if (node instanceof ASTFieldDeclaration) { - variableName = ((ASTFieldDeclaration) node).getVariableName(); + variableName = getVariableNames(((ASTFieldDeclaration) node)); } else if (node instanceof ASTLocalVariableDeclaration) { - variableName = ((ASTLocalVariableDeclaration) node).getVariableName(); + variableName = getVariableNames(((ASTLocalVariableDeclaration) node)); } else if (node instanceof ASTVariableDeclarator) { variableName = node.jjtGetChild(0).getImage(); } else if (node instanceof ASTVariableDeclaratorId) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/PrematureDeclarationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/PrematureDeclarationRule.java index 291a6de34b..51f369b5d4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/PrematureDeclarationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/PrematureDeclarationRule.java @@ -14,6 +14,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; /** @@ -36,17 +37,20 @@ public class PrematureDeclarationRule extends AbstractJavaRule { return super.visit(node, data); } - for (ASTBlockStatement block : statementsAfter(node)) { - if (hasReferencesIn(block, node.getVariableName())) { - break; - } - - if (hasExit(block)) { - addViolation(data, node); - break; + for (ASTVariableDeclaratorId id : node) { + for (ASTBlockStatement block : statementsAfter(node)) { + if (hasReferencesIn(block, id.getVariableName())) { + break; + } + + if (hasExit(block)) { + addViolation(data, node); + break; + } } } + return super.visit(node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/SingletonClassReturningNewInstanceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/SingletonClassReturningNewInstanceRule.java index 10c96c3672..8efd0be149 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/SingletonClassReturningNewInstanceRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/SingletonClassReturningNewInstanceRule.java @@ -15,6 +15,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; public class SingletonClassReturningNewInstanceRule extends AbstractJavaRule { @@ -69,10 +70,12 @@ public class SingletonClassReturningNewInstanceRule extends AbstractJavaRule { .findDescendantsOfType(ASTLocalVariableDeclaration.class); if (!lVarList.isEmpty()) { for (ASTLocalVariableDeclaration localVar : lVarList) { - localVarName = localVar.getVariableName(); - if (returnVariableName != null && returnVariableName.equals(localVarName)) { - violation = true; - break; + for (ASTVariableDeclaratorId id : localVar) { + localVarName = id.getVariableName(); + if (returnVariableName != null && returnVariableName.equals(localVarName)) { + violation = true; + break; + } } } } From 402614c777f89506e03777c939d61e199bfe9967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Nov 2018 08:47:06 +0100 Subject: [PATCH 031/139] Update release notes --- docs/pages/release_notes.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index bc060c9b9d..459b1ec246 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -22,6 +22,22 @@ This is a {{ site.pmd.release_type }} release. ### API Changes +#### Deprecated APIs + +* The interface `net.sourceforge.pmd.lang.java.ast.Dimensionable` has been deprecated. + It gets in the way of a grammar change for 7.0.0 and won't be needed anymore (see [#997](https://github.com/pmd/pmd/issues/997)). + +* Several methods from LocalVariableDeclaration and FieldDeclaration have also been + deprecated: + * FieldDeclaration won't be a TypeNode come 7.0.0, so `getType` and `getTypeDefinition` are deprecated + * The method `getVariableName` on those two nodes will be removed too + + All these are deprecated because those nodes may declare several variables at once, possibly + with different types (and obviously with different names). They both implement `Iterator` + though, so you should iterate on each declared variable. See [#910](https://github.com/pmd/pmd/issues/910) + + + ### External Contributions * [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007) From f19a2e7fdea79918d1c5f961c71e338e910a08b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Nov 2018 09:32:01 +0100 Subject: [PATCH 032/139] Style --- .../sourceforge/pmd/lang/java/ast/ASTType.java | 17 +++++++++++++++++ .../lang/java/ast/ASTVariableDeclaratorId.java | 13 +++++++++++++ .../pmd/lang/java/rule/JavaRuleViolation.java | 4 ++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java index 00d4e72ef3..51303de825 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java @@ -41,6 +41,8 @@ public class ASTType extends AbstractJavaTypeNode { return getFirstDescendantOfType(ASTPrimitiveType.class).getImage(); } + + @Deprecated public int getArrayDepth() { if (jjtGetNumChildren() != 0 && (jjtGetChild(0) instanceof ASTReferenceType || jjtGetChild(0) instanceof ASTPrimitiveType)) { @@ -49,7 +51,22 @@ public class ASTType extends AbstractJavaTypeNode { return 0; // this is not an array } + + /** + * + * @deprecated Use {@link #isArrayType()} + */ + @Deprecated public boolean isArray() { return getArrayDepth() > 0; } + + + /** + * Returns true if this type is an array type. + * + */ + public boolean isArrayType() { + return isArray(); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java index 990f734be4..e110ce07f9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java @@ -76,6 +76,11 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim return arrayDepth; } + + /** + * Returns true if the declared variable has an array type. + * @deprecated Use {@link #hasArrayType()} + */ @Override @Deprecated public boolean isArray() { @@ -83,6 +88,14 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim } + /** + * Returns true if the declared variable has an array type. + */ + public boolean hasArrayType() { + return arrayDepth > 0 || !isTypeInferred() && getTypeNode().isArrayType(); + } + + /** * Returns true if this nodes declares an exception parameter in * a {@code catch} statement. diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java index 4abba055de..59be85dc5a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/JavaRuleViolation.java @@ -145,9 +145,9 @@ public class JavaRuleViolation extends ParametricRuleViolation { private void setVariableNameIfExists(Node node) { if (node instanceof ASTFieldDeclaration) { - variableName = getVariableNames(((ASTFieldDeclaration) node)); + variableName = getVariableNames((ASTFieldDeclaration) node); } else if (node instanceof ASTLocalVariableDeclaration) { - variableName = getVariableNames(((ASTLocalVariableDeclaration) node)); + variableName = getVariableNames((ASTLocalVariableDeclaration) node); } else if (node instanceof ASTVariableDeclarator) { variableName = node.jjtGetChild(0).getImage(); } else if (node instanceof ASTVariableDeclaratorId) { From 9779422e3ecc074f6cd769b8a0114cce06132ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Nov 2018 09:33:37 +0100 Subject: [PATCH 033/139] Fix UseVarargs --- .../main/resources/category/java/bestpractices.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/bestpractices.xml b/pmd-java/src/main/resources/category/java/bestpractices.xml index 5d905a2e4e..682293ffce 100644 --- a/pmd-java/src/main/resources/category/java/bestpractices.xml +++ b/pmd-java/src/main/resources/category/java/bestpractices.xml @@ -1457,23 +1457,24 @@ having to deal with the creation of an array. 4 + From f371524b63d2fc1855df57815763c47fd370b6d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 6 Nov 2018 09:36:24 +0100 Subject: [PATCH 034/139] Migrate other usages --- pmd-java/src/main/resources/category/java/errorprone.xml | 2 +- pmd-java/src/main/resources/category/java/performance.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml index 9c90817ac9..93930f8694 100644 --- a/pmd-java/src/main/resources/category/java/errorprone.xml +++ b/pmd-java/src/main/resources/category/java/errorprone.xml @@ -2628,7 +2628,7 @@ NullPointerExceptions. (Arrays.asList(...)) if that is inconvenient for you and PrimaryExpression/PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name [ - @Image = ancestor::MethodDeclaration//LocalVariableDeclaration[@Array="true"]/VariableDeclarator/VariableDeclaratorId/@Image + @Image = ancestor::MethodDeclaration[1]//LocalVariableDeclaration/VariableDeclarator/VariableDeclaratorId[@ArrayType="true"]/@Image or - @Image = ancestor::MethodDeclaration//FormalParameter/VariableDeclaratorId/@Image + @Image = ancestor::MethodDeclaration[1]//FormalParameter/VariableDeclaratorId/@Image ] /../..[count(.//PrimarySuffix) =1]/PrimarySuffix/Expression/PrimaryExpression/PrimaryPrefix From ff55a230d5ec198b44befe38a473bebc57b389d7 Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Fri, 12 Oct 2018 12:21:56 +0100 Subject: [PATCH 035/139] Added Kotlin support to CPD. The tokenizer uses the ANTLR4 grammar based on the one at https://github.com/shadrina/kotlin-grammar-antlr4 (via https://github.com/antlr/grammars-v4/). --- pmd-dist/pom.xml | 5 + pmd-kotlin/pom.xml | 57 + .../pmd/lang/kotlin/antlr4/Kotlin.g4 | 2233 +++++++++++++++++ .../sourceforge/pmd/cpd/KotlinLanguage.java | 18 + .../sourceforge/pmd/cpd/KotlinTokenizer.java | 83 + .../pmd/lang/kotlin/KotlinLanguageModule.java | 26 + .../services/net.sourceforge.pmd.cpd.Language | 1 + .../net.sourceforge.pmd.lang.Language | 1 + pom.xml | 1 + 9 files changed, 2425 insertions(+) create mode 100644 pmd-kotlin/pom.xml create mode 100644 pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/antlr4/Kotlin.g4 create mode 100644 pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinLanguage.java create mode 100644 pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java create mode 100644 pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java create mode 100644 pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language create mode 100644 pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml index 62c7fe7ef9..6a7e477566 100644 --- a/pmd-dist/pom.xml +++ b/pmd-dist/pom.xml @@ -117,6 +117,11 @@ pmd-visualforce ${project.version} + + net.sourceforge.pmd + pmd-kotlin + ${project.version} + net.sourceforge.pmd pmd-matlab diff --git a/pmd-kotlin/pom.xml b/pmd-kotlin/pom.xml new file mode 100644 index 0000000000..4d58dd1783 --- /dev/null +++ b/pmd-kotlin/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + pmd-kotlin + PMD Kotlin + + + net.sourceforge.pmd + pmd + 6.4.0 + + + + + + org.antlr + antlr4-maven-plugin + + + + maven-resources-plugin + + false + + ${*} + + + + + + + + + org.antlr + antlr4-runtime + + + net.sourceforge.pmd + pmd-core + + + commons-io + commons-io + + + + junit + junit + test + + + net.sourceforge.pmd + pmd-test + test + + + diff --git a/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/antlr4/Kotlin.g4 b/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/antlr4/Kotlin.g4 new file mode 100644 index 0000000000..dce0380786 --- /dev/null +++ b/pmd-kotlin/src/main/antlr4/net/sourceforge/pmd/lang/kotlin/antlr4/Kotlin.g4 @@ -0,0 +1,2233 @@ +/** + * Kotlin Grammar for ANTLR v4 + * + * Based on: + * http://jetbrains.github.io/kotlin-spec/#_grammars_and_parsing + * and + * http://kotlinlang.org/docs/reference/grammar.html + * + * Tested on + * https://github.com/JetBrains/kotlin/tree/master/compiler/testData/psi + */ + +lexer grammar Kotlin; + +/** + * Taken from http://www.antlr3.org/grammar/1345144569663/AntlrUnicode.txt + */ + +//lexer grammar UnicodeClasses; + +UNICODE_CLASS_LL: + '\u0061'..'\u007A' | + '\u00B5' | + '\u00DF'..'\u00F6' | + '\u00F8'..'\u00FF' | + '\u0101' | + '\u0103' | + '\u0105' | + '\u0107' | + '\u0109' | + '\u010B' | + '\u010D' | + '\u010F' | + '\u0111' | + '\u0113' | + '\u0115' | + '\u0117' | + '\u0119' | + '\u011B' | + '\u011D' | + '\u011F' | + '\u0121' | + '\u0123' | + '\u0125' | + '\u0127' | + '\u0129' | + '\u012B' | + '\u012D' | + '\u012F' | + '\u0131' | + '\u0133' | + '\u0135' | + '\u0137' | + '\u0138' | + '\u013A' | + '\u013C' | + '\u013E' | + '\u0140' | + '\u0142' | + '\u0144' | + '\u0146' | + '\u0148' | + '\u0149' | + '\u014B' | + '\u014D' | + '\u014F' | + '\u0151' | + '\u0153' | + '\u0155' | + '\u0157' | + '\u0159' | + '\u015B' | + '\u015D' | + '\u015F' | + '\u0161' | + '\u0163' | + '\u0165' | + '\u0167' | + '\u0169' | + '\u016B' | + '\u016D' | + '\u016F' | + '\u0171' | + '\u0173' | + '\u0175' | + '\u0177' | + '\u017A' | + '\u017C' | + '\u017E'..'\u0180' | + '\u0183' | + '\u0185' | + '\u0188' | + '\u018C' | + '\u018D' | + '\u0192' | + '\u0195' | + '\u0199'..'\u019B' | + '\u019E' | + '\u01A1' | + '\u01A3' | + '\u01A5' | + '\u01A8' | + '\u01AA' | + '\u01AB' | + '\u01AD' | + '\u01B0' | + '\u01B4' | + '\u01B6' | + '\u01B9' | + '\u01BA' | + '\u01BD'..'\u01BF' | + '\u01C6' | + '\u01C9' | + '\u01CC' | + '\u01CE' | + '\u01D0' | + '\u01D2' | + '\u01D4' | + '\u01D6' | + '\u01D8' | + '\u01DA' | + '\u01DC' | + '\u01DD' | + '\u01DF' | + '\u01E1' | + '\u01E3' | + '\u01E5' | + '\u01E7' | + '\u01E9' | + '\u01EB' | + '\u01ED' | + '\u01EF' | + '\u01F0' | + '\u01F3' | + '\u01F5' | + '\u01F9' | + '\u01FB' | + '\u01FD' | + '\u01FF' | + '\u0201' | + '\u0203' | + '\u0205' | + '\u0207' | + '\u0209' | + '\u020B' | + '\u020D' | + '\u020F' | + '\u0211' | + '\u0213' | + '\u0215' | + '\u0217' | + '\u0219' | + '\u021B' | + '\u021D' | + '\u021F' | + '\u0221' | + '\u0223' | + '\u0225' | + '\u0227' | + '\u0229' | + '\u022B' | + '\u022D' | + '\u022F' | + '\u0231' | + '\u0233'..'\u0239' | + '\u023C' | + '\u023F' | + '\u0240' | + '\u0242' | + '\u0247' | + '\u0249' | + '\u024B' | + '\u024D' | + '\u024F'..'\u0293' | + '\u0295'..'\u02AF' | + '\u0371' | + '\u0373' | + '\u0377' | + '\u037B'..'\u037D' | + '\u0390' | + '\u03AC'..'\u03CE' | + '\u03D0' | + '\u03D1' | + '\u03D5'..'\u03D7' | + '\u03D9' | + '\u03DB' | + '\u03DD' | + '\u03DF' | + '\u03E1' | + '\u03E3' | + '\u03E5' | + '\u03E7' | + '\u03E9' | + '\u03EB' | + '\u03ED' | + '\u03EF'..'\u03F3' | + '\u03F5' | + '\u03F8' | + '\u03FB' | + '\u03FC' | + '\u0430'..'\u045F' | + '\u0461' | + '\u0463' | + '\u0465' | + '\u0467' | + '\u0469' | + '\u046B' | + '\u046D' | + '\u046F' | + '\u0471' | + '\u0473' | + '\u0475' | + '\u0477' | + '\u0479' | + '\u047B' | + '\u047D' | + '\u047F' | + '\u0481' | + '\u048B' | + '\u048D' | + '\u048F' | + '\u0491' | + '\u0493' | + '\u0495' | + '\u0497' | + '\u0499' | + '\u049B' | + '\u049D' | + '\u049F' | + '\u04A1' | + '\u04A3' | + '\u04A5' | + '\u04A7' | + '\u04A9' | + '\u04AB' | + '\u04AD' | + '\u04AF' | + '\u04B1' | + '\u04B3' | + '\u04B5' | + '\u04B7' | + '\u04B9' | + '\u04BB' | + '\u04BD' | + '\u04BF' | + '\u04C2' | + '\u04C4' | + '\u04C6' | + '\u04C8' | + '\u04CA' | + '\u04CC' | + '\u04CE' | + '\u04CF' | + '\u04D1' | + '\u04D3' | + '\u04D5' | + '\u04D7' | + '\u04D9' | + '\u04DB' | + '\u04DD' | + '\u04DF' | + '\u04E1' | + '\u04E3' | + '\u04E5' | + '\u04E7' | + '\u04E9' | + '\u04EB' | + '\u04ED' | + '\u04EF' | + '\u04F1' | + '\u04F3' | + '\u04F5' | + '\u04F7' | + '\u04F9' | + '\u04FB' | + '\u04FD' | + '\u04FF' | + '\u0501' | + '\u0503' | + '\u0505' | + '\u0507' | + '\u0509' | + '\u050B' | + '\u050D' | + '\u050F' | + '\u0511' | + '\u0513' | + '\u0515' | + '\u0517' | + '\u0519' | + '\u051B' | + '\u051D' | + '\u051F' | + '\u0521' | + '\u0523' | + '\u0525' | + '\u0527' | + '\u0561'..'\u0587' | + '\u1D00'..'\u1D2B' | + '\u1D6B'..'\u1D77' | + '\u1D79'..'\u1D9A' | + '\u1E01' | + '\u1E03' | + '\u1E05' | + '\u1E07' | + '\u1E09' | + '\u1E0B' | + '\u1E0D' | + '\u1E0F' | + '\u1E11' | + '\u1E13' | + '\u1E15' | + '\u1E17' | + '\u1E19' | + '\u1E1B' | + '\u1E1D' | + '\u1E1F' | + '\u1E21' | + '\u1E23' | + '\u1E25' | + '\u1E27' | + '\u1E29' | + '\u1E2B' | + '\u1E2D' | + '\u1E2F' | + '\u1E31' | + '\u1E33' | + '\u1E35' | + '\u1E37' | + '\u1E39' | + '\u1E3B' | + '\u1E3D' | + '\u1E3F' | + '\u1E41' | + '\u1E43' | + '\u1E45' | + '\u1E47' | + '\u1E49' | + '\u1E4B' | + '\u1E4D' | + '\u1E4F' | + '\u1E51' | + '\u1E53' | + '\u1E55' | + '\u1E57' | + '\u1E59' | + '\u1E5B' | + '\u1E5D' | + '\u1E5F' | + '\u1E61' | + '\u1E63' | + '\u1E65' | + '\u1E67' | + '\u1E69' | + '\u1E6B' | + '\u1E6D' | + '\u1E6F' | + '\u1E71' | + '\u1E73' | + '\u1E75' | + '\u1E77' | + '\u1E79' | + '\u1E7B' | + '\u1E7D' | + '\u1E7F' | + '\u1E81' | + '\u1E83' | + '\u1E85' | + '\u1E87' | + '\u1E89' | + '\u1E8B' | + '\u1E8D' | + '\u1E8F' | + '\u1E91' | + '\u1E93' | + '\u1E95'..'\u1E9D' | + '\u1E9F' | + '\u1EA1' | + '\u1EA3' | + '\u1EA5' | + '\u1EA7' | + '\u1EA9' | + '\u1EAB' | + '\u1EAD' | + '\u1EAF' | + '\u1EB1' | + '\u1EB3' | + '\u1EB5' | + '\u1EB7' | + '\u1EB9' | + '\u1EBB' | + '\u1EBD' | + '\u1EBF' | + '\u1EC1' | + '\u1EC3' | + '\u1EC5' | + '\u1EC7' | + '\u1EC9' | + '\u1ECB' | + '\u1ECD' | + '\u1ECF' | + '\u1ED1' | + '\u1ED3' | + '\u1ED5' | + '\u1ED7' | + '\u1ED9' | + '\u1EDB' | + '\u1EDD' | + '\u1EDF' | + '\u1EE1' | + '\u1EE3' | + '\u1EE5' | + '\u1EE7' | + '\u1EE9' | + '\u1EEB' | + '\u1EED' | + '\u1EEF' | + '\u1EF1' | + '\u1EF3' | + '\u1EF5' | + '\u1EF7' | + '\u1EF9' | + '\u1EFB' | + '\u1EFD' | + '\u1EFF'..'\u1F07' | + '\u1F10'..'\u1F15' | + '\u1F20'..'\u1F27' | + '\u1F30'..'\u1F37' | + '\u1F40'..'\u1F45' | + '\u1F50'..'\u1F57' | + '\u1F60'..'\u1F67' | + '\u1F70'..'\u1F7D' | + '\u1F80'..'\u1F87' | + '\u1F90'..'\u1F97' | + '\u1FA0'..'\u1FA7' | + '\u1FB0'..'\u1FB4' | + '\u1FB6' | + '\u1FB7' | + '\u1FBE' | + '\u1FC2'..'\u1FC4' | + '\u1FC6' | + '\u1FC7' | + '\u1FD0'..'\u1FD3' | + '\u1FD6' | + '\u1FD7' | + '\u1FE0'..'\u1FE7' | + '\u1FF2'..'\u1FF4' | + '\u1FF6' | + '\u1FF7' | + '\u210A' | + '\u210E' | + '\u210F' | + '\u2113' | + '\u212F' | + '\u2134' | + '\u2139' | + '\u213C' | + '\u213D' | + '\u2146'..'\u2149' | + '\u214E' | + '\u2184' | + '\u2C30'..'\u2C5E' | + '\u2C61' | + '\u2C65' | + '\u2C66' | + '\u2C68' | + '\u2C6A' | + '\u2C6C' | + '\u2C71' | + '\u2C73' | + '\u2C74' | + '\u2C76'..'\u2C7B' | + '\u2C81' | + '\u2C83' | + '\u2C85' | + '\u2C87' | + '\u2C89' | + '\u2C8B' | + '\u2C8D' | + '\u2C8F' | + '\u2C91' | + '\u2C93' | + '\u2C95' | + '\u2C97' | + '\u2C99' | + '\u2C9B' | + '\u2C9D' | + '\u2C9F' | + '\u2CA1' | + '\u2CA3' | + '\u2CA5' | + '\u2CA7' | + '\u2CA9' | + '\u2CAB' | + '\u2CAD' | + '\u2CAF' | + '\u2CB1' | + '\u2CB3' | + '\u2CB5' | + '\u2CB7' | + '\u2CB9' | + '\u2CBB' | + '\u2CBD' | + '\u2CBF' | + '\u2CC1' | + '\u2CC3' | + '\u2CC5' | + '\u2CC7' | + '\u2CC9' | + '\u2CCB' | + '\u2CCD' | + '\u2CCF' | + '\u2CD1' | + '\u2CD3' | + '\u2CD5' | + '\u2CD7' | + '\u2CD9' | + '\u2CDB' | + '\u2CDD' | + '\u2CDF' | + '\u2CE1' | + '\u2CE3' | + '\u2CE4' | + '\u2CEC' | + '\u2CEE' | + '\u2CF3' | + '\u2D00'..'\u2D25' | + '\u2D27' | + '\u2D2D' | + '\uA641' | + '\uA643' | + '\uA645' | + '\uA647' | + '\uA649' | + '\uA64B' | + '\uA64D' | + '\uA64F' | + '\uA651' | + '\uA653' | + '\uA655' | + '\uA657' | + '\uA659' | + '\uA65B' | + '\uA65D' | + '\uA65F' | + '\uA661' | + '\uA663' | + '\uA665' | + '\uA667' | + '\uA669' | + '\uA66B' | + '\uA66D' | + '\uA681' | + '\uA683' | + '\uA685' | + '\uA687' | + '\uA689' | + '\uA68B' | + '\uA68D' | + '\uA68F' | + '\uA691' | + '\uA693' | + '\uA695' | + '\uA697' | + '\uA723' | + '\uA725' | + '\uA727' | + '\uA729' | + '\uA72B' | + '\uA72D' | + '\uA72F'..'\uA731' | + '\uA733' | + '\uA735' | + '\uA737' | + '\uA739' | + '\uA73B' | + '\uA73D' | + '\uA73F' | + '\uA741' | + '\uA743' | + '\uA745' | + '\uA747' | + '\uA749' | + '\uA74B' | + '\uA74D' | + '\uA74F' | + '\uA751' | + '\uA753' | + '\uA755' | + '\uA757' | + '\uA759' | + '\uA75B' | + '\uA75D' | + '\uA75F' | + '\uA761' | + '\uA763' | + '\uA765' | + '\uA767' | + '\uA769' | + '\uA76B' | + '\uA76D' | + '\uA76F' | + '\uA771'..'\uA778' | + '\uA77A' | + '\uA77C' | + '\uA77F' | + '\uA781' | + '\uA783' | + '\uA785' | + '\uA787' | + '\uA78C' | + '\uA78E' | + '\uA791' | + '\uA793' | + '\uA7A1' | + '\uA7A3' | + '\uA7A5' | + '\uA7A7' | + '\uA7A9' | + '\uA7FA' | + '\uFB00'..'\uFB06' | + '\uFB13'..'\uFB17' | + '\uFF41'..'\uFF5A'; + +UNICODE_CLASS_LM: + '\u02B0'..'\u02C1' | + '\u02C6'..'\u02D1' | + '\u02E0'..'\u02E4' | + '\u02EC' | + '\u02EE' | + '\u0374' | + '\u037A' | + '\u0559' | + '\u0640' | + '\u06E5' | + '\u06E6' | + '\u07F4' | + '\u07F5' | + '\u07FA' | + '\u081A' | + '\u0824' | + '\u0828' | + '\u0971' | + '\u0E46' | + '\u0EC6' | + '\u10FC' | + '\u17D7' | + '\u1843' | + '\u1AA7' | + '\u1C78'..'\u1C7D' | + '\u1D2C'..'\u1D6A' | + '\u1D78' | + '\u1D9B'..'\u1DBF' | + '\u2071' | + '\u207F' | + '\u2090'..'\u209C' | + '\u2C7C' | + '\u2C7D' | + '\u2D6F' | + '\u2E2F' | + '\u3005' | + '\u3031'..'\u3035' | + '\u303B' | + '\u309D' | + '\u309E' | + '\u30FC'..'\u30FE' | + '\uA015' | + '\uA4F8'..'\uA4FD' | + '\uA60C' | + '\uA67F' | + '\uA717'..'\uA71F' | + '\uA770' | + '\uA788' | + '\uA7F8' | + '\uA7F9' | + '\uA9CF' | + '\uAA70' | + '\uAADD' | + '\uAAF3' | + '\uAAF4' | + '\uFF70' | + '\uFF9E' | + '\uFF9F'; + +UNICODE_CLASS_LO: + '\u00AA' | + '\u00BA' | + '\u01BB' | + '\u01C0'..'\u01C3' | + '\u0294' | + '\u05D0'..'\u05EA' | + '\u05F0'..'\u05F2' | + '\u0620'..'\u063F' | + '\u0641'..'\u064A' | + '\u066E' | + '\u066F' | + '\u0671'..'\u06D3' | + '\u06D5' | + '\u06EE' | + '\u06EF' | + '\u06FA'..'\u06FC' | + '\u06FF' | + '\u0710' | + '\u0712'..'\u072F' | + '\u074D'..'\u07A5' | + '\u07B1' | + '\u07CA'..'\u07EA' | + '\u0800'..'\u0815' | + '\u0840'..'\u0858' | + '\u08A0' | + '\u08A2'..'\u08AC' | + '\u0904'..'\u0939' | + '\u093D' | + '\u0950' | + '\u0958'..'\u0961' | + '\u0972'..'\u0977' | + '\u0979'..'\u097F' | + '\u0985'..'\u098C' | + '\u098F' | + '\u0990' | + '\u0993'..'\u09A8' | + '\u09AA'..'\u09B0' | + '\u09B2' | + '\u09B6'..'\u09B9' | + '\u09BD' | + '\u09CE' | + '\u09DC' | + '\u09DD' | + '\u09DF'..'\u09E1' | + '\u09F0' | + '\u09F1' | + '\u0A05'..'\u0A0A' | + '\u0A0F' | + '\u0A10' | + '\u0A13'..'\u0A28' | + '\u0A2A'..'\u0A30' | + '\u0A32' | + '\u0A33' | + '\u0A35' | + '\u0A36' | + '\u0A38' | + '\u0A39' | + '\u0A59'..'\u0A5C' | + '\u0A5E' | + '\u0A72'..'\u0A74' | + '\u0A85'..'\u0A8D' | + '\u0A8F'..'\u0A91' | + '\u0A93'..'\u0AA8' | + '\u0AAA'..'\u0AB0' | + '\u0AB2' | + '\u0AB3' | + '\u0AB5'..'\u0AB9' | + '\u0ABD' | + '\u0AD0' | + '\u0AE0' | + '\u0AE1' | + '\u0B05'..'\u0B0C' | + '\u0B0F' | + '\u0B10' | + '\u0B13'..'\u0B28' | + '\u0B2A'..'\u0B30' | + '\u0B32' | + '\u0B33' | + '\u0B35'..'\u0B39' | + '\u0B3D' | + '\u0B5C' | + '\u0B5D' | + '\u0B5F'..'\u0B61' | + '\u0B71' | + '\u0B83' | + '\u0B85'..'\u0B8A' | + '\u0B8E'..'\u0B90' | + '\u0B92'..'\u0B95' | + '\u0B99' | + '\u0B9A' | + '\u0B9C' | + '\u0B9E' | + '\u0B9F' | + '\u0BA3' | + '\u0BA4' | + '\u0BA8'..'\u0BAA' | + '\u0BAE'..'\u0BB9' | + '\u0BD0' | + '\u0C05'..'\u0C0C' | + '\u0C0E'..'\u0C10' | + '\u0C12'..'\u0C28' | + '\u0C2A'..'\u0C33' | + '\u0C35'..'\u0C39' | + '\u0C3D' | + '\u0C58' | + '\u0C59' | + '\u0C60' | + '\u0C61' | + '\u0C85'..'\u0C8C' | + '\u0C8E'..'\u0C90' | + '\u0C92'..'\u0CA8' | + '\u0CAA'..'\u0CB3' | + '\u0CB5'..'\u0CB9' | + '\u0CBD' | + '\u0CDE' | + '\u0CE0' | + '\u0CE1' | + '\u0CF1' | + '\u0CF2' | + '\u0D05'..'\u0D0C' | + '\u0D0E'..'\u0D10' | + '\u0D12'..'\u0D3A' | + '\u0D3D' | + '\u0D4E' | + '\u0D60' | + '\u0D61' | + '\u0D7A'..'\u0D7F' | + '\u0D85'..'\u0D96' | + '\u0D9A'..'\u0DB1' | + '\u0DB3'..'\u0DBB' | + '\u0DBD' | + '\u0DC0'..'\u0DC6' | + '\u0E01'..'\u0E30' | + '\u0E32' | + '\u0E33' | + '\u0E40'..'\u0E45' | + '\u0E81' | + '\u0E82' | + '\u0E84' | + '\u0E87' | + '\u0E88' | + '\u0E8A' | + '\u0E8D' | + '\u0E94'..'\u0E97' | + '\u0E99'..'\u0E9F' | + '\u0EA1'..'\u0EA3' | + '\u0EA5' | + '\u0EA7' | + '\u0EAA' | + '\u0EAB' | + '\u0EAD'..'\u0EB0' | + '\u0EB2' | + '\u0EB3' | + '\u0EBD' | + '\u0EC0'..'\u0EC4' | + '\u0EDC'..'\u0EDF' | + '\u0F00' | + '\u0F40'..'\u0F47' | + '\u0F49'..'\u0F6C' | + '\u0F88'..'\u0F8C' | + '\u1000'..'\u102A' | + '\u103F' | + '\u1050'..'\u1055' | + '\u105A'..'\u105D' | + '\u1061' | + '\u1065' | + '\u1066' | + '\u106E'..'\u1070' | + '\u1075'..'\u1081' | + '\u108E' | + '\u10D0'..'\u10FA' | + '\u10FD'..'\u1248' | + '\u124A'..'\u124D' | + '\u1250'..'\u1256' | + '\u1258' | + '\u125A'..'\u125D' | + '\u1260'..'\u1288' | + '\u128A'..'\u128D' | + '\u1290'..'\u12B0' | + '\u12B2'..'\u12B5' | + '\u12B8'..'\u12BE' | + '\u12C0' | + '\u12C2'..'\u12C5' | + '\u12C8'..'\u12D6' | + '\u12D8'..'\u1310' | + '\u1312'..'\u1315' | + '\u1318'..'\u135A' | + '\u1380'..'\u138F' | + '\u13A0'..'\u13F4' | + '\u1401'..'\u166C' | + '\u166F'..'\u167F' | + '\u1681'..'\u169A' | + '\u16A0'..'\u16EA' | + '\u1700'..'\u170C' | + '\u170E'..'\u1711' | + '\u1720'..'\u1731' | + '\u1740'..'\u1751' | + '\u1760'..'\u176C' | + '\u176E'..'\u1770' | + '\u1780'..'\u17B3' | + '\u17DC' | + '\u1820'..'\u1842' | + '\u1844'..'\u1877' | + '\u1880'..'\u18A8' | + '\u18AA' | + '\u18B0'..'\u18F5' | + '\u1900'..'\u191C' | + '\u1950'..'\u196D' | + '\u1970'..'\u1974' | + '\u1980'..'\u19AB' | + '\u19C1'..'\u19C7' | + '\u1A00'..'\u1A16' | + '\u1A20'..'\u1A54' | + '\u1B05'..'\u1B33' | + '\u1B45'..'\u1B4B' | + '\u1B83'..'\u1BA0' | + '\u1BAE' | + '\u1BAF' | + '\u1BBA'..'\u1BE5' | + '\u1C00'..'\u1C23' | + '\u1C4D'..'\u1C4F' | + '\u1C5A'..'\u1C77' | + '\u1CE9'..'\u1CEC' | + '\u1CEE'..'\u1CF1' | + '\u1CF5' | + '\u1CF6' | + '\u2135'..'\u2138' | + '\u2D30'..'\u2D67' | + '\u2D80'..'\u2D96' | + '\u2DA0'..'\u2DA6' | + '\u2DA8'..'\u2DAE' | + '\u2DB0'..'\u2DB6' | + '\u2DB8'..'\u2DBE' | + '\u2DC0'..'\u2DC6' | + '\u2DC8'..'\u2DCE' | + '\u2DD0'..'\u2DD6' | + '\u2DD8'..'\u2DDE' | + '\u3006' | + '\u303C' | + '\u3041'..'\u3096' | + '\u309F' | + '\u30A1'..'\u30FA' | + '\u30FF' | + '\u3105'..'\u312D' | + '\u3131'..'\u318E' | + '\u31A0'..'\u31BA' | + '\u31F0'..'\u31FF' | + '\u3400' | + '\u4DB5' | + '\u4E00' | + '\u9FCC' | + '\uA000'..'\uA014' | + '\uA016'..'\uA48C' | + '\uA4D0'..'\uA4F7' | + '\uA500'..'\uA60B' | + '\uA610'..'\uA61F' | + '\uA62A' | + '\uA62B' | + '\uA66E' | + '\uA6A0'..'\uA6E5' | + '\uA7FB'..'\uA801' | + '\uA803'..'\uA805' | + '\uA807'..'\uA80A' | + '\uA80C'..'\uA822' | + '\uA840'..'\uA873' | + '\uA882'..'\uA8B3' | + '\uA8F2'..'\uA8F7' | + '\uA8FB' | + '\uA90A'..'\uA925' | + '\uA930'..'\uA946' | + '\uA960'..'\uA97C' | + '\uA984'..'\uA9B2' | + '\uAA00'..'\uAA28' | + '\uAA40'..'\uAA42' | + '\uAA44'..'\uAA4B' | + '\uAA60'..'\uAA6F' | + '\uAA71'..'\uAA76' | + '\uAA7A' | + '\uAA80'..'\uAAAF' | + '\uAAB1' | + '\uAAB5' | + '\uAAB6' | + '\uAAB9'..'\uAABD' | + '\uAAC0' | + '\uAAC2' | + '\uAADB' | + '\uAADC' | + '\uAAE0'..'\uAAEA' | + '\uAAF2' | + '\uAB01'..'\uAB06' | + '\uAB09'..'\uAB0E' | + '\uAB11'..'\uAB16' | + '\uAB20'..'\uAB26' | + '\uAB28'..'\uAB2E' | + '\uABC0'..'\uABE2' | + '\uAC00' | + '\uD7A3' | + '\uD7B0'..'\uD7C6' | + '\uD7CB'..'\uD7FB' | + '\uF900'..'\uFA6D' | + '\uFA70'..'\uFAD9' | + '\uFB1D' | + '\uFB1F'..'\uFB28' | + '\uFB2A'..'\uFB36' | + '\uFB38'..'\uFB3C' | + '\uFB3E' | + '\uFB40' | + '\uFB41' | + '\uFB43' | + '\uFB44' | + '\uFB46'..'\uFBB1' | + '\uFBD3'..'\uFD3D' | + '\uFD50'..'\uFD8F' | + '\uFD92'..'\uFDC7' | + '\uFDF0'..'\uFDFB' | + '\uFE70'..'\uFE74' | + '\uFE76'..'\uFEFC' | + '\uFF66'..'\uFF6F' | + '\uFF71'..'\uFF9D' | + '\uFFA0'..'\uFFBE' | + '\uFFC2'..'\uFFC7' | + '\uFFCA'..'\uFFCF' | + '\uFFD2'..'\uFFD7' | + '\uFFDA'..'\uFFDC'; + +UNICODE_CLASS_LT: + '\u01C5' | + '\u01C8' | + '\u01CB' | + '\u01F2' | + '\u1F88'..'\u1F8F' | + '\u1F98'..'\u1F9F' | + '\u1FA8'..'\u1FAF' | + '\u1FBC' | + '\u1FCC' | + '\u1FFC'; + +UNICODE_CLASS_LU: + '\u0041'..'\u005A' | + '\u00C0'..'\u00D6' | + '\u00D8'..'\u00DE' | + '\u0100' | + '\u0102' | + '\u0104' | + '\u0106' | + '\u0108' | + '\u010A' | + '\u010C' | + '\u010E' | + '\u0110' | + '\u0112' | + '\u0114' | + '\u0116' | + '\u0118' | + '\u011A' | + '\u011C' | + '\u011E' | + '\u0120' | + '\u0122' | + '\u0124' | + '\u0126' | + '\u0128' | + '\u012A' | + '\u012C' | + '\u012E' | + '\u0130' | + '\u0132' | + '\u0134' | + '\u0136' | + '\u0139' | + '\u013B' | + '\u013D' | + '\u013F' | + '\u0141' | + '\u0143' | + '\u0145' | + '\u0147' | + '\u014A' | + '\u014C' | + '\u014E' | + '\u0150' | + '\u0152' | + '\u0154' | + '\u0156' | + '\u0158' | + '\u015A' | + '\u015C' | + '\u015E' | + '\u0160' | + '\u0162' | + '\u0164' | + '\u0166' | + '\u0168' | + '\u016A' | + '\u016C' | + '\u016E' | + '\u0170' | + '\u0172' | + '\u0174' | + '\u0176' | + '\u0178' | + '\u0179' | + '\u017B' | + '\u017D' | + '\u0181' | + '\u0182' | + '\u0184' | + '\u0186' | + '\u0187' | + '\u0189'..'\u018B' | + '\u018E'..'\u0191' | + '\u0193' | + '\u0194' | + '\u0196'..'\u0198' | + '\u019C' | + '\u019D' | + '\u019F' | + '\u01A0' | + '\u01A2' | + '\u01A4' | + '\u01A6' | + '\u01A7' | + '\u01A9' | + '\u01AC' | + '\u01AE' | + '\u01AF' | + '\u01B1'..'\u01B3' | + '\u01B5' | + '\u01B7' | + '\u01B8' | + '\u01BC' | + '\u01C4' | + '\u01C7' | + '\u01CA' | + '\u01CD' | + '\u01CF' | + '\u01D1' | + '\u01D3' | + '\u01D5' | + '\u01D7' | + '\u01D9' | + '\u01DB' | + '\u01DE' | + '\u01E0' | + '\u01E2' | + '\u01E4' | + '\u01E6' | + '\u01E8' | + '\u01EA' | + '\u01EC' | + '\u01EE' | + '\u01F1' | + '\u01F4' | + '\u01F6'..'\u01F8' | + '\u01FA' | + '\u01FC' | + '\u01FE' | + '\u0200' | + '\u0202' | + '\u0204' | + '\u0206' | + '\u0208' | + '\u020A' | + '\u020C' | + '\u020E' | + '\u0210' | + '\u0212' | + '\u0214' | + '\u0216' | + '\u0218' | + '\u021A' | + '\u021C' | + '\u021E' | + '\u0220' | + '\u0222' | + '\u0224' | + '\u0226' | + '\u0228' | + '\u022A' | + '\u022C' | + '\u022E' | + '\u0230' | + '\u0232' | + '\u023A' | + '\u023B' | + '\u023D' | + '\u023E' | + '\u0241' | + '\u0243'..'\u0246' | + '\u0248' | + '\u024A' | + '\u024C' | + '\u024E' | + '\u0370' | + '\u0372' | + '\u0376' | + '\u0386' | + '\u0388'..'\u038A' | + '\u038C' | + '\u038E' | + '\u038F' | + '\u0391'..'\u03A1' | + '\u03A3'..'\u03AB' | + '\u03CF' | + '\u03D2'..'\u03D4' | + '\u03D8' | + '\u03DA' | + '\u03DC' | + '\u03DE' | + '\u03E0' | + '\u03E2' | + '\u03E4' | + '\u03E6' | + '\u03E8' | + '\u03EA' | + '\u03EC' | + '\u03EE' | + '\u03F4' | + '\u03F7' | + '\u03F9' | + '\u03FA' | + '\u03FD'..'\u042F' | + '\u0460' | + '\u0462' | + '\u0464' | + '\u0466' | + '\u0468' | + '\u046A' | + '\u046C' | + '\u046E' | + '\u0470' | + '\u0472' | + '\u0474' | + '\u0476' | + '\u0478' | + '\u047A' | + '\u047C' | + '\u047E' | + '\u0480' | + '\u048A' | + '\u048C' | + '\u048E' | + '\u0490' | + '\u0492' | + '\u0494' | + '\u0496' | + '\u0498' | + '\u049A' | + '\u049C' | + '\u049E' | + '\u04A0' | + '\u04A2' | + '\u04A4' | + '\u04A6' | + '\u04A8' | + '\u04AA' | + '\u04AC' | + '\u04AE' | + '\u04B0' | + '\u04B2' | + '\u04B4' | + '\u04B6' | + '\u04B8' | + '\u04BA' | + '\u04BC' | + '\u04BE' | + '\u04C0' | + '\u04C1' | + '\u04C3' | + '\u04C5' | + '\u04C7' | + '\u04C9' | + '\u04CB' | + '\u04CD' | + '\u04D0' | + '\u04D2' | + '\u04D4' | + '\u04D6' | + '\u04D8' | + '\u04DA' | + '\u04DC' | + '\u04DE' | + '\u04E0' | + '\u04E2' | + '\u04E4' | + '\u04E6' | + '\u04E8' | + '\u04EA' | + '\u04EC' | + '\u04EE' | + '\u04F0' | + '\u04F2' | + '\u04F4' | + '\u04F6' | + '\u04F8' | + '\u04FA' | + '\u04FC' | + '\u04FE' | + '\u0500' | + '\u0502' | + '\u0504' | + '\u0506' | + '\u0508' | + '\u050A' | + '\u050C' | + '\u050E' | + '\u0510' | + '\u0512' | + '\u0514' | + '\u0516' | + '\u0518' | + '\u051A' | + '\u051C' | + '\u051E' | + '\u0520' | + '\u0522' | + '\u0524' | + '\u0526' | + '\u0531'..'\u0556' | + '\u10A0'..'\u10C5' | + '\u10C7' | + '\u10CD' | + '\u1E00' | + '\u1E02' | + '\u1E04' | + '\u1E06' | + '\u1E08' | + '\u1E0A' | + '\u1E0C' | + '\u1E0E' | + '\u1E10' | + '\u1E12' | + '\u1E14' | + '\u1E16' | + '\u1E18' | + '\u1E1A' | + '\u1E1C' | + '\u1E1E' | + '\u1E20' | + '\u1E22' | + '\u1E24' | + '\u1E26' | + '\u1E28' | + '\u1E2A' | + '\u1E2C' | + '\u1E2E' | + '\u1E30' | + '\u1E32' | + '\u1E34' | + '\u1E36' | + '\u1E38' | + '\u1E3A' | + '\u1E3C' | + '\u1E3E' | + '\u1E40' | + '\u1E42' | + '\u1E44' | + '\u1E46' | + '\u1E48' | + '\u1E4A' | + '\u1E4C' | + '\u1E4E' | + '\u1E50' | + '\u1E52' | + '\u1E54' | + '\u1E56' | + '\u1E58' | + '\u1E5A' | + '\u1E5C' | + '\u1E5E' | + '\u1E60' | + '\u1E62' | + '\u1E64' | + '\u1E66' | + '\u1E68' | + '\u1E6A' | + '\u1E6C' | + '\u1E6E' | + '\u1E70' | + '\u1E72' | + '\u1E74' | + '\u1E76' | + '\u1E78' | + '\u1E7A' | + '\u1E7C' | + '\u1E7E' | + '\u1E80' | + '\u1E82' | + '\u1E84' | + '\u1E86' | + '\u1E88' | + '\u1E8A' | + '\u1E8C' | + '\u1E8E' | + '\u1E90' | + '\u1E92' | + '\u1E94' | + '\u1E9E' | + '\u1EA0' | + '\u1EA2' | + '\u1EA4' | + '\u1EA6' | + '\u1EA8' | + '\u1EAA' | + '\u1EAC' | + '\u1EAE' | + '\u1EB0' | + '\u1EB2' | + '\u1EB4' | + '\u1EB6' | + '\u1EB8' | + '\u1EBA' | + '\u1EBC' | + '\u1EBE' | + '\u1EC0' | + '\u1EC2' | + '\u1EC4' | + '\u1EC6' | + '\u1EC8' | + '\u1ECA' | + '\u1ECC' | + '\u1ECE' | + '\u1ED0' | + '\u1ED2' | + '\u1ED4' | + '\u1ED6' | + '\u1ED8' | + '\u1EDA' | + '\u1EDC' | + '\u1EDE' | + '\u1EE0' | + '\u1EE2' | + '\u1EE4' | + '\u1EE6' | + '\u1EE8' | + '\u1EEA' | + '\u1EEC' | + '\u1EEE' | + '\u1EF0' | + '\u1EF2' | + '\u1EF4' | + '\u1EF6' | + '\u1EF8' | + '\u1EFA' | + '\u1EFC' | + '\u1EFE' | + '\u1F08'..'\u1F0F' | + '\u1F18'..'\u1F1D' | + '\u1F28'..'\u1F2F' | + '\u1F38'..'\u1F3F' | + '\u1F48'..'\u1F4D' | + '\u1F59' | + '\u1F5B' | + '\u1F5D' | + '\u1F5F' | + '\u1F68'..'\u1F6F' | + '\u1FB8'..'\u1FBB' | + '\u1FC8'..'\u1FCB' | + '\u1FD8'..'\u1FDB' | + '\u1FE8'..'\u1FEC' | + '\u1FF8'..'\u1FFB' | + '\u2102' | + '\u2107' | + '\u210B'..'\u210D' | + '\u2110'..'\u2112' | + '\u2115' | + '\u2119'..'\u211D' | + '\u2124' | + '\u2126' | + '\u2128' | + '\u212A'..'\u212D' | + '\u2130'..'\u2133' | + '\u213E' | + '\u213F' | + '\u2145' | + '\u2183' | + '\u2C00'..'\u2C2E' | + '\u2C60' | + '\u2C62'..'\u2C64' | + '\u2C67' | + '\u2C69' | + '\u2C6B' | + '\u2C6D'..'\u2C70' | + '\u2C72' | + '\u2C75' | + '\u2C7E'..'\u2C80' | + '\u2C82' | + '\u2C84' | + '\u2C86' | + '\u2C88' | + '\u2C8A' | + '\u2C8C' | + '\u2C8E' | + '\u2C90' | + '\u2C92' | + '\u2C94' | + '\u2C96' | + '\u2C98' | + '\u2C9A' | + '\u2C9C' | + '\u2C9E' | + '\u2CA0' | + '\u2CA2' | + '\u2CA4' | + '\u2CA6' | + '\u2CA8' | + '\u2CAA' | + '\u2CAC' | + '\u2CAE' | + '\u2CB0' | + '\u2CB2' | + '\u2CB4' | + '\u2CB6' | + '\u2CB8' | + '\u2CBA' | + '\u2CBC' | + '\u2CBE' | + '\u2CC0' | + '\u2CC2' | + '\u2CC4' | + '\u2CC6' | + '\u2CC8' | + '\u2CCA' | + '\u2CCC' | + '\u2CCE' | + '\u2CD0' | + '\u2CD2' | + '\u2CD4' | + '\u2CD6' | + '\u2CD8' | + '\u2CDA' | + '\u2CDC' | + '\u2CDE' | + '\u2CE0' | + '\u2CE2' | + '\u2CEB' | + '\u2CED' | + '\u2CF2' | + '\uA640' | + '\uA642' | + '\uA644' | + '\uA646' | + '\uA648' | + '\uA64A' | + '\uA64C' | + '\uA64E' | + '\uA650' | + '\uA652' | + '\uA654' | + '\uA656' | + '\uA658' | + '\uA65A' | + '\uA65C' | + '\uA65E' | + '\uA660' | + '\uA662' | + '\uA664' | + '\uA666' | + '\uA668' | + '\uA66A' | + '\uA66C' | + '\uA680' | + '\uA682' | + '\uA684' | + '\uA686' | + '\uA688' | + '\uA68A' | + '\uA68C' | + '\uA68E' | + '\uA690' | + '\uA692' | + '\uA694' | + '\uA696' | + '\uA722' | + '\uA724' | + '\uA726' | + '\uA728' | + '\uA72A' | + '\uA72C' | + '\uA72E' | + '\uA732' | + '\uA734' | + '\uA736' | + '\uA738' | + '\uA73A' | + '\uA73C' | + '\uA73E' | + '\uA740' | + '\uA742' | + '\uA744' | + '\uA746' | + '\uA748' | + '\uA74A' | + '\uA74C' | + '\uA74E' | + '\uA750' | + '\uA752' | + '\uA754' | + '\uA756' | + '\uA758' | + '\uA75A' | + '\uA75C' | + '\uA75E' | + '\uA760' | + '\uA762' | + '\uA764' | + '\uA766' | + '\uA768' | + '\uA76A' | + '\uA76C' | + '\uA76E' | + '\uA779' | + '\uA77B' | + '\uA77D' | + '\uA77E' | + '\uA780' | + '\uA782' | + '\uA784' | + '\uA786' | + '\uA78B' | + '\uA78D' | + '\uA790' | + '\uA792' | + '\uA7A0' | + '\uA7A2' | + '\uA7A4' | + '\uA7A6' | + '\uA7A8' | + '\uA7AA' | + '\uFF21'..'\uFF3A'; + +UNICODE_CLASS_ND: + '\u0030'..'\u0039' | + '\u0660'..'\u0669' | + '\u06F0'..'\u06F9' | + '\u07C0'..'\u07C9' | + '\u0966'..'\u096F' | + '\u09E6'..'\u09EF' | + '\u0A66'..'\u0A6F' | + '\u0AE6'..'\u0AEF' | + '\u0B66'..'\u0B6F' | + '\u0BE6'..'\u0BEF' | + '\u0C66'..'\u0C6F' | + '\u0CE6'..'\u0CEF' | + '\u0D66'..'\u0D6F' | + '\u0E50'..'\u0E59' | + '\u0ED0'..'\u0ED9' | + '\u0F20'..'\u0F29' | + '\u1040'..'\u1049' | + '\u1090'..'\u1099' | + '\u17E0'..'\u17E9' | + '\u1810'..'\u1819' | + '\u1946'..'\u194F' | + '\u19D0'..'\u19D9' | + '\u1A80'..'\u1A89' | + '\u1A90'..'\u1A99' | + '\u1B50'..'\u1B59' | + '\u1BB0'..'\u1BB9' | + '\u1C40'..'\u1C49' | + '\u1C50'..'\u1C59' | + '\uA620'..'\uA629' | + '\uA8D0'..'\uA8D9' | + '\uA900'..'\uA909' | + '\uA9D0'..'\uA9D9' | + '\uAA50'..'\uAA59' | + '\uABF0'..'\uABF9' | + '\uFF10'..'\uFF19'; + +UNICODE_CLASS_NL: + '\u16EE'..'\u16F0' | + '\u2160'..'\u2182' | + '\u2185'..'\u2188' | + '\u3007' | + '\u3021'..'\u3029' | + '\u3038'..'\u303A' | + '\uA6E6'..'\uA6EF'; + +ShebangLine + : '#!' ~[\u000A\u000D]* + -> channel(HIDDEN) + ; + +DelimitedComment + : '/*' ( DelimitedComment | . )*? '*/' + -> channel(HIDDEN) + ; + +LineComment + : '//' ~[\u000A\u000D]* + -> channel(HIDDEN) + ; + +WS + : [\u0020\u0009\u000C] + -> skip + ; + +NL: '\u000A' | '\u000D' '\u000A' ; + +//SEPARATORS & OPERATIONS + +RESERVED: '...' ; +DOT: '.' ; +COMMA: ',' ; +LPAREN: '(' -> pushMode(Inside) ; +RPAREN: ')' ; +LSQUARE: '[' -> pushMode(Inside) ; +RSQUARE: ']' ; +LCURL: '{' ; +RCURL: '}' ; +MULT: '*' ; +MOD: '%' ; +DIV: '/' ; +ADD: '+' ; +SUB: '-' ; +INCR: '++' ; +DECR: '--' ; +CONJ: '&&' ; +DISJ: '||' ; +EXCL: '!' ; +COLON: ':' ; +SEMICOLON: ';' ; +ASSIGNMENT: '=' ; +ADD_ASSIGNMENT: '+=' ; +SUB_ASSIGNMENT: '-=' ; +MULT_ASSIGNMENT: '*=' ; +DIV_ASSIGNMENT: '/=' ; +MOD_ASSIGNMENT: '%=' ; +ARROW: '->' ; +DOUBLE_ARROW: '=>' ; +RANGE: '..' ; +COLONCOLON: '::' ; +Q_COLONCOLON: '?::' ; +DOUBLE_SEMICOLON: ';;' ; +HASH: '#' ; +AT: '@' ; +QUEST: '?' ; +ELVIS: '?:' ; +LANGLE: '<' ; +RANGLE: '>' ; +LE: '<=' ; +GE: '>=' ; +EXCL_EQ: '!=' ; +EXCL_EQEQ: '!==' ; +AS_SAFE: 'as?' ; +EQEQ: '==' ; +EQEQEQ: '===' ; +SINGLE_QUOTE: '\'' ; + +//KEYWORDS + +RETURN_AT: 'return@' Identifier ; +CONTINUE_AT: 'continue@' Identifier ; +BREAK_AT: 'break@' Identifier ; + +FILE: '@file' ; +PACKAGE: 'package' ; +IMPORT: 'import' ; +CLASS: 'class' ; +INTERFACE: 'interface' ; +FUN: 'fun' ; +OBJECT: 'object' ; +VAL: 'val' ; +VAR: 'var' ; +TYPE_ALIAS: 'typealias' ; +CONSTRUCTOR: 'constructor' ; +BY: 'by' ; +COMPANION: 'companion' ; +INIT: 'init' ; +THIS: 'this' ; +SUPER: 'super' ; +TYPEOF: 'typeof' ; +WHERE: 'where' ; +IF: 'if' ; +ELSE: 'else' ; +WHEN: 'when' ; +TRY: 'try' ; +CATCH: 'catch' ; +FINALLY: 'finally' ; +FOR: 'for' ; +DO: 'do' ; +WHILE: 'while' ; +THROW: 'throw' ; +RETURN: 'return' ; +CONTINUE: 'continue' ; +BREAK: 'break' ; +AS: 'as' ; +IS: 'is' ; +IN: 'in' ; +NOT_IS: '!is' (WS | NL)+ ; +NOT_IN: '!in' (WS | NL)+ ; +OUT: 'out' ; +FIELD: '@field' ; +PROPERTY: '@property' ; +GET: '@get' ; +SET: '@set' ; +GETTER: 'get' ; +SETTER: 'set' ; +RECEIVER: '@receiver' ; +PARAM: '@param' ; +SETPARAM: '@setparam' ; +DELEGATE: '@delegate' ; +DYNAMIC: 'dynamic' ; + +//MODIFIERS + +PUBLIC: 'public' ; +PRIVATE: 'private' ; +PROTECTED: 'protected' ; +INTERNAL: 'internal' ; +ENUM: 'enum' ; +SEALED: 'sealed' ; +ANNOTATION: 'annotation' ; +DATA: 'data' ; +INNER: 'inner' ; +TAILREC: 'tailrec' ; +OPERATOR: 'operator' ; +INLINE: 'inline' ; +INFIX: 'infix' ; +EXTERNAL: 'external' ; +SUSPEND: 'suspend' ; +OVERRIDE: 'override' ; +ABSTRACT: 'abstract' ; +FINAL: 'final' ; +OPEN: 'open' ; +CONST: 'const' ; +LATEINIT: 'lateinit' ; +VARARG: 'vararg' ; +NOINLINE: 'noinline' ; +CROSSINLINE: 'crossinline' ; +REIFIED: 'reified' ; + +// + +QUOTE_OPEN: '"' -> pushMode(LineString) ; +TRIPLE_QUOTE_OPEN: '"""' -> pushMode(MultiLineString) ; + +RealLiteral + : FloatLiteral + | DoubleLiteral + ; + +FloatLiteral + : (DoubleLiteral | IntegerLiteral) [fF] + ; + +DoubleLiteral + : ( (DecDigitNoZero DecDigit*)? '.' + | (DecDigitNoZero (DecDigit | '_')* DecDigit)? '.') + ( DecDigit+ + | DecDigit (DecDigit | '_')+ DecDigit + | DecDigit+ [eE] ('+' | '-')? DecDigit+ + | DecDigit+ [eE] ('+' | '-')? DecDigit (DecDigit | '_')+ DecDigit + | DecDigit (DecDigit | '_')+ DecDigit [eE] ('+' | '-')? DecDigit+ + | DecDigit (DecDigit | '_')+ DecDigit [eE] ('+' | '-')? DecDigit (DecDigit | '_')+ DecDigit + ) + ; + +LongLiteral + : (IntegerLiteral | HexLiteral | BinLiteral) 'L' + ; + +IntegerLiteral + : ('0' + | DecDigitNoZero DecDigit* + | DecDigitNoZero (DecDigit | '_')+ DecDigit + | DecDigitNoZero DecDigit* [eE] ('+' | '-')? DecDigit+ + | DecDigitNoZero DecDigit* [eE] ('+' | '-')? DecDigit (DecDigit | '_')+ DecDigit + | DecDigitNoZero (DecDigit | '_')+ DecDigit [eE] ('+' | '-')? DecDigit+ + | DecDigitNoZero (DecDigit | '_')+ DecDigit [eE] ('+' | '-')? DecDigit (DecDigit | '_')+ DecDigit + ) + ; + +fragment DecDigit + : UNICODE_CLASS_ND + ; + +fragment DecDigitNoZero + : UNICODE_CLASS_ND_NoZeros + ; + +fragment UNICODE_CLASS_ND_NoZeros + : '\u0031'..'\u0039' + | '\u0661'..'\u0669' + | '\u06f1'..'\u06f9' + | '\u07c1'..'\u07c9' + | '\u0967'..'\u096f' + | '\u09e7'..'\u09ef' + | '\u0a67'..'\u0a6f' + | '\u0ae7'..'\u0aef' + | '\u0b67'..'\u0b6f' + | '\u0be7'..'\u0bef' + | '\u0c67'..'\u0c6f' + | '\u0ce7'..'\u0cef' + | '\u0d67'..'\u0d6f' + | '\u0de7'..'\u0def' + | '\u0e51'..'\u0e59' + | '\u0ed1'..'\u0ed9' + | '\u0f21'..'\u0f29' + | '\u1041'..'\u1049' + | '\u1091'..'\u1099' + | '\u17e1'..'\u17e9' + | '\u1811'..'\u1819' + | '\u1947'..'\u194f' + | '\u19d1'..'\u19d9' + | '\u1a81'..'\u1a89' + | '\u1a91'..'\u1a99' + | '\u1b51'..'\u1b59' + | '\u1bb1'..'\u1bb9' + | '\u1c41'..'\u1c49' + | '\u1c51'..'\u1c59' + | '\ua621'..'\ua629' + | '\ua8d1'..'\ua8d9' + | '\ua901'..'\ua909' + | '\ua9d1'..'\ua9d9' + | '\ua9f1'..'\ua9f9' + | '\uaa51'..'\uaa59' + | '\uabf1'..'\uabf9' + | '\uff11'..'\uff19' + ; + +HexLiteral + : '0' [xX] HexDigit (HexDigit | '_')* + ; + +fragment HexDigit + : [0-9a-fA-F] + ; + +BinLiteral + : '0' [bB] BinDigit (BinDigit | '_')* + ; + +fragment BinDigit + : [01] + ; + +BooleanLiteral + : 'true' + | 'false' + ; + +NullLiteral + : 'null' + ; + +Identifier + : (Letter | '_') (Letter | '_' | DecDigit)* + | '`' ~('`')+ '`' + ; + +LabelReference + : '@' Identifier + ; + +LabelDefinition + : Identifier '@' + ; + +FieldIdentifier + : '$' Identifier + ; + +CharacterLiteral + : '\'' (EscapeSeq | .) '\'' + ; + +fragment EscapeSeq + : UniCharacterLiteral + | EscapedIdentifier + ; + +fragment UniCharacterLiteral + : '\\' 'u' HexDigit HexDigit HexDigit HexDigit + ; + +fragment EscapedIdentifier + : '\\' ('t' | 'b' | 'r' | 'n' | '\'' | '"' | '\\' | '$') + ; + +fragment Letter + : UNICODE_CLASS_LL + | UNICODE_CLASS_LM + | UNICODE_CLASS_LO + | UNICODE_CLASS_LT + | UNICODE_CLASS_LU + | UNICODE_CLASS_NL + ; + + +mode Inside ; + +Inside_RPAREN: ')' -> popMode, type(RPAREN) ; +Inside_RSQUARE: ']' -> popMode, type(RSQUARE); + +Inside_LPAREN: LPAREN -> pushMode(Inside), type(LPAREN) ; +Inside_LSQUARE: LSQUARE -> pushMode(Inside), type(LSQUARE) ; + +Inside_LCURL: LCURL -> type(LCURL) ; +Inside_RCURL: RCURL -> type(RCURL) ; +Inside_DOT: DOT -> type(DOT) ; +Inside_COMMA: COMMA -> type(COMMA) ; +Inside_MULT: MULT -> type(MULT) ; +Inside_MOD: MOD -> type(MOD) ; +Inside_DIV: DIV -> type(DIV) ; +Inside_ADD: ADD -> type(ADD) ; +Inside_SUB: SUB -> type(SUB) ; +Inside_INCR: INCR -> type(INCR) ; +Inside_DECR: DECR -> type(DECR) ; +Inside_CONJ: CONJ -> type(CONJ) ; +Inside_DISJ: DISJ -> type(DISJ) ; +Inside_EXCL: EXCL -> type(EXCL) ; +Inside_COLON: COLON -> type(COLON) ; +Inside_SEMICOLON: SEMICOLON -> type(SEMICOLON) ; +Inside_ASSIGNMENT: ASSIGNMENT -> type(ASSIGNMENT) ; +Inside_ADD_ASSIGNMENT: ADD_ASSIGNMENT -> type(ADD_ASSIGNMENT) ; +Inside_SUB_ASSIGNMENT: SUB_ASSIGNMENT -> type(SUB_ASSIGNMENT) ; +Inside_MULT_ASSIGNMENT: MULT_ASSIGNMENT -> type(MULT_ASSIGNMENT) ; +Inside_DIV_ASSIGNMENT: DIV_ASSIGNMENT -> type(DIV_ASSIGNMENT) ; +Inside_MOD_ASSIGNMENT: MOD_ASSIGNMENT -> type(MOD_ASSIGNMENT) ; +Inside_ARROW: ARROW -> type(ARROW) ; +Inside_DOUBLE_ARROW: DOUBLE_ARROW -> type(DOUBLE_ARROW) ; +Inside_RANGE: RANGE -> type(RANGE) ; +Inside_RESERVED: RESERVED -> type(RESERVED) ; +Inside_COLONCOLON: COLONCOLON -> type(COLONCOLON) ; +Inside_Q_COLONCOLON: Q_COLONCOLON -> type(Q_COLONCOLON) ; +Inside_DOUBLE_SEMICOLON: DOUBLE_SEMICOLON -> type(DOUBLE_SEMICOLON) ; +Inside_HASH: HASH -> type(HASH) ; +Inside_AT: AT -> type(AT) ; +Inside_QUEST: QUEST -> type(QUEST) ; +Inside_ELVIS: ELVIS -> type(ELVIS) ; +Inside_LANGLE: LANGLE -> type(LANGLE) ; +Inside_RANGLE: RANGLE -> type(RANGLE) ; +Inside_LE: LE -> type(LE) ; +Inside_GE: GE -> type(GE) ; +Inside_EXCL_EQ: EXCL_EQ -> type(EXCL_EQ) ; +Inside_EXCL_EQEQ: EXCL_EQEQ -> type(EXCL_EQEQ) ; +Inside_NOT_IS: NOT_IS -> type(NOT_IS) ; +Inside_NOT_IN: NOT_IN -> type(NOT_IN) ; +Inside_AS_SAFE: AS_SAFE -> type(AS_SAFE) ; +Inside_EQEQ: EQEQ -> type(EQEQ) ; +Inside_EQEQEQ: EQEQEQ -> type(EQEQEQ) ; +Inside_SINGLE_QUOTE: SINGLE_QUOTE -> type(SINGLE_QUOTE) ; +Inside_QUOTE_OPEN: QUOTE_OPEN -> pushMode(LineString), type(QUOTE_OPEN) ; +Inside_TRIPLE_QUOTE_OPEN: TRIPLE_QUOTE_OPEN -> pushMode(MultiLineString), type(TRIPLE_QUOTE_OPEN) ; + +Inside_VAL: VAL -> type(VAL) ; +Inside_VAR: VAR -> type(VAR) ; +Inside_OBJECT: OBJECT -> type(OBJECT) ; +Inside_SUPER: SUPER -> type(SUPER) ; +Inside_IN: IN -> type(IN) ; +Inside_OUT: OUT -> type(OUT) ; +Inside_FIELD: FIELD -> type(FIELD) ; +Inside_FILE: FILE -> type(FILE) ; +Inside_PROPERTY: PROPERTY -> type(PROPERTY) ; +Inside_GET: GET -> type(GET) ; +Inside_SET: SET -> type(SET) ; +Inside_RECEIVER: RECEIVER -> type(RECEIVER) ; +Inside_PARAM: PARAM -> type(PARAM) ; +Inside_SETPARAM: SETPARAM -> type(SETPARAM) ; +Inside_DELEGATE: DELEGATE -> type(DELEGATE) ; +Inside_THROW: THROW -> type(THROW) ; +Inside_RETURN: RETURN -> type(RETURN) ; +Inside_CONTINUE: CONTINUE -> type(CONTINUE) ; +Inside_BREAK: BREAK -> type(BREAK) ; +Inside_RETURN_AT: RETURN_AT -> type(RETURN_AT) ; +Inside_CONTINUE_AT: CONTINUE_AT -> type(CONTINUE_AT) ; +Inside_BREAK_AT: BREAK_AT -> type(BREAK_AT) ; +Inside_IF: IF -> type(IF) ; +Inside_ELSE: ELSE -> type(ELSE) ; +Inside_WHEN: WHEN -> type(WHEN) ; +Inside_TRY: TRY -> type(TRY) ; +Inside_CATCH: CATCH -> type(CATCH) ; +Inside_FINALLY: FINALLY -> type(FINALLY) ; +Inside_FOR: FOR -> type(FOR) ; +Inside_DO: DO -> type(DO) ; +Inside_WHILE: WHILE -> type(WHILE) ; + +Inside_PUBLIC: PUBLIC -> type(PUBLIC) ; +Inside_PRIVATE: PRIVATE -> type(PRIVATE) ; +Inside_PROTECTED: PROTECTED -> type(PROTECTED) ; +Inside_INTERNAL: INTERNAL -> type(INTERNAL) ; +Inside_ENUM: ENUM -> type(ENUM) ; +Inside_SEALED: SEALED -> type(SEALED) ; +Inside_ANNOTATION: ANNOTATION -> type(ANNOTATION) ; +Inside_DATA: DATA -> type(DATA) ; +Inside_INNER: INNER -> type(INNER) ; +Inside_TAILREC: TAILREC -> type(TAILREC) ; +Inside_OPERATOR: OPERATOR -> type(OPERATOR) ; +Inside_INLINE: INLINE -> type(INLINE) ; +Inside_INFIX: INFIX -> type(INFIX) ; +Inside_EXTERNAL: EXTERNAL -> type(EXTERNAL) ; +Inside_SUSPEND: SUSPEND -> type(SUSPEND) ; +Inside_OVERRIDE: OVERRIDE -> type(OVERRIDE) ; +Inside_ABSTRACT: ABSTRACT -> type(ABSTRACT) ; +Inside_FINAL: FINAL -> type(FINAL) ; +Inside_OPEN: OPEN -> type(OPEN) ; +Inside_CONST: CONST -> type(CONST) ; +Inside_LATEINIT: LATEINIT -> type(LATEINIT) ; +Inside_VARARG: VARARG -> type(VARARG) ; +Inside_NOINLINE: NOINLINE -> type(NOINLINE) ; +Inside_CROSSINLINE: CROSSINLINE -> type(CROSSINLINE) ; +Inside_REIFIED: REIFIED -> type(REIFIED) ; + +Inside_BooleanLiteral: BooleanLiteral -> type(BooleanLiteral) ; +Inside_IntegerLiteral: IntegerLiteral -> type(IntegerLiteral) ; +Inside_HexLiteral: HexLiteral -> type(HexLiteral) ; +Inside_BinLiteral: BinLiteral -> type(BinLiteral) ; +Inside_CharacterLiteral: CharacterLiteral -> type(CharacterLiteral) ; +Inside_RealLiteral: RealLiteral -> type(RealLiteral) ; +Inside_NullLiteral: NullLiteral -> type(NullLiteral) ; + +Inside_LongLiteral: LongLiteral -> type(LongLiteral) ; + +Inside_Identifier: Identifier -> type(Identifier) ; +Inside_LabelReference: LabelReference -> type(LabelReference) ; +Inside_LabelDefinition: LabelDefinition -> type(LabelDefinition) ; +Inside_Comment: (LineComment | DelimitedComment) -> channel(HIDDEN) ; +Inside_WS: WS -> skip ; +Inside_NL: NL -> skip ; + + +mode LineString ; + +QUOTE_CLOSE + : '"' -> popMode + ; + +LineStrRef + : FieldIdentifier + ; + +LineStrText + : ~('\\' | '"' | '$')+ | '$' + ; + +LineStrEscapedChar + : '\\' . + | UniCharacterLiteral + ; + +LineStrExprStart + : '${' -> pushMode(StringExpression) + ; + + +mode MultiLineString ; + +TRIPLE_QUOTE_CLOSE + : MultiLineStringQuote? '"""' -> popMode + ; + +MultiLineStringQuote + : '"'+ + ; + +MultiLineStrRef + : FieldIdentifier + ; + +MultiLineStrText + : ~('\\' | '"' | '$')+ | '$' + ; + +MultiLineStrEscapedChar + : '\\' . + ; + +MultiLineStrExprStart + : '${' -> pushMode(StringExpression) + ; + +MultiLineNL: NL -> skip ; + + +mode StringExpression ; + +StrExpr_RCURL: RCURL -> popMode, type(RCURL) ; + +StrExpr_LPAREN: LPAREN -> pushMode(Inside), type(LPAREN) ; +StrExpr_LSQUARE: LSQUARE -> pushMode(Inside), type(LSQUARE) ; + +StrExpr_RPAREN: ')' -> type(RPAREN) ; +StrExpr_RSQUARE: ']' -> type(RSQUARE); +StrExpr_LCURL: LCURL -> pushMode(StringExpression), type(LCURL) ; +StrExpr_DOT: DOT -> type(DOT) ; +StrExpr_COMMA: COMMA -> type(COMMA) ; +StrExpr_MULT: MULT -> type(MULT) ; +StrExpr_MOD: MOD -> type(MOD) ; +StrExpr_DIV: DIV -> type(DIV) ; +StrExpr_ADD: ADD -> type(ADD) ; +StrExpr_SUB: SUB -> type(SUB) ; +StrExpr_INCR: INCR -> type(INCR) ; +StrExpr_DECR: DECR -> type(DECR) ; +StrExpr_CONJ: CONJ -> type(CONJ) ; +StrExpr_DISJ: DISJ -> type(DISJ) ; +StrExpr_EXCL: EXCL -> type(EXCL) ; +StrExpr_COLON: COLON -> type(COLON) ; +StrExpr_SEMICOLON: SEMICOLON -> type(SEMICOLON) ; +StrExpr_ASSIGNMENT: ASSIGNMENT -> type(ASSIGNMENT) ; +StrExpr_ADD_ASSIGNMENT: ADD_ASSIGNMENT -> type(ADD_ASSIGNMENT) ; +StrExpr_SUB_ASSIGNMENT: SUB_ASSIGNMENT -> type(SUB_ASSIGNMENT) ; +StrExpr_MULT_ASSIGNMENT: MULT_ASSIGNMENT -> type(MULT_ASSIGNMENT) ; +StrExpr_DIV_ASSIGNMENT: DIV_ASSIGNMENT -> type(DIV_ASSIGNMENT) ; +StrExpr_MOD_ASSIGNMENT: MOD_ASSIGNMENT -> type(MOD_ASSIGNMENT) ; +StrExpr_ARROW: ARROW -> type(ARROW) ; +StrExpr_DOUBLE_ARROW: DOUBLE_ARROW -> type(DOUBLE_ARROW) ; +StrExpr_RANGE: RANGE -> type(RANGE) ; +StrExpr_COLONCOLON: COLONCOLON -> type(COLONCOLON) ; +StrExpr_Q_COLONCOLON: Q_COLONCOLON -> type(Q_COLONCOLON) ; +StrExpr_DOUBLE_SEMICOLON: DOUBLE_SEMICOLON -> type(DOUBLE_SEMICOLON) ; +StrExpr_HASH: HASH -> type(HASH) ; +StrExpr_AT: AT -> type(AT) ; +StrExpr_QUEST: QUEST -> type(QUEST) ; +StrExpr_ELVIS: ELVIS -> type(ELVIS) ; +StrExpr_LANGLE: LANGLE -> type(LANGLE) ; +StrExpr_RANGLE: RANGLE -> type(RANGLE) ; +StrExpr_LE: LE -> type(LE) ; +StrExpr_GE: GE -> type(GE) ; +StrExpr_EXCL_EQ: EXCL_EQ -> type(EXCL_EQ) ; +StrExpr_EXCL_EQEQ: EXCL_EQEQ -> type(EXCL_EQEQ) ; +StrExpr_AS: AS -> type(IS) ; +StrExpr_IS: IS -> type(IN) ; +StrExpr_IN: IN ; +StrExpr_NOT_IS: NOT_IS -> type(NOT_IS) ; +StrExpr_NOT_IN: NOT_IN -> type(NOT_IN) ; +StrExpr_AS_SAFE: AS_SAFE -> type(AS_SAFE) ; +StrExpr_EQEQ: EQEQ -> type(EQEQ) ; +StrExpr_EQEQEQ: EQEQEQ -> type(EQEQEQ) ; +StrExpr_SINGLE_QUOTE: SINGLE_QUOTE -> type(SINGLE_QUOTE) ; +StrExpr_QUOTE_OPEN: QUOTE_OPEN -> pushMode(LineString), type(QUOTE_OPEN) ; +StrExpr_TRIPLE_QUOTE_OPEN: TRIPLE_QUOTE_OPEN -> pushMode(MultiLineString), type(TRIPLE_QUOTE_OPEN) ; + +StrExpr_BooleanLiteral: BooleanLiteral -> type(BooleanLiteral) ; +StrExpr_IntegerLiteral: IntegerLiteral -> type(IntegerLiteral) ; +StrExpr_HexLiteral: HexLiteral -> type(HexLiteral) ; +StrExpr_BinLiteral: BinLiteral -> type(BinLiteral) ; +StrExpr_CharacterLiteral: CharacterLiteral -> type(CharacterLiteral) ; +StrExpr_RealLiteral: RealLiteral -> type(RealLiteral) ; +StrExpr_NullLiteral: NullLiteral -> type(NullLiteral) ; +StrExpr_LongLiteral: LongLiteral -> type(LongLiteral) ; + +StrExpr_Identifier: Identifier -> type(Identifier) ; +StrExpr_LabelReference: LabelReference -> type(LabelReference) ; +StrExpr_LabelDefinition: LabelDefinition -> type(LabelDefinition) ; +StrExpr_Comment: (LineComment | DelimitedComment) -> channel(HIDDEN) ; +StrExpr_WS: WS -> skip ; +StrExpr_NL: NL -> skip ; diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinLanguage.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinLanguage.java new file mode 100644 index 0000000000..4a14aa766f --- /dev/null +++ b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinLanguage.java @@ -0,0 +1,18 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.cpd; + +/** + * Language implementation for Kotlin + */ +public class KotlinLanguage extends AbstractLanguage { + + /** + * Creates a new Kotlin Language instance. + */ + public KotlinLanguage() { + super("Kotlin", "kotlin", new KotlinTokenizer(), ".kt"); + } +} diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java new file mode 100644 index 0000000000..3dbc7cb595 --- /dev/null +++ b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java @@ -0,0 +1,83 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.cpd; + +import net.sourceforge.pmd.lang.kotlin.antlr4.Kotlin; +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; +import org.antlr.v4.runtime.Token; + +import net.sourceforge.pmd.lang.ast.TokenMgrError; +//import net.sourceforge.pmd.lang.kotlin.antlr4.KotlinLexer; + +/** + * The Kotlin Tokenizer + */ +public class KotlinTokenizer implements Tokenizer { + + @Override + public void tokenize(SourceCode sourceCode, Tokens tokenEntries) { + StringBuilder buffer = sourceCode.getCodeBuffer(); + + try { + ANTLRInputStream ais = new ANTLRInputStream(buffer.toString()); + Kotlin lexer = new Kotlin(ais); + + lexer.removeErrorListeners(); + lexer.addErrorListener(new ErrorHandler()); + Token token = lexer.nextToken(); + + while (token.getType() != Token.EOF) { + if (token.getChannel() != Lexer.HIDDEN) { + TokenEntry tokenEntry = new TokenEntry(token.getText(), sourceCode.getFileName(), token.getLine()); + + tokenEntries.add(tokenEntry); + } + token = lexer.nextToken(); + } + } catch (ANTLRSyntaxError err) { + // Wrap exceptions of the Kotlin tokenizer in a TokenMgrError, so + // they are correctly handled + // when CPD is executed with the '--skipLexicalErrors' command line + // option + throw new TokenMgrError("Lexical error in file " + sourceCode.getFileName() + " at line " + err.getLine() + + ", column " + err.getColumn() + ". Encountered: " + err.getMessage(), + TokenMgrError.LEXICAL_ERROR); + } finally { + tokenEntries.add(TokenEntry.getEOF()); + } + } + + private static class ErrorHandler extends BaseErrorListener { + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, + String msg, RecognitionException ex) { + throw new ANTLRSyntaxError(msg, line, charPositionInLine, ex); + } + } + + private static class ANTLRSyntaxError extends RuntimeException { + private static final long serialVersionUID = 1L; + private final int line; + private final int column; + + ANTLRSyntaxError(String msg, int line, int column, RecognitionException cause) { + super(msg, cause); + this.line = line; + this.column = column; + } + + public int getLine() { + return line; + } + + public int getColumn() { + return column; + } + } +} diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java new file mode 100644 index 0000000000..c405b3f409 --- /dev/null +++ b/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java @@ -0,0 +1,26 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.kotlin; + +import net.sourceforge.pmd.lang.BaseLanguageModule; + +/** + * Language Module for Kotlin + */ +public class KotlinLanguageModule extends BaseLanguageModule { + + /** The name. */ + public static final String NAME = "Kotlin"; + /** The terse name. */ + public static final String TERSE_NAME = "kotlin"; + + /** + * Create a new instance of Kotlin Language Module. + */ + public KotlinLanguageModule() { + super(NAME, null, TERSE_NAME, null, "kotlin"); + addVersion("", null, true); + } +} diff --git a/pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language b/pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language new file mode 100644 index 0000000000..6908eda6c4 --- /dev/null +++ b/pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language @@ -0,0 +1 @@ +net.sourceforge.pmd.cpd.KotlinLanguage diff --git a/pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language b/pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language new file mode 100644 index 0000000000..78c4e9b40d --- /dev/null +++ b/pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language @@ -0,0 +1 @@ +net.sourceforge.pmd.lang.kotlin.KotlinLanguageModule diff --git a/pom.xml b/pom.xml index a83b36385c..60393a208a 100644 --- a/pom.xml +++ b/pom.xml @@ -985,6 +985,7 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code pmd-java pmd-javascript pmd-jsp + pmd-kotlin pmd-matlab pmd-objectivec pmd-perl From dc5b18b512bd23976e094daa2a60261aa0147d60 Mon Sep 17 00:00:00 2001 From: Dennie Reniers Date: Thu, 1 Nov 2018 11:00:37 +0100 Subject: [PATCH 036/139] Adjusted Kotlin tokenizer to skip over package and import statements. This prevents CPD from finding duplications in package and import statements. --- .../sourceforge/pmd/cpd/KotlinTokenizer.java | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java index 3dbc7cb595..2fddcbea8d 100644 --- a/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java +++ b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.cpd; -import net.sourceforge.pmd.lang.kotlin.antlr4.Kotlin; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.Lexer; @@ -14,33 +13,37 @@ import org.antlr.v4.runtime.Token; import net.sourceforge.pmd.lang.ast.TokenMgrError; //import net.sourceforge.pmd.lang.kotlin.antlr4.KotlinLexer; +import net.sourceforge.pmd.lang.kotlin.antlr4.Kotlin; /** * The Kotlin Tokenizer */ public class KotlinTokenizer implements Tokenizer { + private boolean discardingPackageAndImport = false; + @Override - public void tokenize(SourceCode sourceCode, Tokens tokenEntries) { - StringBuilder buffer = sourceCode.getCodeBuffer(); + public void tokenize(final SourceCode sourceCode, final Tokens tokenEntries) { + final StringBuilder buffer = sourceCode.getCodeBuffer(); try { - ANTLRInputStream ais = new ANTLRInputStream(buffer.toString()); - Kotlin lexer = new Kotlin(ais); + final ANTLRInputStream ais = new ANTLRInputStream(buffer.toString()); + final Kotlin lexer = new Kotlin(ais); lexer.removeErrorListeners(); lexer.addErrorListener(new ErrorHandler()); Token token = lexer.nextToken(); while (token.getType() != Token.EOF) { - if (token.getChannel() != Lexer.HIDDEN) { - TokenEntry tokenEntry = new TokenEntry(token.getText(), sourceCode.getFileName(), token.getLine()); - + analyzeTokenStart(token); + if (token.getChannel() != Lexer.HIDDEN && token.getType() != Kotlin.NL && !isDiscarding()) { + final TokenEntry tokenEntry = new TokenEntry(token.getText(), sourceCode.getFileName(), token.getLine()); tokenEntries.add(tokenEntry); } + analyzeTokenEnd(token); token = lexer.nextToken(); } - } catch (ANTLRSyntaxError err) { + } catch (final ANTLRSyntaxError err) { // Wrap exceptions of the Kotlin tokenizer in a TokenMgrError, so // they are correctly handled // when CPD is executed with the '--skipLexicalErrors' command line @@ -53,10 +56,29 @@ public class KotlinTokenizer implements Tokenizer { } } + private boolean isDiscarding() { + return discardingPackageAndImport; + } + + private void analyzeTokenStart(final Token currentToken) { + final int type = currentToken.getType(); + if (type == Kotlin.PACKAGE || type == Kotlin.IMPORT) { + discardingPackageAndImport = true; + } + } + + private void analyzeTokenEnd(final Token currentToken) { + final int type = currentToken.getType(); + if (discardingPackageAndImport && (type == Kotlin.SEMICOLON || type == Kotlin.NL)) { + discardingPackageAndImport = false; + } + } + + private static class ErrorHandler extends BaseErrorListener { @Override - public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, - String msg, RecognitionException ex) { + public void syntaxError(final Recognizer recognizer, final Object offendingSymbol, final int line, final int charPositionInLine, + final String msg, final RecognitionException ex) { throw new ANTLRSyntaxError(msg, line, charPositionInLine, ex); } } @@ -66,7 +88,7 @@ public class KotlinTokenizer implements Tokenizer { private final int line; private final int column; - ANTLRSyntaxError(String msg, int line, int column, RecognitionException cause) { + ANTLRSyntaxError(final String msg, final int line, final int column, final RecognitionException cause) { super(msg, cause); this.line = line; this.column = column; From e7fd1d408cc06fbdd6dad3cf0a02f29612ae19bf Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Wed, 7 Nov 2018 15:15:57 +0100 Subject: [PATCH 037/139] Removed unnecessary import in order to conform to Checkstyle coding standard. --- .../src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java index 2fddcbea8d..8ff8349c1f 100644 --- a/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java +++ b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java @@ -12,7 +12,6 @@ import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.Token; import net.sourceforge.pmd.lang.ast.TokenMgrError; -//import net.sourceforge.pmd.lang.kotlin.antlr4.KotlinLexer; import net.sourceforge.pmd.lang.kotlin.antlr4.Kotlin; /** From eb23b3ce38d54049339378596995f7e6a74dba5f Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Wed, 7 Nov 2018 15:21:29 +0100 Subject: [PATCH 038/139] Adjusted pmd-dist unit test to include Kotlin in the list of supported languages. --- .../test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java index 0317c043c3..dadd67ca6f 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java @@ -108,7 +108,7 @@ public class BinaryDistributionIT { result = CpdExecutor.runCpd(tempDir, "-h"); - result.assertExecutionResult(1, "Supported languages: [apex, cpp, cs, ecmascript, fortran, go, groovy, java, jsp, matlab, objectivec, perl, php, plsql, python, ruby, scala, swift, vf]"); + result.assertExecutionResult(1, "Supported languages: [apex, cpp, cs, ecmascript, fortran, go, groovy, java, jsp, kotlin, matlab, objectivec, perl, php, plsql, python, ruby, scala, swift, vf]"); result = CpdExecutor.runCpd(tempDir, "--minimum-tokens", "10", "--format", "text", "--files", srcDir); result.assertExecutionResult(4, "Found a 10 line (55 tokens) duplication in the following files:"); From 4fadb1ab10c01005f158d1eddce90f79bf71040d Mon Sep 17 00:00:00 2001 From: rajeshggwp Date: Wed, 7 Nov 2018 21:49:06 +0530 Subject: [PATCH 039/139] [old] added support for different bases, exponent, serialVersionUID. --- .../resources/category/java/codestyle.xml | 4 +- .../xml/NumericLiteralConvention.xml | 110 ++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index d31da8bdad..1a6dc87cf9 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1371,7 +1371,9 @@ public class ClassInDefaultPackage { @LongLiteral = true() or @DoubleLiteral = true() or @FloatLiteral = true()] - [not(matches(@Image, "^[0-9]{1,3}(_[0-9]{3})*(l|L|\.[0-9]+)?(d|D|f|F)?$"))] + [not (matches(@Image, "^(0([xb]?[0-9a-fA-F]+)?|[1-9][0-9]{0,2}(_[0-9]{3})*)(l|L|\.[0-9_]+)?([eE][\+-]?[0-9]+)?[dDfF]?$"))] + [ancestor::VariableDeclarator[not (@Name = 'serialVersionUID')] or + not (ancestor::VariableDeclarator)] ]]> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml index 5c057abafe..3861a372b4 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml @@ -164,6 +164,116 @@ ok, String value without '_' + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + From 411ca67b7e4a1d5a978af04141931aa97d73de87 Mon Sep 17 00:00:00 2001 From: rajeshggwp Date: Wed, 7 Nov 2018 22:08:14 +0530 Subject: [PATCH 040/139] Rule name and release version changed --- pmd-java/src/main/resources/category/java/codestyle.xml | 6 +++--- ...onTest.java => UseUnderscoresInNumericLiteralsTest.java} | 2 +- ...alConvention.xml => UseUnderscoresInNumericLiterals.xml} | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/{NumericLiteralConventionTest.java => UseUnderscoresInNumericLiteralsTest.java} (76%) rename pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/{NumericLiteralConvention.xml => UseUnderscoresInNumericLiterals.xml} (100%) diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 1a6dc87cf9..30ff0c9d30 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1351,13 +1351,13 @@ public class ClassInDefaultPackage { - + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#useunderscoresinnumericliterals"> Numeric literals with more than 3 digits must use '_' as a separator. diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/NumericLiteralConventionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/UseUnderscoresInNumericLiteralsTest.java similarity index 76% rename from pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/NumericLiteralConventionTest.java rename to pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/UseUnderscoresInNumericLiteralsTest.java index b753bad7d9..ecaaba4bf3 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/NumericLiteralConventionTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/UseUnderscoresInNumericLiteralsTest.java @@ -6,6 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.codestyle; import net.sourceforge.pmd.testframework.PmdRuleTst; -public class NumericLiteralConventionTest extends PmdRuleTst { +public class UseUnderscoresInNumericLiteralsTest extends PmdRuleTst { // no additional unit tests } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml similarity index 100% rename from pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/NumericLiteralConvention.xml rename to pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml From 2ccfe15a148346b54d9980386c38927499ba26b5 Mon Sep 17 00:00:00 2001 From: rajeshggwp Date: Thu, 8 Nov 2018 20:20:16 +0530 Subject: [PATCH 041/139] added acceptable length property --- docs/pages/pmd/rules/java.md | 2 +- docs/pages/pmd/rules/java/codestyle.md | 68 ++++---- .../resources/category/java/codestyle.xml | 15 +- .../xml/UseUnderscoresInNumericLiterals.xml | 148 +++++++++--------- 4 files changed, 124 insertions(+), 109 deletions(-) diff --git a/docs/pages/pmd/rules/java.md b/docs/pages/pmd/rules/java.md index f8d2a78f1c..0930e39913 100644 --- a/docs/pages/pmd/rules/java.md +++ b/docs/pages/pmd/rules/java.md @@ -98,7 +98,6 @@ folder: pmd/rules * [MethodNamingConventions](pmd_rules_java_codestyle.html#methodnamingconventions): Configurable naming conventions for method declarations. This rule reports method decl... * [MIsLeadingVariableName](pmd_rules_java_codestyle.html#misleadingvariablename): Deprecated Detects when a non-field has a name starting with 'm_'. This usually denotes a field and could b... * [NoPackage](pmd_rules_java_codestyle.html#nopackage): Detects when a class or interface does not have a package definition. -* [NumericLiteralConvention](pmd_rules_java_codestyle.html#numericliteralconvention): Numeric literals with more than 3 digits must use '_' as a separator. * [OnlyOneReturn](pmd_rules_java_codestyle.html#onlyonereturn): A method should have only one exit point, and that should be the last statement in the method. * [PackageCase](pmd_rules_java_codestyle.html#packagecase): Detects when a package definition contains uppercase characters. * [PrematureDeclaration](pmd_rules_java_codestyle.html#prematuredeclaration): Checks for variables that are defined before they might be used. A reference is deemed to be prem... @@ -117,6 +116,7 @@ folder: pmd/rules * [UnnecessaryReturn](pmd_rules_java_codestyle.html#unnecessaryreturn): Avoid the use of unnecessary return statements. * [UselessParentheses](pmd_rules_java_codestyle.html#uselessparentheses): Useless parentheses should be removed. * [UselessQualifiedThis](pmd_rules_java_codestyle.html#uselessqualifiedthis): Reports qualified this usages in the same class. +* [UseUnderscoresInNumericLiterals](pmd_rules_java_codestyle.html#useunderscoresinnumericliterals): Numeric literals with more than 3 digits must use '_' as a separator. * [VariableNamingConventions](pmd_rules_java_codestyle.html#variablenamingconventions): Deprecated A variable naming conventions rule - customize this to your liking. Currently, itchecks for fina... * [WhileLoopsMustUseBraces](pmd_rules_java_codestyle.html#whileloopsmustusebraces): Deprecated Avoid using 'while' statements without using braces to surround the code block. If the code forma... diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index 247b846cac..e4f9a6ba21 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -5,7 +5,7 @@ permalink: pmd_rules_java_codestyle.html folder: pmd/rules/java sidebaractiveurl: /pmd_rules_java.html editmepath: ../pmd-java/src/main/resources/category/java/codestyle.xml -keywords: Code Style, AbstractNaming, AtLeastOneConstructor, AvoidDollarSigns, AvoidFinalLocalVariable, AvoidPrefixingMethodParameters, AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending, AvoidUsingNativeCode, BooleanGetMethodName, CallSuperInConstructor, ClassNamingConventions, CommentDefaultAccessModifier, ConfusingTernary, ControlStatementBraces, DefaultPackage, DontImportJavaLang, DuplicateImports, EmptyMethodInAbstractClassShouldBeAbstract, ExtendsObject, FieldDeclarationsShouldBeAtStartOfClass, FieldNamingConventions, ForLoopShouldBeWhileLoop, ForLoopsMustUseBraces, FormalParameterNamingConventions, GenericsNaming, IdenticalCatchBranches, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, LinguisticNaming, LocalHomeNamingConvention, LocalInterfaceSessionNamingConvention, LocalVariableCouldBeFinal, LocalVariableNamingConventions, LongVariable, MDBAndSessionBeanNamingConvention, MethodArgumentCouldBeFinal, MethodNamingConventions, MIsLeadingVariableName, NoPackage, NumericLiteralConvention, OnlyOneReturn, PackageCase, PrematureDeclaration, RemoteInterfaceNamingConvention, RemoteSessionInterfaceNamingConvention, ShortClassName, ShortMethodName, ShortVariable, SuspiciousConstantFieldName, TooManyStaticImports, UnnecessaryAnnotationValueElement, UnnecessaryConstructor, UnnecessaryFullyQualifiedName, UnnecessaryLocalBeforeReturn, UnnecessaryModifier, UnnecessaryReturn, UselessParentheses, UselessQualifiedThis, VariableNamingConventions, WhileLoopsMustUseBraces +keywords: Code Style, AbstractNaming, AtLeastOneConstructor, AvoidDollarSigns, AvoidFinalLocalVariable, AvoidPrefixingMethodParameters, AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending, AvoidUsingNativeCode, BooleanGetMethodName, CallSuperInConstructor, ClassNamingConventions, CommentDefaultAccessModifier, ConfusingTernary, ControlStatementBraces, DefaultPackage, DontImportJavaLang, DuplicateImports, EmptyMethodInAbstractClassShouldBeAbstract, ExtendsObject, FieldDeclarationsShouldBeAtStartOfClass, FieldNamingConventions, ForLoopShouldBeWhileLoop, ForLoopsMustUseBraces, FormalParameterNamingConventions, GenericsNaming, IdenticalCatchBranches, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, LinguisticNaming, LocalHomeNamingConvention, LocalInterfaceSessionNamingConvention, LocalVariableCouldBeFinal, LocalVariableNamingConventions, LongVariable, MDBAndSessionBeanNamingConvention, MethodArgumentCouldBeFinal, MethodNamingConventions, MIsLeadingVariableName, NoPackage, UseUnderscoresInNumericLiterals, OnlyOneReturn, PackageCase, PrematureDeclaration, RemoteInterfaceNamingConvention, RemoteSessionInterfaceNamingConvention, ShortClassName, ShortMethodName, ShortVariable, SuspiciousConstantFieldName, TooManyStaticImports, UnnecessaryAnnotationValueElement, UnnecessaryConstructor, UnnecessaryFullyQualifiedName, UnnecessaryLocalBeforeReturn, UnnecessaryModifier, UnnecessaryReturn, UselessParentheses, UselessQualifiedThis, VariableNamingConventions, WhileLoopsMustUseBraces language: Java --- ## AbstractNaming @@ -1508,38 +1508,6 @@ public class ClassInDefaultPackage { ``` -## NumericLiteralConvention - -**Since:** PMD 6.9.0 - -**Priority:** Medium (3) - -**Minimum Language Version:** Java 1.7 - -Numeric literals with more than 3 digits must use '_' as a separator. - -**This rule is defined by the following XPath expression:** -``` xpath -//Literal[@IntLiteral = true() or - @LongLiteral = true() or - @DoubleLiteral = true() or - @FloatLiteral = true()] - [not(matches(@Image, "^[0-9]{1,3}(_[0-9]{3})*(l|L|\.[0-9]+)?(d|D|f|F)?$"))] -``` - -**Example(s):** - -``` java -public class Foo { - private int num = 1000000; // should be 1_000_000 -} -``` - -**Use this rule by referencing it:** -``` xml - -``` - ## OnlyOneReturn **Since:** PMD 1.0 @@ -2235,6 +2203,40 @@ public class Foo { ``` +## UseUnderscoresInNumericLiterals + +**Since:** PMD 6.10.0 + +**Priority:** Medium (3) + +**Minimum Language Version:** Java 1.7 + +Numeric literals with more than 3 digits must use '_' as a separator. + +**This rule is defined by the following XPath expression:** +``` xpath +//Literal[@IntLiteral = true() or + @LongLiteral = true() or + @DoubleLiteral = true() or + @FloatLiteral = true()] + [not (matches(@Image, "^(0([xb]?[0-9a-fA-F]+)?|[1-9][0-9]{0,2}(_[0-9]{3})*)(l|L|\.[0-9_]+)?([eE][\+-]?[0-9]+)?[dDfF]?$"))] + [ancestor::VariableDeclarator[not (@Name = 'serialVersionUID')] or + not (ancestor::VariableDeclarator)] +``` + +**Example(s):** + +``` java +public class Foo { + private int num = 1000000; // should be 1_000_000 +} +``` + +**Use this rule by referencing it:** +``` xml + +``` + ## VariableNamingConventions Deprecated diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index e7ef25cdda..f1f3361ac1 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1366,6 +1366,8 @@ public class ClassInDefaultPackage { 3 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml index 3861a372b4..7b598d5975 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml @@ -4,9 +4,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> - + + ok, numeric literal with correct '_' usage + 0 - + + bad, numeric literal without '_' + 1 - + + bad, numeric literal used as a method parameter without '_' + 1 - + + ok, float value with less than 3 numbers. + 0 - + + bad, double value without '_' + 1 - + + ok, numeric literal used as a method parameter with '_' + 0 - + + ok, Long value with 'l' used as a method parameter with '_' + 0 - + + bad, numeric literal with incorrect '_' usage + 1 - + + ok, Double value with 'D' used as a method parameter with '_' + 0 - + + ok, Float value with 'F' with less than 3 numbers + 0 - + + ok, Double value with 'd' with correct '_' usage + 0 - + + ok, Long value with 'L' used as a method parameter with '_' + 0 - + + ok, String value with '_' + 0 - + + ok, String value without '_' + 0 - + + ok, Numeric Literal in binary + 0 - + + ok, Numeric Literal in octal + 0 - + + ok, Numeric Literal in hexadecimal + 0 - + + ok, Numeric Literal in negative binary + 0 - + + ok, Numeric Literal in negative octal + 0 - + + ok, Numeric Literal in negative hexadecimal + 0 - + + ok, Numeric Literal with exponent + 0 - - 0 + + bad, Negative exponent without '_' + + 1 - + + ok, Numeric Literal with positive exponent + 0 - + + ok, Lengthy numeric literal with variable name as serialVersionUID + 0 Date: Thu, 8 Nov 2018 21:43:48 +0530 Subject: [PATCH 042/139] Revert "added acceptable length property" This reverts commit 2ccfe15a148346b54d9980386c38927499ba26b5. --- docs/pages/pmd/rules/java.md | 2 +- docs/pages/pmd/rules/java/codestyle.md | 68 ++++---- .../resources/category/java/codestyle.xml | 15 +- .../xml/UseUnderscoresInNumericLiterals.xml | 148 +++++++++--------- 4 files changed, 109 insertions(+), 124 deletions(-) diff --git a/docs/pages/pmd/rules/java.md b/docs/pages/pmd/rules/java.md index 0930e39913..f8d2a78f1c 100644 --- a/docs/pages/pmd/rules/java.md +++ b/docs/pages/pmd/rules/java.md @@ -98,6 +98,7 @@ folder: pmd/rules * [MethodNamingConventions](pmd_rules_java_codestyle.html#methodnamingconventions): Configurable naming conventions for method declarations. This rule reports method decl... * [MIsLeadingVariableName](pmd_rules_java_codestyle.html#misleadingvariablename): Deprecated Detects when a non-field has a name starting with 'm_'. This usually denotes a field and could b... * [NoPackage](pmd_rules_java_codestyle.html#nopackage): Detects when a class or interface does not have a package definition. +* [NumericLiteralConvention](pmd_rules_java_codestyle.html#numericliteralconvention): Numeric literals with more than 3 digits must use '_' as a separator. * [OnlyOneReturn](pmd_rules_java_codestyle.html#onlyonereturn): A method should have only one exit point, and that should be the last statement in the method. * [PackageCase](pmd_rules_java_codestyle.html#packagecase): Detects when a package definition contains uppercase characters. * [PrematureDeclaration](pmd_rules_java_codestyle.html#prematuredeclaration): Checks for variables that are defined before they might be used. A reference is deemed to be prem... @@ -116,7 +117,6 @@ folder: pmd/rules * [UnnecessaryReturn](pmd_rules_java_codestyle.html#unnecessaryreturn): Avoid the use of unnecessary return statements. * [UselessParentheses](pmd_rules_java_codestyle.html#uselessparentheses): Useless parentheses should be removed. * [UselessQualifiedThis](pmd_rules_java_codestyle.html#uselessqualifiedthis): Reports qualified this usages in the same class. -* [UseUnderscoresInNumericLiterals](pmd_rules_java_codestyle.html#useunderscoresinnumericliterals): Numeric literals with more than 3 digits must use '_' as a separator. * [VariableNamingConventions](pmd_rules_java_codestyle.html#variablenamingconventions): Deprecated A variable naming conventions rule - customize this to your liking. Currently, itchecks for fina... * [WhileLoopsMustUseBraces](pmd_rules_java_codestyle.html#whileloopsmustusebraces): Deprecated Avoid using 'while' statements without using braces to surround the code block. If the code forma... diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index e4f9a6ba21..247b846cac 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -5,7 +5,7 @@ permalink: pmd_rules_java_codestyle.html folder: pmd/rules/java sidebaractiveurl: /pmd_rules_java.html editmepath: ../pmd-java/src/main/resources/category/java/codestyle.xml -keywords: Code Style, AbstractNaming, AtLeastOneConstructor, AvoidDollarSigns, AvoidFinalLocalVariable, AvoidPrefixingMethodParameters, AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending, AvoidUsingNativeCode, BooleanGetMethodName, CallSuperInConstructor, ClassNamingConventions, CommentDefaultAccessModifier, ConfusingTernary, ControlStatementBraces, DefaultPackage, DontImportJavaLang, DuplicateImports, EmptyMethodInAbstractClassShouldBeAbstract, ExtendsObject, FieldDeclarationsShouldBeAtStartOfClass, FieldNamingConventions, ForLoopShouldBeWhileLoop, ForLoopsMustUseBraces, FormalParameterNamingConventions, GenericsNaming, IdenticalCatchBranches, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, LinguisticNaming, LocalHomeNamingConvention, LocalInterfaceSessionNamingConvention, LocalVariableCouldBeFinal, LocalVariableNamingConventions, LongVariable, MDBAndSessionBeanNamingConvention, MethodArgumentCouldBeFinal, MethodNamingConventions, MIsLeadingVariableName, NoPackage, UseUnderscoresInNumericLiterals, OnlyOneReturn, PackageCase, PrematureDeclaration, RemoteInterfaceNamingConvention, RemoteSessionInterfaceNamingConvention, ShortClassName, ShortMethodName, ShortVariable, SuspiciousConstantFieldName, TooManyStaticImports, UnnecessaryAnnotationValueElement, UnnecessaryConstructor, UnnecessaryFullyQualifiedName, UnnecessaryLocalBeforeReturn, UnnecessaryModifier, UnnecessaryReturn, UselessParentheses, UselessQualifiedThis, VariableNamingConventions, WhileLoopsMustUseBraces +keywords: Code Style, AbstractNaming, AtLeastOneConstructor, AvoidDollarSigns, AvoidFinalLocalVariable, AvoidPrefixingMethodParameters, AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending, AvoidUsingNativeCode, BooleanGetMethodName, CallSuperInConstructor, ClassNamingConventions, CommentDefaultAccessModifier, ConfusingTernary, ControlStatementBraces, DefaultPackage, DontImportJavaLang, DuplicateImports, EmptyMethodInAbstractClassShouldBeAbstract, ExtendsObject, FieldDeclarationsShouldBeAtStartOfClass, FieldNamingConventions, ForLoopShouldBeWhileLoop, ForLoopsMustUseBraces, FormalParameterNamingConventions, GenericsNaming, IdenticalCatchBranches, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, LinguisticNaming, LocalHomeNamingConvention, LocalInterfaceSessionNamingConvention, LocalVariableCouldBeFinal, LocalVariableNamingConventions, LongVariable, MDBAndSessionBeanNamingConvention, MethodArgumentCouldBeFinal, MethodNamingConventions, MIsLeadingVariableName, NoPackage, NumericLiteralConvention, OnlyOneReturn, PackageCase, PrematureDeclaration, RemoteInterfaceNamingConvention, RemoteSessionInterfaceNamingConvention, ShortClassName, ShortMethodName, ShortVariable, SuspiciousConstantFieldName, TooManyStaticImports, UnnecessaryAnnotationValueElement, UnnecessaryConstructor, UnnecessaryFullyQualifiedName, UnnecessaryLocalBeforeReturn, UnnecessaryModifier, UnnecessaryReturn, UselessParentheses, UselessQualifiedThis, VariableNamingConventions, WhileLoopsMustUseBraces language: Java --- ## AbstractNaming @@ -1508,6 +1508,38 @@ public class ClassInDefaultPackage { ``` +## NumericLiteralConvention + +**Since:** PMD 6.9.0 + +**Priority:** Medium (3) + +**Minimum Language Version:** Java 1.7 + +Numeric literals with more than 3 digits must use '_' as a separator. + +**This rule is defined by the following XPath expression:** +``` xpath +//Literal[@IntLiteral = true() or + @LongLiteral = true() or + @DoubleLiteral = true() or + @FloatLiteral = true()] + [not(matches(@Image, "^[0-9]{1,3}(_[0-9]{3})*(l|L|\.[0-9]+)?(d|D|f|F)?$"))] +``` + +**Example(s):** + +``` java +public class Foo { + private int num = 1000000; // should be 1_000_000 +} +``` + +**Use this rule by referencing it:** +``` xml + +``` + ## OnlyOneReturn **Since:** PMD 1.0 @@ -2203,40 +2235,6 @@ public class Foo { ``` -## UseUnderscoresInNumericLiterals - -**Since:** PMD 6.10.0 - -**Priority:** Medium (3) - -**Minimum Language Version:** Java 1.7 - -Numeric literals with more than 3 digits must use '_' as a separator. - -**This rule is defined by the following XPath expression:** -``` xpath -//Literal[@IntLiteral = true() or - @LongLiteral = true() or - @DoubleLiteral = true() or - @FloatLiteral = true()] - [not (matches(@Image, "^(0([xb]?[0-9a-fA-F]+)?|[1-9][0-9]{0,2}(_[0-9]{3})*)(l|L|\.[0-9_]+)?([eE][\+-]?[0-9]+)?[dDfF]?$"))] - [ancestor::VariableDeclarator[not (@Name = 'serialVersionUID')] or - not (ancestor::VariableDeclarator)] -``` - -**Example(s):** - -``` java -public class Foo { - private int num = 1000000; // should be 1_000_000 -} -``` - -**Use this rule by referencing it:** -``` xml - -``` - ## VariableNamingConventions Deprecated diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index f1f3361ac1..e7ef25cdda 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1366,8 +1366,6 @@ public class ClassInDefaultPackage { 3 - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml index 7b598d5975..3861a372b4 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml @@ -4,9 +4,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> - - ok, numeric literal with correct '_' usage - + 0 - - bad, numeric literal without '_' - + 1 - - bad, numeric literal used as a method parameter without '_' - + 1 - - ok, float value with less than 3 numbers. - + 0 - - bad, double value without '_' - + 1 - - ok, numeric literal used as a method parameter with '_' - + 0 - - ok, Long value with 'l' used as a method parameter with '_' - + 0 - - bad, numeric literal with incorrect '_' usage - + 1 - - ok, Double value with 'D' used as a method parameter with '_' - + 0 - - ok, Float value with 'F' with less than 3 numbers - + 0 - - ok, Double value with 'd' with correct '_' usage - + 0 - - ok, Long value with 'L' used as a method parameter with '_' - + 0 - - ok, String value with '_' - + 0 - - ok, String value without '_' - + 0 - - ok, Numeric Literal in binary - + 0 - - ok, Numeric Literal in octal - + 0 - - ok, Numeric Literal in hexadecimal - + 0 - - ok, Numeric Literal in negative binary - + 0 - - ok, Numeric Literal in negative octal - + 0 - - ok, Numeric Literal in negative hexadecimal - + 0 - - ok, Numeric Literal with exponent - + 0 - - bad, Negative exponent without '_' - - 1 + + 0 - - ok, Numeric Literal with positive exponent - + 0 - - ok, Lengthy numeric literal with variable name as serialVersionUID - + 0 Date: Thu, 8 Nov 2018 22:52:54 +0530 Subject: [PATCH 043/139] added acceptable length property --- docs/pages/pmd/rules/java.md | 2 +- docs/pages/pmd/rules/java/codestyle.md | 68 +++---- .../resources/category/java/codestyle.xml | 15 +- .../xml/UseUnderscoresInNumericLiterals.xml | 174 ++++++++++-------- 4 files changed, 150 insertions(+), 109 deletions(-) diff --git a/docs/pages/pmd/rules/java.md b/docs/pages/pmd/rules/java.md index f8d2a78f1c..0930e39913 100644 --- a/docs/pages/pmd/rules/java.md +++ b/docs/pages/pmd/rules/java.md @@ -98,7 +98,6 @@ folder: pmd/rules * [MethodNamingConventions](pmd_rules_java_codestyle.html#methodnamingconventions): Configurable naming conventions for method declarations. This rule reports method decl... * [MIsLeadingVariableName](pmd_rules_java_codestyle.html#misleadingvariablename): Deprecated Detects when a non-field has a name starting with 'm_'. This usually denotes a field and could b... * [NoPackage](pmd_rules_java_codestyle.html#nopackage): Detects when a class or interface does not have a package definition. -* [NumericLiteralConvention](pmd_rules_java_codestyle.html#numericliteralconvention): Numeric literals with more than 3 digits must use '_' as a separator. * [OnlyOneReturn](pmd_rules_java_codestyle.html#onlyonereturn): A method should have only one exit point, and that should be the last statement in the method. * [PackageCase](pmd_rules_java_codestyle.html#packagecase): Detects when a package definition contains uppercase characters. * [PrematureDeclaration](pmd_rules_java_codestyle.html#prematuredeclaration): Checks for variables that are defined before they might be used. A reference is deemed to be prem... @@ -117,6 +116,7 @@ folder: pmd/rules * [UnnecessaryReturn](pmd_rules_java_codestyle.html#unnecessaryreturn): Avoid the use of unnecessary return statements. * [UselessParentheses](pmd_rules_java_codestyle.html#uselessparentheses): Useless parentheses should be removed. * [UselessQualifiedThis](pmd_rules_java_codestyle.html#uselessqualifiedthis): Reports qualified this usages in the same class. +* [UseUnderscoresInNumericLiterals](pmd_rules_java_codestyle.html#useunderscoresinnumericliterals): Numeric literals with more than 3 digits must use '_' as a separator. * [VariableNamingConventions](pmd_rules_java_codestyle.html#variablenamingconventions): Deprecated A variable naming conventions rule - customize this to your liking. Currently, itchecks for fina... * [WhileLoopsMustUseBraces](pmd_rules_java_codestyle.html#whileloopsmustusebraces): Deprecated Avoid using 'while' statements without using braces to surround the code block. If the code forma... diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index 247b846cac..e4f9a6ba21 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -5,7 +5,7 @@ permalink: pmd_rules_java_codestyle.html folder: pmd/rules/java sidebaractiveurl: /pmd_rules_java.html editmepath: ../pmd-java/src/main/resources/category/java/codestyle.xml -keywords: Code Style, AbstractNaming, AtLeastOneConstructor, AvoidDollarSigns, AvoidFinalLocalVariable, AvoidPrefixingMethodParameters, AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending, AvoidUsingNativeCode, BooleanGetMethodName, CallSuperInConstructor, ClassNamingConventions, CommentDefaultAccessModifier, ConfusingTernary, ControlStatementBraces, DefaultPackage, DontImportJavaLang, DuplicateImports, EmptyMethodInAbstractClassShouldBeAbstract, ExtendsObject, FieldDeclarationsShouldBeAtStartOfClass, FieldNamingConventions, ForLoopShouldBeWhileLoop, ForLoopsMustUseBraces, FormalParameterNamingConventions, GenericsNaming, IdenticalCatchBranches, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, LinguisticNaming, LocalHomeNamingConvention, LocalInterfaceSessionNamingConvention, LocalVariableCouldBeFinal, LocalVariableNamingConventions, LongVariable, MDBAndSessionBeanNamingConvention, MethodArgumentCouldBeFinal, MethodNamingConventions, MIsLeadingVariableName, NoPackage, NumericLiteralConvention, OnlyOneReturn, PackageCase, PrematureDeclaration, RemoteInterfaceNamingConvention, RemoteSessionInterfaceNamingConvention, ShortClassName, ShortMethodName, ShortVariable, SuspiciousConstantFieldName, TooManyStaticImports, UnnecessaryAnnotationValueElement, UnnecessaryConstructor, UnnecessaryFullyQualifiedName, UnnecessaryLocalBeforeReturn, UnnecessaryModifier, UnnecessaryReturn, UselessParentheses, UselessQualifiedThis, VariableNamingConventions, WhileLoopsMustUseBraces +keywords: Code Style, AbstractNaming, AtLeastOneConstructor, AvoidDollarSigns, AvoidFinalLocalVariable, AvoidPrefixingMethodParameters, AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending, AvoidUsingNativeCode, BooleanGetMethodName, CallSuperInConstructor, ClassNamingConventions, CommentDefaultAccessModifier, ConfusingTernary, ControlStatementBraces, DefaultPackage, DontImportJavaLang, DuplicateImports, EmptyMethodInAbstractClassShouldBeAbstract, ExtendsObject, FieldDeclarationsShouldBeAtStartOfClass, FieldNamingConventions, ForLoopShouldBeWhileLoop, ForLoopsMustUseBraces, FormalParameterNamingConventions, GenericsNaming, IdenticalCatchBranches, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, LinguisticNaming, LocalHomeNamingConvention, LocalInterfaceSessionNamingConvention, LocalVariableCouldBeFinal, LocalVariableNamingConventions, LongVariable, MDBAndSessionBeanNamingConvention, MethodArgumentCouldBeFinal, MethodNamingConventions, MIsLeadingVariableName, NoPackage, UseUnderscoresInNumericLiterals, OnlyOneReturn, PackageCase, PrematureDeclaration, RemoteInterfaceNamingConvention, RemoteSessionInterfaceNamingConvention, ShortClassName, ShortMethodName, ShortVariable, SuspiciousConstantFieldName, TooManyStaticImports, UnnecessaryAnnotationValueElement, UnnecessaryConstructor, UnnecessaryFullyQualifiedName, UnnecessaryLocalBeforeReturn, UnnecessaryModifier, UnnecessaryReturn, UselessParentheses, UselessQualifiedThis, VariableNamingConventions, WhileLoopsMustUseBraces language: Java --- ## AbstractNaming @@ -1508,38 +1508,6 @@ public class ClassInDefaultPackage { ``` -## NumericLiteralConvention - -**Since:** PMD 6.9.0 - -**Priority:** Medium (3) - -**Minimum Language Version:** Java 1.7 - -Numeric literals with more than 3 digits must use '_' as a separator. - -**This rule is defined by the following XPath expression:** -``` xpath -//Literal[@IntLiteral = true() or - @LongLiteral = true() or - @DoubleLiteral = true() or - @FloatLiteral = true()] - [not(matches(@Image, "^[0-9]{1,3}(_[0-9]{3})*(l|L|\.[0-9]+)?(d|D|f|F)?$"))] -``` - -**Example(s):** - -``` java -public class Foo { - private int num = 1000000; // should be 1_000_000 -} -``` - -**Use this rule by referencing it:** -``` xml - -``` - ## OnlyOneReturn **Since:** PMD 1.0 @@ -2235,6 +2203,40 @@ public class Foo { ``` +## UseUnderscoresInNumericLiterals + +**Since:** PMD 6.10.0 + +**Priority:** Medium (3) + +**Minimum Language Version:** Java 1.7 + +Numeric literals with more than 3 digits must use '_' as a separator. + +**This rule is defined by the following XPath expression:** +``` xpath +//Literal[@IntLiteral = true() or + @LongLiteral = true() or + @DoubleLiteral = true() or + @FloatLiteral = true()] + [not (matches(@Image, "^(0([xb]?[0-9a-fA-F]+)?|[1-9][0-9]{0,2}(_[0-9]{3})*)(l|L|\.[0-9_]+)?([eE][\+-]?[0-9]+)?[dDfF]?$"))] + [ancestor::VariableDeclarator[not (@Name = 'serialVersionUID')] or + not (ancestor::VariableDeclarator)] +``` + +**Example(s):** + +``` java +public class Foo { + private int num = 1000000; // should be 1_000_000 +} +``` + +**Use this rule by referencing it:** +``` xml + +``` + ## VariableNamingConventions Deprecated diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index e7ef25cdda..fcac95d2d8 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1366,6 +1366,8 @@ public class ClassInDefaultPackage { 3 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml index 3861a372b4..a9630167a1 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml @@ -4,9 +4,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> - + + ok, numeric literal with correct '_' usage + 0 - + + bad, numeric literal without '_' + 1 - + + bad, numeric literal used as a method parameter without '_' + 1 - + + ok, float value with less than 3 numbers. + 0 - + + bad, double value without '_' + 1 - + + ok, numeric literal used as a method parameter with '_' + 0 - + + ok, Long value with 'l' used as a method parameter with '_' + 0 - + + bad, numeric literal with incorrect '_' usage + 1 - + + ok, Double value with 'D' used as a method parameter with '_' + 0 - + + ok, Float value with 'F' with less than 3 numbers + 0 - + + ok, Double value with 'd' with correct '_' usage + 0 - + + ok, Long value with 'L' used as a method parameter with '_' + 0 - + + ok, String value with '_' + 0 - + + ok, String value without '_' + 0 - + + ok, Numeric Literal in binary + 0 - + + ok, Numeric Literal in octal + 0 - + + ok, Numeric Literal in hexadecimal + 0 - + + ok, Numeric Literal in negative binary + 0 - + + ok, Numeric Literal in negative octal + 0 - + + ok, Numeric Literal in negative hexadecimal + 0 - + + ok, Numeric Literal with exponent + 0 - - 0 + + bad, Negative exponent without '_' + + 1 - + + ok, Numeric Literal with positive exponent + 0 - + + ok, Lengthy numeric literal with variable name as serialVersionUID + 0 + + 3 + + bad, testing acceptableDecimalLength + + 1 + + + + 5 + + ok, testing acceptableDecimalLength + + 0 + + From 9b6b1a4d15b7013b302467edab093f941f5d8fc4 Mon Sep 17 00:00:00 2001 From: rajeshggwp Date: Fri, 9 Nov 2018 10:49:30 +0530 Subject: [PATCH 044/139] minor changes --- docs/pages/pmd/rules/java/codestyle.md | 19 ++++++++++++++++++- .../resources/category/java/codestyle.xml | 5 ++--- .../xml/UseUnderscoresInNumericLiterals.xml | 18 +++++++++++++++--- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index e4f9a6ba21..b996c4d06d 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -2219,7 +2219,18 @@ Numeric literals with more than 3 digits must use '_' as a separator. @LongLiteral = true() or @DoubleLiteral = true() or @FloatLiteral = true()] - [not (matches(@Image, "^(0([xb]?[0-9a-fA-F]+)?|[1-9][0-9]{0,2}(_[0-9]{3})*)(l|L|\.[0-9_]+)?([eE][\+-]?[0-9]+)?[dDfF]?$"))] + [ not (matches(@Image, "^0([xb]?[0-9a-fA-F]+)?$"))] + [ + some $num in tokenize(@Image, "[.dDfFlL]|[eE][\+-]?") + satisfies not( + string-length($num) <= $acceptableDecimalLength + and ( + not(contains($num,"_")) + or matches($num, "^[0-9]{1,3}(_[0-9]{3})*$") + ) + or matches($num, "^[0-9]{1,3}(_[0-9]{3})*$") + ) + ] [ancestor::VariableDeclarator[not (@Name = 'serialVersionUID')] or not (ancestor::VariableDeclarator)] ``` @@ -2232,6 +2243,12 @@ public class Foo { } ``` +**This rule has the following properties:** + +|Name|Default Value|Description|Multivalued| +|----|-------------|-----------|-----------| +|acceptableDecimalLength|4|Maximum acceptable length within which the rule is not applicable|no| + **Use this rule by referencing it:** ``` xml diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index fcac95d2d8..35e1390724 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1357,7 +1357,7 @@ public class ClassInDefaultPackage { language="java" since="6.10.0" minimumLanguageVersion="1.7" - message="Numeric literals with more than 3 digits must use '_' as a separator" + message="Number {0} should separate every third digit with an underscore" class="net.sourceforge.pmd.lang.rule.XPathRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#useunderscoresinnumericliterals"> @@ -1366,7 +1366,7 @@ public class ClassInDefaultPackage { 3 - @@ -1382,7 +1382,6 @@ public class ClassInDefaultPackage { string-length($num) <= $acceptableDecimalLength and ( not(contains($num,"_")) - or matches($num, "^[0-9]{1,3}(_[0-9]{3})*$") ) or matches($num, "^[0-9]{1,3}(_[0-9]{3})*$") ) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml index a9630167a1..965fa06f22 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml @@ -273,15 +273,15 @@ public class Foo { 0 - 3 bad, testing acceptableDecimalLength + 3 1 - 5 ok, testing acceptableDecimalLength + 5 0 + + + + bad, testing acceptableDecimalLength + + 10 + 1 + From 750381c65a02e9faf2461a9386644ca7c417b7f8 Mon Sep 17 00:00:00 2001 From: rajeshggwp Date: Sat, 10 Nov 2018 16:04:29 +0530 Subject: [PATCH 045/139] minor regex change --- docs/pages/pmd/rules/java/codestyle.md | 5 ++--- .../src/main/resources/category/java/codestyle.xml | 4 ++-- .../xml/UseUnderscoresInNumericLiterals.xml | 13 ++++++++++++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index b996c4d06d..73484fe5de 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -2219,14 +2219,13 @@ Numeric literals with more than 3 digits must use '_' as a separator. @LongLiteral = true() or @DoubleLiteral = true() or @FloatLiteral = true()] - [ not (matches(@Image, "^0([xb]?[0-9a-fA-F]+)?$"))] + [ not (matches(@Image, "^0[^.]"))] [ - some $num in tokenize(@Image, "[.dDfFlL]|[eE][\+-]?") + some $num in tokenize(@Image, "[.dDfFlLeE\-\+]") satisfies not( string-length($num) <= $acceptableDecimalLength and ( not(contains($num,"_")) - or matches($num, "^[0-9]{1,3}(_[0-9]{3})*$") ) or matches($num, "^[0-9]{1,3}(_[0-9]{3})*$") ) diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 35e1390724..126948bab4 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1375,9 +1375,9 @@ public class ClassInDefaultPackage { @LongLiteral = true() or @DoubleLiteral = true() or @FloatLiteral = true()] - [ not (matches(@Image, "^0([xb]?[0-9a-fA-F]+)?$"))] + [ not (matches(@Image, "^0[^.]"))] [ - some $num in tokenize(@Image, "[.dDfFlL]|[eE][\+-]?") + some $num in tokenize(@Image, "[.dDfFlLeE\-\+]") satisfies not( string-length($num) <= $acceptableDecimalLength and ( diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml index 965fa06f22..403dfd7d1f 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseUnderscoresInNumericLiterals.xml @@ -307,11 +307,22 @@ public class Foo { bad, testing acceptableDecimalLength - 10 + 15 1 + + + + ok, Decimal number test + + 0 + From acff745aae6c7052e0463f87703a7779c24871a1 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 10 Nov 2018 08:10:00 -0300 Subject: [PATCH 046/139] Infer type in generic instance creation. Infer type in generic instance creation. --- .../main/java/net/sourceforge/pmd/cpd/FortranTokenizer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pmd-fortran/src/main/java/net/sourceforge/pmd/cpd/FortranTokenizer.java b/pmd-fortran/src/main/java/net/sourceforge/pmd/cpd/FortranTokenizer.java index 30d3ba70dd..d5a30f1bb8 100644 --- a/pmd-fortran/src/main/java/net/sourceforge/pmd/cpd/FortranTokenizer.java +++ b/pmd-fortran/src/main/java/net/sourceforge/pmd/cpd/FortranTokenizer.java @@ -19,16 +19,16 @@ public class FortranTokenizer extends AbstractTokenizer implements Tokenizer { public FortranTokenizer() { this.spanMultipleLinesString = false; // No such thing in Fortran ! // setting markers for "string" in Fortran - this.stringToken = new ArrayList(); + this.stringToken = new ArrayList<>(); this.stringToken.add("\'"); // setting markers for 'ignorable character' in Fortran - this.ignorableCharacter = new ArrayList(); + this.ignorableCharacter = new ArrayList<>(); this.ignorableCharacter.add("("); this.ignorableCharacter.add(")"); this.ignorableCharacter.add(","); // setting markers for 'ignorable string' in Fortran - this.ignorableStmt = new ArrayList(); + this.ignorableStmt = new ArrayList<>(); this.ignorableStmt.add("do"); this.ignorableStmt.add("while"); this.ignorableStmt.add("end"); From 9c179234ac48fc094aa7f4e2b12ed23ba52dc51f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Sat, 10 Nov 2018 13:32:33 -0300 Subject: [PATCH 047/139] Add new rules to release sourceset --- .../src/main/resources/rulesets/releases/6100.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 pmd-core/src/main/resources/rulesets/releases/6100.xml diff --git a/pmd-core/src/main/resources/rulesets/releases/6100.xml b/pmd-core/src/main/resources/rulesets/releases/6100.xml new file mode 100644 index 0000000000..61132559f2 --- /dev/null +++ b/pmd-core/src/main/resources/rulesets/releases/6100.xml @@ -0,0 +1,14 @@ + + + + +This ruleset contains links to rules that are new in PMD v6.10.0 + + + + + + From 85c82c3c6da364d5cd60f2ae87ac7e11d8f59b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Sat, 10 Nov 2018 13:38:37 -0300 Subject: [PATCH 048/139] Update release notes, refs #1384 --- docs/pages/release_notes.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 782bfa0d1e..89d1f50e57 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,18 +14,26 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### New Rules + +* The new Java rule [`UseUnderscoresInNumericLiterals`](https://pmd.github.io/pmd-6.10.0/pmd_rules_java_codestyle.html#useunderscoresinnumericliterals) + (`java-codestyle`) verifies that numeric literals over a given length (4 chars by default, but configurable) are using underscores every 3 digits for readability. + The rule only applies to Java 7+ codebases. + ### Fixed Issues * all * [#1318](https://github.com/pmd/pmd/issues/1318): \[test] Kotlin DSL to ease test writing * [#1341](https://github.com/pmd/pmd/issues/1341): \[doc] Documentation Error with Regex Properties * java-codestyle + * [#1232](https://github.com/pmd/pmd/issues/1232): \[java] Detector for large numbers not separated by _ * [#1372](https://github.com/pmd/pmd/issues/1372): \[java] false positive for UselessQualifiedThis ### API Changes ### External Contributions +* [#1384](https://github.com/pmd/pmd/pull/1384): \[java] New Rule - UseUnderscoresInNumericLiterals - [RajeshR](https://github.com/rajeshggwp) * [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007) * [#1428](https://github.com/pmd/pmd/pull/1428): \[core] Upgrading JCommander from 1.48 to 1.72 - [Thunderforge](https://github.com/Thunderforge) * [#1430](https://github.com/pmd/pmd/pull/1430): \[doc] Who really knows regex? - [Dem Pilafian](https://github.com/dpilafian) From 3f92b9d44d8c3e98139171e4b1d77e1aa50a94fa Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 10 Nov 2018 18:00:11 +0100 Subject: [PATCH 049/139] [doc] Mention PmdRuleTst class in "Testing your rules" --- docs/pages/pmd/userdocs/extending/testing.md | 31 +++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/testing.md b/docs/pages/pmd/userdocs/extending/testing.md index 53935be048..d7ac79032c 100644 --- a/docs/pages/pmd/userdocs/extending/testing.md +++ b/docs/pages/pmd/userdocs/extending/testing.md @@ -3,7 +3,7 @@ title: Testing your rules tags: [extending, userdocs] summary: "Learn how to use PMD's simple test framework for unit testing rules." permalink: pmd_userdocs_extending_testing.html -last_updated: September 2017 +last_updated: November 2018 author: Andreas Dangel --- @@ -14,7 +14,7 @@ a violation - and a negative test case - a code example, that doesn't trigger th Of course, the more tests, the better the rule is verified. If the rule is more complex or defines properties, with which the behavior can be modified, then these different cases can also be tested. -And if there is a bug fix for a rule, be it a false positive or a false negative case, should be accompanied +And if there is a bug fix for a rule, be it a false positive or a false negative case, it should be accompanied with an additional test case, so that the bug is not accidentally reintroduced later on. ## How it works @@ -25,7 +25,7 @@ Each category-ruleset has a single abstract base test class, from which the indi We have one test class per rule, which executes all test cases for a single rule. The actual test cases are stored in separate XML files, for each rule a separate file is used. -All the test classes inherit from `net.sourceforge.pmd.testframework.SimpleAggregatorTst`, +All the test classes inherit from `net.sourceforge.pmd.testframework.PmdRuleTst`, which provides the seamless integration with JUnit. This base class determines the language, the category name and the rule name from the concrete test class. It then searches the test code on its own. E.g. the individual rule test class @@ -41,7 +41,7 @@ test case and just execute this one. ## Where to place the test code -The `SimpleAggregatorTst` class searches the XML file, that describes the test cases for a certain rule +The `PmdRuleTst` class searches the XML file, that describes the test cases for a certain rule using the following convention: The XML file is a test resource, so it is searched in the tree under `src/test/resources`. @@ -65,19 +65,22 @@ In general, the class name and file name pattern for the test class and data is Just search in the project for a file `.xml`. Search for a class `Test` to find the unit test class for the given rule." %} +{%include note.html content="If you want to use the test framework with a different package structure, +see [Using the test framework externally](#using-the-test-framework-externally)." %} + ## Simple example ### Test Class: AbstractClassWithoutAbstractMethodTest -This class inherits from `SimpleAggregatorTst` and is located in the package "bestpractices", since the rule +This class inherits from `PmdRuleTst` and is located in the package "bestpractices", since the rule belongs to the category "Best Practices": ``` java package net.sourceforge.pmd.lang.java.rule.bestpractices; -import net.sourceforge.pmd.testframework.SimpleAggregatorTst; +import net.sourceforge.pmd.testframework.PmdRuleTst; -public class AbstractClassWithoutAbstractMethodTest extends SimpleAggregatorTst { +public class AbstractClassWithoutAbstractMethodTest extends PmdRuleTst { // no additional unit tests } ``` @@ -94,7 +97,7 @@ This is a stripped down example which just contains two test cases. + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests https://pmd.sourceforge.io/rule-tests_1_0_0.xsd"> concrete class 0 @@ -177,7 +180,11 @@ in a "CDATA" section, so that no further XML escapes (entity references such as ``` xml - + + Just a description, will be used as the test name for JUnit in the reports propValue @@ -252,7 +259,11 @@ The test data should be placed in an xml file located in "src/test/resources" un The framework uses a custom JUnit test runner under the hood, among a couple of utility classes: -* `SimpleAggregatorTst`: This is the base class for the test classes and defines the custom JUnit test runner. +* `PmdRuleTst`: This is the base class for tests in PMD's code base. It is a subclass of `RuleTst` and just + contains the logic to determine the test resources based on the test class name. + +* `SimpleAggregatorTst`: This is a more generic base class for the test classes and defines + the custom JUnit test runner. It doesn't register any test cases on its own. It itself is a subclass of `RuleTst`. * `RuleTst`: contains the logic to parse the XML files and provide a list of `TestDescriptor`s. Each test descriptor From 2e3866fbd4a6f4458fea6899822d82bfc9a7ce3d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 10 Nov 2018 18:00:30 +0100 Subject: [PATCH 050/139] [doc] Update gems --- docs/Gemfile.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index bcbffbb980..beeebfcad2 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -15,7 +15,7 @@ GEM colorator (1.1.0) commonmarker (0.17.13) ruby-enum (~> 0.5) - concurrent-ruby (1.0.5) + concurrent-ruby (1.1.3) dnsruby (1.61.2) addressable (~> 2.5) em-websocket (0.5.1) @@ -81,7 +81,7 @@ GEM octokit (~> 4.0) public_suffix (~> 2.0) typhoeus (~> 1.3) - html-pipeline (2.8.4) + html-pipeline (2.9.0) activesupport (>= 2) nokogiri (>= 1.4) http_parser.rb (0.6.0) @@ -185,7 +185,7 @@ GEM jekyll-seo-tag (~> 2.0) jekyll-titles-from-headings (0.5.1) jekyll (~> 3.3) - jekyll-watch (2.0.0) + jekyll-watch (2.1.2) listen (~> 3.0) jemoji (0.10.1) gemoji (~> 3.0) @@ -205,11 +205,11 @@ GEM jekyll-seo-tag (~> 2.1) minitest (5.11.3) multipart-post (2.0.0) - nokogiri (1.8.4) + nokogiri (1.8.5) mini_portile2 (~> 2.3.0) - octokit (4.12.0) + octokit (4.13.0) sawyer (~> 0.8.0, >= 0.5.3) - pathutil (0.16.1) + pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (2.0.5) rb-fsevent (0.10.3) @@ -221,7 +221,7 @@ GEM ruby_dep (1.5.0) rubyzip (1.2.2) safe_yaml (1.0.4) - sass (3.6.0) + sass (3.7.2) sass-listen (~> 4.0.0) sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) @@ -232,7 +232,7 @@ GEM terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) thread_safe (0.3.6) - typhoeus (1.3.0) + typhoeus (1.3.1) ethon (>= 0.9.0) tzinfo (1.2.5) thread_safe (~> 0.1) From 1aa1d1f2a53bed8a659f853e839531b4a0507534 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 10 Nov 2018 19:20:02 +0100 Subject: [PATCH 051/139] [ui] make the language dependencies optional * This makes it easier to create a customized and tailored PMD distribution. * Also sort the languages alphabetically --- pmd-ui/pom.xml | 60 ++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/pmd-ui/pom.xml b/pmd-ui/pom.xml index 77843bb713..89b7862a28 100644 --- a/pmd-ui/pom.xml +++ b/pmd-ui/pom.xml @@ -70,11 +70,6 @@ net.sourceforge.pmd pmd-core - - net.sourceforge.pmd - pmd-java - ${project.version} - @@ -147,36 +142,49 @@ net.sourceforge.pmd pmd-apex ${project.version} + true net.sourceforge.pmd - pmd-jsp - ${project.version} - - - net.sourceforge.pmd - pmd-plsql - ${project.version} - - - net.sourceforge.pmd - pmd-visualforce - ${project.version} - - - net.sourceforge.pmd - pmd-xml - ${project.version} - - - net.sourceforge.pmd - pmd-vm + pmd-java ${project.version} + true net.sourceforge.pmd pmd-javascript ${project.version} + true + + + net.sourceforge.pmd + pmd-jsp + ${project.version} + true + + + net.sourceforge.pmd + pmd-plsql + ${project.version} + true + + + net.sourceforge.pmd + pmd-visualforce + ${project.version} + true + + + net.sourceforge.pmd + pmd-vm + ${project.version} + true + + + net.sourceforge.pmd + pmd-xml + ${project.version} + true junit From 2aae4b0272e0310037b40319b356784c59ed2ed8 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 10 Nov 2018 20:37:14 +0100 Subject: [PATCH 052/139] Update release notes, use rule tag --- docs/pages/release_notes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 89d1f50e57..35e8909643 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -16,9 +16,9 @@ This is a {{ site.pmd.release_type }} release. #### New Rules -* The new Java rule [`UseUnderscoresInNumericLiterals`](https://pmd.github.io/pmd-6.10.0/pmd_rules_java_codestyle.html#useunderscoresinnumericliterals) - (`java-codestyle`) verifies that numeric literals over a given length (4 chars by default, but configurable) are using underscores every 3 digits for readability. - The rule only applies to Java 7+ codebases. +* The new Java rule {% rule "java/codestyle/UseUnderscoresInNumericLiterals" %} (`java-codestyle`) + verifies that numeric literals over a given length (4 chars by default, but configurable) are using + underscores every 3 digits for readability. The rule only applies to Java 7+ codebases. ### Fixed Issues From b0518c902fd0b9f516a0660f4a1f5aee3a0576e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 11 Nov 2018 14:07:23 +0100 Subject: [PATCH 053/139] Format UseUnderscoresInNumericLiterals xpath --- .../resources/category/java/codestyle.xml | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 126948bab4..b5ded22baf 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1361,33 +1361,39 @@ public class ClassInDefaultPackage { class="net.sourceforge.pmd.lang.rule.XPathRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#useunderscoresinnumericliterals"> - Numeric literals with more than 3 digits must use '_' as a separator. + Since Java 1.7, numeric literals can use underscores to separate digits. This rule enforces that + numeric literals above a certain length use these underscores to increase readability. + + The rule only supports decimal (base 10) literals for now. The acceptable length under which literals + are not required to have underscores is configurable via a property. Even under that length, underscores + that are misplaced (not making groups of 3 digits) are reported. 3 + description="Length under which literals in base 10 are not required to have underscores"/> From 1cfc477e4877696b6370ebd772fa7ef19a872647 Mon Sep 17 00:00:00 2001 From: "Travis CI (pmd-bot)" Date: Sun, 11 Nov 2018 13:25:37 +0000 Subject: [PATCH 054/139] Update documentation TRAVIS_JOB_NUMBER=3044.1 TRAVIS_COMMIT_RANGE=2aae4b0272e0...b0518c902fd0 --- docs/pages/pmd/rules/java.md | 2 +- docs/pages/pmd/rules/java/codestyle.md | 40 +++++++++++++++----------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/docs/pages/pmd/rules/java.md b/docs/pages/pmd/rules/java.md index 0930e39913..12b3ab615d 100644 --- a/docs/pages/pmd/rules/java.md +++ b/docs/pages/pmd/rules/java.md @@ -116,7 +116,7 @@ folder: pmd/rules * [UnnecessaryReturn](pmd_rules_java_codestyle.html#unnecessaryreturn): Avoid the use of unnecessary return statements. * [UselessParentheses](pmd_rules_java_codestyle.html#uselessparentheses): Useless parentheses should be removed. * [UselessQualifiedThis](pmd_rules_java_codestyle.html#uselessqualifiedthis): Reports qualified this usages in the same class. -* [UseUnderscoresInNumericLiterals](pmd_rules_java_codestyle.html#useunderscoresinnumericliterals): Numeric literals with more than 3 digits must use '_' as a separator. +* [UseUnderscoresInNumericLiterals](pmd_rules_java_codestyle.html#useunderscoresinnumericliterals): Since Java 1.7, numeric literals can use underscores to separate digits. This rule enforces that ... * [VariableNamingConventions](pmd_rules_java_codestyle.html#variablenamingconventions): Deprecated A variable naming conventions rule - customize this to your liking. Currently, itchecks for fina... * [WhileLoopsMustUseBraces](pmd_rules_java_codestyle.html#whileloopsmustusebraces): Deprecated Avoid using 'while' statements without using braces to surround the code block. If the code forma... diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index 73484fe5de..4341da7a73 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -2211,27 +2211,33 @@ public class Foo { **Minimum Language Version:** Java 1.7 -Numeric literals with more than 3 digits must use '_' as a separator. +Since Java 1.7, numeric literals can use underscores to separate digits. This rule enforces that +numeric literals above a certain length use these underscores to increase readability. + +The rule only supports decimal (base 10) literals for now. The acceptable length under which literals +are not required to have underscores is configurable via a property. Even under that length, underscores +that are misplaced (not making groups of 3 digits) are reported. **This rule is defined by the following XPath expression:** ``` xpath -//Literal[@IntLiteral = true() or - @LongLiteral = true() or - @DoubleLiteral = true() or - @FloatLiteral = true()] - [ not (matches(@Image, "^0[^.]"))] +//Literal[ + @IntLiteral = true() + or @LongLiteral = true() + or @DoubleLiteral = true() + or @FloatLiteral = true() +] + (: Filter out literals in base other than 10 :) + [not(matches(@Image, "^0[^.]"))] + (: Filter out ignored field name :) + [not(ancestor::VariableDeclarator[1][@Name = 'serialVersionUID'])] [ - some $num in tokenize(@Image, "[.dDfFlLeE\-\+]") - satisfies not( - string-length($num) <= $acceptableDecimalLength - and ( - not(contains($num,"_")) - ) - or matches($num, "^[0-9]{1,3}(_[0-9]{3})*$") - ) + some $num in tokenize(@Image, "[.dDfFlLeE+\-]") + satisfies not( + string-length($num) <= $acceptableDecimalLength + and not(contains($num,"_")) + or matches($num, "^[0-9]{1,3}(_[0-9]{3})*$") + ) ] - [ancestor::VariableDeclarator[not (@Name = 'serialVersionUID')] or - not (ancestor::VariableDeclarator)] ``` **Example(s):** @@ -2246,7 +2252,7 @@ public class Foo { |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|acceptableDecimalLength|4|Maximum acceptable length within which the rule is not applicable|no| +|acceptableDecimalLength|4|Length under which literals in base 10 are not required to have underscores|no| **Use this rule by referencing it:** ``` xml From 6fb8b6b1b6b65a168e0c23e88763ac95ddc2c365 Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Mon, 12 Nov 2018 01:56:35 +0530 Subject: [PATCH 055/139] Adding the fix for #1440 --- pmd-java/etc/grammar/Java.jjt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 991335622f..6045a4d59a 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1854,7 +1854,7 @@ void ConstructorDeclaration(int modifiers) : Token t;} { [ TypeParameters() ] - FormalParameters() [ "throws" NameList() ] + t= {jjtThis.setImage(t.image);} FormalParameters() [ "throws" NameList() ] "{" [ LOOKAHEAD(ExplicitConstructorInvocation()) ExplicitConstructorInvocation() ] ( BlockStatement() )* From b83698a58e74d813a4556a2b6a2a869fc4ef3a64 Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Mon, 12 Nov 2018 11:12:49 +0100 Subject: [PATCH 056/139] Added test cases for Kotlin support for CPD. --- .../sourceforge/pmd/LanguageVersionTest.java | 27 +++++++++ .../pmd/cpd/KotlinTokenizerTest.java | 56 +++++++++++++++++++ .../net/sourceforge/pmd/cpd/comment.kt | 27 +++++++++ .../net/sourceforge/pmd/cpd/imports.kt | 4 ++ .../net/sourceforge/pmd/cpd/increment.kt | 25 +++++++++ 5 files changed, 139 insertions(+) create mode 100644 pmd-kotlin/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java create mode 100644 pmd-kotlin/src/test/java/net/sourceforge/pmd/cpd/KotlinTokenizerTest.java create mode 100644 pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/comment.kt create mode 100644 pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/imports.kt create mode 100644 pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/increment.kt diff --git a/pmd-kotlin/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java b/pmd-kotlin/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java new file mode 100644 index 0000000000..a60ae63ecc --- /dev/null +++ b/pmd-kotlin/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java @@ -0,0 +1,27 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import java.util.Arrays; +import java.util.Collection; + +import org.junit.runners.Parameterized.Parameters; + +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.kotlin.KotlinLanguageModule; + +public class LanguageVersionTest extends AbstractLanguageVersionTest { + + public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) { + super(name, terseName, version, expected); + } + + @Parameters + public static Collection data() { + return Arrays.asList(new Object[][] { { KotlinLanguageModule.NAME, KotlinLanguageModule.TERSE_NAME, "1.3", + LanguageRegistry.getLanguage(KotlinLanguageModule.NAME).getDefaultVersion(), }, }); + } +} diff --git a/pmd-kotlin/src/test/java/net/sourceforge/pmd/cpd/KotlinTokenizerTest.java b/pmd-kotlin/src/test/java/net/sourceforge/pmd/cpd/KotlinTokenizerTest.java new file mode 100644 index 0000000000..6d45a5bc8b --- /dev/null +++ b/pmd-kotlin/src/test/java/net/sourceforge/pmd/cpd/KotlinTokenizerTest.java @@ -0,0 +1,56 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.cpd; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; + +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import net.sourceforge.pmd.testframework.AbstractTokenizerTest; + +@RunWith(Parameterized.class) +public class KotlinTokenizerTest extends AbstractTokenizerTest { + + private final String filename; + private final int nExpectedTokens; + + public KotlinTokenizerTest(String filename, int nExpectedTokens) { + this.filename = filename; + this.nExpectedTokens = nExpectedTokens; + } + + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList( + new Object[] { "comment.kt", 5 }, + new Object[] { "increment.kt", 185 }, + new Object[] { "imports.kt", 1 } + ); + } + + @Before + @Override + public void buildTokenizer() throws IOException { + this.tokenizer = new KotlinTokenizer(); + this.sourceCode = new SourceCode(new SourceCode.StringCodeLoader(this.getSampleCode(), this.filename)); + } + + @Override + public String getSampleCode() throws IOException { + return IOUtils.toString(KotlinTokenizer.class.getResourceAsStream(this.filename)); + } + + @Test + public void tokenizeTest() throws IOException { + this.expectedTokenCount = nExpectedTokens; + super.tokenizeTest(); + } +} diff --git a/pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/comment.kt b/pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/comment.kt new file mode 100644 index 0000000000..3f0e783d82 --- /dev/null +++ b/pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/comment.kt @@ -0,0 +1,27 @@ +package com.github.shyiko.ktlint.internal + +var x = 0 + +/* +fun increment1() { x += 1 } +fun increment2() { x += 1 } +fun increment3() { x += 1 } +fun increment4() { x += 1 } +fun increment5() { x += 1 } +fun increment6() { x += 1 } +fun increment7() { x += 1 } +fun increment8() { x += 1 } +fun increment9() { x += 1 } +fun increment10() { x += 1 } +fun increment11() { x += 1 } +fun increment12() { x += 1 } +fun increment13() { x += 1 } +fun increment14() { x += 1 } +fun increment15() { x += 1 } +fun increment16() { x += 1 } +fun increment17() { x += 1 } +fun increment18() { x += 1 } +fun increment19() { x += 1 } +fun increment20() { x += 1 } +*/ + diff --git a/pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/imports.kt b/pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/imports.kt new file mode 100644 index 0000000000..3f284aa546 --- /dev/null +++ b/pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/imports.kt @@ -0,0 +1,4 @@ +import java.math.BigInteger +import java.math.BigInteger as BigInt +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.* diff --git a/pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/increment.kt b/pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/increment.kt new file mode 100644 index 0000000000..58bd764e53 --- /dev/null +++ b/pmd-kotlin/src/test/resources/net/sourceforge/pmd/cpd/increment.kt @@ -0,0 +1,25 @@ +package com.github.shyiko.ktlint.internal + +var x = 0 + +fun increment1() { x += 1 } +fun increment2() { x += 1 } +fun increment3() { x += 1 } +fun increment4() { x += 1 } +fun increment5() { x += 1 } +fun increment6() { x += 1 } +fun increment7() { x += 1 } +fun increment8() { x += 1 } +fun increment9() { x += 1 } +fun increment10() { x += 1 } +fun increment11() { x += 1 } +fun increment12() { x += 1 } +fun increment13() { x += 1 } +fun increment14() { x += 1 } +fun increment15() { x += 1 } +fun increment16() { x += 1 } +fun increment17() { x += 1 } +fun increment18() { x += 1 } +fun increment19() { x += 1 } +fun increment20() { x += 1 } + From a7f3f714013c2953229e5b388237f33e506f4008 Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Mon, 12 Nov 2018 11:15:05 +0100 Subject: [PATCH 057/139] Adjusted Kotlin language module to specify version and correct extension. --- .../net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java index c405b3f409..acfa4cbf0d 100644 --- a/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java +++ b/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java @@ -20,7 +20,7 @@ public class KotlinLanguageModule extends BaseLanguageModule { * Create a new instance of Kotlin Language Module. */ public KotlinLanguageModule() { - super(NAME, null, TERSE_NAME, null, "kotlin"); - addVersion("", null, true); + super(NAME, null, TERSE_NAME, null, "kt"); + addVersion("1.3", null, true); } } From a46331264651423e8a11c748561a5704eca5524b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 12 Nov 2018 12:56:14 +0100 Subject: [PATCH 058/139] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d1e1deec2f..2c40e966e1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Build Status](https://travis-ci.org/pmd/pmd.svg?branch=master)](https://travis-ci.org/pmd/pmd) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/net.sourceforge.pmd/pmd/badge.svg)](https://maven-badges.herokuapp.com/maven-central/net.sourceforge.pmd/pmd) [![Coverage Status](https://coveralls.io/repos/github/pmd/pmd/badge.svg)](https://coveralls.io/github/pmd/pmd) - +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a674ee8642ed44c6ba7633626ee95967)](https://www.codacy.com/app/pmd/pmd?utm_source=github.com&utm_medium=referral&utm_content=pmd/pmd&utm_campaign=Badge_Grade) ## About **PMD** is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, From 874b528da842b84c28077acff9b63f8130c4bdd2 Mon Sep 17 00:00:00 2001 From: Rohit Kumar Date: Mon, 12 Nov 2018 17:35:29 +0530 Subject: [PATCH 059/139] Adding test cases and fixing review comments --- pmd-java/etc/grammar/Java.jjt | 2 +- .../xml/CommentDefaultAccessModifier.xml | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 6045a4d59a..b84165ca98 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1854,7 +1854,7 @@ void ConstructorDeclaration(int modifiers) : Token t;} { [ TypeParameters() ] - t= {jjtThis.setImage(t.image);} FormalParameters() [ "throws" NameList() ] + {jjtThis.setImage(getToken(0).getImage());} FormalParameters() [ "throws" NameList() ] "{" [ LOOKAHEAD(ExplicitConstructorInvocation()) ExplicitConstructorInvocation() ] ( BlockStatement() )* diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml index 2a8874ff8e..a01d2c9997 100755 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml @@ -254,4 +254,25 @@ public class CommentDefaultAccessModifier { } ]]> + + + + + Add a comment to the constructors with default access modifiers to avoid mistakes + 2 + 2,4 + + To avoid mistakes add a comment at the beginning of the Foo constructor if you want a default access modifier + To avoid mistakes add a comment at the beginning of the Foo constructor if you want a default access modifier + + + \ No newline at end of file From 1dd9cfd17b0a77b08861591cc59794dfd7828081 Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Mon, 12 Nov 2018 14:31:23 +0100 Subject: [PATCH 060/139] Adjusted version of pmd-kotlin subproject. --- pmd-kotlin/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-kotlin/pom.xml b/pmd-kotlin/pom.xml index 4d58dd1783..42693d5485 100644 --- a/pmd-kotlin/pom.xml +++ b/pmd-kotlin/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.4.0 + 6.10.0-SNAPSHOT From 166e17f483bc3df38f2be547ba63aa30e29d9f02 Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Mon, 12 Nov 2018 14:35:59 +0100 Subject: [PATCH 061/139] Simplified Kotlin tokenizer. --- .../sourceforge/pmd/cpd/KotlinTokenizer.java | 92 +++++-------------- 1 file changed, 25 insertions(+), 67 deletions(-) diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java index 8ff8349c1f..17da5ec802 100644 --- a/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java +++ b/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java @@ -4,101 +4,59 @@ package net.sourceforge.pmd.cpd; -import org.antlr.v4.runtime.ANTLRInputStream; -import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import org.antlr.v4.runtime.RecognitionException; -import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.Token; -import net.sourceforge.pmd.lang.ast.TokenMgrError; +import net.sourceforge.pmd.cpd.token.AntlrToken; +import net.sourceforge.pmd.lang.antlr.AntlrTokenManager; import net.sourceforge.pmd.lang.kotlin.antlr4.Kotlin; /** * The Kotlin Tokenizer */ -public class KotlinTokenizer implements Tokenizer { +public class KotlinTokenizer extends AntlrTokenizer { private boolean discardingPackageAndImport = false; @Override - public void tokenize(final SourceCode sourceCode, final Tokens tokenEntries) { - final StringBuilder buffer = sourceCode.getCodeBuffer(); - - try { - final ANTLRInputStream ais = new ANTLRInputStream(buffer.toString()); - final Kotlin lexer = new Kotlin(ais); - - lexer.removeErrorListeners(); - lexer.addErrorListener(new ErrorHandler()); - Token token = lexer.nextToken(); - - while (token.getType() != Token.EOF) { - analyzeTokenStart(token); - if (token.getChannel() != Lexer.HIDDEN && token.getType() != Kotlin.NL && !isDiscarding()) { - final TokenEntry tokenEntry = new TokenEntry(token.getText(), sourceCode.getFileName(), token.getLine()); - tokenEntries.add(tokenEntry); - } - analyzeTokenEnd(token); - token = lexer.nextToken(); + protected AntlrTokenManager getLexerForSource(SourceCode sourceCode) { + CharStream charStream = AntlrTokenizer.getCharStreamFromSourceCode(sourceCode); + final Lexer lexer = new Kotlin(charStream); + final AntlrTokenManager tokenManager = new AntlrTokenManager(lexer, sourceCode.getFileName()) { + @Override + public Object getNextToken() { + AntlrToken nextToken; + boolean done = false; + do { + nextToken = (AntlrToken) super.getNextToken(); + analyzeTokenStart(nextToken); + if (!nextToken.isHidden() && nextToken.getType() != Kotlin.NL && !isDiscarding()) { + done = true; + } + analyzeTokenEnd(nextToken); + } while (!done && nextToken.getType() != Token.EOF); + return nextToken; } - } catch (final ANTLRSyntaxError err) { - // Wrap exceptions of the Kotlin tokenizer in a TokenMgrError, so - // they are correctly handled - // when CPD is executed with the '--skipLexicalErrors' command line - // option - throw new TokenMgrError("Lexical error in file " + sourceCode.getFileName() + " at line " + err.getLine() - + ", column " + err.getColumn() + ". Encountered: " + err.getMessage(), - TokenMgrError.LEXICAL_ERROR); - } finally { - tokenEntries.add(TokenEntry.getEOF()); - } + }; + return tokenManager; } private boolean isDiscarding() { return discardingPackageAndImport; } - private void analyzeTokenStart(final Token currentToken) { + private void analyzeTokenStart(final AntlrToken currentToken) { final int type = currentToken.getType(); if (type == Kotlin.PACKAGE || type == Kotlin.IMPORT) { discardingPackageAndImport = true; } } - private void analyzeTokenEnd(final Token currentToken) { + private void analyzeTokenEnd(final AntlrToken currentToken) { final int type = currentToken.getType(); if (discardingPackageAndImport && (type == Kotlin.SEMICOLON || type == Kotlin.NL)) { discardingPackageAndImport = false; } } - - - private static class ErrorHandler extends BaseErrorListener { - @Override - public void syntaxError(final Recognizer recognizer, final Object offendingSymbol, final int line, final int charPositionInLine, - final String msg, final RecognitionException ex) { - throw new ANTLRSyntaxError(msg, line, charPositionInLine, ex); - } - } - - private static class ANTLRSyntaxError extends RuntimeException { - private static final long serialVersionUID = 1L; - private final int line; - private final int column; - - ANTLRSyntaxError(final String msg, final int line, final int column, final RecognitionException cause) { - super(msg, cause); - this.line = line; - this.column = column; - } - - public int getLine() { - return line; - } - - public int getColumn() { - return column; - } - } } From 698935d2b4367bff19674a0fa436580e69c19aac Mon Sep 17 00:00:00 2001 From: ledoyen Date: Fri, 9 Nov 2018 15:05:34 +0100 Subject: [PATCH 062/139] Resolve type for ASTLiteral --- .../pmd/lang/java/ast/ASTLiteral.java | 68 +++++++------------ .../pmd/lang/java/ast/ASTLiteralTest.java | 24 +++++-- 2 files changed, 44 insertions(+), 48 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java index 2a18732390..b8ac76dacf 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java @@ -11,11 +11,6 @@ import java.util.regex.Pattern; public class ASTLiteral extends AbstractJavaTypeNode { - private boolean isInt; - private boolean isFloat; - private boolean isChar; - private boolean isString; - /** * Pattern used to detect a single escaped character or octal character in a * String. @@ -40,17 +35,18 @@ public class ASTLiteral extends AbstractJavaTypeNode { } public void setIntLiteral() { - this.isInt = true; + String image = getImage(); + if (image != null) { + if (image.endsWith("l") || image.endsWith("L")) { + setType(long.class); + } else { + setType(int.class); + } + } } public boolean isIntLiteral() { - String image = getImage(); - if (isInt && image != null && image.length() > 0) { - if (!image.endsWith("l") && !image.endsWith("L")) { - return true; - } - } - return false; + return int.class == getType(); } /** @@ -59,28 +55,23 @@ public class ASTLiteral extends AbstractJavaTypeNode { * @return true if this literal is a long */ public boolean isLongLiteral() { - String image = getImage(); - if (isInt && image != null && image.length() > 0) { - if (image.endsWith("l") || image.endsWith("L")) { - return true; - } - } - return false; + return long.class == getType(); } public void setFloatLiteral() { - this.isFloat = true; + String image = getImage(); + if (image != null && !image.isEmpty()) { + char lastChar = image.charAt(image.length() - 1); + if (lastChar == 'f' || lastChar == 'F') { + setType(float.class); + } else if (lastChar == 'd' || lastChar == 'D' || Character.isDigit(lastChar) || lastChar == '.') { + setType(double.class); + } + } } public boolean isFloatLiteral() { - String image = getImage(); - if (isFloat && image != null && image.length() > 0) { - char lastChar = image.charAt(image.length() - 1); - if (lastChar == 'f' || lastChar == 'F') { - return true; - } - } - return false; + return float.class == getType(); } /** @@ -89,14 +80,7 @@ public class ASTLiteral extends AbstractJavaTypeNode { * @return true if this literal is a double. */ public boolean isDoubleLiteral() { - String image = getImage(); - if (isFloat && image != null && image.length() > 0) { - char lastChar = image.charAt(image.length() - 1); - if (lastChar == 'd' || lastChar == 'D' || Character.isDigit(lastChar) || lastChar == '.') { - return true; - } - } - return false; + return double.class == getType(); } private String stripIntValue() { @@ -166,19 +150,19 @@ public class ASTLiteral extends AbstractJavaTypeNode { } public void setCharLiteral() { - this.isChar = true; + setType(char.class); } public boolean isCharLiteral() { - return isChar; + return char.class == getType(); } public void setStringLiteral() { - this.isString = true; + setType(String.class); } public boolean isStringLiteral() { - return isString; + return String.class == getType(); } /** @@ -217,7 +201,7 @@ public class ASTLiteral extends AbstractJavaTypeNode { * @return true is this is a String literal with only one character */ public boolean isSingleCharacterStringLiteral() { - if (isString) { + if (isStringLiteral()) { String image = getImage(); int length = image.length(); if (length == 3) { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java index eb99628175..d3bbef0084 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java @@ -20,7 +20,9 @@ public class ASTLiteralTest { @Test public void testIsStringLiteral() { Set literals = getNodes(ASTLiteral.class, TEST1); - assertTrue((literals.iterator().next()).isStringLiteral()); + ASTLiteral literal = literals.iterator().next(); + assertTrue(literal.isStringLiteral()); + assertEquals("java.lang.String", literal.getType().getName()); } @Test @@ -32,31 +34,41 @@ public class ASTLiteralTest { @Test public void testIsIntIntLiteral() { Set literals = getNodes(ASTLiteral.class, TEST3); - assertTrue((literals.iterator().next()).isIntLiteral()); + ASTLiteral literal = literals.iterator().next(); + assertTrue(literal.isIntLiteral()); + assertEquals("int", literal.getType().getName()); } @Test public void testIsIntLongLiteral() { Set literals = getNodes(ASTLiteral.class, TEST4); - assertTrue((literals.iterator().next()).isLongLiteral()); + ASTLiteral literal = literals.iterator().next(); + assertTrue(literal.isLongLiteral()); + assertEquals("long", literal.getType().getName()); } @Test public void testIsFloatFloatLiteral() { Set literals = getNodes(ASTLiteral.class, TEST5); - assertTrue((literals.iterator().next()).isFloatLiteral()); + ASTLiteral literal = literals.iterator().next(); + assertTrue(literal.isFloatLiteral()); + assertEquals("float", literal.getType().getName()); } @Test public void testIsFloatDoubleLiteral() { Set literals = getNodes(ASTLiteral.class, TEST6); - assertTrue((literals.iterator().next()).isDoubleLiteral()); + ASTLiteral literal = literals.iterator().next(); + assertTrue(literal.isDoubleLiteral()); + assertEquals("double", literal.getType().getName()); } @Test public void testIsCharLiteral() { Set literals = getNodes(ASTLiteral.class, TEST7); - assertTrue((literals.iterator().next()).isCharLiteral()); + ASTLiteral literal = literals.iterator().next(); + assertTrue(literal.isCharLiteral()); + assertEquals("char", literal.getType().getName()); } @Test From a5483b36e481ad8aae3921d66e4e90f3f1867f69 Mon Sep 17 00:00:00 2001 From: ledoyen Date: Fri, 9 Nov 2018 15:12:54 +0100 Subject: [PATCH 063/139] Recognize direct inferred type in VariableNameDeclaration --- .../java/ast/ASTVariableDeclaratorId.java | 2 +- .../symboltable/VariableNameDeclaration.java | 17 ++++++ .../VariableNameDeclarationTest.java | 60 +++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java index 5a549e5977..75c0b2e96b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java @@ -120,7 +120,7 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim } - private boolean isLambdaParamWithNoType() { + public boolean isLambdaParamWithNoType() { return jjtGetParent() instanceof ASTLambdaExpression; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclaration.java index 1a3a226cbf..8480f9866e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclaration.java @@ -4,8 +4,10 @@ package net.sourceforge.pmd.lang.java.symboltable; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; +import net.sourceforge.pmd.lang.java.ast.ASTLiteral; import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; import net.sourceforge.pmd.lang.java.ast.ASTType; @@ -74,12 +76,24 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements && getAccessNodeParent().getFirstChildOfType(ASTType.class).jjtGetChild(0) instanceof ASTPrimitiveType; } + public boolean isLambdaParamWithNoType() { + return getDeclaratorId().isLambdaParamWithNoType(); + } + @Override public String getTypeImage() { TypeNode typeNode = getTypeNode(); if (typeNode != null) { return typeNode.getImage(); } + ASTLiteral assignedLiteral = getAccessNodeParent().getFirstDescendantOfType(ASTLiteral.class); + if (assignedLiteral != null + && !isLambdaParamWithNoType() + && assignedLiteral.getType() != null) { + // Even if ASTLiteral is a TypeNode, it is handled differently as + // the image is the literal value (example: 42L) and not the type (example: long) + return assignedLiteral.getType().getName(); + } return null; } @@ -109,6 +123,9 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements if (!isTypeInferred()) { return (TypeNode) getAccessNodeParent().getFirstChildOfType(ASTType.class).jjtGetChild(0).jjtGetChild(0); } + if (!isLambdaParamWithNoType()) { + return getAccessNodeParent().getFirstDescendantOfType(ASTClassOrInterfaceType.class); + } return null; } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclarationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclarationTest.java index 777c8a5753..1d84acc422 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclarationTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclarationTest.java @@ -8,6 +8,8 @@ import static net.sourceforge.pmd.lang.java.ParserTstUtil.getNodes; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import org.junit.Test; @@ -85,6 +87,50 @@ public class VariableNameDeclarationTest extends STBBaseTst { assertEquals("String", ((TypedNameDeclaration) decl).getTypeImage()); } + @Test + public void testVarKeywordTypeImage() { + parseCode(TEST6); + NameDeclaration decl = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope() + .getDeclarations().keySet().iterator().next(); + assertEquals("MyObject", ((TypedNameDeclaration) decl).getTypeImage()); + } + + @Test + public void testVarKeywordWithPrimitiveTypeImage() { + parseCode(TEST7); + NameDeclaration decl = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope() + .getDeclarations().keySet().iterator().next(); + assertEquals("long", ((TypedNameDeclaration) decl).getTypeImage()); + } + + @Test + public void testVarKeywordWithIndirectReference() { + parseCode(TEST8); + Iterator nameDeclarationIterator = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope() + .getDeclarations().keySet().iterator(); + nameDeclarationIterator.next(); // first variable 'bar' + NameDeclaration decl = nameDeclarationIterator.next(); // second variable 'foo' + assertEquals(null, ((TypedNameDeclaration) decl).getTypeImage()); + } + + @Test + public void testLamdaParameterTypeImage() { + parseCode(TEST9); + List variableDeclaratorIds = acu.findDescendantsOfType( + ASTVariableDeclaratorId.class, + true + ); + + List nameDeclarations = new ArrayList<>(); + for (ASTVariableDeclaratorId variableDeclaratorId : variableDeclaratorIds) { + nameDeclarations.add(variableDeclaratorId.getNameDeclaration()); + } + + assertEquals("Map", nameDeclarations.get(0).getTypeImage()); // variable 'bar' + assertEquals(null, nameDeclarations.get(1).getTypeImage()); // variable 'key' + assertEquals(null, nameDeclarations.get(2).getTypeImage()); // variable 'value' + assertEquals("long", nameDeclarations.get(3).getTypeImage()); // variable 'foo' + } private static final String EXCEPTION_PARAMETER = "public class Test { { try {} catch(Exception ie) {} } }"; @@ -101,6 +147,20 @@ public class VariableNameDeclarationTest extends STBBaseTst { + PMD.EOL + " }" + PMD.EOL + "}"; public static final String TEST5 = "public class Foo {" + PMD.EOL + " void foo(String x) {}" + PMD.EOL + "}"; + public static final String TEST6 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL + + " var bar = new MyObject(\"param\");" + PMD.EOL + " }" + PMD.EOL + "}"; + + public static final String TEST7 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL + " var bar = 42L;" + + PMD.EOL + " }" + PMD.EOL + "}"; + + public static final String TEST8 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL + + " var bar = \"test\";" + PMD.EOL + " var foo = bar;" + PMD.EOL + " }" + PMD.EOL + "}"; + + public static final String TEST9 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL + + " Map bar = new HashMap<>();" + PMD.EOL + " bar.forEach((key, value) -> {" + PMD.EOL + + " if (value instanceof String) {" + PMD.EOL + " var foo = 42L;" + PMD.EOL + + " System.out.println(value);" + PMD.EOL + " }" + PMD.EOL + " });" + PMD.EOL + " }" + PMD.EOL + "}"; + public static junit.framework.Test suite() { return new junit.framework.JUnit4TestAdapter(VariableNameDeclarationTest.class); } From cc8181edc9f9c8f9676c78aba66428040120c17a Mon Sep 17 00:00:00 2001 From: ledoyen Date: Mon, 12 Nov 2018 10:47:18 +0100 Subject: [PATCH 064/139] Make AssertJ soft assertions count as assertions --- pmd-java/pom.xml | 5 ++ .../JUnitTestsShouldIncludeAssertRule.java | 52 ++++++++++++++++--- .../lang/java/typeresolution/TypeHelper.java | 47 +++++++++++------ .../xml/JUnitTestsShouldIncludeAssert.xml | 42 +++++++++++++++ pom.xml | 5 ++ 5 files changed, 129 insertions(+), 22 deletions(-) diff --git a/pmd-java/pom.xml b/pmd-java/pom.xml index e212339c44..9d8f8fe151 100644 --- a/pmd-java/pom.xml +++ b/pmd-java/pom.xml @@ -176,5 +176,10 @@ ant-testutil test + + org.assertj + assertj-core + test + diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitTestsShouldIncludeAssertRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitTestsShouldIncludeAssertRule.java index 071b76840f..4cbfb154b2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitTestsShouldIncludeAssertRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitTestsShouldIncludeAssertRule.java @@ -20,6 +20,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; import net.sourceforge.pmd.lang.java.rule.AbstractJUnitRule; +import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; import net.sourceforge.pmd.lang.symboltable.NameDeclaration; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; @@ -39,10 +40,12 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule { public Object visit(ASTMethodDeclaration method, Object data) { if (isJUnitMethod(method, data)) { if (!isExpectAnnotated(method.jjtGetParent())) { + Map variables = getVariables(method); + Scope classScope = method.getScope().getParent(); Map> expectables = getRuleAnnotatedExpectedExceptions(classScope); - - if (!containsExpectOrAssert(method.getBlock(), expectables)) { + + if (!containsExpectOrAssert(method.getBlock(), expectables, variables)) { addViolation(data, method); } } @@ -50,24 +53,35 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule { return data; } - private boolean containsExpectOrAssert(Node n, Map> expectables) { + private boolean containsExpectOrAssert(Node n, + Map> expectables, + Map variables) { if (n instanceof ASTStatementExpression) { if (isExpectStatement((ASTStatementExpression) n, expectables) || isAssertOrFailStatement((ASTStatementExpression) n) - || isVerifyStatement((ASTStatementExpression) n)) { + || isVerifyStatement((ASTStatementExpression) n) + || isSoftAssertionStatement((ASTStatementExpression) n, variables)) { return true; } } else { for (int i = 0; i < n.jjtGetNumChildren(); i++) { Node c = n.jjtGetChild(i); - if (containsExpectOrAssert(c, expectables)) { + if (containsExpectOrAssert(c, expectables, variables)) { return true; } } } return false; } - + + private Map getVariables(ASTMethodDeclaration method) { + Map variables = new HashMap<>(); + for (VariableNameDeclaration vnd : method.getScope().getDeclarations(VariableNameDeclaration.class).keySet()) { + variables.put(vnd.getName(), vnd); + } + return variables; + } + /** * Gets a list of NameDeclarations for all the fields that have type * ExpectedException and have a Rule annotation. @@ -189,4 +203,30 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule { } return false; } + + private boolean isSoftAssertionStatement(ASTStatementExpression expression, + Map variables) { + if (expression != null) { + ASTPrimaryExpression pe = expression.getFirstChildOfType(ASTPrimaryExpression.class); + if (pe != null) { + Node name = pe.getFirstDescendantOfType(ASTName.class); + if (name != null) { + String img = name.getImage(); + if (img.indexOf(".") == -1) { + return false; + } + String[] tokens = img.split("\\."); + String methodName = tokens[1]; + boolean methodIsAssertAll = "assertAll".equals(methodName); + + String varName = tokens[0]; + boolean variableTypeIsSoftAssertion = variables.containsKey(varName) + && TypeHelper.isA(variables.get(varName), "org.assertj.core.api.AbstractSoftAssertions"); + + return methodIsAssertAll && variableTypeIsSoftAssertion; + } + } + } + return false; + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java index c77263615a..8635735a07 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java @@ -54,23 +54,29 @@ public final class TypeHelper { private static Class loadClassWithNodeClassloader(final TypeNode n, final String clazzName) { if (n.getType() != null) { - try { - ClassLoader classLoader = n.getType().getClassLoader(); - if (classLoader == null) { - // Using the system classloader then - classLoader = ClassLoader.getSystemClassLoader(); - } - - // If the requested type is in the classpath, using the same classloader should work - return ClassUtils.getClass(classLoader, clazzName); - } catch (final ClassNotFoundException ignored) { - // The requested type is not on the auxclasspath. This might happen, if the type node - // is probed for a specific type (e.g. is is a JUnit5 Test Annotation class). - // Failing to resolve clazzName does not necessarily indicate an incomplete auxclasspath. - } catch (final LinkageError expected) { - // We found the class but it's invalid / incomplete. This may be an incomplete auxclasspath - // if it was a NoClassDefFoundError. TODO : Report it? + return loadClass(n.getType().getClassLoader(), clazzName); + } + + return null; + } + + private static Class loadClass(final ClassLoader nullableClassLoader, final String clazzName) { + try { + ClassLoader classLoader = nullableClassLoader; + if (classLoader == null) { + // Using the system classloader then + classLoader = ClassLoader.getSystemClassLoader(); } + + // If the requested type is in the classpath, using the same classloader should work + return ClassUtils.getClass(classLoader, clazzName); + } catch (ClassNotFoundException ignored) { + // The requested type is not on the auxclasspath. This might happen, if the type node + // is probed for a specific type (e.g. is is a JUnit5 Test Annotation class). + // Failing to resolve clazzName does not necessarily indicate an incomplete auxclasspath. + } catch (final LinkageError expected) { + // We found the class but it's invalid / incomplete. This may be an incomplete auxclasspath + // if it was a NoClassDefFoundError. TODO : Report it? } return null; @@ -133,4 +139,13 @@ public final class TypeHelper { return clazz.isAssignableFrom(type); } + + public static boolean isA(TypedNameDeclaration vnd, String className) { + Class type = vnd.getType(); + if (type != null) { + Class expected = loadClass(type.getClassLoader(), className); + return expected.isAssignableFrom(type); + } + return false; + } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml index b69044eff3..7c31031804 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml @@ -429,6 +429,48 @@ class Style { public void moveOutOfBoundsFrom() { doSomething(); } +}]]> + + + #1435 Treat AssertJ soft assertions as assert expressions + 0 + + + + #1435 Treat AssertJ soft assertion rule for JUnit 4 as assert expressions + 0 + diff --git a/pom.xml b/pom.xml index 52722c32d2..bdaed4be92 100644 --- a/pom.xml +++ b/pom.xml @@ -936,6 +936,11 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code system-rules 1.8.0 + + org.assertj + assertj-core + 3.11.0 + From 3c6278bbb82155c65b490d305fd88315b93d5f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 12 Nov 2018 19:08:53 +0100 Subject: [PATCH 065/139] Update docs/pages/release_notes.md Co-Authored-By: oowekyala --- docs/pages/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 4e9f375bc3..bbdfe83a69 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -31,7 +31,7 @@ This is a {{ site.pmd.release_type }} release. `PropertyTypeId#isPropertyPackaged` are also deprecated. * All classes of net.sourceforge.pmd.properties.modules are deprecated and will be removed. They were never intended as public api. - * The classes PropertyDescriptorField, PropertyDescriptorBuilderConversionWrapper, and the methods + * The classes `PropertyDescriptorField`, `PropertyDescriptorBuilderConversionWrapper`, and the methods `PropertyDescriptor#attributeValuesById`, `PropertyDescriptor#isDefinedExternally` and `PropertyTypeId#getFactory` are deprecated with no intended replacement. These were used to read and write properties to and from XML, and were never intended as public API. From 130994db5dcaf9f92aded69beca361c9f12727c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 12 Nov 2018 19:11:10 +0100 Subject: [PATCH 066/139] Update docs/pages/release_notes.md Co-Authored-By: oowekyala --- docs/pages/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index bbdfe83a69..dd319ff417 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -26,7 +26,7 @@ This is a {{ site.pmd.release_type }} release. are discontinued for lack of a use-case, and will probably not be replaced with 7.0.0. Users of FloatProperty should consider using a DoubleProperty. * EnumeratedPropertyDescriptor, NumericPropertyDescriptor, PackagedPropertyDescriptor, and the related builders - (in net.sourceforge.pmd.properties.builders) will be removed. In the future, these interfaces won't be around + (in `net.sourceforge.pmd.properties.builders`) will be removed. In the future, these interfaces won't be around but their functionality will, under another form. The related methods `PropertyTypeId#isPropertyNumeric` and `PropertyTypeId#isPropertyPackaged` are also deprecated. * All classes of net.sourceforge.pmd.properties.modules are deprecated and will be removed. They were From d662bd51294e870874bafe0415e335fb4f32ee6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 12 Nov 2018 19:11:14 +0100 Subject: [PATCH 067/139] Update docs/pages/release_notes.md Co-Authored-By: oowekyala --- docs/pages/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index dd319ff417..5d398903c5 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -25,7 +25,7 @@ This is a {{ site.pmd.release_type }} release. * MethodProperty, FloatProperty, FileProperty, TypeProperty and their multi-valued counterparts are discontinued for lack of a use-case, and will probably not be replaced with 7.0.0. Users of FloatProperty should consider using a DoubleProperty. - * EnumeratedPropertyDescriptor, NumericPropertyDescriptor, PackagedPropertyDescriptor, and the related builders + * `EnumeratedPropertyDescriptor`, `NumericPropertyDescriptor`, `PackagedPropertyDescriptor`, and the related builders (in `net.sourceforge.pmd.properties.builders`) will be removed. In the future, these interfaces won't be around but their functionality will, under another form. The related methods `PropertyTypeId#isPropertyNumeric` and `PropertyTypeId#isPropertyPackaged` are also deprecated. From 7f6debe52416d5e60af99dbf4f64e1e6f54f1654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 12 Nov 2018 19:11:18 +0100 Subject: [PATCH 068/139] Update docs/pages/release_notes.md Co-Authored-By: oowekyala --- docs/pages/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 5d398903c5..cce1734b6f 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -24,7 +24,7 @@ This is a {{ site.pmd.release_type }} release. * Several classes and interfaces from the properties framework are now deprecated and will be removed with 7.0.0. * MethodProperty, FloatProperty, FileProperty, TypeProperty and their multi-valued counterparts are discontinued for lack of a use-case, and will probably not be replaced with 7.0.0. - Users of FloatProperty should consider using a DoubleProperty. + Users of `FloatProperty` should consider using a `DoubleProperty`. * `EnumeratedPropertyDescriptor`, `NumericPropertyDescriptor`, `PackagedPropertyDescriptor`, and the related builders (in `net.sourceforge.pmd.properties.builders`) will be removed. In the future, these interfaces won't be around but their functionality will, under another form. The related methods `PropertyTypeId#isPropertyNumeric` and From c33db52f9e1708a4bd891ed82b0f8cf61e255d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 12 Nov 2018 19:11:21 +0100 Subject: [PATCH 069/139] Update docs/pages/release_notes.md Co-Authored-By: oowekyala --- docs/pages/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index cce1734b6f..e60e1a4bb0 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -22,7 +22,7 @@ This is a {{ site.pmd.release_type }} release. ### API Changes * Several classes and interfaces from the properties framework are now deprecated and will be removed with 7.0.0. - * MethodProperty, FloatProperty, FileProperty, TypeProperty and their multi-valued counterparts + * `MethodProperty`, `FloatProperty`, `FileProperty`, `TypeProperty` and their multi-valued counterparts are discontinued for lack of a use-case, and will probably not be replaced with 7.0.0. Users of `FloatProperty` should consider using a `DoubleProperty`. * `EnumeratedPropertyDescriptor`, `NumericPropertyDescriptor`, `PackagedPropertyDescriptor`, and the related builders From f5d67655033cfd6ee2861855aa8ebbb35d0a14bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 12 Nov 2018 19:23:49 +0100 Subject: [PATCH 070/139] Deprecate uiOrder and Comparable --- .../pmd/properties/PropertyDescriptor.java | 23 ++++++++++++++----- .../pmd/properties/ValueParser.java | 5 ++++ .../builders/PropertyDescriptorBuilder.java | 2 ++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index d25bcba046..04da7e7d52 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -16,12 +16,6 @@ import net.sourceforge.pmd.annotation.InternalApi; * any associated GUIs. While concrete descriptor instances are static and immutable they provide validation, * serialization, and default values for any specific datatypes. * - *

This interface is primarily specialized according to whether the property is multi-valued or single-valued, see - * {@link SingleValuePropertyDescriptor} and {@link MultiValuePropertyDescriptor}. - * - *

Several interfaces further specialize the behaviour of descriptors to accommodate specific types of descriptors, - * see {@link NumericPropertyDescriptor} and {@link EnumeratedPropertyDescriptor}. - * *

Upcoming API changes to the properties framework: see wiki

* * @param type of the property's value. This is a list type for multi-valued properties. @@ -91,7 +85,10 @@ public interface PropertyDescriptor extends Comparable> * @param value The value to check. * * @return A diagnostic message. + * + * @deprecated PMD 7.0.0 will change the return type to {@code Optional} */ + @Deprecated String errorFor(T value); // TODO Java 1.8 make optional @@ -101,10 +98,24 @@ public interface PropertyDescriptor extends Comparable> * adjacent fields on the same row. * * @return The relative order compared to other properties of the same rule + * + * @deprecated This method confuses the presentation layer and the business logic. The order of the + * property in a UI is irrelevant to the functioning of the property in PMD. With PMD 7.0.0, this + * method will be removed, and descriptors will be documented in the order they were defined on their + * PropertySource. */ + @Deprecated float uiOrder(); + /** + * @deprecated Comparing property descriptors is not useful within PMD + */ + @Deprecated + @Override + int compareTo(PropertyDescriptor o); + + /** * Returns the value represented by this string. * diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParser.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParser.java index 4ce4acdcad..ba4dd796c3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParser.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/ValueParser.java @@ -4,12 +4,17 @@ package net.sourceforge.pmd.properties; +import net.sourceforge.pmd.annotation.InternalApi; + + /** * Parses a value from a string. * * @param The type of the value to parse */ // FUTURE @FunctionalInterface +@Deprecated +@InternalApi public interface ValueParser { /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java index 5aa1ef3959..392e5ea80f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/builders/PropertyDescriptorBuilder.java @@ -60,8 +60,10 @@ public abstract class PropertyDescriptorBuilder Date: Mon, 12 Nov 2018 19:53:34 +0100 Subject: [PATCH 071/139] Formatting --- docs/pages/release_notes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 97ed71baa1..b630e76147 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -18,8 +18,8 @@ This is a {{ site.pmd.release_type }} release. ### API Changes -* The implementation of the adapters for the XPath engines Saxon and Jaxen (package net.sourceforge.pmd.lang.ast.xpath) - are now deprecated. They'll be moved to an internal package come 7.0.0. Only Attribute remains public API. +* The implementation of the adapters for the XPath engines Saxon and Jaxen (package `net.sourceforge.pmd.lang.ast.xpath`) + are now deprecated. They'll be moved to an internal package come 7.0.0. Only `Attribute` remains public API. ### External Contributions From 175d0c13bf0ddbea1c1717928845b264a2e4c77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 12 Nov 2018 19:58:01 +0100 Subject: [PATCH 072/139] Update PropertyDescriptor.java --- .../net/sourceforge/pmd/properties/PropertyDescriptor.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index 04da7e7d52..fb6a0e28c4 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -101,8 +101,7 @@ public interface PropertyDescriptor extends Comparable> * * @deprecated This method confuses the presentation layer and the business logic. The order of the * property in a UI is irrelevant to the functioning of the property in PMD. With PMD 7.0.0, this - * method will be removed, and descriptors will be documented in the order they were defined on their - * PropertySource. + * method will be removed. UI and documentation tools will decide on their own convention. */ @Deprecated float uiOrder(); From 0e90269b95691985fee4a84649e8f56b68058012 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 12 Nov 2018 20:08:46 +0100 Subject: [PATCH 073/139] Update release notes, fixes #1284 --- docs/pages/release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 8c5a72c673..08cb6b901b 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -15,6 +15,8 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy ### Fixed Issues +* all + * [#1284](https://github.com/pmd/pmd/issues/1284): \[doc] Keep record of every currently deprecated API ### API Changes From 4c1a0145f51a9a6949e140ba7f8739b7cc924f9f Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 12 Nov 2018 20:14:54 +0100 Subject: [PATCH 074/139] Update release docu --- do-release.sh | 3 +++ docs/pages/pmd/projectdocs/committers/releasing.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/do-release.sh b/do-release.sh index 63a1bb92f9..a38a055660 100755 --- a/do-release.sh +++ b/do-release.sh @@ -75,6 +75,9 @@ echo echo "* Ensure all the new rules are listed in the proper file:" echo " ${RELEASE_RULESET}" echo +echo "* Update **docs/pages/next_major_development.md** with the API changes for" +echo " the new release based on the release notes" +echo echo "* Update **../pmd.github.io/_config.yml** to mention the new release" echo echo "Press enter to continue..." diff --git a/docs/pages/pmd/projectdocs/committers/releasing.md b/docs/pages/pmd/projectdocs/committers/releasing.md index 4800ca41fc..4aeeb7e1a2 100644 --- a/docs/pages/pmd/projectdocs/committers/releasing.md +++ b/docs/pages/pmd/projectdocs/committers/releasing.md @@ -40,6 +40,9 @@ The release notes usual mention any new rules that have been added since the las Please double check the file `pmd-core/src/main/resources/rulesets/releases/.xml`, so that all new rules are listed. +We maintain a documentation for the [next major release](pmd_next_major_development.html). Copy the API +changes from the current release notes to this document: `docs/pages/next_major_development.md`. + Check in all (version) changes to branch master or any other branch, from which the release takes place: $ git commit -a -m "Prepare pmd release " From 21f015048bf5db76c93d3d3c405dc75c394ae631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 5 Nov 2018 01:34:14 +0100 Subject: [PATCH 075/139] Checkstyle --- .../constraints/ConstraintFactory.java | 25 +++++++------- .../constraints/NumericConstraints.java | 34 ++++++++++--------- .../constraints/PropertyConstraint.java | 2 +- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java index 7218ca6c5c..a1a2c276dc 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java @@ -62,18 +62,19 @@ final class ConstraintFactory { @Override public PropertyConstraint> toMulti() { final PropertyConstraint thisValidator = this; - return fromPredicate(new Predicate>() { - @Override - public boolean test(Iterable us) { - for (U u : us) { - if (!thisValidator.test(u)) { - return false; - } - } - return true; - } - }, - "Components " + StringUtils.uncapitalize(thisValidator.getConstraintDescription()) + return fromPredicate( + new Predicate>() { + @Override + public boolean test(Iterable us) { + for (U u : us) { + if (!thisValidator.test(u)) { + return false; + } + } + return true; + } + }, + "Components " + StringUtils.uncapitalize(thisValidator.getConstraintDescription()) ); } }; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java index 70d4481b4c..68ee5feafa 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java @@ -15,13 +15,13 @@ import net.sourceforge.pmd.properties.constraints.ConstraintFactory.Predicate; * @see PropertyConstraint * @since 6.10.0 */ -public class NumericConstraints { +public final class NumericConstraints { private NumericConstraints() { } - // Methods are named as adjectives to mix well with the "require" syntax. + // Methods are named to mix well with the "require" syntax. /** @@ -34,13 +34,14 @@ public class NumericConstraints { * @return A range constraint */ public static PropertyConstraint inRange(final N minInclusive, final N maxInclusive) { - return ConstraintFactory.fromPredicate(new Predicate() { - @Override - public boolean test(N t) { - return minInclusive.intValue() <= t.intValue() && maxInclusive.intValue() >= t.intValue(); - } - }, - "Should be between " + minInclusive + " and " + maxInclusive + return ConstraintFactory.fromPredicate( + new Predicate() { + @Override + public boolean test(N t) { + return minInclusive.intValue() <= t.intValue() && maxInclusive.intValue() >= t.intValue(); + } + }, + "Should be between " + minInclusive + " and " + maxInclusive ); } @@ -54,13 +55,14 @@ public class NumericConstraints { * @return A positivity constraint */ public static PropertyConstraint positive() { - return ConstraintFactory.fromPredicate(new Predicate() { - @Override - public boolean test(N t) { - return t.intValue() > 0; - } - }, - "Should be positive" + return ConstraintFactory.fromPredicate( + new Predicate() { + @Override + public boolean test(N t) { + return t.intValue() > 0; + } + }, + "Should be positive" ); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java index e7cbfcfcfe..5991bb4428 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java @@ -11,7 +11,7 @@ import net.sourceforge.pmd.annotation.Experimental; * Validates the value of a property. * *

This interface will change a lot with PMD 7.0.0, - * because of the introduction of Java 8. Please use + * because of the switch to Java 8. Please use * only the ready-made validators in {@link NumericConstraints} * for now. * From 5e64dd44735fe1d83c5df10b889576a1b327556a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Nov 2018 00:57:02 +0100 Subject: [PATCH 076/139] Update release notes --- docs/pages/release_notes.md | 29 +++++++++++-- .../pmd/properties/PropertyDescriptor.java | 42 ++++++++++--------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index e60e1a4bb0..7a90340bac 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -21,6 +21,12 @@ This is a {{ site.pmd.release_type }} release. ### API Changes + +#### Properties framework + +The properties framework is about to get a lifting, and for that reason, the following APIs are +now deprecated until 7.0.0. The proposed changes to the API are described [on the wiki](https://github.com/pmd/pmd/wiki/Property-framework-7-0-0) + * Several classes and interfaces from the properties framework are now deprecated and will be removed with 7.0.0. * `MethodProperty`, `FloatProperty`, `FileProperty`, `TypeProperty` and their multi-valued counterparts are discontinued for lack of a use-case, and will probably not be replaced with 7.0.0. @@ -35,10 +41,25 @@ This is a {{ site.pmd.release_type }} release. `PropertyDescriptor#attributeValuesById`, `PropertyDescriptor#isDefinedExternally` and `PropertyTypeId#getFactory` are deprecated with no intended replacement. These were used to read and write properties to and from XML, and were never intended as public API. - * The class ValueParserConstants is deprecated with no intended replacement, it was not intended as - public API. - * The method `PropertyDescriptor#preferredRowCount` is deprecated with no intended replacement. It was - never implemented, and does not belong in this interface. + * The class `ValueParserConstants` and the interface `ValueParser` are deprecated with no intended replacement, + they were not intended as public API. + * Methods from `PropertyDescriptor`: + * `preferredRowCount` is deprecated with no intended replacement. It was never implemented, and does not belong + in this interface. The methods `uiOrder` and `compareTo` are deprecated for the same reason. These methods mix presentation logic + with business logic and are not necessary for PropertyDescriptors to work. `PropertyDescriptor` will not + extend `Comparable` anymore come 7.0.0. + * The method `PropertyDescriptor#propertyErrorFor` is deprecated and will be removed with no intended + replacement. It's really just a shortcut for `prop.errorFor(rule.getProperty(prop))`. + * `T valueFrom(String)` and `String asDelimitedString(T)` are deprecated and will be removed. These were + used to serialize and deserialize properties to/from a string, but 7.0.0 will introduce a more flexible + XML syntax which will make them obsolete. + * `isMultiValue` and `type` are deprecated and won't be replaced. The new XML syntax will remove the need + for a divide between multi- and single-value properties, and will allow arbitrary types to be represented. + Since arbitrary types may be represented, `type` will become obsolete as it can't represent generic types, + which will nevertheless be representable with the XML syntax. It was only used for documentation, but a + new way to document these properties exhaustively will be added with 7.0.0. + * `errorFor` is deprecated as its return type will be changed to `Optional` with the shift to Java 8. + ### External Contributions diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index fb6a0e28c4..1d105aab5b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -42,6 +42,28 @@ public interface PropertyDescriptor extends Comparable> String description(); + /** + * Default value to use when the user hasn't specified one or when they wish to revert to a known-good state. + * + * @return Object + */ + T defaultValue(); + + + /** + * Validation function that returns a diagnostic error message for a sample property value. Returns null if the + * value is acceptable. + * + * @param value The value to check. + * + * @return A diagnostic message. + * + * @deprecated PMD 7.0.0 will change the return type to {@code Optional} + */ + @Deprecated + String errorFor(T value); // TODO Java 1.8 make optional + + /** * Denotes the value datatype. For multi value properties, this is not the List class but the list's component * class. @@ -70,26 +92,6 @@ public interface PropertyDescriptor extends Comparable> boolean isMultiValue(); - /** - * Default value to use when the user hasn't specified one or when they wish to revert to a known-good state. - * - * @return Object - */ - T defaultValue(); - - - /** - * Validation function that returns a diagnostic error message for a sample property value. Returns null if the - * value is acceptable. - * - * @param value The value to check. - * - * @return A diagnostic message. - * - * @deprecated PMD 7.0.0 will change the return type to {@code Optional} - */ - @Deprecated - String errorFor(T value); // TODO Java 1.8 make optional /** From 2b8cff49f1f4eb99760301220d41cd2231c1446b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Nov 2018 14:00:44 +0100 Subject: [PATCH 077/139] add jdoc and jdoc_package liquid tags --- docs/_plugins/javadoc_tag.rb | 131 +++++++++++++++++++++++++++++++++++ docs/pages/release_notes.md | 5 +- 2 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 docs/_plugins/javadoc_tag.rb diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb new file mode 100644 index 0000000000..14dd83b788 --- /dev/null +++ b/docs/_plugins/javadoc_tag.rb @@ -0,0 +1,131 @@ +# Tag to reference a javadoc page or package summary. +# +# * The tag "jdoc" is used for a type or member reference +# * The tag "jdoc_package" is used for a package reference +# * DO NOT confuse the two +# +# Usage (don't miss the DO NOT section at the bottom): +# +# * Simple type reference: {% jdoc core net.sourceforge.pmd.properties.PropertyDescriptor %} +# * First arg must be the name of the module, without the "pmd-" prefix, eg "core" will be expanded to "pmd-core" +# * After a space, the fqcn of the type to reference is mentioned +# * This will be expanded to [`PropertyDescriptor`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/latest/net/sourceforge/pmd/properties/PropertyDescriptor.html) +# * Only the simple name of the type is visible by default +# * If you want to make the visible text expand to the FQCN like so [`net.sourceforge.pmd.properties.PropertyDescriptor`](...), +# then prefix the type name with a double bang (!!), e.g. {% jdoc core !!net.sourceforge.pmd.properties.PropertyDescriptor %} +# +# * Using context: +# * The variable javadoc_context may be used to shorten references +# * You can assign it like so: +# * {% assign javadoc_context = "core @.properties" %} +# * The "@" symbol in the initializer is expanded to "net.sourceforge.pmd" +# * So this assignment sets the context to pmd-core/net.sourceforge.pmd.properties +# * Then the symbol "@" in a javadoc tag will be expanded to "core net.sourceforge.pmd.properties" +# * E.g. the reference {% jdoc @.PropertyDescriptor %} is expanded to the same as {% jdoc core net.sourceforge.pmd.properties.PropertyDescriptor %} +# * Again, you may use "!!" to show the FQCN, like {% jdoc !!@.PropertyDescriptor %} +# * If the variable is not set, then "@" in a javadoc tag means "core net.sourceforge.pmd", eg +# {% jdoc @.properties.PropertyDescriptor %} works. +# * The artifact can be overridden from the context, eg with the default context "core net.sourceforge.pmd" +# {% jdoc java @.lang.java.JavaLanguageModule %} will be linked correctly to pmd-java, and @ will be expanded to +# "net.sourceforge.pmd" +# +# * To reference a method or field: {% jdoc core @.Rule#addRuleChainVisit(java.lang.Class) %} +# * The suffix # is followed by the name of the method +# * The (erased) types of method arguments must be fully qualified!! This is the same +# convention as in javadoc {@link} tags +# +# * To reference a package: {% jdoc_package @.properties %}, or {% jdoc-package @ %} +# * The "!!" is implicit, the full package name is always displayed +# +# * DO NOT: +# - Include spaces between dots, or anywhere except between the artifact reference and the page reference +# - Use double or single quotes around the arguments +# - Use the "#" suffix to reference a nested type, instead, use a dot "." and reference it like a normal type name +# +class JavadocTag < Liquid::Tag + def initialize(tag_name, doc_ref, tokens) + super + + if %r/(\w+\s+)?(!!)?(@(?:\.\w+)*)(#.*)?/ =~ doc_ref + + @artifact_name = $1 && ("pmd-" + $1.strip) # is nil if not mentioned + @show_full_name = !!$2 + @type_fqcn = $3 # may be just "@" + @member_suffix = $4 || "" # default to empty string instead of nil + + else + fail "Invalid javadoc reference format, see doc on javadoc_tag.rb" + end + + + if tag_name == "jdoc_package" + @is_package_ref = true + @show_full_name = true + end + + end + + def render(context) + + + doc_ctx = context["javadoc_context"] || "core net.sourceforge.pmd" + doc_ctx = doc_ctx.sub("@", "net.sourceforge.pmd") # Allows to use @ as shortcut when assigning javadoc_context + doc_ctx = doc_ctx.split(" ") # first is module, snd is package + + p doc_ctx + + if @type_fqcn.include?("@") # Expand using the context + if doc_ctx.length == 2 # if it's two words then the first is the module name + # if the artifact was mentioned in the tag, it takes precedence + @artifact_name = @artifact_name || ("pmd-" + doc_ctx.first) + @type_fqcn = @type_fqcn.sub("@", doc_ctx.last) + elsif doc_ctx.length == 1 + p @type_fqcn + @type_fqcn = @type_fqcn.sub("@", doc_ctx.last) + p @type_fqcn + else + fail "Invalid javadoc context format (spaces), use either one word for a package prefix, or two words for module + package prefix" + end + end + + unless @artifact_name + fail "No artifact id was mentioned either in the tag or in the context" + end + + + p @type_fqcn + + if @show_full_name # !! was mentioned + visible_name = @type_fqcn + else + visible_name = @type_fqcn.split("\.").last # simple name + end + + + # Hack to reference the package summary + # Has to be done after finding the visible_name + if @is_package_ref + @type_fqcn = @type_fqcn + ".package-summary" + end + + + # Always hardcode the artifact version instead of using "latest" + api_version = context["site.pmd.version"] + + markup_link(visible_name, doclink(@artifact_name, api_version, @type_fqcn, @member_suffix)) + end + + private + + def doclink(artifact, api_version, type_name, member_suffix) + "https://javadoc.io/page/net.sourceforge.pmd/#{artifact}/#{api_version}/#{type_name.gsub("\.", "/")}.html#{member_suffix}" + end + + def markup_link(rname, link) + "[`#{rname}`](#{link})" + end + +end + +Liquid::Template.register_tag('jdoc', JavadocTag) +Liquid::Template.register_tag('jdoc_package', JavadocTag) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 5baf27eb74..0a66b9d727 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -32,9 +32,10 @@ This is a {{ site.pmd.release_type }} release. * [#1372](https://github.com/pmd/pmd/issues/1372): \[java] false positive for UselessQualifiedThis ### API Changes +{% assign javadoc_context = "core @.lang.ast.xpath" %} -* The implementation of the adapters for the XPath engines Saxon and Jaxen (package `net.sourceforge.pmd.lang.ast.xpath`) - are now deprecated. They'll be moved to an internal package come 7.0.0. Only `Attribute` remains public API. +* The implementation of the adapters for the XPath engines Saxon and Jaxen (package {% jdoc_package @ %}) + are now deprecated. They'll be moved to an internal package come 7.0.0. Only {% jdoc @.Attribute %} remains public API. ### External Contributions From da9a8f3be54f3c2703ea95e889f5fe6ef033c39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Nov 2018 14:15:21 +0100 Subject: [PATCH 078/139] Add jdoc_old --- docs/_config.yml | 1 + docs/_plugins/javadoc_tag.rb | 41 ++++++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/docs/_config.yml b/docs/_config.yml index 7236c2817f..8fcdabf962 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -2,6 +2,7 @@ repository: pmd/pmd pmd: version: 6.10.0 + previous_version: 6.9.0 date: ??-????-2018 release_type: minor diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb index 14dd83b788..59a97ad9ba 100644 --- a/docs/_plugins/javadoc_tag.rb +++ b/docs/_plugins/javadoc_tag.rb @@ -1,8 +1,16 @@ -# Tag to reference a javadoc page or package summary. +# Tags to reference a javadoc page or package summary. # +# Provides several tags, which should not be mixed up: # * The tag "jdoc" is used for a type or member reference -# * The tag "jdoc_package" is used for a package reference -# * DO NOT confuse the two +# * The tag "jdoc_package" is used for a package summary reference +# +# Both of these link to the latest version of the API so when editing the site, +# since it concerns an unpublished API version, the links don't work. When releasing +# though, links on the published jekyll site will work. +# To refer to the previous API version, e.g. to refer to a type or member that was removed, +# the tag "jdoc_old" may be used. This tag is used exactly the same way as "jdoc". There's +# no "jdoc_package_old" tag. +# # # Usage (don't miss the DO NOT section at the bottom): # @@ -18,7 +26,7 @@ # * The variable javadoc_context may be used to shorten references # * You can assign it like so: # * {% assign javadoc_context = "core @.properties" %} -# * The "@" symbol in the initializer is expanded to "net.sourceforge.pmd" +# * The "@" symbol in the initializer is expanded to "net.sourceforge.pmd", the artifact id is not optional though # * So this assignment sets the context to pmd-core/net.sourceforge.pmd.properties # * Then the symbol "@" in a javadoc tag will be expanded to "core net.sourceforge.pmd.properties" # * E.g. the reference {% jdoc @.PropertyDescriptor %} is expanded to the same as {% jdoc core net.sourceforge.pmd.properties.PropertyDescriptor %} @@ -39,6 +47,7 @@ # # * DO NOT: # - Include spaces between dots, or anywhere except between the artifact reference and the page reference +# - Forget to use an artifact id whenever setting javadoc_context # - Use double or single quotes around the arguments # - Use the "#" suffix to reference a nested type, instead, use a dot "." and reference it like a normal type name # @@ -61,6 +70,8 @@ class JavadocTag < Liquid::Tag if tag_name == "jdoc_package" @is_package_ref = true @show_full_name = true + elsif tag_name == "jdoc_old" + @use_previous_api_version = true end end @@ -72,19 +83,13 @@ class JavadocTag < Liquid::Tag doc_ctx = doc_ctx.sub("@", "net.sourceforge.pmd") # Allows to use @ as shortcut when assigning javadoc_context doc_ctx = doc_ctx.split(" ") # first is module, snd is package - p doc_ctx - if @type_fqcn.include?("@") # Expand using the context if doc_ctx.length == 2 # if it's two words then the first is the module name # if the artifact was mentioned in the tag, it takes precedence @artifact_name = @artifact_name || ("pmd-" + doc_ctx.first) @type_fqcn = @type_fqcn.sub("@", doc_ctx.last) - elsif doc_ctx.length == 1 - p @type_fqcn - @type_fqcn = @type_fqcn.sub("@", doc_ctx.last) - p @type_fqcn else - fail "Invalid javadoc context format (spaces), use either one word for a package prefix, or two words for module + package prefix" + fail "Invalid javadoc context format, you must specify artifact + package prefix in exactly two words" end end @@ -92,16 +97,12 @@ class JavadocTag < Liquid::Tag fail "No artifact id was mentioned either in the tag or in the context" end - - p @type_fqcn - if @show_full_name # !! was mentioned visible_name = @type_fqcn else visible_name = @type_fqcn.split("\.").last # simple name end - # Hack to reference the package summary # Has to be done after finding the visible_name if @is_package_ref @@ -110,7 +111,14 @@ class JavadocTag < Liquid::Tag # Always hardcode the artifact version instead of using "latest" - api_version = context["site.pmd.version"] + api_version = + if @use_previous_api_version + then + context["site.pmd.previous_version"] + else + context["site.pmd.version"] + end + markup_link(visible_name, doclink(@artifact_name, api_version, @type_fqcn, @member_suffix)) end @@ -129,3 +137,4 @@ end Liquid::Template.register_tag('jdoc', JavadocTag) Liquid::Template.register_tag('jdoc_package', JavadocTag) +Liquid::Template.register_tag('jdoc_old', JavadocTag) From 7f3d6e6e891bdfc388e8b6e9886b4655d4ba0c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Tue, 13 Nov 2018 11:54:18 -0300 Subject: [PATCH 079/139] [java] Fix concurrency error - Resolves #1460 --- .../typeresolution/typedefinition/JavaTypeDefinition.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinition.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinition.java index 6c5bc5b3d6..101fa8a9bd 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinition.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinition.java @@ -7,17 +7,17 @@ package net.sourceforge.pmd.lang.java.typeresolution.typedefinition; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang3.ArrayUtils; public abstract class JavaTypeDefinition implements TypeDefinition { // contains non-generic and raw EXACT types - private static final Map, JavaTypeDefinition> CLASS_EXACT_TYPE_DEF_CACHE = new HashMap<>(); + private static final Map, JavaTypeDefinition> CLASS_EXACT_TYPE_DEF_CACHE = new ConcurrentHashMap<>(); private final TypeDefinitionType definitionType; From d85e16732ab51b9cadb34bcf0552a6298004cc7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Nov 2018 16:41:05 +0100 Subject: [PATCH 080/139] Implement options and method references --- docs/_plugins/javadoc_tag.rb | 241 ++++++++++++++---- docs/pages/release_notes.md | 5 +- .../pmd/properties/LongMultiProperty.java | 2 + 3 files changed, 201 insertions(+), 47 deletions(-) diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb index 59a97ad9ba..b6dda4c122 100644 --- a/docs/_plugins/javadoc_tag.rb +++ b/docs/_plugins/javadoc_tag.rb @@ -1,3 +1,4 @@ + # Tags to reference a javadoc page or package summary. # # Provides several tags, which should not be mixed up: @@ -5,7 +6,7 @@ # * The tag "jdoc_package" is used for a package summary reference # # Both of these link to the latest version of the API so when editing the site, -# since it concerns an unpublished API version, the links don't work. When releasing +# since it refers to an unpublished API version, the links don't work. When releasing # though, links on the published jekyll site will work. # To refer to the previous API version, e.g. to refer to a type or member that was removed, # the tag "jdoc_old" may be used. This tag is used exactly the same way as "jdoc". There's @@ -15,50 +16,89 @@ # Usage (don't miss the DO NOT section at the bottom): # # * Simple type reference: {% jdoc core net.sourceforge.pmd.properties.PropertyDescriptor %} -# * First arg must be the name of the module, without the "pmd-" prefix, eg "core" will be expanded to "pmd-core" +# * First arg must be the name of the artifact, without the "pmd-" prefix, eg "core" will be expanded to "pmd-core" # * After a space, the fqcn of the type to reference is mentioned # * This will be expanded to [`PropertyDescriptor`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/latest/net/sourceforge/pmd/properties/PropertyDescriptor.html) # * Only the simple name of the type is visible by default -# * If you want to make the visible text expand to the FQCN like so [`net.sourceforge.pmd.properties.PropertyDescriptor`](...), -# then prefix the type name with a double bang (!!), e.g. {% jdoc core !!net.sourceforge.pmd.properties.PropertyDescriptor %} +# * Prefixing the reference with a double bang ("!!") displays the FQCN instead of the simple name +# * E.g. {% jdoc core !!net.sourceforge.pmd.properties.PropertyDescriptor %} -> [`net.sourceforge.pmd.properties.PropertyDescriptor`](...), # # * Using context: -# * The variable javadoc_context may be used to shorten references -# * You can assign it like so: -# * {% assign javadoc_context = "core @.properties" %} -# * The "@" symbol in the initializer is expanded to "net.sourceforge.pmd", the artifact id is not optional though -# * So this assignment sets the context to pmd-core/net.sourceforge.pmd.properties -# * Then the symbol "@" in a javadoc tag will be expanded to "core net.sourceforge.pmd.properties" +# * A context block may be used to shorten references +# * {% jdoc %} tags and such may be surrounded by a {% jdoc_context %} ... {% endjdoc_context %} block +# * You can open it like so: +# * {% jdoc_context core @.properties %} +# * The first word is the artifact id, the second is the name of e.g. a package or type +# * The "@" symbol *in the second word* is expanded to "net.sourceforge.pmd" regardless of the enclosing context +# * So inside the block, the context will be set to "pmd-core net.sourceforge.pmd.properties" +# * Then the symbol "@" in a jdoc tag will be expanded to "core net.sourceforge.pmd.properties" # * E.g. the reference {% jdoc @.PropertyDescriptor %} is expanded to the same as {% jdoc core net.sourceforge.pmd.properties.PropertyDescriptor %} # * Again, you may use "!!" to show the FQCN, like {% jdoc !!@.PropertyDescriptor %} -# * If the variable is not set, then "@" in a javadoc tag means "core net.sourceforge.pmd", eg -# {% jdoc @.properties.PropertyDescriptor %} works. +# * If a jdoc link occurs outside of a context block, then "@" in a javadoc tag means "core net.sourceforge.pmd", eg +# {% jdoc @.properties.PropertyDescriptor %} works anywhere. # * The artifact can be overridden from the context, eg with the default context "core net.sourceforge.pmd" # {% jdoc java @.lang.java.JavaLanguageModule %} will be linked correctly to pmd-java, and @ will be expanded to # "net.sourceforge.pmd" # -# * To reference a method or field: {% jdoc core @.Rule#addRuleChainVisit(java.lang.Class) %} -# * The suffix # is followed by the name of the method -# * The (erased) types of method arguments must be fully qualified!! This is the same -# convention as in javadoc {@link} tags +# * To reference a method or field: {% jdoc @.Rule#addRuleChainVisit(java.lang.Class) %} +# * The suffix # is followed by the name of the method or field +# * The (erased) types of method arguments must be fully qualified. This is the same +# convention as in javadoc {@link} tags, so you can use you're IDE's javadoc auto- +# complete and copy-paste. The "@" can still be used to reference the context package +# to shorten FQCNs. +# +# * To reference a package: {% jdoc_package @.properties %}, or {% jdoc-package @ %}, context works the same +# +# * Bang options: +# * Rendering may be customized by prefixing the reference to the linked member or type with some options. +# * Option syntax is "!name", and the options, if any, must be separated from the reference by another bang ("!") +# * Available options: +# * No options -> just the member name: +# * {% jdoc @.Rule %} -> [`Rule`](...) +# * {% jdoc @.Rule#setName(java.lang.String) %} -> [`setName`](...) +# * {% jdoc @.AbstractRule#children %} -> [`children`](...) +# * args -> adds the simple name of the argument types for method references, noop for other references +# * {% jdoc !args!@.Rule#setName(java.lang.String) %} -> [`setName(String)`](...) +# * qualify -> prefix with the fqcn of the class, noop for package references +# * {% jdoc !qualify!@.Rule %} -> [`net.sourceforge.pmd.Rule`](...) +# * {% jdoc !qualify!@.Rule#setName(java.lang.String) %} -> [`net.sourceforge.pmd.Rule#setName`](...) +# * class -> prefix the class name for member references, noop for type and package references, or if "qualify" is specified +# * {% jdoc !class!@.Rule#setName(java.lang.String) %} -> [`Rule#setName`](...) +# +# * Double-bang shorthands: +# * For field or method references, "!!" is the "class" option +# * {% jdoc !!@.Rule#setName(java.lang.String) %} -> [`Rule#setName`](...) +# * For type references, "!!" is the "qualify" option +# * {% jdoc !!@.Rule %} -> [`net.sourceforge.pmd.Rule`](...) +# * For package references, "!!" is a noop, they're always fully qualified +# * Options may be concatenated: +# * {% jdoc !args!!@.Rule#setName(java.lang.String) %} -> [`Rule#setName(String)`](...) +# * {% jdoc !args!qualify!@.Rule#setName(java.lang.String) %} -> [`net.sourceforge.pmd.Rule#setName(String)`](...) # -# * To reference a package: {% jdoc_package @.properties %}, or {% jdoc-package @ %} -# * The "!!" is implicit, the full package name is always displayed # # * DO NOT: # - Include spaces between dots, or anywhere except between the artifact reference and the page reference -# - Forget to use an artifact id whenever setting javadoc_context +# - Forget to use an artifact id whenever opening a jdoc_context block # - Use double or single quotes around the arguments # - Use the "#" suffix to reference a nested type, instead, use a dot "." and reference it like a normal type name # class JavadocTag < Liquid::Tag + + FQCN_OPTION = "qualify" + ARGS_OPTION = "args" + CLASS_OPTION = "class" + DOUBLE_BANG_OPTION = "shorthand" + def initialize(tag_name, doc_ref, tokens) super - if %r/(\w+\s+)?(!!)?(@(?:\.\w+)*)(#.*)?/ =~ doc_ref + options_str = "" + + if %r/^"?(\w+\s+)?((?:!\w+)*!?!)?(@(?:\.\w+)*)(#.*)?"?$/ =~ doc_ref.strip @artifact_name = $1 && ("pmd-" + $1.strip) # is nil if not mentioned - @show_full_name = !!$2 + options_str = $2 || "" + @display_options = [] # empty @type_fqcn = $3 # may be just "@" @member_suffix = $4 || "" # default to empty string instead of nil @@ -66,42 +106,81 @@ class JavadocTag < Liquid::Tag fail "Invalid javadoc reference format, see doc on javadoc_tag.rb" end + if options_str.end_with?("!!") + @display_options.push(DOUBLE_BANG_OPTION) + end + + @display_options += options_str.split("!").compact.reject {|s| s.empty?} # filter out empty if tag_name == "jdoc_package" @is_package_ref = true - @show_full_name = true + @display_options.push("qualify") elsif tag_name == "jdoc_old" @use_previous_api_version = true end - end - - def render(context) - - - doc_ctx = context["javadoc_context"] || "core net.sourceforge.pmd" - doc_ctx = doc_ctx.sub("@", "net.sourceforge.pmd") # Allows to use @ as shortcut when assigning javadoc_context - doc_ctx = doc_ctx.split(" ") # first is module, snd is package - - if @type_fqcn.include?("@") # Expand using the context - if doc_ctx.length == 2 # if it's two words then the first is the module name - # if the artifact was mentioned in the tag, it takes precedence - @artifact_name = @artifact_name || ("pmd-" + doc_ctx.first) - @type_fqcn = @type_fqcn.sub("@", doc_ctx.last) - else - fail "Invalid javadoc context format, you must specify artifact + package prefix in exactly two words" + @display_options.each do |opt| + if opt != FQCN_OPTION && opt != ARGS_OPTION && opt != CLASS_OPTION && opt != DOUBLE_BANG_OPTION + fail "Unknown display option '#{opt}'" end end + end - unless @artifact_name - fail "No artifact id was mentioned either in the tag or in the context" + def get_visible_name + + + # method or field + if @member_suffix && /#(\w+)(\((\s*[\w.]+(?:\[\])*(?:,\s*[\w.]+(?:\[\])*)*)\s*\))?/ =~ @member_suffix + + + suffix = $1 # method or field name + + if @display_options.include?(ARGS_OPTION) && $2 && !$2.empty? # is method + + p $3 + + + args = ($3 || "").split(",").map {|a| a.gsub(/\w+\./, "").strip} # map to simple names + + p args + + suffix = "#{suffix}(#{args.join(", ")})" + end + + visible_name = if @display_options.include?(FQCN_OPTION) + @type_fqcn + "#" + suffix + elsif @display_options.include?(CLASS_OPTION) || @display_options.include?(DOUBLE_BANG_OPTION) + @type_fqcn.split("\.").last + "#" + suffix # type simple name + else + suffix + end + + return visible_name end - if @show_full_name # !! was mentioned - visible_name = @type_fqcn + # else package or type, for packages the FQCN_OPTION is present + + if @display_options.include? FQCN_OPTION || @display_options.include?(DOUBLE_BANG_OPTION) + @type_fqcn else - visible_name = @type_fqcn.split("\.").last # simple name + @type_fqcn.split("\.").last end + end + + def render(rendering_context) + + + + if @type_fqcn.include?("@") # Expand using the context + + doc_ctx = JDocContextBlock.get_jdoc_context(rendering_context) + + @artifact_name = @artifact_name || doc_ctx.first # if the artifact was mentioned in the tag, it takes precedence + @type_fqcn = @type_fqcn.sub("@", doc_ctx.last) + @member_suffix = @member_suffix.gsub("@", doc_ctx.last) + end + + visible_name = get_visible_name # Hack to reference the package summary # Has to be done after finding the visible_name @@ -114,9 +193,9 @@ class JavadocTag < Liquid::Tag api_version = if @use_previous_api_version then - context["site.pmd.previous_version"] + rendering_context["site.pmd.previous_version"] else - context["site.pmd.version"] + rendering_context["site.pmd.version"] end @@ -126,7 +205,7 @@ class JavadocTag < Liquid::Tag private def doclink(artifact, api_version, type_name, member_suffix) - "https://javadoc.io/page/net.sourceforge.pmd/#{artifact}/#{api_version}/#{type_name.gsub("\.", "/")}.html#{member_suffix}" + "https://javadoc.io/page/net.sourceforge.pmd/#{artifact}/#{api_version}/#{type_name.gsub("\.", "/")}.html#{member_suffix.gsub(/\s+/, "")}" end def markup_link(rname, link) @@ -135,6 +214,76 @@ class JavadocTag < Liquid::Tag end + +# Block used to set the javadoc context +# +# Usage: +# +# {% jdoc_context java @.lang.java.ast} +# +# Links here in here use the context "java net.sourceforge.pmd.lang.java.ast" as context +# +# {% endjdoc_context %} +# +# Context is reset to the previous value +# +# If no arg is provided to the opening tag, context is reset to the default +# +# +class JDocContextBlock < Liquid::Block + + DEFAULT_JDOC_CONTEXT = "core net.sourceforge.pmd" + JDOC_CONTEXT_VARNAME = "javadoc_context" + + + def initialize(tag_name, arg, tokens) + super + + @this_context = JDocContextBlock.build_ctx(arg || DEFAULT_JDOC_CONTEXT).join(" ") #just a syntax check + + @body = tokens + end + + def render(context) + + ctx_sfg = context[JDOC_CONTEXT_VARNAME] || DEFAULT_JDOC_CONTEXT + + context[JDOC_CONTEXT_VARNAME] = @this_context + + contents = @body.render(context) + + context[JDOC_CONTEXT_VARNAME] = ctx_sfg + + contents + end + + + def self.build_ctx(ctx_str) + # Allows to use @ as shortcut when assigning javadoc_context + ctx_str = ctx_str.to_s.sub("@", "net.sourceforge.pmd").gsub("\"", "") + res = ctx_str.split(" ") + + if res.length != 2 + fail "Invalid javadoc context format, you must specify artifact + package prefix in exactly two words" + end + + unless res[0].strip.start_with?("pmd-") + res[0] = "pmd-#{res[0].strip}" + end + + res + end + + def self.get_jdoc_context(context) + build_ctx(context[JDOC_CONTEXT_VARNAME] || DEFAULT_JDOC_CONTEXT) + end + +end + +Liquid::Template.register_tag('jdoc_context', JDocContextBlock) Liquid::Template.register_tag('jdoc', JavadocTag) Liquid::Template.register_tag('jdoc_package', JavadocTag) Liquid::Template.register_tag('jdoc_old', JavadocTag) + + + diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 0a66b9d727..c1288ade03 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -32,11 +32,14 @@ This is a {{ site.pmd.release_type }} release. * [#1372](https://github.com/pmd/pmd/issues/1372): \[java] false positive for UselessQualifiedThis ### API Changes -{% assign javadoc_context = "core @.lang.ast.xpath" %} + +{% jdoc_context "core @.lang.ast.xpath" %} * The implementation of the adapters for the XPath engines Saxon and Jaxen (package {% jdoc_package @ %}) are now deprecated. They'll be moved to an internal package come 7.0.0. Only {% jdoc @.Attribute %} remains public API. +{% endjdoc_context %} + ### External Contributions * [#1384](https://github.com/pmd/pmd/pull/1384): \[java] New Rule - UseUnderscoresInNumericLiterals - [RajeshR](https://github.com/rajeshggwp) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/LongMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/LongMultiProperty.java index eb07bf17bc..827cbf2aa3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/LongMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/LongMultiProperty.java @@ -6,7 +6,9 @@ package net.sourceforge.pmd.properties; import java.util.Arrays; import java.util.List; +import java.util.Set; +import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.properties.builders.MultiNumericPropertyBuilder; import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilderConversionWrapper; From f610839ceae067f87044e4bbb9502ad469e60863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 13 Nov 2018 17:46:48 +0100 Subject: [PATCH 081/139] Add << path navigation --- docs/_config.yml | 2 +- docs/_plugins/javadoc_tag.rb | 24 +++++++++++++------ .../userdocs/extending/defining_properties.md | 7 ++++-- .../pmd/userdocs/extending/metrics_howto.md | 22 ++++++++++------- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/docs/_config.yml b/docs/_config.yml index 8fcdabf962..f1d6e64a9c 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,7 +1,7 @@ repository: pmd/pmd pmd: - version: 6.10.0 + version: 6.9.0 previous_version: 6.9.0 date: ??-????-2018 release_type: minor diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb index b6dda4c122..7e77335550 100644 --- a/docs/_plugins/javadoc_tag.rb +++ b/docs/_plugins/javadoc_tag.rb @@ -39,6 +39,9 @@ # * The artifact can be overridden from the context, eg with the default context "core net.sourceforge.pmd" # {% jdoc java @.lang.java.JavaLanguageModule %} will be linked correctly to pmd-java, and @ will be expanded to # "net.sourceforge.pmd" +# * The special package name "<<" may be used to go up once in the package tree. E.g. if the context is +# "core @.properties", then {% jdoc @.<<.rule.Rule %} is first expanded to {% jdoc core net.sourceforge.pmd.properties.<<.Rule %}, +# then reduced to {% jdoc core net.sourceforge.pmd.Rule %}. "<<" behaves the same as ".." in file system paths. # # * To reference a method or field: {% jdoc @.Rule#addRuleChainVisit(java.lang.Class) %} # * The suffix # is followed by the name of the method or field @@ -94,7 +97,7 @@ class JavadocTag < Liquid::Tag options_str = "" - if %r/^"?(\w+\s+)?((?:!\w+)*!?!)?(@(?:\.\w+)*)(#.*)?"?$/ =~ doc_ref.strip + if %r/^"?(\w+\s+)?((?:!\w+)*!?!)?(@(?:\.?+(?:<<|\w+))*)(#.*)?"?$/ =~ doc_ref.strip @artifact_name = $1 && ("pmd-" + $1.strip) # is nil if not mentioned options_str = $2 || "" @@ -137,13 +140,9 @@ class JavadocTag < Liquid::Tag if @display_options.include?(ARGS_OPTION) && $2 && !$2.empty? # is method - p $3 - args = ($3 || "").split(",").map {|a| a.gsub(/\w+\./, "").strip} # map to simple names - p args - suffix = "#{suffix}(#{args.join(", ")})" end @@ -167,6 +166,17 @@ class JavadocTag < Liquid::Tag end end + def escape_path(fqcn, ctx) + + fqcn = fqcn.gsub("@", ctx.last) + + while fqcn.include? ".<<" + fqcn = fqcn.gsub(/\.\w+\.<, Romain Pelisse , Clément Fournier --- +{% jdoc_context core @.properties %} ## Defining properties @@ -52,9 +53,9 @@ Note that RegexProperty doesn't have a multivalued variant, since the delimiters The procedure to define a property is quite straightforward: * Create a property descriptor of the type you want, using its builder; -* Call `definePropertyDescriptor()` in the rule's noarg constructor. +* Call {% jdoc !args!@.PropertySource#definePropertyDescriptor(@.PropertyDescriptor) %}` in the rule's noarg constructor. -You can then retrieve the value of the property at any time using `getProperty()`. +You can then retrieve the value of the property at any time using {% jdoc !args!@.PropertySource#getProperty(@.PropertyDescriptor) %}. #### Creating a descriptor @@ -171,3 +172,5 @@ Multivalued properties are also allowed and their `type` attribute has the form ``` Notice that in the example above, `@Image = $reportedIdentifiers` doesn't test `@Image` for equality with the whole sequence `('foo', 'bar')`, it tests whether the sequence *contains* `@Image`. That is, the above rule will report all variables named `foo` or `bar`. All other XPath 2.0 [functions operating on sequences](https://www.w3.org/TR/xpath-functions/#sequence-functions) are supported. + +{% endjdoc_context %} diff --git a/docs/pages/pmd/userdocs/extending/metrics_howto.md b/docs/pages/pmd/userdocs/extending/metrics_howto.md index 5ccabe03cd..8b657d4288 100644 --- a/docs/pages/pmd/userdocs/extending/metrics_howto.md +++ b/docs/pages/pmd/userdocs/extending/metrics_howto.md @@ -9,6 +9,9 @@ permalink: pmd_userdocs_extending_metrics_howto.html author: Clément Fournier --- +{% jdoc_context java @.lang.java.metrics %} + + ## Using the metrics framework {%include note.html content="The following explains how to use the Java metrics framework. The Apex framework @@ -19,9 +22,9 @@ a numeric result. In the Java framework, metrics can be computed on operation de method declaration), and type declaration nodes (class, interface, enum, and annotation declarations). A metric object in the framework can only handle either types or operations, but not both. -PMD ships with a library of already implemented metrics. These metrics are referenced by `MetricKey` objects, -which are listed in two public enums: `JavaClassMetricKey` and `JavaOperationMetricKey`. Metric keys wrap a metric, and -know which type of node their metric can be computed on. That way, you cannot compute an operation metric on a class +PMD ships with a library of already implemented metrics. These metrics are referenced by {% jdoc @.<<.<<.metrics.MetricKey %} objects, +which are listed in two public enums: {% jdoc @.api.JavaClassMetricKey %} and {% jdoc @.api.JavaOperationMetricKey %}. +Metric keys wrap a metric, and know which type of node their metric can be computed on. That way, you cannot compute an operation metric on a class declaration node. Metrics that can be computed on both operation and type declarations (e.g. NCSS) have one metric key in each enum. @@ -32,9 +35,9 @@ which is the name of the metric key as defined in `JavaClassMetricKey` or `Java will be **computed on the context node**. The function will throw an exception in the following cases: -* The context node is neither an instance of `ASTAnyTypeDeclaration` or `ASTMethodOrConstructorDeclaration`, that is, +* The context node is neither an instance of {% jdoc @.<<.ast.ASTAnyTypeDeclaration %} or {% jdoc @.<<.ast.MethodLikeNode %}, that is, it's not one of `ClassOrInterfaceDeclaration`, `EnumDeclaration`, `AnnotationDeclaration`, `MethodDeclaration`, -or `ConstructorDeclaration`. +`ConstructorDeclaration`, or `LambdaExpression`. * The metric key does not exist (the name is case insensitive) or is not defined for the type of the context node. {%include note.html @@ -50,7 +53,7 @@ or `ConstructorDeclaration`. ## For Java Rules -The static façade class `JavaMetrics` is the single entry point to compute metrics in the Java framework. +The static façade class {% jdoc @.JavaMetrics %} is the single entry point to compute metrics in the Java framework. This class provides the method `get` and its overloads. The following sections describes the interface of this class. @@ -80,7 +83,8 @@ to `JavaMetrics.get`. ### Capability checking Metrics are not necessarily computable on any node of the type they handle. For example, Cyclo cannot be computed on -abstract methods. Metric keys provides a `supports(Node)` boolean method to find out if the metric can be computed on +abstract methods. Metric keys provides a {% jdoc core @.<<.<<.metrics.MetricKey#supports(@.<<.<<.ast.Node) %} boolean method +to find out if the metric can be computed on the specified node. **If the metric cannot be computed on the given node, `JavaMetrics.get` will return `Double.NaN` .** If you're concerned about that, you can condition your call on whether the node is supported or not: ```java @@ -101,7 +105,7 @@ Some metrics define options that can be used to slightly modify the computation. gathered inside an enum in the implementation class of the metric, for example `CycloMetric.CycloOption`. They're also documented on the [index of metrics](pmd_java_metrics_index.html). -To use options with a metric, you must first bundle them into a `MetricOptions` object. `MetricOptions` provides the +To use options with a metric, you must first bundle them into a {% jdoc @.<<.<<.metrics.MetricOptions %} object. `MetricOptions` provides the utility method `ofOptions` to get a `MetricOptions` bundle from a collection or with varargs parameters. You can then pass this bundle as a parameter to `JavaMetrics.get`: ```java @@ -295,3 +299,5 @@ Language | Java | Apex | -----------|------|------| Operation metrics| supports constructors and non abstract methods| supports any non abstract method (including triggers), except ``, ``, and `clone` Type declaration|supports classes and enums|supports classes + +{% endjdoc_context %} From 07635370bca6a7ea3925eeb8d2bf6bbb961b7b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 14 Nov 2018 00:50:46 +0100 Subject: [PATCH 082/139] Use @{handles} --- docs/_plugins/javadoc_tag.rb | 185 ++++++++++-------- .../pmd/userdocs/extending/metrics_howto.md | 16 +- 2 files changed, 116 insertions(+), 85 deletions(-) diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb index 7e77335550..a3abc0fba7 100644 --- a/docs/_plugins/javadoc_tag.rb +++ b/docs/_plugins/javadoc_tag.rb @@ -23,34 +23,37 @@ # * Prefixing the reference with a double bang ("!!") displays the FQCN instead of the simple name # * E.g. {% jdoc core !!net.sourceforge.pmd.properties.PropertyDescriptor %} -> [`net.sourceforge.pmd.properties.PropertyDescriptor`](...), # -# * Using context: -# * A context block may be used to shorten references -# * {% jdoc %} tags and such may be surrounded by a {% jdoc_context %} ... {% endjdoc_context %} block -# * You can open it like so: -# * {% jdoc_context core @.properties %} -# * The first word is the artifact id, the second is the name of e.g. a package or type -# * The "@" symbol *in the second word* is expanded to "net.sourceforge.pmd" regardless of the enclosing context -# * So inside the block, the context will be set to "pmd-core net.sourceforge.pmd.properties" -# * Then the symbol "@" in a jdoc tag will be expanded to "core net.sourceforge.pmd.properties" -# * E.g. the reference {% jdoc @.PropertyDescriptor %} is expanded to the same as {% jdoc core net.sourceforge.pmd.properties.PropertyDescriptor %} -# * Again, you may use "!!" to show the FQCN, like {% jdoc !!@.PropertyDescriptor %} -# * If a jdoc link occurs outside of a context block, then "@" in a javadoc tag means "core net.sourceforge.pmd", eg -# {% jdoc @.properties.PropertyDescriptor %} works anywhere. -# * The artifact can be overridden from the context, eg with the default context "core net.sourceforge.pmd" -# {% jdoc java @.lang.java.JavaLanguageModule %} will be linked correctly to pmd-java, and @ will be expanded to -# "net.sourceforge.pmd" -# * The special package name "<<" may be used to go up once in the package tree. E.g. if the context is -# "core @.properties", then {% jdoc @.<<.rule.Rule %} is first expanded to {% jdoc core net.sourceforge.pmd.properties.<<.Rule %}, -# then reduced to {% jdoc core net.sourceforge.pmd.Rule %}. "<<" behaves the same as ".." in file system paths. +# * Using context handles +# * FQCNs are tedious to write and read so you can define shortcuts to a package or type name relevant +# to what you're documenting to save some keystrokes. +# * I call these shortcuts "context handles", they consist of an artifact id and a package or type name +# * The "jdoc_handle" tag is used to declare a handle. E.g. +# {% jdoc_handle @{coreast} core @.lang.ast %} +# {% jdoc_handle @{jast} java @.lang.java.ast} +# * The first argument is the handle as it will be referenced. It must have the form @{handle_name} +# * The second argument is the artifact id of the package. +# * The third argument is the package name, within which "@" is expanded to "net.sourceforge.pmd". Other handles +# may not be used within it. +# * After a handle is declared, it's used with the @{name} syntax, eg +# {% jdoc @{jast}.ASTType %}, or {% jdoc @{coreast}.Node %} +# The artifact id of the handle used for the type reference is used implicitly, +# and the handle reference is expanded to the package name. +# * "@" not followed by braces (not a handle) is expanded to "net.sourceforge.pmd", so +# {% jdoc core !!@.properties.PropertyDescriptor %} is the same as {% jdoc core !!net.sourceforge.pmd.properties.PropertyDescriptor %} +# Note that using "@" doesn't provide an implicit artifact id. +# * Handles can be used in method arguments but their artifact id is ignored. E.g. +# {% jdoc @.lang.java.ast.JavaNode.#(@{coreast}.Node) %} is invalid because neither +# * the artifact id was on the jdoc tag, nor did +# * the reference to JavaNode use a context handle that would have provided +# an implicit artifact id # # * To reference a method or field: {% jdoc @.Rule#addRuleChainVisit(java.lang.Class) %} # * The suffix # is followed by the name of the method or field # * The (erased) types of method arguments must be fully qualified. This is the same # convention as in javadoc {@link} tags, so you can use you're IDE's javadoc auto- -# complete and copy-paste. The "@" can still be used to reference the context package -# to shorten FQCNs. +# complete and copy-paste. "@" and context handles can still be used to shorten FQCNs. # -# * To reference a package: {% jdoc_package @.properties %}, or {% jdoc-package @ %}, context works the same +# * To reference a package: eg {% jdoc_package @{foo}.properties %}, {% jdoc-package @ %} # # * Bang options: # * Rendering may be customized by prefixing the reference to the linked member or type with some options. @@ -81,7 +84,6 @@ # # * DO NOT: # - Include spaces between dots, or anywhere except between the artifact reference and the page reference -# - Forget to use an artifact id whenever opening a jdoc_context block # - Use double or single quotes around the arguments # - Use the "#" suffix to reference a nested type, instead, use a dot "." and reference it like a normal type name # @@ -97,7 +99,7 @@ class JavadocTag < Liquid::Tag options_str = "" - if %r/^"?(\w+\s+)?((?:!\w+)*!?!)?(@(?:\.?+(?:<<|\w+))*)(#.*)?"?$/ =~ doc_ref.strip + if %r/^"?(\w+\s+)?((?:!\w+)*!?!)?(@(?:\{\w+\})?(?:\.?\w+)*)(#.*)?"?$/ =~ doc_ref.strip @artifact_name = $1 && ("pmd-" + $1.strip) # is nil if not mentioned options_str = $2 || "" @@ -131,6 +133,8 @@ class JavadocTag < Liquid::Tag def get_visible_name + fqcn_regex = + # method or field if @member_suffix && /#(\w+)(\((\s*[\w.]+(?:\[\])*(?:,\s*[\w.]+(?:\[\])*)*)\s*\))?/ =~ @member_suffix @@ -166,29 +170,11 @@ class JavadocTag < Liquid::Tag end end - def escape_path(fqcn, ctx) - - fqcn = fqcn.gsub("@", ctx.last) - - while fqcn.include? ".<<" - fqcn = fqcn.gsub(/\.\w+\.< --- -{% jdoc_context java @.lang.java.metrics %} +{% jdoc_handle @{coremx} core @.lang.metrics %} +{% jdoc_handle @{coreast} core @.lang.ast %} +{% jdoc_handle @{jmx} java @.lang.java.metrics %} +{% jdoc_handle @{jast} java @.lang.java.ast %} ## Using the metrics framework @@ -22,8 +25,8 @@ a numeric result. In the Java framework, metrics can be computed on operation de method declaration), and type declaration nodes (class, interface, enum, and annotation declarations). A metric object in the framework can only handle either types or operations, but not both. -PMD ships with a library of already implemented metrics. These metrics are referenced by {% jdoc @.<<.<<.metrics.MetricKey %} objects, -which are listed in two public enums: {% jdoc @.api.JavaClassMetricKey %} and {% jdoc @.api.JavaOperationMetricKey %}. +PMD ships with a library of already implemented metrics. These metrics are referenced by {% jdoc @{coremx}.MetricKey %} objects, +which are listed in two public enums: {% jdoc @{jmx}.api.JavaClassMetricKey %} and {% jdoc @{jmx}.api.JavaOperationMetricKey %}. Metric keys wrap a metric, and know which type of node their metric can be computed on. That way, you cannot compute an operation metric on a class declaration node. Metrics that can be computed on both operation and type declarations (e.g. NCSS) have one metric key in each enum. @@ -35,7 +38,7 @@ which is the name of the metric key as defined in `JavaClassMetricKey` or `Java will be **computed on the context node**. The function will throw an exception in the following cases: -* The context node is neither an instance of {% jdoc @.<<.ast.ASTAnyTypeDeclaration %} or {% jdoc @.<<.ast.MethodLikeNode %}, that is, +* The context node is neither an instance of {% jdoc @{jast}.ASTAnyTypeDeclaration %} or {% jdoc @{jast}.MethodLikeNode %}, that is, it's not one of `ClassOrInterfaceDeclaration`, `EnumDeclaration`, `AnnotationDeclaration`, `MethodDeclaration`, `ConstructorDeclaration`, or `LambdaExpression`. * The metric key does not exist (the name is case insensitive) or is not defined for the type of the context node. @@ -53,7 +56,7 @@ it's not one of `ClassOrInterfaceDeclaration`, `EnumDeclaration`, `AnnotationDec ## For Java Rules -The static façade class {% jdoc @.JavaMetrics %} is the single entry point to compute metrics in the Java framework. +The static façade class {% jdoc @{jmx}.JavaMetrics %} is the single entry point to compute metrics in the Java framework. This class provides the method `get` and its overloads. The following sections describes the interface of this class. @@ -83,7 +86,7 @@ to `JavaMetrics.get`. ### Capability checking Metrics are not necessarily computable on any node of the type they handle. For example, Cyclo cannot be computed on -abstract methods. Metric keys provides a {% jdoc core @.<<.<<.metrics.MetricKey#supports(@.<<.<<.ast.Node) %} boolean method +abstract methods. Metric keys provides a {% jdoc !args!@{coremx}.MetricKey#supports(@{coreast}.Node) %} boolean method to find out if the metric can be computed on the specified node. **If the metric cannot be computed on the given node, `JavaMetrics.get` will return `Double.NaN` .** If you're concerned about that, you can condition your call on whether the node is supported or not: @@ -300,4 +303,3 @@ Language | Java | Apex | Operation metrics| supports constructors and non abstract methods| supports any non abstract method (including triggers), except ``, ``, and `clone` Type declaration|supports classes and enums|supports classes -{% endjdoc_context %} From 3d7cd1964010ba54c52f22eaba401bc3eaf1760a Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Wed, 14 Nov 2018 18:46:20 +0100 Subject: [PATCH 083/139] Revert "Resolve type for ASTLiteral" This reverts commit 698935d2b4367bff19674a0fa436580e69c19aac. --- .../pmd/lang/java/ast/ASTLiteral.java | 68 ++++++++++++------- .../pmd/lang/java/ast/ASTLiteralTest.java | 24 ++----- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java index b8ac76dacf..2a18732390 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java @@ -11,6 +11,11 @@ import java.util.regex.Pattern; public class ASTLiteral extends AbstractJavaTypeNode { + private boolean isInt; + private boolean isFloat; + private boolean isChar; + private boolean isString; + /** * Pattern used to detect a single escaped character or octal character in a * String. @@ -35,18 +40,17 @@ public class ASTLiteral extends AbstractJavaTypeNode { } public void setIntLiteral() { - String image = getImage(); - if (image != null) { - if (image.endsWith("l") || image.endsWith("L")) { - setType(long.class); - } else { - setType(int.class); - } - } + this.isInt = true; } public boolean isIntLiteral() { - return int.class == getType(); + String image = getImage(); + if (isInt && image != null && image.length() > 0) { + if (!image.endsWith("l") && !image.endsWith("L")) { + return true; + } + } + return false; } /** @@ -55,23 +59,28 @@ public class ASTLiteral extends AbstractJavaTypeNode { * @return true if this literal is a long */ public boolean isLongLiteral() { - return long.class == getType(); + String image = getImage(); + if (isInt && image != null && image.length() > 0) { + if (image.endsWith("l") || image.endsWith("L")) { + return true; + } + } + return false; } public void setFloatLiteral() { - String image = getImage(); - if (image != null && !image.isEmpty()) { - char lastChar = image.charAt(image.length() - 1); - if (lastChar == 'f' || lastChar == 'F') { - setType(float.class); - } else if (lastChar == 'd' || lastChar == 'D' || Character.isDigit(lastChar) || lastChar == '.') { - setType(double.class); - } - } + this.isFloat = true; } public boolean isFloatLiteral() { - return float.class == getType(); + String image = getImage(); + if (isFloat && image != null && image.length() > 0) { + char lastChar = image.charAt(image.length() - 1); + if (lastChar == 'f' || lastChar == 'F') { + return true; + } + } + return false; } /** @@ -80,7 +89,14 @@ public class ASTLiteral extends AbstractJavaTypeNode { * @return true if this literal is a double. */ public boolean isDoubleLiteral() { - return double.class == getType(); + String image = getImage(); + if (isFloat && image != null && image.length() > 0) { + char lastChar = image.charAt(image.length() - 1); + if (lastChar == 'd' || lastChar == 'D' || Character.isDigit(lastChar) || lastChar == '.') { + return true; + } + } + return false; } private String stripIntValue() { @@ -150,19 +166,19 @@ public class ASTLiteral extends AbstractJavaTypeNode { } public void setCharLiteral() { - setType(char.class); + this.isChar = true; } public boolean isCharLiteral() { - return char.class == getType(); + return isChar; } public void setStringLiteral() { - setType(String.class); + this.isString = true; } public boolean isStringLiteral() { - return String.class == getType(); + return isString; } /** @@ -201,7 +217,7 @@ public class ASTLiteral extends AbstractJavaTypeNode { * @return true is this is a String literal with only one character */ public boolean isSingleCharacterStringLiteral() { - if (isStringLiteral()) { + if (isString) { String image = getImage(); int length = image.length(); if (length == 3) { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java index d3bbef0084..eb99628175 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java @@ -20,9 +20,7 @@ public class ASTLiteralTest { @Test public void testIsStringLiteral() { Set literals = getNodes(ASTLiteral.class, TEST1); - ASTLiteral literal = literals.iterator().next(); - assertTrue(literal.isStringLiteral()); - assertEquals("java.lang.String", literal.getType().getName()); + assertTrue((literals.iterator().next()).isStringLiteral()); } @Test @@ -34,41 +32,31 @@ public class ASTLiteralTest { @Test public void testIsIntIntLiteral() { Set literals = getNodes(ASTLiteral.class, TEST3); - ASTLiteral literal = literals.iterator().next(); - assertTrue(literal.isIntLiteral()); - assertEquals("int", literal.getType().getName()); + assertTrue((literals.iterator().next()).isIntLiteral()); } @Test public void testIsIntLongLiteral() { Set literals = getNodes(ASTLiteral.class, TEST4); - ASTLiteral literal = literals.iterator().next(); - assertTrue(literal.isLongLiteral()); - assertEquals("long", literal.getType().getName()); + assertTrue((literals.iterator().next()).isLongLiteral()); } @Test public void testIsFloatFloatLiteral() { Set literals = getNodes(ASTLiteral.class, TEST5); - ASTLiteral literal = literals.iterator().next(); - assertTrue(literal.isFloatLiteral()); - assertEquals("float", literal.getType().getName()); + assertTrue((literals.iterator().next()).isFloatLiteral()); } @Test public void testIsFloatDoubleLiteral() { Set literals = getNodes(ASTLiteral.class, TEST6); - ASTLiteral literal = literals.iterator().next(); - assertTrue(literal.isDoubleLiteral()); - assertEquals("double", literal.getType().getName()); + assertTrue((literals.iterator().next()).isDoubleLiteral()); } @Test public void testIsCharLiteral() { Set literals = getNodes(ASTLiteral.class, TEST7); - ASTLiteral literal = literals.iterator().next(); - assertTrue(literal.isCharLiteral()); - assertEquals("char", literal.getType().getName()); + assertTrue((literals.iterator().next()).isCharLiteral()); } @Test From f23e962595b7f67e3073de90068c2423f4582c97 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Wed, 14 Nov 2018 19:43:07 +0100 Subject: [PATCH 084/139] [java] TypeResolution / SymbolFacade for var inferred types The returned type of the variable name declaration is now also the inferred type. Note: getTypeImage() still returns null, since there is no TypeNode and therefore no image for "var" variable declarations. --- .../java/ast/ASTVariableDeclaratorId.java | 2 +- .../symboltable/VariableNameDeclaration.java | 21 +++-------------- .../pmd/lang/java/symboltable/STBBaseTst.java | 6 ++--- .../VariableNameDeclarationTest.java | 23 ++++++++++++++----- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java index 75c0b2e96b..5a549e5977 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java @@ -120,7 +120,7 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim } - public boolean isLambdaParamWithNoType() { + private boolean isLambdaParamWithNoType() { return jjtGetParent() instanceof ASTLambdaExpression; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclaration.java index 8480f9866e..d6c2492df4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclaration.java @@ -4,10 +4,8 @@ package net.sourceforge.pmd.lang.java.symboltable; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; -import net.sourceforge.pmd.lang.java.ast.ASTLiteral; import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; import net.sourceforge.pmd.lang.java.ast.ASTType; @@ -76,24 +74,12 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements && getAccessNodeParent().getFirstChildOfType(ASTType.class).jjtGetChild(0) instanceof ASTPrimitiveType; } - public boolean isLambdaParamWithNoType() { - return getDeclaratorId().isLambdaParamWithNoType(); - } - @Override public String getTypeImage() { TypeNode typeNode = getTypeNode(); if (typeNode != null) { return typeNode.getImage(); } - ASTLiteral assignedLiteral = getAccessNodeParent().getFirstDescendantOfType(ASTLiteral.class); - if (assignedLiteral != null - && !isLambdaParamWithNoType() - && assignedLiteral.getType() != null) { - // Even if ASTLiteral is a TypeNode, it is handled differently as - // the image is the literal value (example: 42L) and not the type (example: long) - return assignedLiteral.getType().getName(); - } return null; } @@ -123,9 +109,6 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements if (!isTypeInferred()) { return (TypeNode) getAccessNodeParent().getFirstChildOfType(ASTType.class).jjtGetChild(0).jjtGetChild(0); } - if (!isLambdaParamWithNoType()) { - return getAccessNodeParent().getFirstDescendantOfType(ASTClassOrInterfaceType.class); - } return null; } @@ -135,7 +118,9 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements if (typeNode != null) { return typeNode.getType(); } - return null; + // if there is no type node, then return the type of the declarator id. + // this might be a inferred type + return getDeclaratorId().getType(); } @Override diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/STBBaseTst.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/STBBaseTst.java index e020c72f28..b08fc9dc18 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/STBBaseTst.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/STBBaseTst.java @@ -20,7 +20,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; public abstract class STBBaseTst { protected ASTCompilationUnit acu; - protected SymbolFacade stb; protected void parseCode(final String code) { parseCode(code, LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getDefaultVersion()); @@ -34,8 +33,9 @@ public abstract class STBBaseTst { final LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler(); acu = (ASTCompilationUnit) languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions()) .parse(null, new StringReader(code)); - stb = new SymbolFacade(); - stb.initializeWith(acu); + languageVersionHandler.getQualifiedNameResolutionFacade(STBBaseTst.class.getClassLoader()).start(acu); + languageVersionHandler.getSymbolFacade(STBBaseTst.class.getClassLoader()).start(acu); + languageVersionHandler.getTypeResolutionFacade(STBBaseTst.class.getClassLoader()).start(acu); } // Note: If you're using Eclipse or some other IDE to run this test, you diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclarationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclarationTest.java index 1d84acc422..c9d31b52f4 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclarationTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/VariableNameDeclarationTest.java @@ -92,7 +92,9 @@ public class VariableNameDeclarationTest extends STBBaseTst { parseCode(TEST6); NameDeclaration decl = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope() .getDeclarations().keySet().iterator().next(); - assertEquals("MyObject", ((TypedNameDeclaration) decl).getTypeImage()); + assertEquals("java.util.ArrayList", ((TypedNameDeclaration) decl).getType().getName()); + // since the type is inferred, there is no type image + assertEquals(null, ((TypedNameDeclaration) decl).getTypeImage()); } @Test @@ -100,7 +102,9 @@ public class VariableNameDeclarationTest extends STBBaseTst { parseCode(TEST7); NameDeclaration decl = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope() .getDeclarations().keySet().iterator().next(); - assertEquals("long", ((TypedNameDeclaration) decl).getTypeImage()); + assertEquals("long", ((TypedNameDeclaration) decl).getType().getName()); + // since the type is inferred, there is no type image + assertEquals(null, ((TypedNameDeclaration) decl).getTypeImage()); } @Test @@ -110,6 +114,8 @@ public class VariableNameDeclarationTest extends STBBaseTst { .getDeclarations().keySet().iterator(); nameDeclarationIterator.next(); // first variable 'bar' NameDeclaration decl = nameDeclarationIterator.next(); // second variable 'foo' + assertEquals("java.lang.String", ((TypedNameDeclaration) decl).getType().getName()); + // since the type is inferred, there is no type image assertEquals(null, ((TypedNameDeclaration) decl).getTypeImage()); } @@ -121,7 +127,7 @@ public class VariableNameDeclarationTest extends STBBaseTst { true ); - List nameDeclarations = new ArrayList<>(); + List nameDeclarations = new ArrayList<>(); for (ASTVariableDeclaratorId variableDeclaratorId : variableDeclaratorIds) { nameDeclarations.add(variableDeclaratorId.getNameDeclaration()); } @@ -129,7 +135,12 @@ public class VariableNameDeclarationTest extends STBBaseTst { assertEquals("Map", nameDeclarations.get(0).getTypeImage()); // variable 'bar' assertEquals(null, nameDeclarations.get(1).getTypeImage()); // variable 'key' assertEquals(null, nameDeclarations.get(2).getTypeImage()); // variable 'value' - assertEquals("long", nameDeclarations.get(3).getTypeImage()); // variable 'foo' + + // variable 'foo' + assertEquals("foo", nameDeclarations.get(3).getName()); + assertEquals("long", nameDeclarations.get(3).getType().getName()); + // since the type is inferred, there is no type image + assertEquals(null, nameDeclarations.get(3).getTypeImage()); } private static final String EXCEPTION_PARAMETER = "public class Test { { try {} catch(Exception ie) {} } }"; @@ -147,8 +158,8 @@ public class VariableNameDeclarationTest extends STBBaseTst { + PMD.EOL + " }" + PMD.EOL + "}"; public static final String TEST5 = "public class Foo {" + PMD.EOL + " void foo(String x) {}" + PMD.EOL + "}"; - public static final String TEST6 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL - + " var bar = new MyObject(\"param\");" + PMD.EOL + " }" + PMD.EOL + "}"; + public static final String TEST6 = "import java.util.ArrayList; public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL + + " var bar = new ArrayList(\"param\");" + PMD.EOL + " }" + PMD.EOL + "}"; public static final String TEST7 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL + " var bar = 42L;" + PMD.EOL + " }" + PMD.EOL + "}"; From 42f5b8dd0db6fd7f6caaeca006eaa162a93dcd6e Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Wed, 14 Nov 2018 20:07:53 +0100 Subject: [PATCH 085/139] [java] JUnitTestsShouldIncludeAssert: Add negative test case for SoftAssertions --- .../xml/JUnitTestsShouldIncludeAssert.xml | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml index 7c31031804..c375a11924 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnitTestsShouldIncludeAssert.xml @@ -453,6 +453,29 @@ class FooTest { softly.assertThat("doesn't matter").isEqualTo("doesn't matter"); softly.assertAll(); } +}]]> + + + #1435 Treat AssertJ soft assertions as assert expressions - missing assertAll + 2 + 7,13 + From 246c2adbe3401f7900c780badc603ac785799bd1 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Wed, 14 Nov 2018 20:10:34 +0100 Subject: [PATCH 086/139] Update release notes, refs #1434, fixes #1435 --- docs/pages/release_notes.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 35e8909643..8802ab3b22 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -20,6 +20,11 @@ This is a {{ site.pmd.release_type }} release. verifies that numeric literals over a given length (4 chars by default, but configurable) are using underscores every 3 digits for readability. The rule only applies to Java 7+ codebases. +#### Modified Rules + +* The Java rule {% rule "java/bestpractices/JUnitTestsShouldIncludeAssert" %} (`java-bestpractices`) + now also detects [Soft Assertions](https://github.com/joel-costigliola/assertj-core). + ### Fixed Issues * all @@ -28,6 +33,7 @@ This is a {{ site.pmd.release_type }} release. * java-codestyle * [#1232](https://github.com/pmd/pmd/issues/1232): \[java] Detector for large numbers not separated by _ * [#1372](https://github.com/pmd/pmd/issues/1372): \[java] false positive for UselessQualifiedThis + * [#1435](https://github.com/pmd/pmd/issues/1435): \[java] JUnitTestsShouldIncludeAssert: Support AssertJ soft assertions ### API Changes @@ -37,6 +43,7 @@ This is a {{ site.pmd.release_type }} release. * [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007) * [#1428](https://github.com/pmd/pmd/pull/1428): \[core] Upgrading JCommander from 1.48 to 1.72 - [Thunderforge](https://github.com/Thunderforge) * [#1430](https://github.com/pmd/pmd/pull/1430): \[doc] Who really knows regex? - [Dem Pilafian](https://github.com/dpilafian) +* [#1434](https://github.com/pmd/pmd/pull/1434): \[java] JUnitTestsShouldIncludeAssert: Recognize AssertJ soft assertions as valid assert statements - [Loïc Ledoyen](https://github.com/ledoyen) {% endtocmaker %} From a7f7802ceb3faa0c1194b42bbc173fcdb5d1788c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 14 Nov 2018 14:13:59 +0100 Subject: [PATCH 087/139] Use namespaces:: --- docs/_plugins/javadoc_tag.rb | 374 +++++++----------- docs/_plugins/jdoc_namespace_tag.rb | 110 ++++++ .../userdocs/extending/defining_properties.md | 7 +- .../pmd/userdocs/extending/metrics_howto.md | 20 +- docs/pages/release_notes.md | 9 +- 5 files changed, 271 insertions(+), 249 deletions(-) create mode 100644 docs/_plugins/jdoc_namespace_tag.rb diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb index a3abc0fba7..8be83cca4f 100644 --- a/docs/_plugins/javadoc_tag.rb +++ b/docs/_plugins/javadoc_tag.rb @@ -1,4 +1,4 @@ - +require_relative 'jdoc_namespace_tag' # Tags to reference a javadoc page or package summary. # # Provides several tags, which should not be mixed up: @@ -15,168 +15,123 @@ # # Usage (don't miss the DO NOT section at the bottom): # -# * Simple type reference: {% jdoc core net.sourceforge.pmd.properties.PropertyDescriptor %} -# * First arg must be the name of the artifact, without the "pmd-" prefix, eg "core" will be expanded to "pmd-core" -# * After a space, the fqcn of the type to reference is mentioned -# * This will be expanded to [`PropertyDescriptor`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/latest/net/sourceforge/pmd/properties/PropertyDescriptor.html) -# * Only the simple name of the type is visible by default -# * Prefixing the reference with a double bang ("!!") displays the FQCN instead of the simple name -# * E.g. {% jdoc core !!net.sourceforge.pmd.properties.PropertyDescriptor %} -> [`net.sourceforge.pmd.properties.PropertyDescriptor`](...), +# * Simple type reference: {% jdoc core::properties.PropertyDescriptor %} +# * The arg of the tag is the FQCN of the type to reference, prefixed by a namespace +# * A namespaced qname is of the form 'nspace::a.b.Class' +# * The 'nspace::' identifies the namespace. A namespace is a shorthand for a package +# name and also stores the reference to the maven artifact to link to. The package +# name stored by the namespace is prefixed to the qname following the "::" +# * Namespaces for the maven modules of PMD are predefined. E.g. 'core::' points to pmd-core, 'java::' +# points to pmd-java. The package prefixes of these are all "net.sourceforge.pmd" +# * Example: +# * {% jdoc core::properties.PropertyDescriptor %} links to pmd-core, and the FQCN +# 'properties.PropertyDescriptor' is expanded to 'net.sourceforge.pmd.properties.PropertyDescriptor' +# This is rendered as [`PropertyDescriptor`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.10.0/net/sourceforge/pmd/properties/PropertyDescriptor.html) # -# * Using context handles -# * FQCNs are tedious to write and read so you can define shortcuts to a package or type name relevant -# to what you're documenting to save some keystrokes. -# * I call these shortcuts "context handles", they consist of an artifact id and a package or type name -# * The "jdoc_handle" tag is used to declare a handle. E.g. -# {% jdoc_handle @{coreast} core @.lang.ast %} -# {% jdoc_handle @{jast} java @.lang.java.ast} -# * The first argument is the handle as it will be referenced. It must have the form @{handle_name} -# * The second argument is the artifact id of the package. -# * The third argument is the package name, within which "@" is expanded to "net.sourceforge.pmd". Other handles -# may not be used within it. -# * After a handle is declared, it's used with the @{name} syntax, eg -# {% jdoc @{jast}.ASTType %}, or {% jdoc @{coreast}.Node %} -# The artifact id of the handle used for the type reference is used implicitly, -# and the handle reference is expanded to the package name. -# * "@" not followed by braces (not a handle) is expanded to "net.sourceforge.pmd", so -# {% jdoc core !!@.properties.PropertyDescriptor %} is the same as {% jdoc core !!net.sourceforge.pmd.properties.PropertyDescriptor %} -# Note that using "@" doesn't provide an implicit artifact id. -# * Handles can be used in method arguments but their artifact id is ignored. E.g. -# {% jdoc @.lang.java.ast.JavaNode.#(@{coreast}.Node) %} is invalid because neither -# * the artifact id was on the jdoc tag, nor did -# * the reference to JavaNode use a context handle that would have provided -# an implicit artifact id +# * Defining custom namespaces +# * you can define a namespace pointing to a package name relevant to what +# you're documenting to save some keystrokes. +# * They're defined with the 'jdoc_nspace' tag, e.g. +# {% jdoc_nspace :coreast core::lang.ast %} +# {% jdoc_nspace :jmx java::lang.java.metrics %} +# * The first argument is the name of the namespace, (optionally prefixed with a colon) +# * The second argument is a namespaced FQCN identifying the package the namespace points to +# * You need a namespace to define another namespace. Again, predefined namespaces point to +# the different maven modules, eg 'core::' or 'apex::' +# * After a jdoc_nspace tag, the namespace can be used with the 'name::' syntax in +# jdoc tags or other jdoc_nspace tags. E.g. +# {% jdoc coreast::Node %} -> points to pmd-core, expanded to 'net.sourceforge.pmd.lang.ast.Node' +# {% jdoc jmx::impl.NcssVisitor %} -> points to pmd-java, expanded to 'net.sourceforge.pmd.lang.java.metrics.impl.NcssVisitor' # -# * To reference a method or field: {% jdoc @.Rule#addRuleChainVisit(java.lang.Class) %} +# * To reference a method or field: {% jdoc core::Rule#addRuleChainVisit(java.lang.Class) %} # * The suffix # is followed by the name of the method or field # * The (erased) types of method arguments must be fully qualified. This is the same # convention as in javadoc {@link} tags, so you can use you're IDE's javadoc auto- -# complete and copy-paste. "@" and context handles can still be used to shorten FQCNs. +# complete and copy-paste. Namespaces also can be used for method arguments if they're from PMD. # -# * To reference a package: eg {% jdoc_package @{foo}.properties %}, {% jdoc-package @ %} +# * To reference a package: eg {% jdoc_package core::properties %} +# * If you want to reference the package prefix of a namespace, you can do so +# by using the syntax ':nspace', e.g. +# {% jdoc_package :jmx %} -> points to pmd-java, expanded to 'net.sourceforge.pmd.lang.ast.Node' +# {% jdoc_package :coreast %} -> points to pmd-core, expanded to 'net.sourceforge.pmd.lang.java.metrics' # # * Bang options: -# * Rendering may be customized by prefixing the reference to the linked member or type with some options. -# * Option syntax is "!name", and the options, if any, must be separated from the reference by another bang ("!") +# * The visible text of the link may be customized by prefixing the reference to the +# linked member or type with some options. +# * Option syntax is "!opts!", and prefixes the namespace. Options are one-character switches. # * Available options: # * No options -> just the member name: # * {% jdoc @.Rule %} -> [`Rule`](...) # * {% jdoc @.Rule#setName(java.lang.String) %} -> [`setName`](...) # * {% jdoc @.AbstractRule#children %} -> [`children`](...) -# * args -> adds the simple name of the argument types for method references, noop for other references -# * {% jdoc !args!@.Rule#setName(java.lang.String) %} -> [`setName(String)`](...) -# * qualify -> prefix with the fqcn of the class, noop for package references -# * {% jdoc !qualify!@.Rule %} -> [`net.sourceforge.pmd.Rule`](...) -# * {% jdoc !qualify!@.Rule#setName(java.lang.String) %} -> [`net.sourceforge.pmd.Rule#setName`](...) -# * class -> prefix the class name for member references, noop for type and package references, or if "qualify" is specified -# * {% jdoc !class!@.Rule#setName(java.lang.String) %} -> [`Rule#setName`](...) -# -# * Double-bang shorthands: -# * For field or method references, "!!" is the "class" option -# * {% jdoc !!@.Rule#setName(java.lang.String) %} -> [`Rule#setName`](...) -# * For type references, "!!" is the "qualify" option -# * {% jdoc !!@.Rule %} -> [`net.sourceforge.pmd.Rule`](...) -# * For package references, "!!" is a noop, they're always fully qualified -# * Options may be concatenated: -# * {% jdoc !args!!@.Rule#setName(java.lang.String) %} -> [`Rule#setName(String)`](...) -# * {% jdoc !args!qualify!@.Rule#setName(java.lang.String) %} -> [`net.sourceforge.pmd.Rule#setName(String)`](...) -# +# * a (args) -> adds the simple name of the argument types for method references, noop for other references +# * {% jdoc !a!@.Rule#setName(java.lang.String) %} -> [`setName(String)`](...) +# * q (qualify) -> prefix with the fqcn of the class, noop for package references +# * {% jdoc !q!@.Rule %} -> [`net.sourceforge.pmd.Rule`](...) +# * {% jdoc !q!@.Rule#setName(java.lang.String) %} -> [`net.sourceforge.pmd.Rule#setName`](...) +# * c (class) -> prefix the class name for member references, noop for type and package references, or if "qualify" is specified +# * {% jdoc !c!@.Rule#setName(java.lang.String) %} -> [`Rule#setName`](...) +# * Empty options ("!!") - > shorthand to a commonly relevant option +# * For field or method references, "!!" is the "c" option +# * {% jdoc !!@.Rule#setName(java.lang.String) %} -> [`Rule#setName`](...) +# * For type references, "!!" is the "q" option +# * {% jdoc !!@.Rule %} -> [`net.sourceforge.pmd.Rule`](...) +# * For package references, "!!" is a noop, they're always fully qualified +# * Several options may be used at once, though this is only useful for method references: +# * {% jdoc !ac!@.Rule#setName(java.lang.String) %} -> [`Rule#setName(String)`](...) +# * {% jdoc !aq!@.Rule#setName(java.lang.String) %} -> [`net.sourceforge.pmd.Rule#setName(String)`](...) # # * DO NOT: -# - Include spaces between dots, or anywhere except between the artifact reference and the page reference +# - Include spaces in any part of the reference # - Use double or single quotes around the arguments # - Use the "#" suffix to reference a nested type, instead, use a dot "." and reference it like a normal type name # +# class JavadocTag < Liquid::Tag - FQCN_OPTION = "qualify" - ARGS_OPTION = "args" - CLASS_OPTION = "class" - DOUBLE_BANG_OPTION = "shorthand" + QNAME_NO_NAMESPACE_REGEX = /((?:\w+\.)*\w+)/ + + ARG_REGEX = Regexp.new(Regexp.union(JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX, QNAME_NO_NAMESPACE_REGEX).source + '(\[\])*') + ARGUMENTS_REGEX = Regexp.new('\(\)|\((' + ARG_REGEX.source + "(?:," + ARG_REGEX.source + ")*" + ')\)') + def initialize(tag_name, doc_ref, tokens) super - options_str = "" + # sanitize a little + doc_ref.delete! " \"'" - if %r/^"?(\w+\s+)?((?:!\w+)*!?!)?(@(?:\{\w+\})?(?:\.?\w+)*)(#.*)?"?$/ =~ doc_ref.strip + arr = doc_ref.split("#") # split into fqcn + member suffix - @artifact_name = $1 && ("pmd-" + $1.strip) # is nil if not mentioned - options_str = $2 || "" - @display_options = [] # empty - @type_fqcn = $3 # may be just "@" - @member_suffix = $4 || "" # default to empty string instead of nil + @type_fqcn = arr[0] + @member_suffix = arr[1] || "" # default to empty string - else - fail "Invalid javadoc reference format, see doc on javadoc_tag.rb" + unless Regexp.new('(!\w*!)?' + JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX.source) =~ @type_fqcn + "Wrong syntax for type reference, expected eg nspace::a.b.C, !!nspace::a.b.C, or !opts!nspace::a.b.C" end - if options_str.end_with?("!!") - @display_options.push(DOUBLE_BANG_OPTION) - end + # If no options, then split produces [@type_fqcn] + # If options are present, then split produces eg ["", "aq", @type_fqcn] (there's an empty string first) + # If !!, then split produces eg ["", "", @type_fqcn] + *opts, @type_fqcn = @type_fqcn.split("!") # split into options + type fqcn - @display_options += options_str.split("!").compact.reject {|s| s.empty?} # filter out empty + @opts = Options.new(opts.last) # ignore first empty string, may be nil if tag_name == "jdoc_package" @is_package_ref = true - @display_options.push("qualify") elsif tag_name == "jdoc_old" @use_previous_api_version = true end - - @display_options.each do |opt| - if opt != FQCN_OPTION && opt != ARGS_OPTION && opt != CLASS_OPTION && opt != DOUBLE_BANG_OPTION - fail "Unknown display option '#{opt}'" - end - end end - def get_visible_name + def render(var_ctx) - fqcn_regex = + artifact_name, @type_fqcn = JDocNamespaceDeclaration::parse_fqcn(@type_fqcn, var_ctx) + # Expand FQCN of arguments + @member_suffix.gsub!(JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX) {|fqcn| JDocNamespaceDeclaration::parse_fqcn(fqcn, var_ctx)[1]} - # method or field - if @member_suffix && /#(\w+)(\((\s*[\w.]+(?:\[\])*(?:,\s*[\w.]+(?:\[\])*)*)\s*\))?/ =~ @member_suffix - - - suffix = $1 # method or field name - - if @display_options.include?(ARGS_OPTION) && $2 && !$2.empty? # is method - - - args = ($3 || "").split(",").map {|a| a.gsub(/\w+\./, "").strip} # map to simple names - - suffix = "#{suffix}(#{args.join(", ")})" - end - - visible_name = if @display_options.include?(FQCN_OPTION) - @type_fqcn + "#" + suffix - elsif @display_options.include?(CLASS_OPTION) || @display_options.include?(DOUBLE_BANG_OPTION) - @type_fqcn.split("\.").last + "#" + suffix # type simple name - else - suffix - end - - return visible_name - end - - # else package or type, for packages the FQCN_OPTION is present - - if @display_options.include? FQCN_OPTION || @display_options.include?(DOUBLE_BANG_OPTION) - @type_fqcn - else - @type_fqcn.split("\.").last - end - end - - def render(rendering_context) - - doc_ctx, @type_fqcn = JDocContextDeclaration::escape_path(@type_fqcn, rendering_context) - @artifact_name = @artifact_name || doc_ctx.first # if the artifact was mentioned in the tag, it takes precedence - _, @member_suffix = JDocContextDeclaration::escape_path(@member_suffix, rendering_context) - - visible_name = get_visible_name + visible_name = JavadocTag::get_visible_name(@opts, @type_fqcn, @member_suffix, @is_package_ref) # Hack to reference the package summary # Has to be done after finding the visible_name @@ -184,145 +139,102 @@ class JavadocTag < Liquid::Tag @type_fqcn = @type_fqcn + ".package-summary" end - - # Always hardcode the artifact version instead of using "latest" - api_version = - if @use_previous_api_version - then - rendering_context["site.pmd.previous_version"] - else - rendering_context["site.pmd.version"] - end + # Hardcode the artifact version instead of using "latest" + api_version = var_ctx["site.pmd." + (@use_previous_api_version ? "previous_version" : "version")] - markup_link(visible_name, doclink(@artifact_name, api_version, @type_fqcn, @member_suffix)) + markup_link(visible_name, doclink(artifact_name, api_version, @type_fqcn, @member_suffix)) end private def doclink(artifact, api_version, type_name, member_suffix) - "https://javadoc.io/page/net.sourceforge.pmd/#{artifact}/#{api_version}/#{type_name.gsub("\.", "/")}.html#{member_suffix.gsub(/\s+/, "")}" + "https://javadoc.io/page/net.sourceforge.pmd/#{artifact}/#{api_version}/#{type_name.gsub("\.", "/")}.html##{member_suffix}" end def markup_link(rname, link) "[`#{rname}`](#{link})" end -end + def self.get_visible_name(opts, type_fqcn, member_suffix, is_package_ref) -# Tag used to declare a javadoc handle to shorten javadoc references. -# -# Usage: -# {% jdoc_handle @{coreast} core @.lang.ast %} -# {% jdoc_handle @{jast} java @.lang.java.ast} -# -# * The first argument is the handle as it will be referenced. It must have the form @{handle_name} -# * The second argument is the artifact id of the package. -# * The third argument is the package name, within which "@" means net.sourceforge.pmd. Other handles -# may not be used within it. -# -# After those tags have been declared, the handle is used with the @{name} syntax, eg {% jdoc @{jast}.ASTType %} -# -class JDocContextDeclaration < Liquid::Tag + # method or field + if member_suffix && Regexp.new('(\w+)(' + ARGUMENTS_REGEX.source + ")?") =~ member_suffix - DEFAULT_JDOC_CONTEXT = ["pmd-core", "net.sourceforge.pmd"] - JDOC_CONTEXT_NAMESPACE = "jdoc_context" + suffix = $1 # method or field name + if opts.show_args? && $2 && !$2.empty? # is method - def initialize(tag_name, arg, tokens) - super + args = $3.split(",").map {|a| a.gsub(/\w+\./, "").strip} # map to simple names - all_args = arg.split(" ") - - @ctx_name = JDocContextDeclaration::get_handle_name(all_args.shift) - - @this_context = JDocContextDeclaration::validate_ctx(all_args || DEFAULT_JDOC_CONTEXT) - - end - - def render(ctx) - - unless ctx[JDOC_CONTEXT_NAMESPACE] - ctx[JDOC_CONTEXT_NAMESPACE] = {} #empty map - end - - ctx[JDOC_CONTEXT_NAMESPACE][@ctx_name] = @this_context - - "" - end - - - def self.validate_ctx(ctx_arr) - - unless ctx_arr && ctx_arr.compact.length == 2 - fail "Invalid javadoc context format, you must specify artifact + package prefix in exactly two words" - end - - # Allows to use @ as shortcut when assigning javadoc_context - ctx_arr[1].sub!("@", "net.sourceforge.pmd").gsub!("\"", "") - - - unless ctx_arr[0].strip.start_with?("pmd-") - ctx_arr[0] = "pmd-#{ctx_arr[0].strip}" - end - - ctx_arr - end - - - # gets the expansion of a full handle, given as @{name} - def self.get_context(at_prefixed_name, ctx) - - name = get_handle_name(at_prefixed_name) - - unless ctx[JDOC_CONTEXT_NAMESPACE] && ctx[JDOC_CONTEXT_NAMESPACE][name] - fail "Undeclared javadoc context handle #{at_prefixed_name}" - end - - ctx[JDOC_CONTEXT_NAMESPACE][name] # return the variable - end - - def self.get_handle_name(at_prefixed_name) - if /@\{(\w+)\}/ =~ at_prefixed_name - $1 - else - fail "Invalid format for javadoc context handle, expected @{name}, was #{at_prefixed_name}" - end - end - - - def self.escape_path(fqcn, rendering_ctx) - - unless fqcn - return [DEFAULT_JDOC_CONTEXT, nil] - end - - doc_ctx = DEFAULT_JDOC_CONTEXT - - fqcn = fqcn.gsub(/@(\{(\w+)\})?/) do |h| - if $1 - doc_ctx = get_context(h, rendering_ctx) - else - doc_ctx = DEFAULT_JDOC_CONTEXT + suffix = "#{suffix}(#{args.join(", ")})" end - doc_ctx[1] + + visible_name = if opts.show_fqcn? + type_fqcn + "#" + suffix + elsif opts.is_double_bang? || opts.show_class? + type_fqcn.split("\.").last + "#" + suffix # type simple name + else + suffix # just method name + possibly args + end + + return visible_name end - # return the last found context - # For the type fqcn there's only one so it's ok - # For argument types there may be several but they're ignored so it's ok - [doc_ctx, fqcn] + # else package or type, for packages the FQCN_OPTION is present + + if is_package_ref || opts.show_fqcn? || opts.is_double_bang? + type_fqcn + else + type_fqcn.split("\.").last # type simple name + end + end + + + class Options + + def initialize(str) + if str.nil? + @opts = "" + return + else + @opts = str.empty? ? "!!" : str + end + + invalid = str.delete("aqc") + + unless invalid.empty? + fail "Unknown display options '#{invalid}', I know only aqc" + end + end + + def is_double_bang? + @opts == "!!" + end + + def show_args? + @opts.include? "a" + end + + def show_fqcn? + @opts.include? "q" + end + + + def show_class? + @opts.include? "c" + end end end -Liquid::Template.register_tag('jdoc_context', JDocContextBlock) + Liquid::Template.register_tag('jdoc', JavadocTag) Liquid::Template.register_tag('jdoc_package', JavadocTag) Liquid::Template.register_tag('jdoc_old', JavadocTag) -Liquid::Template.register_tag('jdoc_handle', JDocContextDeclaration) +Liquid::Template.register_tag('jdoc_nspace', JDocNamespaceDeclaration) diff --git a/docs/_plugins/jdoc_namespace_tag.rb b/docs/_plugins/jdoc_namespace_tag.rb new file mode 100644 index 0000000000..1c2ba22e20 --- /dev/null +++ b/docs/_plugins/jdoc_namespace_tag.rb @@ -0,0 +1,110 @@ +# Tag used to declare a javadoc namespace to shorten javadoc references. +# +# Usage: +# {% jdoc_nspace :coreast core::lang.ast %} +# {% jdoc_nspace :jast java::lang.java.ast %} +# +# * The first argument is the name of the namespace, it can be prefixed with a ":" for readability +# * The second argument is the package prefix of the namespace, which itself must use an already declared namespace +# Base namespaces are declared for most of the modules of PMD, with the "net.sourceforge.pmd" package prefix. +# E.g. "core::" and "pmd-core::" (aliased) point to pmd-core's "net.sourceforge.pmd" package. +# +# After those tags have been declared, the handle is used with the "name::" syntax, eg {% jdoc jast::ASTType %} +# To refer to only the package prefix defined by the namespace, use instead the ":name" syntax, e.g. {% jdoc_package :jast %} +# +class JDocNamespaceDeclaration < Liquid::Tag + + # a namespace is a pair [artifactId, base package] + + def initialize(tag_name, arg, tokens) + super + + all_args = arg.split(" ") + + if all_args.size != 2 + "Invalid arguments for jdoc namespace declaration, expected ':name baseNSpace::package.prefix'" + end + + + @nspace_name = all_args.first.delete(":") + + if RESERVED_NSPACES.include?(@nspace_name) + fail "Javadoc namespace #{@nspace_name} is reserved and cannot be redefined" + end + + @this_fqcn_unresolved = all_args.last + + end + + def render(var_ctx) + + unless var_ctx[JDOC_NAMESPACE_MAP] + var_ctx[JDOC_NAMESPACE_MAP] = JDocNamespaceDeclaration::make_base_namespaces #base namespace map + end + + # Add the resolved QName to the map + var_ctx[JDOC_NAMESPACE_MAP][@nspace_name] = JDocNamespaceDeclaration::parse_fqcn(@this_fqcn_unresolved, var_ctx) + + "" + end + + # Regex to match a prefixed fqcn, used for method arguments + NAMESPACED_FQCN_REGEX = /(\w[\w-]*)::((?:\w+\.)*\w+)/ + SYM_REGEX = /:(\w[\w-]*)/ + + # Parses a namespaced fqcn of the form nspace::a.b.c.Class into a tuple [artifactId, expandedFQCN] + # If allow_sym is true, then the syntax :nspace is allowed as well + def self.parse_fqcn(fqcn, var_ctx, allow_sym = true) + + nspace = nil + fqcn_suffix = "" + + if NAMESPACED_FQCN_REGEX =~ fqcn + nspace = $1 + fqcn_suffix = $2 + elsif allow_sym && SYM_REGEX =~ fqcn + nspace = $1 + fqcn_suffix = "" + else + fail "Invalid javadoc fqcn format, expected nspace::a.b.c.Class" + (allow_sym ? " or :nspace" : "") + ", but was " + fqcn + end + + resolved_nspace = [] + + unless var_ctx[JDOC_NAMESPACE_MAP] && (resolved_nspace = var_ctx[JDOC_NAMESPACE_MAP][nspace]) + fail "Undeclared javadoc namespace #{nspace}" + end + + unless resolved_nspace.size == 2 + fail "Badly registered namespace (implementation bug)" # just to be safe + end + + expanded_fqcn = resolved_nspace.last + unless fqcn_suffix.empty? + expanded_fqcn += "." + fqcn_suffix + end + + + # Return the resolved artifactId + the expanded FQCN + [resolved_nspace.first, expanded_fqcn] + end + + private + + JDOC_NAMESPACE_MAP = "jdoc_nspaces" + RESERVED_NSPACES = ['core', 'java', 'apex', 'dist', 'doc', 'xml', 'visualforce', 'ui', 'test'].flat_map {|m| [m, "pmd-" + m]} + + def self.make_base_namespaces + res = {} + RESERVED_NSPACES.each do |mod| + pmd_prefixed = mod.start_with?("pmd") ? mod : ("pmd-" + mod) + + # Each is aliased, eg core:: is equivalent to pmd-core:: + res[mod] = [pmd_prefixed, "net.sourceforge.pmd"] + res[pmd_prefixed] = [pmd_prefixed, "net.sourceforge.pmd"] + end + + res + end + +end \ No newline at end of file diff --git a/docs/pages/pmd/userdocs/extending/defining_properties.md b/docs/pages/pmd/userdocs/extending/defining_properties.md index b8d5f7775b..8b455d7c28 100644 --- a/docs/pages/pmd/userdocs/extending/defining_properties.md +++ b/docs/pages/pmd/userdocs/extending/defining_properties.md @@ -8,7 +8,7 @@ permalink: pmd_userdocs_extending_defining_properties.html author: Hooper Bloob , Romain Pelisse , Clément Fournier --- -{% jdoc_context core @.properties %} +{% jdoc_nspace :props core::properties %} ## Defining properties @@ -53,9 +53,9 @@ Note that RegexProperty doesn't have a multivalued variant, since the delimiters The procedure to define a property is quite straightforward: * Create a property descriptor of the type you want, using its builder; -* Call {% jdoc !args!@.PropertySource#definePropertyDescriptor(@.PropertyDescriptor) %}` in the rule's noarg constructor. +* Call {% jdoc !a!props::PropertySource#definePropertyDescriptor(props::PropertyDescriptor) %}` in the rule's noarg constructor. -You can then retrieve the value of the property at any time using {% jdoc !args!@.PropertySource#getProperty(@.PropertyDescriptor) %}. +You can then retrieve the value of the property at any time using {% jdoc !a!props::PropertySource#getProperty(props::PropertyDescriptor) %}. #### Creating a descriptor @@ -173,4 +173,3 @@ Multivalued properties are also allowed and their `type` attribute has the form Notice that in the example above, `@Image = $reportedIdentifiers` doesn't test `@Image` for equality with the whole sequence `('foo', 'bar')`, it tests whether the sequence *contains* `@Image`. That is, the above rule will report all variables named `foo` or `bar`. All other XPath 2.0 [functions operating on sequences](https://www.w3.org/TR/xpath-functions/#sequence-functions) are supported. -{% endjdoc_context %} diff --git a/docs/pages/pmd/userdocs/extending/metrics_howto.md b/docs/pages/pmd/userdocs/extending/metrics_howto.md index 9f68c11c4d..0b6708fc49 100644 --- a/docs/pages/pmd/userdocs/extending/metrics_howto.md +++ b/docs/pages/pmd/userdocs/extending/metrics_howto.md @@ -9,10 +9,10 @@ permalink: pmd_userdocs_extending_metrics_howto.html author: Clément Fournier --- -{% jdoc_handle @{coremx} core @.lang.metrics %} -{% jdoc_handle @{coreast} core @.lang.ast %} -{% jdoc_handle @{jmx} java @.lang.java.metrics %} -{% jdoc_handle @{jast} java @.lang.java.ast %} +{% jdoc_nspace :coremx core::lang.metrics %} +{% jdoc_nspace :coreast core::lang.ast %} +{% jdoc_nspace :jmx java::lang.java.metrics %} +{% jdoc_nspace :jast java::lang.java.ast %} ## Using the metrics framework @@ -25,8 +25,8 @@ a numeric result. In the Java framework, metrics can be computed on operation de method declaration), and type declaration nodes (class, interface, enum, and annotation declarations). A metric object in the framework can only handle either types or operations, but not both. -PMD ships with a library of already implemented metrics. These metrics are referenced by {% jdoc @{coremx}.MetricKey %} objects, -which are listed in two public enums: {% jdoc @{jmx}.api.JavaClassMetricKey %} and {% jdoc @{jmx}.api.JavaOperationMetricKey %}. +PMD ships with a library of already implemented metrics. These metrics are referenced by {% jdoc coremx::MetricKey %} objects, +which are listed in two public enums: {% jdoc jmx::api.JavaClassMetricKey %} and {% jdoc jmx::api.JavaOperationMetricKey %}. Metric keys wrap a metric, and know which type of node their metric can be computed on. That way, you cannot compute an operation metric on a class declaration node. Metrics that can be computed on both operation and type declarations (e.g. NCSS) have one metric key in each enum. @@ -38,7 +38,7 @@ which is the name of the metric key as defined in `JavaClassMetricKey` or `Java will be **computed on the context node**. The function will throw an exception in the following cases: -* The context node is neither an instance of {% jdoc @{jast}.ASTAnyTypeDeclaration %} or {% jdoc @{jast}.MethodLikeNode %}, that is, +* The context node is neither an instance of {% jdoc jast::ASTAnyTypeDeclaration %} or {% jdoc jast::MethodLikeNode %}, that is, it's not one of `ClassOrInterfaceDeclaration`, `EnumDeclaration`, `AnnotationDeclaration`, `MethodDeclaration`, `ConstructorDeclaration`, or `LambdaExpression`. * The metric key does not exist (the name is case insensitive) or is not defined for the type of the context node. @@ -56,7 +56,7 @@ it's not one of `ClassOrInterfaceDeclaration`, `EnumDeclaration`, `AnnotationDec ## For Java Rules -The static façade class {% jdoc @{jmx}.JavaMetrics %} is the single entry point to compute metrics in the Java framework. +The static façade class {% jdoc jmx::JavaMetrics %} is the single entry point to compute metrics in the Java framework. This class provides the method `get` and its overloads. The following sections describes the interface of this class. @@ -86,7 +86,7 @@ to `JavaMetrics.get`. ### Capability checking Metrics are not necessarily computable on any node of the type they handle. For example, Cyclo cannot be computed on -abstract methods. Metric keys provides a {% jdoc !args!@{coremx}.MetricKey#supports(@{coreast}.Node) %} boolean method +abstract methods. Metric keys provides a {% jdoc !a!coremx::MetricKey#supports(coreast::Node) %} boolean method to find out if the metric can be computed on the specified node. **If the metric cannot be computed on the given node, `JavaMetrics.get` will return `Double.NaN` .** If you're concerned about that, you can condition your call on whether the node is supported or not: @@ -108,7 +108,7 @@ Some metrics define options that can be used to slightly modify the computation. gathered inside an enum in the implementation class of the metric, for example `CycloMetric.CycloOption`. They're also documented on the [index of metrics](pmd_java_metrics_index.html). -To use options with a metric, you must first bundle them into a {% jdoc @.<<.<<.metrics.MetricOptions %} object. `MetricOptions` provides the +To use options with a metric, you must first bundle them into a {% jdoc coremx::MetricOptions %} object. `MetricOptions` provides the utility method `ofOptions` to get a `MetricOptions` bundle from a collection or with varargs parameters. You can then pass this bundle as a parameter to `JavaMetrics.get`: ```java diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index c1288ade03..1d741d4fd5 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -33,12 +33,13 @@ This is a {{ site.pmd.release_type }} release. ### API Changes -{% jdoc_context "core @.lang.ast.xpath" %} +{% jdoc_nspace :xpath core::lang.ast.xpath %} -* The implementation of the adapters for the XPath engines Saxon and Jaxen (package {% jdoc_package @ %}) - are now deprecated. They'll be moved to an internal package come 7.0.0. Only {% jdoc @.Attribute %} remains public API. +* The implementation of the adapters for the XPath engines Saxon and Jaxen (package {% jdoc_package :xpath %}) + are now deprecated. They'll be moved to an internal package come 7.0.0. Only {% jdoc xpath::Attribute %} remains public API. + +{% jdoc !aq!core::lang.rule.stat.StatisticalRule#SIGMA_DESCRIPTOR %} -{% endjdoc_context %} ### External Contributions From 79c1dbe55213e4b7322ac1ca769d1c8bd0f059f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 14 Nov 2018 20:56:28 +0100 Subject: [PATCH 088/139] Update release notes, refs #1461 --- docs/pages/release_notes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 5baf27eb74..2b2d14ecf0 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -23,10 +23,10 @@ This is a {{ site.pmd.release_type }} release. ### Fixed Issues * all * [#1284](https://github.com/pmd/pmd/issues/1284): \[doc] Keep record of every currently deprecated API - -* all * [#1318](https://github.com/pmd/pmd/issues/1318): \[test] Kotlin DSL to ease test writing * [#1341](https://github.com/pmd/pmd/issues/1341): \[doc] Documentation Error with Regex Properties +* java + * [#1460](https://github.com/pmd/pmd/issues/1460): \[java] Intermittent PMD failure : PMD processing errors while no violations reported * java-codestyle * [#1232](https://github.com/pmd/pmd/issues/1232): \[java] Detector for large numbers not separated by _ * [#1372](https://github.com/pmd/pmd/issues/1372): \[java] false positive for UselessQualifiedThis From 5fb0cf576bbee2a35f261125cade76f8d5a90fa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 14 Nov 2018 20:47:18 +0100 Subject: [PATCH 089/139] Releasable --- .travis/render_release_notes.rb | 11 ++-- docs/_config.yml | 2 +- docs/_plugins/all_extensions.rb | 3 ++ docs/_plugins/javadoc_tag.rb | 53 ++++++++++--------- docs/pages/release_notes.md | 6 +-- .../pmd/properties/LongMultiProperty.java | 2 - 6 files changed, 42 insertions(+), 35 deletions(-) create mode 100644 docs/_plugins/all_extensions.rb diff --git a/.travis/render_release_notes.rb b/.travis/render_release_notes.rb index dc0eb0877d..c7d0542cd7 100755 --- a/.travis/render_release_notes.rb +++ b/.travis/render_release_notes.rb @@ -12,9 +12,7 @@ require "liquid" require "safe_yaml" # include some custom liquid extensions -require_relative "../docs/_plugins/rule_tag" -require_relative "../docs/_plugins/tocmaker_block" -require_relative "../docs/_plugins/custom_filters" +require_relative "../docs/_plugins/all_extensions" # explicitly setting safe mode to get rid of the warning SafeYAML::OPTIONS[:default_mode] = :safe @@ -22,15 +20,18 @@ SafeYAML::OPTIONS[:default_mode] = :safe # START OF THE SCRIPT unless ARGV.length == 1 && File.exists?(ARGV[0]) - print "\e[31m[ERROR] In #{$0}: The first arg must be a valid file name\e[0m" + print "\e[31m[ERROR] In #{$0}: The first arg must be a valid file name\e[0m\n" exit 1 end release_notes_file = ARGV[0] +# Make the script execute wherever we are +travis_dir = File.expand_path File.dirname(__FILE__) + liquid_env = { # wrap the config under a "site." namespace because that's how jekyll does it - 'site' => YAML.load_file("docs/_config.yml"), + 'site' => YAML.load_file(travis_dir + "/../docs/_config.yml"), # This signals the links in {% rule %} tags that they should be rendered as absolute 'is_release_notes_processor' => true } diff --git a/docs/_config.yml b/docs/_config.yml index f1d6e64a9c..8fcdabf962 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,7 +1,7 @@ repository: pmd/pmd pmd: - version: 6.9.0 + version: 6.10.0 previous_version: 6.9.0 date: ??-????-2018 release_type: minor diff --git a/docs/_plugins/all_extensions.rb b/docs/_plugins/all_extensions.rb new file mode 100644 index 0000000000..fe23de11c4 --- /dev/null +++ b/docs/_plugins/all_extensions.rb @@ -0,0 +1,3 @@ +# This file requires all the defined Liquid extensions for ease of reference +# Thanks stackoverflow <3 +Dir[File.join(File.dirname(__FILE__), "*.rb")].reject {|file| file == __FILE__}.each {|file| require file} diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb index 8be83cca4f..f6bb45d075 100644 --- a/docs/_plugins/javadoc_tag.rb +++ b/docs/_plugins/javadoc_tag.rb @@ -28,6 +28,16 @@ require_relative 'jdoc_namespace_tag' # 'properties.PropertyDescriptor' is expanded to 'net.sourceforge.pmd.properties.PropertyDescriptor' # This is rendered as [`PropertyDescriptor`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.10.0/net/sourceforge/pmd/properties/PropertyDescriptor.html) # +# +# * To reference a package: eg {% jdoc_package core::properties %} -> points to pmd-core, expanded to 'net.sourceforge.pmd.properties' +# +# * To reference a method or field: {% jdoc core::Rule#addRuleChainVisit(java.lang.Class) %} +# * The suffix # is followed by the name of the method or field +# * The (erased) types of method arguments must be fully qualified. This is the same +# convention as in javadoc {@link} tags, so you can use you're IDE's javadoc auto- +# complete and copy-paste. Namespaces also can be used for method arguments if they're from PMD. +# +# # * Defining custom namespaces # * you can define a namespace pointing to a package name relevant to what # you're documenting to save some keystrokes. @@ -42,18 +52,13 @@ require_relative 'jdoc_namespace_tag' # jdoc tags or other jdoc_nspace tags. E.g. # {% jdoc coreast::Node %} -> points to pmd-core, expanded to 'net.sourceforge.pmd.lang.ast.Node' # {% jdoc jmx::impl.NcssVisitor %} -> points to pmd-java, expanded to 'net.sourceforge.pmd.lang.java.metrics.impl.NcssVisitor' -# -# * To reference a method or field: {% jdoc core::Rule#addRuleChainVisit(java.lang.Class) %} -# * The suffix # is followed by the name of the method or field -# * The (erased) types of method arguments must be fully qualified. This is the same -# convention as in javadoc {@link} tags, so you can use you're IDE's javadoc auto- -# complete and copy-paste. Namespaces also can be used for method arguments if they're from PMD. -# -# * To reference a package: eg {% jdoc_package core::properties %} # * If you want to reference the package prefix of a namespace, you can do so # by using the syntax ':nspace', e.g. -# {% jdoc_package :jmx %} -> points to pmd-java, expanded to 'net.sourceforge.pmd.lang.ast.Node' -# {% jdoc_package :coreast %} -> points to pmd-core, expanded to 'net.sourceforge.pmd.lang.java.metrics' +# {% jdoc_package :jmx %} -> points to pmd-java, expanded to 'net.sourceforge.pmd.lang.java.metrics' +# {% jdoc_package :coreast %} -> points to pmd-core, expanded to 'net.sourceforge.pmd.lang.ast' +# * This is especially cool because it allows you to assign a namespace to a type name and then add a method suffix, eg +# {% jdoc_nspace :PrD core::properties.PropertyDescriptor %} +# {% jdoc :PrD#description() %} # # * Bang options: # * The visible text of the link may be customized by prefixing the reference to the @@ -61,25 +66,25 @@ require_relative 'jdoc_namespace_tag' # * Option syntax is "!opts!", and prefixes the namespace. Options are one-character switches. # * Available options: # * No options -> just the member name: -# * {% jdoc @.Rule %} -> [`Rule`](...) -# * {% jdoc @.Rule#setName(java.lang.String) %} -> [`setName`](...) -# * {% jdoc @.AbstractRule#children %} -> [`children`](...) +# * {% jdoc core::Rule %} -> [`Rule`](...) +# * {% jdoc core::Rule#setName(java.lang.String) %} -> [`setName`](...) +# * {% jdoc core::AbstractRule#children %} -> [`children`](...) # * a (args) -> adds the simple name of the argument types for method references, noop for other references -# * {% jdoc !a!@.Rule#setName(java.lang.String) %} -> [`setName(String)`](...) +# * {% jdoc !a!core::Rule#setName(java.lang.String) %} -> [`setName(String)`](...) # * q (qualify) -> prefix with the fqcn of the class, noop for package references -# * {% jdoc !q!@.Rule %} -> [`net.sourceforge.pmd.Rule`](...) -# * {% jdoc !q!@.Rule#setName(java.lang.String) %} -> [`net.sourceforge.pmd.Rule#setName`](...) +# * {% jdoc !q!core::Rule %} -> [`net.sourceforge.pmd.Rule`](...) +# * {% jdoc !q!core::Rule#setName(java.lang.String) %} -> [`net.sourceforge.pmd.Rule#setName`](...) # * c (class) -> prefix the class name for member references, noop for type and package references, or if "qualify" is specified -# * {% jdoc !c!@.Rule#setName(java.lang.String) %} -> [`Rule#setName`](...) +# * {% jdoc !c!core::Rule#setName(java.lang.String) %} -> [`Rule#setName`](...) # * Empty options ("!!") - > shorthand to a commonly relevant option # * For field or method references, "!!" is the "c" option -# * {% jdoc !!@.Rule#setName(java.lang.String) %} -> [`Rule#setName`](...) +# * {% jdoc !!core::Rule#setName(java.lang.String) %} -> [`Rule#setName`](...) # * For type references, "!!" is the "q" option -# * {% jdoc !!@.Rule %} -> [`net.sourceforge.pmd.Rule`](...) +# * {% jdoc !!core::Rule %} -> [`net.sourceforge.pmd.Rule`](...) # * For package references, "!!" is a noop, they're always fully qualified # * Several options may be used at once, though this is only useful for method references: -# * {% jdoc !ac!@.Rule#setName(java.lang.String) %} -> [`Rule#setName(String)`](...) -# * {% jdoc !aq!@.Rule#setName(java.lang.String) %} -> [`net.sourceforge.pmd.Rule#setName(String)`](...) +# * {% jdoc !ac!core::Rule#setName(java.lang.String) %} -> [`Rule#setName(String)`](...) +# * {% jdoc !aq!core::Rule#setName(java.lang.String) %} -> [`net.sourceforge.pmd.Rule#setName(String)`](...) # # * DO NOT: # - Include spaces in any part of the reference @@ -106,8 +111,8 @@ class JavadocTag < Liquid::Tag @type_fqcn = arr[0] @member_suffix = arr[1] || "" # default to empty string - unless Regexp.new('(!\w*!)?' + JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX.source) =~ @type_fqcn - "Wrong syntax for type reference, expected eg nspace::a.b.C, !!nspace::a.b.C, or !opts!nspace::a.b.C" + unless Regexp.new('(!\w*!)?' + Regexp.union(JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX, JDocNamespaceDeclaration::SYM_REGEX).source ) =~ @type_fqcn + fail "Wrong syntax for type reference, expected eg nspace::a.b.C, !opts!nspace::a.b.C, or :nspace" end # If no options, then split produces [@type_fqcn] @@ -166,7 +171,7 @@ class JavadocTag < Liquid::Tag if opts.show_args? && $2 && !$2.empty? # is method - args = $3.split(",").map {|a| a.gsub(/\w+\./, "").strip} # map to simple names + args = ($3 || "").split(",").map {|a| a.gsub(/\w+\./, "").strip} # map to simple names suffix = "#{suffix}(#{args.join(", ")})" end diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 1d741d4fd5..661a62b56b 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -38,8 +38,6 @@ This is a {{ site.pmd.release_type }} release. * The implementation of the adapters for the XPath engines Saxon and Jaxen (package {% jdoc_package :xpath %}) are now deprecated. They'll be moved to an internal package come 7.0.0. Only {% jdoc xpath::Attribute %} remains public API. -{% jdoc !aq!core::lang.rule.stat.StatisticalRule#SIGMA_DESCRIPTOR %} - ### External Contributions @@ -50,5 +48,7 @@ This is a {{ site.pmd.release_type }} release. {% endtocmaker %} -{% include note.html content="The release notes of previous versions are available [here](pmd_release_notes_old.html)" %} +{% unless is_release_notes_processor %} + {% include note.html content="The release notes of previous versions are available [here](pmd_release_notes_old.html)" %} +{% endunless %} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/LongMultiProperty.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/LongMultiProperty.java index 827cbf2aa3..eb07bf17bc 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/LongMultiProperty.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/LongMultiProperty.java @@ -6,9 +6,7 @@ package net.sourceforge.pmd.properties; import java.util.Arrays; import java.util.List; -import java.util.Set; -import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.properties.builders.MultiNumericPropertyBuilder; import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilderConversionWrapper; From a5419f5d3f9a5aa9908a10fb3e8a3f5621a3548d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 14 Nov 2018 23:10:16 +0100 Subject: [PATCH 090/139] Add check for existence --- docs/_plugins/javadoc_tag.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb index f6bb45d075..f2b1df8523 100644 --- a/docs/_plugins/javadoc_tag.rb +++ b/docs/_plugins/javadoc_tag.rb @@ -133,6 +133,8 @@ class JavadocTag < Liquid::Tag artifact_name, @type_fqcn = JDocNamespaceDeclaration::parse_fqcn(@type_fqcn, var_ctx) + JavadocTag::check_exists(artifact_name, @type_fqcn, @is_package_ref) + # Expand FQCN of arguments @member_suffix.gsub!(JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX) {|fqcn| JDocNamespaceDeclaration::parse_fqcn(fqcn, var_ctx)[1]} @@ -196,6 +198,24 @@ class JavadocTag < Liquid::Tag end end + BASE_PMD_DIR = File.join(File.expand_path(File.dirname(__FILE__)), "..", "..") + + def self.check_exists(artifact_id, fqcn, is_package) + artifact_dir = File.join(BASE_PMD_DIR, artifact_id) + src_dirs = [ + File.join(artifact_dir, "src", "main", "java"), + File.join(artifact_dir, "target", "generated-sources", "javacc") + ].select {|dir| File.exist?(dir)} + + targets = src_dirs + .map {|dir| File.join(dir, fqcn.split("."))} + .select {|f_or_dir| is_package ? File.exist?(f_or_dir) : File.file?(f_or_dir + ".java")} + + if targets.empty? + warn "\e[33;1mjdoc generated link to #{fqcn}, but the #{is_package ? "directory" : "source file"} couldn't be found in the source tree of #{artifact_id}\e[0m" + end + + end class Options From d68d856043d387072e308d904b6adaa57981ad63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 15 Nov 2018 01:59:49 +0100 Subject: [PATCH 091/139] Improve diagnostic --- docs/_plugins/javadoc_tag.rb | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb index f2b1df8523..4149e6376d 100644 --- a/docs/_plugins/javadoc_tag.rb +++ b/docs/_plugins/javadoc_tag.rb @@ -133,7 +133,7 @@ class JavadocTag < Liquid::Tag artifact_name, @type_fqcn = JDocNamespaceDeclaration::parse_fqcn(@type_fqcn, var_ctx) - JavadocTag::check_exists(artifact_name, @type_fqcn, @is_package_ref) + JavadocTag::diagnose(artifact_name, @type_fqcn, @is_package_ref) # Expand FQCN of arguments @member_suffix.gsub!(JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX) {|fqcn| JDocNamespaceDeclaration::parse_fqcn(fqcn, var_ctx)[1]} @@ -200,7 +200,24 @@ class JavadocTag < Liquid::Tag BASE_PMD_DIR = File.join(File.expand_path(File.dirname(__FILE__)), "..", "..") - def self.check_exists(artifact_id, fqcn, is_package) + def self.diagnose(artifact_id, fqcn, expect_package) + resolved_type = JavadocTag::fqcn_type(artifact_id, fqcn) + + tag_name= expect_package ? "jdoc_package" : "jdoc" + + if resolved_type == :package && !expect_package + warn "\e[33;1m#{tag_name} generated link to #{fqcn}, but it was found to be a package name. Did you mean to use jdoc_package instead of jdoc?\e[0m" + elsif resolved_type == :file && expect_package + warn "\e[33;1m#{tag_name} generated link to #{fqcn}, but it was found to be a java file name. Did you mean to use jdoc instead of jdoc_package?\e[0m" + elsif !resolved_type + warn "\e[33;1m#{tag_name} generated link to #{fqcn}, but the #{expect_package ? "directory" : "source file"} couldn't be found in the source tree of #{artifact_id}\e[0m" + end + end + + # Returns :package, or :file depending on the type of entity the fqcn refers to on the filesystem + # Returns nil if it cannot be found + def self.fqcn_type(artifact_id, fqcn) + artifact_dir = File.join(BASE_PMD_DIR, artifact_id) src_dirs = [ File.join(artifact_dir, "src", "main", "java"), @@ -209,12 +226,10 @@ class JavadocTag < Liquid::Tag targets = src_dirs .map {|dir| File.join(dir, fqcn.split("."))} - .select {|f_or_dir| is_package ? File.exist?(f_or_dir) : File.file?(f_or_dir + ".java")} - - if targets.empty? - warn "\e[33;1mjdoc generated link to #{fqcn}, but the #{is_package ? "directory" : "source file"} couldn't be found in the source tree of #{artifact_id}\e[0m" - end + .map {|f| File.file?(f + ".java") ? :file : File.exist?(f) ? :package : nil} + .compact + targets.first end class Options From e42564c0193b029f4f6e428ae9a8f3ce17a75880 Mon Sep 17 00:00:00 2001 From: Maxime Robert Date: Thu, 15 Nov 2018 12:46:54 +0100 Subject: [PATCH 092/139] Fix XSS on documentation web page Ironically, the corresponding documentation page (https://pmd.github.io/latest/pmd_rules_jsp_security.html#nounsanitizedjspexpression) is subject to XSS! --- docs/pages/pmd/rules/jsp/security.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/pmd/rules/jsp/security.md b/docs/pages/pmd/rules/jsp/security.md index 0cc3cc60e5..def214e011 100644 --- a/docs/pages/pmd/rules/jsp/security.md +++ b/docs/pages/pmd/rules/jsp/security.md @@ -46,7 +46,7 @@ through SSL. See http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q261188 **Priority:** Medium (3) Avoid using expressions without escaping / sanitizing. This could lead to cross site scripting - as the expression -would be interpreted by the browser directly (e.g. ""). +would be interpreted by the browser directly (e.g. "<script>alert('hello');</script>"). **This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.jsp.rule.security.NoUnsanitizedJSPExpressionRule](https://github.com/pmd/pmd/blob/master/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/rule/security/NoUnsanitizedJSPExpressionRule.java) From 51a2869131e80f503150884a98c2f157b5d8ed54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Thu, 15 Nov 2018 11:51:29 -0300 Subject: [PATCH 093/139] Update changelog, refs #1464 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 2b2d14ecf0..bdff24d82e 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -42,6 +42,7 @@ This is a {{ site.pmd.release_type }} release. * [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007) * [#1428](https://github.com/pmd/pmd/pull/1428): \[core] Upgrading JCommander from 1.48 to 1.72 - [Thunderforge](https://github.com/Thunderforge) * [#1430](https://github.com/pmd/pmd/pull/1430): \[doc] Who really knows regex? - [Dem Pilafian](https://github.com/dpilafian) +* [#1464](https://github.com/pmd/pmd/pull/1464): \[doc] Fix XSS on documentation web page - [Maxime Robert](https://github.com/marob) {% endtocmaker %} From fda3aa16a368aa9ce1d3586734927b6fe8738d1b Mon Sep 17 00:00:00 2001 From: "Travis CI (pmd-bot)" Date: Thu, 15 Nov 2018 15:06:23 +0000 Subject: [PATCH 094/139] Update documentation TRAVIS_JOB_NUMBER=3081.1 TRAVIS_COMMIT_RANGE=79c1dbe55213...0023e5b0d330 --- docs/pages/pmd/rules/jsp/security.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/pmd/rules/jsp/security.md b/docs/pages/pmd/rules/jsp/security.md index def214e011..0cc3cc60e5 100644 --- a/docs/pages/pmd/rules/jsp/security.md +++ b/docs/pages/pmd/rules/jsp/security.md @@ -46,7 +46,7 @@ through SSL. See http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q261188 **Priority:** Medium (3) Avoid using expressions without escaping / sanitizing. This could lead to cross site scripting - as the expression -would be interpreted by the browser directly (e.g. "<script>alert('hello');</script>"). +would be interpreted by the browser directly (e.g. ""). **This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.jsp.rule.security.NoUnsanitizedJSPExpressionRule](https://github.com/pmd/pmd/blob/master/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/rule/security/NoUnsanitizedJSPExpressionRule.java) From 085ef717e7c290885fd8e2cb1709f39d11dcc9ac Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 15 Nov 2018 16:42:00 +0100 Subject: [PATCH 095/139] Avoid NPE if class is not found The class org.assertj.core.api.AbstractSoftAssertions might not be on the auxclasspath, which would cause this NPE. --- .../pmd/lang/java/typeresolution/TypeHelper.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java index 8635735a07..d552af93c4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelper.java @@ -143,8 +143,10 @@ public final class TypeHelper { public static boolean isA(TypedNameDeclaration vnd, String className) { Class type = vnd.getType(); if (type != null) { - Class expected = loadClass(type.getClassLoader(), className); - return expected.isAssignableFrom(type); + Class clazz = loadClass(type.getClassLoader(), className); + if (clazz != null) { + return clazz.isAssignableFrom(type); + } } return false; } From 3720cb7a02dc15e5905989c004c144971a683735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 15 Nov 2018 17:05:47 +0100 Subject: [PATCH 096/139] Update design.xml --- pmd-java/src/main/resources/category/java/design.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index 82a3534b0d..414bde44d8 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -410,7 +410,7 @@ in a single method makes its behaviour hard to read and change. Cyclomatic complexity assesses the complexity of a method by counting the number of decision points in a method, plus one for the method entry. Decision points are places where the control flow jumps to another place in the program. As such, they include all control flow statements, such as `if`, `while`, `for`, and `case`. For more -details on the calculation, see the documentation of the [Cyclo metric](/pmd_java_metrics_index.html#cyclomatic-complexity-cyclo). +details on the calculation, see the documentation of the [Cyclo metric](pmd_java_metrics_index.html#cyclomatic-complexity-cyclo). Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10. From 97869dea682e4be6d24053d0aece0dd11b9085e6 Mon Sep 17 00:00:00 2001 From: "Travis CI (pmd-bot)" Date: Thu, 15 Nov 2018 16:25:04 +0000 Subject: [PATCH 097/139] Update documentation TRAVIS_JOB_NUMBER=3086.1 TRAVIS_COMMIT_RANGE=fda3aa16a368...b8069dd0c39e --- docs/pages/pmd/rules/java/design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/pmd/rules/java/design.md b/docs/pages/pmd/rules/java/design.md index f0eb4ed843..f30c2520a3 100644 --- a/docs/pages/pmd/rules/java/design.md +++ b/docs/pages/pmd/rules/java/design.md @@ -411,7 +411,7 @@ in a single method makes its behaviour hard to read and change. Cyclomatic complexity assesses the complexity of a method by counting the number of decision points in a method, plus one for the method entry. Decision points are places where the control flow jumps to another place in the program. As such, they include all control flow statements, such as `if`, `while`, `for`, and `case`. For more -details on the calculation, see the documentation of the [Cyclo metric](/pmd_java_metrics_index.html#cyclomatic-complexity-cyclo). +details on the calculation, see the documentation of the [Cyclo metric](pmd_java_metrics_index.html#cyclomatic-complexity-cyclo). Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10. From 75b157928558b220cf9eff04eae45fda88431586 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 15 Nov 2018 18:22:12 +0100 Subject: [PATCH 098/139] [doc] Extend test case with more XSS problems --- pmd-doc/src/test/resources/expected/java.md | 3 +- pmd-doc/src/test/resources/expected/sample.md | 77 ++++++++++++++++++- .../resources/rulesets/ruledoctest/sample.xml | 74 ++++++++++++++++++ 3 files changed, 151 insertions(+), 3 deletions(-) diff --git a/pmd-doc/src/test/resources/expected/java.md b/pmd-doc/src/test/resources/expected/java.md index 5fcdf1f6fc..177bf4beee 100644 --- a/pmd-doc/src/test/resources/expected/java.md +++ b/pmd-doc/src/test/resources/expected/java.md @@ -8,13 +8,14 @@ folder: pmd/rules --- ## Sample -{% include callout.html content="Sample ruleset to test rule doc generation." %} +{% include callout.html content="Sample ruleset to test rule doc generation. Here might be <script>alert('XSS');</script> as well. And "quotes". Inside CDATA <script>alert('XSS');</script>." %} * [DeprecatedSample](pmd_rules_java_sample.html#deprecatedsample): Deprecated Just some description of a deprecated rule. * [JumbledIncrementer](pmd_rules_java_sample.html#jumbledincrementer): Avoid jumbled loop incrementers - its usually a mistake, and is confusing even if intentional. * [MovedRule](pmd_rules_java_sample.html#movedrule): Deprecated The rule has been moved to another ruleset. Use instead [JumbledIncrementer](pmd_rules_java_sample2.html#jumbledincrementer). * [OverrideBothEqualsAndHashcode](pmd_rules_java_sample.html#overridebothequalsandhashcode): Override both 'public boolean Object.equals(Object other)', and 'public int Object.hashCode()', o... * [RenamedRule](pmd_rules_java_sample.html#renamedrule): Deprecated The rule has been renamed. Use instead [JumbledIncrementer](pmd_rules_java_sample.html#jumbledincrementer). +* [XSSInDocumentation](pmd_rules_java_sample.html#xssindocumentation): <script>alert('XSS at the beginning');</script> HTML tags might appear at various places. ... ## Additional rulesets diff --git a/pmd-doc/src/test/resources/expected/sample.md b/pmd-doc/src/test/resources/expected/sample.md index 49d2ddccb9..598cf3b840 100644 --- a/pmd-doc/src/test/resources/expected/sample.md +++ b/pmd-doc/src/test/resources/expected/sample.md @@ -1,11 +1,11 @@ --- title: Sample -summary: Sample ruleset to test rule doc generation. +summary: Sample ruleset to test rule doc generation. Here might be <script>alert('XSS');</script> as well. And "quotes". Inside CDATA <script>alert('XSS');</script>. permalink: pmd_rules_java_sample.html folder: pmd/rules/java sidebaractiveurl: /pmd_rules_java.html editmepath: ../rulesets/ruledoctest/sample.xml -keywords: Sample, OverrideBothEqualsAndHashcode, JumbledIncrementer, DeprecatedSample, RenamedRule, MovedRule +keywords: Sample, XSSInDocumentation, OverrideBothEqualsAndHashcode, JumbledIncrementer, DeprecatedSample, RenamedRule, MovedRule language: Java --- ## DeprecatedSample @@ -226,3 +226,76 @@ public class JumbledIncrementerRule1 { ``` xml ``` + +## XSSInDocumentation + +**Since:** PMD 0.1 + +**Priority:** Medium (3) + +<script>alert('XSS at the beginning');</script> HTML tags might appear at various places. +Sometimes they should be escaped, sometimes not: + + For example, in a code sample, it should not be escaped. + This means, is no problem here. + +Also in backticks `` like here it is no problem. + +The tags are already escaped in the text, e.g. <script>alert('XSS');</script>. + +A valid case in markdown is a + + +If using CDATA you don't need to escape, but this <script>alert('XSS');</script> +should still not be executed. + + +> this is a +> block quote +> in markdown + +The paragraph after the quotation. + + +> block quote +> in cdata + + +If the description contains a code example, then e.g. "quotes" should not be escaped: + +``` +if (0 > 1 && 0 < 1) { + System.out.println("impossible"); +} +``` + +**This rule is defined by the following XPath expression:** +``` xpath +//ForStatement +``` + +**Example(s):** + +``` java +public class Bar { + public boolean foo() { + if (0 < 1) { // less-than should not be escaped in markdown + String s = "abc"; // the quotes should not be escaped in markdown. + } + } + // +} +``` + +**This rule has the following properties:** + +|Name|Default Value|Description|Multivalued| +|----|-------------|-----------|-----------| +|sampleRegexProperty|\\/\\\*\\s+(default\|package)\\s+\\\*\\/|The property is of type regex|no| +|XSSpropertyTest <script>alert('XSS');</script>|<script>alert('XSS');</script>|<script>alert('XSS');</script>|no| +|escapingNeeded|this is escaped: \||You should be able to use \| in the description|no| + +**Use this rule by referencing it:** +``` xml + +``` diff --git a/pmd-doc/src/test/resources/rulesets/ruledoctest/sample.xml b/pmd-doc/src/test/resources/rulesets/ruledoctest/sample.xml index ec8a02c9b7..aa49c9a6f2 100644 --- a/pmd-doc/src/test/resources/rulesets/ruledoctest/sample.xml +++ b/pmd-doc/src/test/resources/rulesets/ruledoctest/sample.xml @@ -6,8 +6,82 @@ xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> Sample ruleset to test rule doc generation. + +Here might be <script>alert('XSS');</script> as well. And "quotes". + +alert('XSS');.]]> + + + <script>alert('XSS at the beginning');</script> HTML tags might appear at various places. + Sometimes they should be escaped, sometimes not: + + For example, in a code sample, it should <strong>not</strong> be escaped. + This means, <script>alert('XSS');</script> is no problem here. + + Also in backticks `<script>alert('XSS');</script>` like here it is no problem. + + The tags are already escaped in the text, e.g. <script>alert('XSS');</script>. + + A valid case in markdown is a <https://en.wikipedia.org/wiki/Hyperlink> + + alert('XSS'); + should still not be executed. + ]]> + + > this is a + > block quote + > in markdown + + The paragraph after the quotation. + + block quote + > in cdata + ]]> + + If the description contains a code example, then e.g. "quotes" should not be escaped: + + ``` + if (0 > 1 && 0 < 1) { + System.out.println("impossible"); + } + ``` + + 3 + + + + + + + + + + + +alert('XSS'); +} +]]> + + + Date: Thu, 15 Nov 2018 21:18:03 +0100 Subject: [PATCH 099/139] Ugly fix for #1468 --- pmd-doc/pom.xml | 5 + .../pmd/docs/RuleDocGenerator.java | 165 +++++++++++++++--- 2 files changed, 149 insertions(+), 21 deletions(-) diff --git a/pmd-doc/pom.xml b/pmd-doc/pom.xml index a147471791..9916c5d031 100644 --- a/pmd-doc/pom.xml +++ b/pmd-doc/pom.xml @@ -62,6 +62,11 @@ org.apache.commons commons-lang3 + + org.apache.commons + commons-text + 1.6 + org.yaml snakeyaml diff --git a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java index aac961c168..19d22dbcad 100644 --- a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java +++ b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java @@ -32,6 +32,7 @@ import java.util.regex.Pattern; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleSet; @@ -194,7 +195,7 @@ public class RuleDocGenerator { for (RuleSet ruleset : entry.getValue()) { lines.add("## " + ruleset.getName()); lines.add(""); - lines.add("{% include callout.html content=\"" + getRuleSetDescriptionSingleLine(ruleset).replaceAll("\"", "'") + "\" %}"); + lines.add("{% include callout.html content=\"" + getRuleSetDescriptionSingleLine(ruleset) + "\" %}"); lines.add(""); for (Rule rule : getSortedRules(ruleset)) { @@ -293,15 +294,20 @@ public class RuleDocGenerator { * @return */ private static String getShortRuleDescription(Rule rule) { - return StringUtils.abbreviate( - StringUtils.stripToEmpty(rule.getDescription().replaceAll("\n|\r", "") + return StringEscapeUtils.escapeHtml4( + StringUtils.abbreviate( + StringUtils.stripToEmpty( + rule.getDescription() + .replaceAll("\n|\r", "") .replaceAll("\\|", "\\\\|") .replaceAll("`", "'") - .replaceAll("\\*", "")), 100); + .replaceAll("\\*", "")), + 100)); } private static String getRuleSetDescriptionSingleLine(RuleSet ruleset) { String description = ruleset.getDescription(); + description = StringEscapeUtils.escapeHtml4(description); description = description.replaceAll("\\n|\\r", " "); description = StringUtils.stripToEmpty(description); return description; @@ -389,7 +395,7 @@ public class RuleDocGenerator { lines.add(""); } - lines.addAll(toLines(stripIndentation(rule.getDescription()))); + lines.addAll(escapeLines(toLines(stripIndentation(rule.getDescription())))); lines.add(""); if (rule instanceof XPathRule || rule instanceof RuleReference && ((RuleReference) rule).getRule() instanceof XPathRule) { @@ -430,9 +436,11 @@ public class RuleDocGenerator { lines.add("|----|-------------|-----------|-----------|"); for (PropertyDescriptor propertyDescriptor : properties) { String description = propertyDescriptor.description(); - if (description != null && description.toLowerCase(Locale.ROOT).startsWith(DEPRECATED_RULE_PROPERTY_MARKER)) { - description = DEPRECATION_LABEL_SMALL - + description.substring(DEPRECATED_RULE_PROPERTY_MARKER.length()); + boolean isDeprecated = false; + if (description != null && description.toLowerCase(Locale.ROOT) + .startsWith(DEPRECATED_RULE_PROPERTY_MARKER)) { + isDeprecated = true; + description = description.substring(DEPRECATED_RULE_PROPERTY_MARKER.length()); } String defaultValue = ""; @@ -452,14 +460,6 @@ public class RuleDocGenerator { } } - defaultValue = defaultValue.replace("\\", "\\\\") - .replace("*", "\\*") - .replace("_", "\\_") - .replace("~", "\\~") - .replace("[", "\\[") - .replace("]", "\\]") - .replace("|", "\\|"); - String multiValued = "no"; if (propertyDescriptor.isMultiValue()) { MultiValuePropertyDescriptor multiValuePropertyDescriptor = @@ -468,11 +468,11 @@ public class RuleDocGenerator { + multiValuePropertyDescriptor.multiValueDelimiter() + "'."; } - lines.add("|" + propertyDescriptor.name() - + "|" + defaultValue - + "|" + description - + "|" + multiValued.replace("|", "\\|") - + "|"); + lines.add("|" + escapeMarkdown(StringEscapeUtils.escapeHtml4(propertyDescriptor.name())) + + "|" + escapeMarkdown(StringEscapeUtils.escapeHtml4(defaultValue)) + "|" + + escapeMarkdown((isDeprecated ? DEPRECATION_LABEL_SMALL : "") + + StringEscapeUtils.escapeHtml4(description)) + + "|" + escapeMarkdown(StringEscapeUtils.escapeHtml4(multiValued)) + "|"); } lines.add(""); } @@ -615,4 +615,127 @@ public class RuleDocGenerator { return FilenameUtils.normalize(relativeSourceFilename, true); } + + private static String escapeMarkdown(String unescaped) { + return unescaped.replace("\\", "\\\\").replace("*", "\\*").replace("_", "\\_").replace("~", "\\~") + .replace("[", "\\[").replace("]", "\\]").replace("|", "\\|"); + } + + private enum State { + S, LT, LT_H, LT_H_T, LT_H_T_T, LT_H_T_T_P, LT_H_T_T_P1, LT_H_T_T_P_S, LT_H_T_T_P_S1; + } + + private static String escapeSingleLine(String line) { + StringBuilder escaped = new StringBuilder(line.length() + 16); + State s = State.S; + boolean needsEscape = true; + for (int i = 0; i < line.length(); i++) { + char c = line.charAt(i); + if (c == '`') { + needsEscape = !needsEscape; + } + switch (s) { + case S: + if (c == '<') { + s = State.LT; + } else if (c == '>') { + if (needsEscape) { + escaped.append(">"); + } else { + escaped.append(c); + } + } else { + escaped.append(c); + } + break; + case LT: + if (c == 'h' || c == 'H') { + s = State.LT_H; + } else { + if (needsEscape) { + escaped.append("<").append(c); + } else { + escaped.append("<").append(c); + } + s = State.S; + } + break; + case LT_H: + if (c == 't' || c == 'T') { + s = State.LT_H_T; + } else { + escaped.append("<h").append(c); + s = State.S; + } + break; + case LT_H_T: + if (c == 't' || c == 'T') { + s = State.LT_H_T_T; + } else { + escaped.append("<ht").append(c); + s = State.S; + } + break; + case LT_H_T_T: + if (c == 'p' || c == 'P') { + s = State.LT_H_T_T_P; + } else { + escaped.append("<htt").append(c); + s = State.S; + } + break; + case LT_H_T_T_P: + if (c == 's' || c == 'S') { + s = State.LT_H_T_T_P_S; + } else if (c == ':') { + escaped.append("') { + s = State.S; + } + break; + case LT_H_T_T_P_S: + if (c == ':') { + escaped.append("') { + s = State.S; + } + break; + default: + escaped.append(c); + break; + } + } + return escaped.toString(); + } + + private static List escapeLines(List lines) { + boolean needsEscape = true; + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + if (line.startsWith("```")) { + needsEscape = !needsEscape; + } + if (needsEscape && !line.startsWith(" ") && !line.startsWith(">")) { + line = escapeSingleLine(line); + } + lines.set(i, line); + } + return lines; + } } From e0da7b83b6832d0d98767ade4cf4913eb6778182 Mon Sep 17 00:00:00 2001 From: Alberto Fernandez Date: Fri, 16 Nov 2018 00:19:10 +0100 Subject: [PATCH 100/139] Configurable max loops in DAAPathFinder --- .../pmd/lang/dfa/pathfinder/DAAPathFinder.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/pathfinder/DAAPathFinder.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/pathfinder/DAAPathFinder.java index c2d7c59ce1..2fc9f12ee6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/pathfinder/DAAPathFinder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/pathfinder/DAAPathFinder.java @@ -30,17 +30,26 @@ public class DAAPathFinder { private CurrentPath currentPath = new CurrentPath(); private DefaultMutableTreeNode stack = new DefaultMutableTreeNode(); private int maxPaths; + private int maxLoops; public DAAPathFinder(DataFlowNode rootNode, Executable shim) { this.rootNode = rootNode; this.shim = shim; this.maxPaths = MAX_PATHS; + this.maxLoops = MAX_LOOPS; } public DAAPathFinder(DataFlowNode rootNode, Executable shim, int maxPaths) { this.rootNode = rootNode; this.shim = shim; this.maxPaths = maxPaths; + this.maxLoops = MAX_LOOPS; + } + public DAAPathFinder(DataFlowNode rootNode, Executable shim, int maxPaths, int maxLoops) { + this.rootNode = rootNode; + this.shim = shim; + this.maxPaths = maxPaths; + this.maxLoops = maxLoops; } public void run() { @@ -69,7 +78,7 @@ public class DAAPathFinder { */ private void phase2(boolean flag) { int i = 0; - while (!currentPath.isEndNode() && i < MAX_LOOPS) { + while (!currentPath.isEndNode() && i < this.maxLoops) { i++; if (currentPath.isBranch() || currentPath.isFirstDoStatement()) { if (flag) { From ae3adf7c489c0f94486cad1f975f8ea3a4027e51 Mon Sep 17 00:00:00 2001 From: Alberto Fernandez Date: Fri, 16 Nov 2018 00:28:21 +0100 Subject: [PATCH 101/139] checkstyle --- .../net/sourceforge/pmd/lang/dfa/pathfinder/DAAPathFinder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/pathfinder/DAAPathFinder.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/pathfinder/DAAPathFinder.java index 2fc9f12ee6..ae12cc02dd 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/pathfinder/DAAPathFinder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/pathfinder/DAAPathFinder.java @@ -45,6 +45,7 @@ public class DAAPathFinder { this.maxPaths = maxPaths; this.maxLoops = MAX_LOOPS; } + public DAAPathFinder(DataFlowNode rootNode, Executable shim, int maxPaths, int maxLoops) { this.rootNode = rootNode; this.shim = shim; From c4deebb889099e127dbb69676e8c8f2ee52e0350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 16 Nov 2018 02:48:21 +0100 Subject: [PATCH 102/139] Cleanup --- .../pmd/properties/PropertyBuilder.java | 26 ++++++++++++------- .../pmd/properties/PropertyDescriptor.java | 6 ++++- .../pmd/properties/PropertyFactory.java | 5 ++-- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java index 4d2e67c7d2..d1e1381359 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java @@ -14,7 +14,6 @@ import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; -import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.properties.PropertyBuilder.GenericCollectionPropertyBuilder.Supplier; import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilder; import net.sourceforge.pmd.properties.constraints.PropertyConstraint; @@ -29,9 +28,8 @@ import net.sourceforge.pmd.properties.constraints.PropertyConstraint; * @param Type of values the property handles * * @author Clément Fournier - * @since 6.7.0 + * @since 6.10.0 */ -@Experimental public abstract class PropertyBuilder, T> { private static final Pattern NAME_PATTERN = Pattern.compile("[a-zA-Z][\\w-]*"); @@ -54,6 +52,7 @@ public abstract class PropertyBuilder, T> { } + // will maybe be scrapped @Deprecated void setDefinedExternally(boolean bool) { this.isDefinedExternally = bool; @@ -70,6 +69,7 @@ public abstract class PropertyBuilder, T> { } + @Deprecated float getUiOrder() { return uiOrder; } @@ -103,8 +103,11 @@ public abstract class PropertyBuilder, T> { * @param f The UI order * * @return The same builder + * + * @deprecated see {@link PropertyDescriptor#uiOrder()} */ @SuppressWarnings("unchecked") + @Deprecated public B uiOrder(float f) { this.uiOrder = f; return (B) this; @@ -113,13 +116,15 @@ public abstract class PropertyBuilder, T> { /** * Add a constraint on the values that this property may take. - * The validity of values will be checked when constructing the XML - * and invalid values will be reported. + * The validity of values will be checked when parsing the XML, + * and invalid values will be reported. A rule will never be run + * if some of its properties violate some constraints. * * @param constraint The constraint * * @return The same builder */ + // TODO we could probably specify the order of execution of constraints come 7.0.0, for now this remains unspecified @SuppressWarnings("unchecked") public B require(PropertyConstraint constraint) { validators.add(constraint); @@ -206,6 +211,7 @@ public abstract class PropertyBuilder, T> { */ /* package private */ GenericCollectionPropertyBuilder> toList() { + // TODO 7.0.0 this is obviously a lambda Supplier> listSupplier = new Supplier>() { @Override public List get() { @@ -255,10 +261,10 @@ public abstract class PropertyBuilder, T> { /** * Generic builder for a collection-valued property. - * This builder allows some nice syntax to define - * the {@linkplain #defaultValues(Object[]) default value}. + * This class adds overloads to {@linkplain #defaultValues(Object[])} + * to make its use more flexible. * - *

Note: this is meant to support arbitrary collections. + *

Note: this is designed to support arbitrary collections. * Pre-7.0.0, the only collections available from the {@link PropertyFactory} * are list types though. * @@ -333,8 +339,8 @@ public abstract class PropertyBuilder, T> { * @return The same builder * * @deprecated PMD 7.0.0 will introduce a new XML syntax for multi-valued properties which will not rely on delimiters. - * This method is kept until this is implemented for compatibility reasons with the pre-7.0.0 framework, but - * it will be scrapped come 7.0.0. + * This method is kept until this is implemented for compatibility reasons with the pre-7.0.0 framework, but + * it will be scrapped come 7.0.0. */ @Deprecated public GenericCollectionPropertyBuilder delim(char delim) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index b2f437094e..8c3dde160a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -120,6 +120,8 @@ public interface PropertyDescriptor extends Comparable> * * @param propertyString The string to parse * + * @return The value represented by the string + * * @throws IllegalArgumentException if the given string cannot be parsed * @deprecated PMD 7.0.0 will use a more powerful scheme to represent values than * simple strings, this method won't be general enough @@ -148,8 +150,10 @@ public interface PropertyDescriptor extends Comparable> * * @param rule Rule * + * @return String + * * @deprecated Used nowhere, and fails if the rule doesn't define the property descriptor - * A better solution will be added on property source + * A better solution will be added on property source */ @Deprecated String propertyErrorFor(Rule rule); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java index 73c1801b71..723e5f4ed2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java @@ -16,6 +16,8 @@ import net.sourceforge.pmd.properties.PropertyBuilder.GenericPropertyBuilder; * Note: from 7.0.0 on, this will be the only way to * build property descriptors. * + * TODO next PR add doc + * * @author Clément Fournier * @since 6.10.0 */ @@ -59,8 +61,7 @@ public final class PropertyFactory { public static GenericPropertyBuilder enumProperty(String name, Map nameToValue) { // TODO find solution to document the set of possible values // At best, map that requirement to a constraint (eg make parser return null if not found, and - // add a non-null constraint with the right description. But if we disallow null values everywhere, - // this will get caught early on.) + // add a non-null constraint with the right description.) return new GenericPropertyBuilder<>(name, ValueParserConstants.enumerationParser(nameToValue), (Class) Object.class); } From c3af76b8ad464c5fde059aa88de3a3ddfe4defbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 16 Nov 2018 02:58:04 +0100 Subject: [PATCH 103/139] Remove the uiOrder from the new builder --- .../pmd/properties/PropertyBuilder.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java index d1e1381359..e52ab4bec4 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java @@ -97,23 +97,6 @@ public abstract class PropertyBuilder, T> { } - /** - * Specify the UI order of the property. - * - * @param f The UI order - * - * @return The same builder - * - * @deprecated see {@link PropertyDescriptor#uiOrder()} - */ - @SuppressWarnings("unchecked") - @Deprecated - public B uiOrder(float f) { - this.uiOrder = f; - return (B) this; - } - - /** * Add a constraint on the values that this property may take. * The validity of values will be checked when parsing the XML, From f3e618b8677058bb3cb3e983dc52dc641520fcde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 16 Nov 2018 03:05:22 +0100 Subject: [PATCH 104/139] Add configuration error if property has wrong value --- .../pmd/properties/AbstractPropertySource.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertySource.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertySource.java index 2212750a7d..386837f0a9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertySource.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPropertySource.java @@ -238,6 +238,17 @@ public abstract class AbstractPropertySource implements PropertySource { // todo Java 8 move up to interface @Override public String dysfunctionReason() { + for (PropertyDescriptor descriptor : getOverriddenPropertyDescriptors()) { + String error = errorForPropCapture(descriptor); + if (error != null) { + return error; + } + } return null; } + + + private String errorForPropCapture(PropertyDescriptor descriptor) { + return descriptor.errorFor(getProperty(descriptor)); + } } From d0401eb17ce79639cca3882109143e3025e75a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 16 Nov 2018 03:32:15 +0100 Subject: [PATCH 105/139] Test --- .../net/sourceforge/pmd/RuleSetFactory.java | 4 +- .../GenericMultiValuePropertyDescriptor.java | 8 +- .../properties/GenericPropertyDescriptor.java | 5 ++ .../constraints/ConstraintFactory.java | 4 +- .../properties/PropertyDescriptorTest.java | 76 +++++++++++++++++++ 5 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java index ec47ae5a54..da05efacab 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java @@ -265,13 +265,13 @@ public class RuleSetFactory { } /** - * Creates a new RuleSet for a single rule + * Creates a new RuleSet containing a single rule. * * @param rule * The rule being created * @return The newly created RuleSet */ - public RuleSet createSingleRuleRuleSet(final Rule rule) { + public RuleSet createSingleRuleRuleSet(final Rule rule) { // TODO make static? final long checksum; if (rule instanceof XPathRule) { checksum = rule.getProperty(XPathRule.XPATH_DESCRIPTOR).hashCode(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java index 9ee69179ac..017a6e33ca 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericMultiValuePropertyDescriptor.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.properties; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; @@ -33,11 +34,16 @@ final class GenericMultiValuePropertyDescriptor> exte ValueParser parser, char delim, Class type) { - + // this cast is safe until 7.0.0 super(name, description, (List) defaultValue, uiOrder, delim, false); this.listValidators = listValidators; this.parser = parser; this.type = type; + + String dftValueError = errorFor(new ArrayList<>(defaultValue)); + if (dftValueError != null) { + throw new IllegalStateException(dftValueError); + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java index 95198119fd..a059707d1d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/GenericPropertyDescriptor.java @@ -36,6 +36,11 @@ final class GenericPropertyDescriptor extends AbstractSingleValueProperty this.constraints = constraints; this.parser = parser; this.type = type; + + String dftValueError = errorFor(defaultValue); + if (dftValueError != null) { + throw new IllegalStateException(dftValueError); + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java index a1a2c276dc..078f034c0c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java @@ -46,10 +46,10 @@ final class ConstraintFactory { return pred.test(value); } - + // TODO message could be better, eg include name of the property @Override public String validate(U value) { - return pred.test(value) ? null : "Constraint violated on value '" + value + "' (" + constraintDescription + ")"; + return pred.test(value) ? null : "Constraint violated on property value '" + value + "' (" + constraintDescription + ")"; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java new file mode 100644 index 0000000000..2e26a8503f --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java @@ -0,0 +1,76 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties; + +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasItem; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import net.sourceforge.pmd.FooRule; +import net.sourceforge.pmd.RuleSet; +import net.sourceforge.pmd.RuleSetFactory; +import net.sourceforge.pmd.properties.constraints.NumericConstraints; +import net.sourceforge.pmd.properties.constraints.PropertyConstraint; + + +/** + * Mostly TODO, I'd rather implement tests on the final version of the framework. + * + * @author Clément Fournier + * @since 7.0.0 + */ +public class PropertyDescriptorTest { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + + @Test + public void testConstraintViolationCausesDysfunctionalRule() { + PropertyDescriptor intProperty = PropertyFactory.intProperty("fooProp") + .desc("hello") + .defaultValue(4) + .require(NumericConstraints.inRange(1, 10)) + .build(); + + FooRule rule = new FooRule(); + rule.definePropertyDescriptor(intProperty); + rule.setProperty(intProperty, 1000); + RuleSet ruleSet = new RuleSetFactory().createSingleRuleRuleSet(rule); + + List dysfunctional = new ArrayList<>(); + ruleSet.removeDysfunctionalRules(dysfunctional); + + assertEquals(1, dysfunctional.size()); + assertThat(dysfunctional, hasItem(rule)); + } + + + @Test + public void testDefaultValueConstraintViolationCausesFailure() { + PropertyConstraint constraint = NumericConstraints.inRange(1, 10); + + thrown.expect(IllegalStateException.class); + thrown.expectMessage(allOf(containsString("Constraint violat"/*-ed or -ion*/), + containsString(constraint.getConstraintDescription()))); + + PropertyDescriptor intProperty = PropertyFactory.intProperty("fooProp") + .desc("hello") + .defaultValue(1000) + .require(constraint) + .build(); + } + + +} From 0fd8f91bb420a32fe04986277d4963a10f96fae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 16 Nov 2018 12:41:35 +0100 Subject: [PATCH 106/139] Add some more tests --- .../pmd/properties/PropertyBuilder.java | 29 +++--- .../constraints/ConstraintFactory.java | 2 +- .../constraints/PropertyConstraint.java | 3 +- .../properties/PropertyDescriptorTest.java | 99 +++++++++++++++++-- 4 files changed, 114 insertions(+), 19 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java index e52ab4bec4..6cddaa50bd 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java @@ -134,7 +134,7 @@ public abstract class PropertyBuilder, T> { * * @return The built descriptor * - * @throws IllegalArgumentException if parameters are incorrect + * @throws IllegalStateException if the default value doesn't satisfy the given constraints */ public abstract PropertyDescriptor build(); @@ -194,7 +194,6 @@ public abstract class PropertyBuilder, T> { */ /* package private */ GenericCollectionPropertyBuilder> toList() { - // TODO 7.0.0 this is obviously a lambda Supplier> listSupplier = new Supplier>() { @Override public List get() { @@ -205,7 +204,7 @@ public abstract class PropertyBuilder, T> { return toCollection(listSupplier); } - + // TODO 7.0.0 this can be inlined private > GenericCollectionPropertyBuilder toCollection(Supplier emptyCollSupplier) { if (getDefaultValue() != null) { throw new IllegalStateException("The default value is already set!"); @@ -217,7 +216,7 @@ public abstract class PropertyBuilder, T> { getType()); for (PropertyConstraint validator : getConstraints()) { - result.require(validator.toMulti()); + result.require(validator.toCollectionConstraint()); } return result; @@ -308,8 +307,21 @@ public abstract class PropertyBuilder, T> { */ @SuppressWarnings("unchecked") public GenericCollectionPropertyBuilder defaultValues(V... val) { - super.defaultValue(getDefaultValue(Arrays.asList(val))); - return this; + return super.defaultValue(getDefaultValue(Arrays.asList(val))); + } + + + /** + * Require that the given constraint be fulfilled on each item of the + * value of this properties. This is a convenient shorthand for + * {@code require(constraint.toCollectionConstraint())}. + * + * @param constraint Constraint to impose on the items of the collection value + * + * @return The same builder + */ + public GenericCollectionPropertyBuilder requireEach(PropertyConstraint constraint) { + return super.require(constraint.toCollectionConstraint()); } @@ -332,11 +344,6 @@ public abstract class PropertyBuilder, T> { } - /** - * Builds a new property descriptor with the configuration held in this builder. - * - * @return A new property - */ @SuppressWarnings("unchecked") @Override public PropertyDescriptor build() { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java index 078f034c0c..4aa0b5adc2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java @@ -60,7 +60,7 @@ final class ConstraintFactory { @Override - public PropertyConstraint> toMulti() { + public PropertyConstraint> toCollectionConstraint() { final PropertyConstraint thisValidator = this; return fromPredicate( new Predicate>() { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java index 5991bb4428..57b1600151 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/PropertyConstraint.java @@ -59,7 +59,8 @@ public interface PropertyConstraint { * * @return A collection validator */ - PropertyConstraint> toMulti(); + @Experimental + PropertyConstraint> toCollectionConstraint(); // TODO Java 8 move ConstraintFactory#fromPredicate here diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java index 2e26a8503f..c1b31f1062 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java @@ -4,15 +4,21 @@ package net.sourceforge.pmd.properties; +import static net.sourceforge.pmd.properties.constraints.NumericConstraints.inRange; import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasItem; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; +import org.hamcrest.core.SubstringMatcher; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -20,7 +26,6 @@ import org.junit.rules.ExpectedException; import net.sourceforge.pmd.FooRule; import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.RuleSetFactory; -import net.sourceforge.pmd.properties.constraints.NumericConstraints; import net.sourceforge.pmd.properties.constraints.PropertyConstraint; @@ -41,7 +46,7 @@ public class PropertyDescriptorTest { PropertyDescriptor intProperty = PropertyFactory.intProperty("fooProp") .desc("hello") .defaultValue(4) - .require(NumericConstraints.inRange(1, 10)) + .require(inRange(1, 10)) .build(); FooRule rule = new FooRule(); @@ -57,13 +62,33 @@ public class PropertyDescriptorTest { } + @Test + public void testConstraintViolationCausesDysfunctionalRuleMulti() { + PropertyDescriptor> descriptor = PropertyFactory.doubleListProperty("fooProp") + .desc("hello") + .defaultValues(2., 11.) // 11. is in range + .requireEach(inRange(1d, 20d)) + .build(); + + FooRule rule = new FooRule(); + rule.definePropertyDescriptor(descriptor); + rule.setProperty(descriptor, Collections.singletonList(1000d)); // not in range + RuleSet ruleSet = new RuleSetFactory().createSingleRuleRuleSet(rule); + + List dysfunctional = new ArrayList<>(); + ruleSet.removeDysfunctionalRules(dysfunctional); + + assertEquals(1, dysfunctional.size()); + assertThat(dysfunctional, hasItem(rule)); + } + @Test public void testDefaultValueConstraintViolationCausesFailure() { - PropertyConstraint constraint = NumericConstraints.inRange(1, 10); + PropertyConstraint constraint = inRange(1, 10); thrown.expect(IllegalStateException.class); - thrown.expectMessage(allOf(containsString("Constraint violat"/*-ed or -ion*/), - containsString(constraint.getConstraintDescription()))); + thrown.expectMessage(allOf(containsIgnoreCase("Constraint violat"/*-ed or -ion*/), + containsIgnoreCase(constraint.getConstraintDescription()))); PropertyDescriptor intProperty = PropertyFactory.intProperty("fooProp") .desc("hello") @@ -73,4 +98,66 @@ public class PropertyDescriptorTest { } + @Test + public void testDefaultValueConstraintViolationCausesFailureMulti() { + PropertyConstraint constraint = inRange(1d, 10d); + + thrown.expect(IllegalStateException.class); + thrown.expectMessage(allOf(containsIgnoreCase("Constraint violat"/*-ed or -ion*/), + containsIgnoreCase(constraint.getConstraintDescription()))); + + PropertyFactory.doubleListProperty("fooProp") + .desc("hello") + .defaultValues(2., 11.) // 11. is out of range + .requireEach(constraint) + .build(); + } + + + @Test + public void testNoConstraintViolationCausesIsOkMulti() { + + PropertyDescriptor> descriptor = PropertyFactory.doubleListProperty("fooProp") + .desc("hello") + .defaultValues(2., 11.) // 11. is in range + .requireEach(inRange(1d, 20d)) + .build(); + + assertEquals("fooProp", descriptor.name()); + assertEquals("hello", descriptor.description()); + assertThat(descriptor.defaultValue(), Matchers.contains(2., 11.)); + } + + + + @Test + public void testNoConstraintViolationCausesIsOk() { + + PropertyDescriptor descriptor = PropertyFactory.stringProperty("fooProp") + .desc("hello") + .defaultValue("bazooli") + .build(); + + assertEquals("fooProp", descriptor.name()); + assertEquals("hello", descriptor.description()); + assertEquals("bazooli", descriptor.defaultValue()); + } + + + private static Matcher containsIgnoreCase(final String substring) { + return new SubstringMatcher(substring) { + + @Override + protected boolean evalSubstringOf(String string) { + return StringUtils.indexOfIgnoreCase(string, substring) != -1; + } + + + @Override + protected String relationship() { + return "containing ignoring case"; + } + }; + } + } From d662094d4cf980ab76cdd7bc23f29fa2b0ec98b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 16 Nov 2018 13:05:56 +0100 Subject: [PATCH 107/139] checkstyle --- .../net/sourceforge/pmd/properties/PropertyDescriptorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java index c1b31f1062..6171832a29 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java @@ -11,7 +11,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; From 2229905257ca97209fc2cf4e2e14166a8156f81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 16 Nov 2018 17:46:39 +0100 Subject: [PATCH 108/139] Fix build --- .../pmd/lang/apex/rule/design/CyclomaticComplexityRule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java index d17b7d6b9c..8bb26c4d7b 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java @@ -33,14 +33,14 @@ public class CyclomaticComplexityRule extends AbstractApexRule { .desc("Total class complexity reporting threshold") .require(positive()) .defaultValue(40) - .uiOrder(1.0f).build(); + .build(); private static final PropertyDescriptor METHOD_LEVEL_DESCRIPTOR = PropertyFactory.intProperty("methodReportLevel") .desc("Cyclomatic complexity reporting threshold") .require(positive()) .defaultValue(10) - .uiOrder(2.0f).build(); + .build(); private Stack classNames = new Stack<>(); private boolean inTrigger; From 47617ea0c4fc5dc7a53dccdf4ce1fbf8889a76bb Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 16 Nov 2018 19:52:23 +0100 Subject: [PATCH 109/139] Update build-tools, update checkstyle --- .../sourceforge/pmd/util/fxdesigner/less/editor-theme.less | 2 +- pom.xml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/less/editor-theme.less b/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/less/editor-theme.less index 0e434691c1..b30a872676 100644 --- a/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/less/editor-theme.less +++ b/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/less/editor-theme.less @@ -124,4 +124,4 @@ } } -@import "syntax-highlighting"; \ No newline at end of file +@import "syntax-highlighting"; diff --git a/pom.xml b/pom.xml index bdaed4be92..6cf7567005 100644 --- a/pom.xml +++ b/pom.xml @@ -282,7 +282,7 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code -Xmx512m -Dfile.encoding=${project.build.sourceEncoding} - 1.2 + 1.3-SNAPSHOT @@ -653,7 +653,7 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code com.puppycrawl.tools checkstyle - 8.8 + 8.12 net.sourceforge.pmd @@ -668,6 +668,7 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code ${project.build.sourceDirectory} + **/*.properties,**/*.less From 447b7c5bceda14c5fa6096d8e868d85b8fd20b2d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 16 Nov 2018 19:57:31 +0100 Subject: [PATCH 110/139] [doc] Update location of eclipse-code-formatter.xml Refs pmd/build-tools#11 --- docs/pages/pmd/userdocs/extending/rule_guidelines.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/rule_guidelines.md b/docs/pages/pmd/userdocs/extending/rule_guidelines.md index 91f03f6dba..d752ed5efd 100644 --- a/docs/pages/pmd/userdocs/extending/rule_guidelines.md +++ b/docs/pages/pmd/userdocs/extending/rule_guidelines.md @@ -27,9 +27,12 @@ For instance, let’s take the ExplicitCallToGC rule (“Do not explicitly trigg ## Code formatting -We try to keep a consistent code formatting through out PMD code base to ensure an easier maintenance and also make the diff send to the mailing list as readable as possible. +We try to keep a consistent code formatting through out PMD code base to ensure an easier maintenance and also make +the pull request as readable as possible. -In order to ensure this, we use a PMD specific Eclipse formatter configuration: **tools/config/eclipse-code-formatter-settings.xml**. Please do not forget to uses it before committing or any source code! +In order to ensure this, we use a PMD specific Eclipse formatter configuration, which is maintained in a +separate project - "build-tools": [eclipse-code-formatter.xml](https://github.com/pmd/build-tools/blob/master/eclipse/pmd-eclipse-code-formatter.xml). +Please do not forget to use it before committing or any source code! ## Correctness From f0dbb3640ff3a18a174beea9bb113b7215c9be0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 16 Nov 2018 21:19:24 +0100 Subject: [PATCH 111/139] Remove constraints on StatisticalRule descriptors They make no sense as they are shared by all StatisticalRules, and provoke configuration errors on normal inputs since uncorrectly configured properties now cause the rule not to be run --- .../net/sourceforge/pmd/lang/rule/stat/StatisticalRule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRule.java index fe3a515d23..73b06e6570 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/stat/StatisticalRule.java @@ -20,8 +20,8 @@ import net.sourceforge.pmd.stat.Metric; */ public interface StatisticalRule extends Rule { - DoubleProperty SIGMA_DESCRIPTOR = new DoubleProperty("sigma", "Sigma value", 0d, 100d, null, 1.0f); - DoubleProperty MINIMUM_DESCRIPTOR = new DoubleProperty("minimum", "Minimum reporting threshold", 0d, 100d, null, + DoubleProperty SIGMA_DESCRIPTOR = new DoubleProperty("sigma", "Sigma value", -10000000d, 1000000d, null, 1.0f); + DoubleProperty MINIMUM_DESCRIPTOR = new DoubleProperty("minimum", "Minimum reporting threshold", -10000000d, 1000000000d, null, 2.0f); IntegerProperty TOP_SCORE_DESCRIPTOR = new IntegerProperty("topscore", "Top score value", 1, 100, null, 3.0f); From 9cdfe6ff96c7c0e8ff13ed39c6bb4068b4af88a9 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 18 Nov 2018 12:17:13 +0100 Subject: [PATCH 112/139] Move escape methods into own utility, add unit tests --- .../net/sourceforge/pmd/docs/EscapeUtils.java | 147 ++++++++++++++++++ .../pmd/docs/RuleDocGenerator.java | 133 +--------------- .../sourceforge/pmd/docs/EscapeUtilsTest.java | 56 +++++++ 3 files changed, 208 insertions(+), 128 deletions(-) create mode 100644 pmd-doc/src/main/java/net/sourceforge/pmd/docs/EscapeUtils.java create mode 100644 pmd-doc/src/test/java/net/sourceforge/pmd/docs/EscapeUtilsTest.java diff --git a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/EscapeUtils.java b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/EscapeUtils.java new file mode 100644 index 0000000000..5166750757 --- /dev/null +++ b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/EscapeUtils.java @@ -0,0 +1,147 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.docs; + +import java.util.List; + +public final class EscapeUtils { + private EscapeUtils() { + // This is a utility class + } + + public static String escapeMarkdown(String unescaped) { + return unescaped.replace("\\", "\\\\") + .replace("*", "\\*") + .replace("_", "\\_") + .replace("~", "\\~") + .replace("[", "\\[") + .replace("]", "\\]") + .replace("|", "\\|"); + } + + private enum State { + S, LT, LT_H, LT_H_T, LT_H_T_T, LT_H_T_T_P, LT_H_T_T_P1, LT_H_T_T_P_S, LT_H_T_T_P_S1; + } + + public static String escapeSingleLine(String line) { + StringBuilder escaped = new StringBuilder(line.length() + 16); + State s = State.S; + boolean needsEscape = true; + for (int i = 0; i < line.length(); i++) { + char c = line.charAt(i); + if (c == '`') { + needsEscape = !needsEscape; + } + switch (s) { + case S: + if (c == '<') { + s = State.LT; + } else if (c == '>') { + if (needsEscape && i > 0) { + escaped.append(">"); + } else { + escaped.append(c); + } + } else if (c == '"') { + if (needsEscape) { + escaped.append("""); + } else { + escaped.append(c); + } + } else { + escaped.append(c); + } + break; + case LT: + if (c == 'h' || c == 'H') { + s = State.LT_H; + } else { + if (needsEscape) { + escaped.append("<").append(c); + } else { + escaped.append("<").append(c); + } + s = State.S; + } + break; + case LT_H: + if (c == 't' || c == 'T') { + s = State.LT_H_T; + } else { + escaped.append("<h").append(c); + s = State.S; + } + break; + case LT_H_T: + if (c == 't' || c == 'T') { + s = State.LT_H_T_T; + } else { + escaped.append("<ht").append(c); + s = State.S; + } + break; + case LT_H_T_T: + if (c == 'p' || c == 'P') { + s = State.LT_H_T_T_P; + } else { + escaped.append("<htt").append(c); + s = State.S; + } + break; + case LT_H_T_T_P: + if (c == 's' || c == 'S') { + s = State.LT_H_T_T_P_S; + } else if (c == ':') { + escaped.append("') { + s = State.S; + } + break; + case LT_H_T_T_P_S: + if (c == ':') { + escaped.append("') { + s = State.S; + } + break; + default: + escaped.append(c); + break; + } + } + return escaped.toString(); + } + + public static List escapeLines(List lines) { + boolean needsEscape = true; + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + if (line.startsWith("```")) { + needsEscape = !needsEscape; + } + if (needsEscape && !line.startsWith(" ")) { + line = escapeSingleLine(line); + } + lines.set(i, line); + } + return lines; + } +} diff --git a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java index 19d22dbcad..16fe848df0 100644 --- a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java +++ b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java @@ -395,7 +395,7 @@ public class RuleDocGenerator { lines.add(""); } - lines.addAll(escapeLines(toLines(stripIndentation(rule.getDescription())))); + lines.addAll(EscapeUtils.escapeLines(toLines(stripIndentation(rule.getDescription())))); lines.add(""); if (rule instanceof XPathRule || rule instanceof RuleReference && ((RuleReference) rule).getRule() instanceof XPathRule) { @@ -468,11 +468,11 @@ public class RuleDocGenerator { + multiValuePropertyDescriptor.multiValueDelimiter() + "'."; } - lines.add("|" + escapeMarkdown(StringEscapeUtils.escapeHtml4(propertyDescriptor.name())) - + "|" + escapeMarkdown(StringEscapeUtils.escapeHtml4(defaultValue)) + "|" - + escapeMarkdown((isDeprecated ? DEPRECATION_LABEL_SMALL : "") + lines.add("|" + EscapeUtils.escapeMarkdown(StringEscapeUtils.escapeHtml4(propertyDescriptor.name())) + + "|" + EscapeUtils.escapeMarkdown(StringEscapeUtils.escapeHtml4(defaultValue)) + "|" + + EscapeUtils.escapeMarkdown((isDeprecated ? DEPRECATION_LABEL_SMALL : "") + StringEscapeUtils.escapeHtml4(description)) - + "|" + escapeMarkdown(StringEscapeUtils.escapeHtml4(multiValued)) + "|"); + + "|" + EscapeUtils.escapeMarkdown(StringEscapeUtils.escapeHtml4(multiValued)) + "|"); } lines.add(""); } @@ -615,127 +615,4 @@ public class RuleDocGenerator { return FilenameUtils.normalize(relativeSourceFilename, true); } - - private static String escapeMarkdown(String unescaped) { - return unescaped.replace("\\", "\\\\").replace("*", "\\*").replace("_", "\\_").replace("~", "\\~") - .replace("[", "\\[").replace("]", "\\]").replace("|", "\\|"); - } - - private enum State { - S, LT, LT_H, LT_H_T, LT_H_T_T, LT_H_T_T_P, LT_H_T_T_P1, LT_H_T_T_P_S, LT_H_T_T_P_S1; - } - - private static String escapeSingleLine(String line) { - StringBuilder escaped = new StringBuilder(line.length() + 16); - State s = State.S; - boolean needsEscape = true; - for (int i = 0; i < line.length(); i++) { - char c = line.charAt(i); - if (c == '`') { - needsEscape = !needsEscape; - } - switch (s) { - case S: - if (c == '<') { - s = State.LT; - } else if (c == '>') { - if (needsEscape) { - escaped.append(">"); - } else { - escaped.append(c); - } - } else { - escaped.append(c); - } - break; - case LT: - if (c == 'h' || c == 'H') { - s = State.LT_H; - } else { - if (needsEscape) { - escaped.append("<").append(c); - } else { - escaped.append("<").append(c); - } - s = State.S; - } - break; - case LT_H: - if (c == 't' || c == 'T') { - s = State.LT_H_T; - } else { - escaped.append("<h").append(c); - s = State.S; - } - break; - case LT_H_T: - if (c == 't' || c == 'T') { - s = State.LT_H_T_T; - } else { - escaped.append("<ht").append(c); - s = State.S; - } - break; - case LT_H_T_T: - if (c == 'p' || c == 'P') { - s = State.LT_H_T_T_P; - } else { - escaped.append("<htt").append(c); - s = State.S; - } - break; - case LT_H_T_T_P: - if (c == 's' || c == 'S') { - s = State.LT_H_T_T_P_S; - } else if (c == ':') { - escaped.append("') { - s = State.S; - } - break; - case LT_H_T_T_P_S: - if (c == ':') { - escaped.append("') { - s = State.S; - } - break; - default: - escaped.append(c); - break; - } - } - return escaped.toString(); - } - - private static List escapeLines(List lines) { - boolean needsEscape = true; - for (int i = 0; i < lines.size(); i++) { - String line = lines.get(i); - if (line.startsWith("```")) { - needsEscape = !needsEscape; - } - if (needsEscape && !line.startsWith(" ") && !line.startsWith(">")) { - line = escapeSingleLine(line); - } - lines.set(i, line); - } - return lines; - } } diff --git a/pmd-doc/src/test/java/net/sourceforge/pmd/docs/EscapeUtilsTest.java b/pmd-doc/src/test/java/net/sourceforge/pmd/docs/EscapeUtilsTest.java new file mode 100644 index 0000000000..1010f375ad --- /dev/null +++ b/pmd-doc/src/test/java/net/sourceforge/pmd/docs/EscapeUtilsTest.java @@ -0,0 +1,56 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.docs; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +public class EscapeUtilsTest { + + @Test + public void testEscapeMarkdown() { + assertEquals("This is a \\\\backslash", EscapeUtils.escapeMarkdown("This is a \\backslash")); + assertEquals("This \"\\*\" is not a emphasis", EscapeUtils.escapeMarkdown("This \"*\" is not a emphasis")); + assertEquals("This \"\\*\\*\" is not a strong style", EscapeUtils.escapeMarkdown("This \"**\" is not a strong style")); + assertEquals("This \"\\[foo\\]\" does not start a link", EscapeUtils.escapeMarkdown("This \"[foo]\" does not start a link")); + assertEquals("This \"\\~bar\\~\" is not a strike-through", EscapeUtils.escapeMarkdown("This \"~bar~\" is not a strike-through")); + assertEquals("That's \"\\|\" just a bar", EscapeUtils.escapeMarkdown("That's \"|\" just a bar")); + assertEquals("This \"\\_\" is just a underscore", EscapeUtils.escapeMarkdown("This \"_\" is just a underscore")); + } + + @Test + public void testEscapeHtmlWithinMarkdownSingleLine() { + assertEquals("a <script> tag outside of `"). +would be interpreted by the browser directly (e.g. "<script>alert('hello');</script>"). **This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.jsp.rule.security.NoUnsanitizedJSPExpressionRule](https://github.com/pmd/pmd/blob/master/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/rule/security/NoUnsanitizedJSPExpressionRule.java) diff --git a/docs/pages/pmd/rules/plsql.md b/docs/pages/pmd/rules/plsql.md index 7dfe05bca8..151a6cdf1b 100644 --- a/docs/pages/pmd/rules/plsql.md +++ b/docs/pages/pmd/rules/plsql.md @@ -6,11 +6,12 @@ language_name: PLSQL permalink: pmd_rules_plsql.html folder: pmd/rules --- + ## Best Practices {% include callout.html content="Rules which enforce generally accepted best practices." %} -* [TomKytesDespair](pmd_rules_plsql_bestpractices.html#tomkytesdespair): "WHEN OTHERS THEN NULL" hides all errors - (Re)RAISE an exception or call RAISE_APPLICATION_ERROR +* [TomKytesDespair](pmd_rules_plsql_bestpractices.html#tomkytesdespair): "WHEN OTHERS THEN NULL" hides all errors - (Re)RAISE an exception or call RAISE_APPLICATION_ERROR ## Code Style diff --git a/docs/pages/pmd/rules/plsql/bestpractices.md b/docs/pages/pmd/rules/plsql/bestpractices.md index 498922eab2..3dc2813b31 100644 --- a/docs/pages/pmd/rules/plsql/bestpractices.md +++ b/docs/pages/pmd/rules/plsql/bestpractices.md @@ -8,13 +8,14 @@ editmepath: ../pmd-plsql/src/main/resources/category/plsql/bestpractices.xml keywords: Best Practices, TomKytesDespair language: PLSQL --- + ## TomKytesDespair **Since:** PMD 5.1 **Priority:** Medium (3) -"WHEN OTHERS THEN NULL" hides all errors - (Re)RAISE an exception or call RAISE_APPLICATION_ERROR +"WHEN OTHERS THEN NULL" hides all errors - (Re)RAISE an exception or call RAISE_APPLICATION_ERROR **This rule is defined by the following XPath expression:** ``` xpath diff --git a/docs/pages/pmd/rules/plsql/codestyle.md b/docs/pages/pmd/rules/plsql/codestyle.md index eeecd344a3..607d522e8c 100644 --- a/docs/pages/pmd/rules/plsql/codestyle.md +++ b/docs/pages/pmd/rules/plsql/codestyle.md @@ -8,6 +8,7 @@ editmepath: ../pmd-plsql/src/main/resources/category/plsql/codestyle.xml keywords: Code Style, CodeFormat, MisplacedPragma, ForLoopNaming language: PLSQL --- + ## CodeFormat **Since:** PMD 6.9.0 diff --git a/docs/pages/pmd/rules/plsql/design.md b/docs/pages/pmd/rules/plsql/design.md index 68e2fb29b7..76129b9f61 100644 --- a/docs/pages/pmd/rules/plsql/design.md +++ b/docs/pages/pmd/rules/plsql/design.md @@ -8,6 +8,7 @@ editmepath: ../pmd-plsql/src/main/resources/category/plsql/design.xml keywords: Design, CyclomaticComplexity, ExcessiveMethodLength, ExcessiveObjectLength, ExcessivePackageBodyLength, ExcessivePackageSpecificationLength, ExcessiveParameterList, ExcessiveTypeLength, NcssMethodCount, NcssObjectCount, NPathComplexity, TooManyFields, TooManyMethods language: PLSQL --- + ## CyclomaticComplexity **Since:** PMD 5.1 diff --git a/docs/pages/pmd/rules/plsql/errorprone.md b/docs/pages/pmd/rules/plsql/errorprone.md index 17b048571b..08504e4f2a 100644 --- a/docs/pages/pmd/rules/plsql/errorprone.md +++ b/docs/pages/pmd/rules/plsql/errorprone.md @@ -8,6 +8,7 @@ editmepath: ../pmd-plsql/src/main/resources/category/plsql/errorprone.xml keywords: Error Prone, TO_DATE_TO_CHAR, TO_DATEWithoutDateFormat, TO_TIMESTAMPWithoutDateFormat language: PLSQL --- + ## TO_DATE_TO_CHAR **Since:** PMD 5.1 diff --git a/docs/pages/pmd/rules/pom.md b/docs/pages/pmd/rules/pom.md index 0b5e8f692f..04f8650f53 100644 --- a/docs/pages/pmd/rules/pom.md +++ b/docs/pages/pmd/rules/pom.md @@ -6,6 +6,7 @@ language_name: Maven POM permalink: pmd_rules_pom.html folder: pmd/rules --- + ## Error Prone {% include callout.html content="Rules to detect constructs that are either broken, extremely confusing or prone to runtime errors." %} diff --git a/docs/pages/pmd/rules/pom/errorprone.md b/docs/pages/pmd/rules/pom/errorprone.md index 7dff1d6ec5..3168a75a4a 100644 --- a/docs/pages/pmd/rules/pom/errorprone.md +++ b/docs/pages/pmd/rules/pom/errorprone.md @@ -8,6 +8,7 @@ editmepath: ../pmd-xml/src/main/resources/category/pom/errorprone.xml keywords: Error Prone, InvalidDependencyTypes, ProjectVersionAsDependencyVersion language: Maven POM --- + ## InvalidDependencyTypes **Since:** PMD 5.4 diff --git a/docs/pages/pmd/rules/vf.md b/docs/pages/pmd/rules/vf.md index 0e0ad6a889..9aac04f746 100644 --- a/docs/pages/pmd/rules/vf.md +++ b/docs/pages/pmd/rules/vf.md @@ -6,6 +6,7 @@ language_name: Salesforce VisualForce permalink: pmd_rules_vf.html folder: pmd/rules --- + ## Security {% include callout.html content="Rules that flag potential security flaws." %} diff --git a/docs/pages/pmd/rules/vf/security.md b/docs/pages/pmd/rules/vf/security.md index 28a4b5a6bf..86f8e57ef5 100644 --- a/docs/pages/pmd/rules/vf/security.md +++ b/docs/pages/pmd/rules/vf/security.md @@ -8,6 +8,7 @@ editmepath: ../pmd-visualforce/src/main/resources/category/vf/security.xml keywords: Security, VfCsrf, VfUnescapeEl language: Salesforce VisualForce --- + ## VfCsrf **Since:** PMD 5.6.0 diff --git a/docs/pages/pmd/rules/vm.md b/docs/pages/pmd/rules/vm.md index 10be2fe45b..c53d22f9b0 100644 --- a/docs/pages/pmd/rules/vm.md +++ b/docs/pages/pmd/rules/vm.md @@ -6,6 +6,7 @@ language_name: VM permalink: pmd_rules_vm.html folder: pmd/rules --- + ## Best Practices {% include callout.html content="Rules which enforce generally accepted best practices." %} diff --git a/docs/pages/pmd/rules/vm/bestpractices.md b/docs/pages/pmd/rules/vm/bestpractices.md index 6823e639a4..20fc70348b 100644 --- a/docs/pages/pmd/rules/vm/bestpractices.md +++ b/docs/pages/pmd/rules/vm/bestpractices.md @@ -8,6 +8,7 @@ editmepath: ../pmd-vm/src/main/resources/category/vm/bestpractices.xml keywords: Best Practices, AvoidReassigningParameters, UnusedMacroParameter language: VM --- + ## AvoidReassigningParameters **Since:** PMD 5.1 diff --git a/docs/pages/pmd/rules/vm/design.md b/docs/pages/pmd/rules/vm/design.md index 089de4f926..2b9aa4b5b6 100644 --- a/docs/pages/pmd/rules/vm/design.md +++ b/docs/pages/pmd/rules/vm/design.md @@ -8,6 +8,7 @@ editmepath: ../pmd-vm/src/main/resources/category/vm/design.xml keywords: Design, AvoidDeeplyNestedIfStmts, CollapsibleIfStatements, ExcessiveTemplateLength, NoInlineJavaScript, NoInlineStyles language: VM --- + ## AvoidDeeplyNestedIfStmts **Since:** PMD 5.1 diff --git a/docs/pages/pmd/rules/vm/errorprone.md b/docs/pages/pmd/rules/vm/errorprone.md index 8fdce71143..79c61646f0 100644 --- a/docs/pages/pmd/rules/vm/errorprone.md +++ b/docs/pages/pmd/rules/vm/errorprone.md @@ -8,6 +8,7 @@ editmepath: ../pmd-vm/src/main/resources/category/vm/errorprone.xml keywords: Error Prone, EmptyForeachStmt, EmptyIfStmt language: VM --- + ## EmptyForeachStmt **Since:** PMD 5.1 diff --git a/docs/pages/pmd/rules/xml.md b/docs/pages/pmd/rules/xml.md index 4c3ca2ec0a..0b10fd891b 100644 --- a/docs/pages/pmd/rules/xml.md +++ b/docs/pages/pmd/rules/xml.md @@ -6,11 +6,12 @@ language_name: XML permalink: pmd_rules_xml.html folder: pmd/rules --- + ## Error Prone {% include callout.html content="Rules to detect constructs that are either broken, extremely confusing or prone to runtime errors." %} -* [MistypedCDATASection](pmd_rules_xml_errorprone.html#mistypedcdatasection): An XML CDATA section begins with a mar... +* [MistypedCDATASection](pmd_rules_xml_errorprone.html#mistypedcdatasection): An XML CDATA section begins with a <!CDATA[ marker, which has only one [, and ends with a ]]> mar... ## Additional rulesets diff --git a/docs/pages/pmd/rules/xml/errorprone.md b/docs/pages/pmd/rules/xml/errorprone.md index 01e61d9539..2ddd87c822 100644 --- a/docs/pages/pmd/rules/xml/errorprone.md +++ b/docs/pages/pmd/rules/xml/errorprone.md @@ -8,13 +8,14 @@ editmepath: ../pmd-xml/src/main/resources/category/xml/errorprone.xml keywords: Error Prone, MistypedCDATASection language: XML --- + ## MistypedCDATASection **Since:** PMD 5.0 **Priority:** Medium (3) -An XML CDATA section begins with a marker, which has only two ]. +An XML CDATA section begins with a <!CDATA[ marker, which has only one [, and ends with a ]]> marker, which has only two ]. **This rule is defined by the following XPath expression:** ``` xpath diff --git a/docs/pages/pmd/rules/xsl.md b/docs/pages/pmd/rules/xsl.md index ffaf5e0b2d..dba91076aa 100644 --- a/docs/pages/pmd/rules/xsl.md +++ b/docs/pages/pmd/rules/xsl.md @@ -6,11 +6,12 @@ language_name: XSL permalink: pmd_rules_xsl.html folder: pmd/rules --- + ## Code Style {% include callout.html content="Rules which enforce a specific coding style." %} -* [UseConcatOnce](pmd_rules_xsl_codestyle.html#useconcatonce): The XPath concat() functions accepts as many arguments as required so you can have"concat($a,'b',... +* [UseConcatOnce](pmd_rules_xsl_codestyle.html#useconcatonce): The XPath concat() functions accepts as many arguments as required so you can have"concat($a,'b',... ## Performance diff --git a/docs/pages/pmd/rules/xsl/codestyle.md b/docs/pages/pmd/rules/xsl/codestyle.md index 8e66e2fabf..a0c276933e 100644 --- a/docs/pages/pmd/rules/xsl/codestyle.md +++ b/docs/pages/pmd/rules/xsl/codestyle.md @@ -8,6 +8,7 @@ editmepath: ../pmd-xml/src/main/resources/category/xsl/codestyle.xml keywords: Code Style, UseConcatOnce language: XSL --- + ## UseConcatOnce **Since:** PMD 5.0 @@ -15,7 +16,7 @@ language: XSL **Priority:** Medium (3) The XPath concat() functions accepts as many arguments as required so you can have -"concat($a,'b',$c)" rather than "concat($a,concat('b',$c)". +"concat($a,'b',$c)" rather than "concat($a,concat('b',$c)". **This rule is defined by the following XPath expression:** ``` xpath diff --git a/docs/pages/pmd/rules/xsl/performance.md b/docs/pages/pmd/rules/xsl/performance.md index 24adc757e8..400b0855d9 100644 --- a/docs/pages/pmd/rules/xsl/performance.md +++ b/docs/pages/pmd/rules/xsl/performance.md @@ -8,6 +8,7 @@ editmepath: ../pmd-xml/src/main/resources/category/xsl/performance.xml keywords: Performance, AvoidAxisNavigation language: XSL --- + ## AvoidAxisNavigation **Since:** PMD 5.0 From 3ac8d962ed2dac6f57ad2a0c398959e9aaffb8a7 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 18 Nov 2018 13:13:14 +0100 Subject: [PATCH 117/139] Update release notes, fixes #1468 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 8b3fee5092..b6fe14b58d 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -30,6 +30,7 @@ This is a {{ site.pmd.release_type }} release. * [#1284](https://github.com/pmd/pmd/issues/1284): \[doc] Keep record of every currently deprecated API * [#1318](https://github.com/pmd/pmd/issues/1318): \[test] Kotlin DSL to ease test writing * [#1341](https://github.com/pmd/pmd/issues/1341): \[doc] Documentation Error with Regex Properties + * [#1468](https://github.com/pmd/pmd/issues/1468): \[doc] Missing escaping leads to XSS * java * [#1460](https://github.com/pmd/pmd/issues/1460): \[java] Intermittent PMD failure : PMD processing errors while no violations reported * java-codestyle From 16473915074618fd01a6cba7f3bc92af91635c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 20 Nov 2018 17:23:08 +0100 Subject: [PATCH 118/139] Delegate to non-deprecated method --- .../main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java index 51303de825..74192f1f0c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java @@ -58,7 +58,7 @@ public class ASTType extends AbstractJavaTypeNode { */ @Deprecated public boolean isArray() { - return getArrayDepth() > 0; + return isArrayType(); } @@ -67,6 +67,6 @@ public class ASTType extends AbstractJavaTypeNode { * */ public boolean isArrayType() { - return isArray(); + return getArrayDepth() > 0; } } From 21d2bc5a93cc663ac7d2f21d2628ba906a9eda7b Mon Sep 17 00:00:00 2001 From: "Travis CI (pmd-bot)" Date: Wed, 21 Nov 2018 17:46:58 +0000 Subject: [PATCH 119/139] Update documentation TRAVIS_JOB_NUMBER=3098.1 TRAVIS_COMMIT_RANGE=447b7c5bceda...956ee2ff5613 --- docs/pages/pmd/rules/java/bestpractices.md | 12 ++++++------ docs/pages/pmd/rules/java/errorprone.md | 2 +- docs/pages/pmd/rules/java/performance.md | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/pages/pmd/rules/java/bestpractices.md b/docs/pages/pmd/rules/java/bestpractices.md index 4c46a7a429..ea047c1389 100644 --- a/docs/pages/pmd/rules/java/bestpractices.md +++ b/docs/pages/pmd/rules/java/bestpractices.md @@ -1557,18 +1557,18 @@ having to deal with the creation of an array. ``` xpath //FormalParameters/FormalParameter [position()=last()] - [@Array='true'] - [@Varargs='false'] - [not (./Type/ReferenceType[@Array='true'][PrimitiveType[@Image='byte']])] + [VariableDeclaratorId/@ArrayType=true()] + [@Varargs=false()] + [not (./Type[@ArrayType=true()]/ReferenceType[PrimitiveType[@Image='byte']])] [not (./Type/ReferenceType[ClassOrInterfaceType[@Image='Byte']])] [not (./Type/PrimitiveType[@Image='byte'])] [not (ancestor::MethodDeclaration/preceding-sibling::Annotation/*/Name[@Image='Override'])] [not( ancestor::MethodDeclaration - [@Public='true' and @Static='true'] - [child::ResultType[@Void='true']] and + [@Public=true() and @Static=true()] + [child::ResultType[@Void=true()]] and ancestor::MethodDeclarator[@Image='main'] and - ..[@ParameterCount='1'] and + ..[@ParameterCount=1] and ./Type/ReferenceType[ClassOrInterfaceType[@Image='String']] )] ``` diff --git a/docs/pages/pmd/rules/java/errorprone.md b/docs/pages/pmd/rules/java/errorprone.md index b81d6b9f20..eefc198ef4 100644 --- a/docs/pages/pmd/rules/java/errorprone.md +++ b/docs/pages/pmd/rules/java/errorprone.md @@ -2750,7 +2750,7 @@ NullPointerExceptions. ``` xpath //MethodDeclaration [ -(./ResultType/Type[@Array='true']) +(./ResultType/Type[@ArrayType='true']) and (./Block/BlockStatement/Statement/ReturnStatement/Expression/PrimaryExpression/PrimaryPrefix/Literal/NullLiteral) ] diff --git a/docs/pages/pmd/rules/java/performance.md b/docs/pages/pmd/rules/java/performance.md index d86c5214a5..dad1655335 100644 --- a/docs/pages/pmd/rules/java/performance.md +++ b/docs/pages/pmd/rules/java/performance.md @@ -903,9 +903,9 @@ You must use new ArrayList<>(Arrays.asList(...)) if that is inconvenient for you and PrimaryExpression/PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Name [ - @Image = ancestor::MethodDeclaration//LocalVariableDeclaration[@Array="true"]/VariableDeclarator/VariableDeclaratorId/@Image + @Image = ancestor::MethodDeclaration[1]//LocalVariableDeclaration/VariableDeclarator/VariableDeclaratorId[@ArrayType="true"]/@Image or - @Image = ancestor::MethodDeclaration//FormalParameter/VariableDeclaratorId/@Image + @Image = ancestor::MethodDeclaration[1]//FormalParameter/VariableDeclaratorId/@Image ] /../..[count(.//PrimarySuffix) =1]/PrimarySuffix/Expression/PrimaryExpression/PrimaryPrefix From bc29973c3b06dbfa85453f3ecf06694587d40173 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Wed, 21 Nov 2018 20:10:46 +0100 Subject: [PATCH 120/139] Update release notes, refs #1447 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 782bfa0d1e..bd344bcb2a 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -29,6 +29,7 @@ This is a {{ site.pmd.release_type }} release. * [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007) * [#1428](https://github.com/pmd/pmd/pull/1428): \[core] Upgrading JCommander from 1.48 to 1.72 - [Thunderforge](https://github.com/Thunderforge) * [#1430](https://github.com/pmd/pmd/pull/1430): \[doc] Who really knows regex? - [Dem Pilafian](https://github.com/dpilafian) +* [#1447](https://github.com/pmd/pmd/pull/1447): \[fortran] Use diamond operator in impl - [reudismam](https://github.com/reudismam) {% endtocmaker %} From 8daa8a6e594a2f9454feeb5a3091712da9a386ce Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Wed, 21 Nov 2018 20:53:09 +0100 Subject: [PATCH 121/139] Fix more missing diamond operator cases --- .../java/net/sourceforge/pmd/lang/apex/ast/ASTAnnotation.java | 2 +- .../src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java | 2 +- .../java/rule/codestyle/CommentDefaultAccessModifierRule.java | 2 +- .../rule/errorprone/CloneMethodMustImplementCloneableRule.java | 2 +- .../java/rule/errorprone/InvalidSlf4jMessageFormatRule.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnnotation.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnnotation.java index 1ba073df4b..6bc20bb3c3 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnnotation.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnnotation.java @@ -36,7 +36,7 @@ public class ASTAnnotation extends AbstractApexNode { String image = param.getImage(); if (image != null) { - Set paramValues = new TreeSet(String.CASE_INSENSITIVE_ORDER); + Set paramValues = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); paramValues.addAll(Arrays.asList(image.replaceAll("\\s+", "").split(","))); if (paramValues.contains("PMD") || paramValues.contains(ruleAnno) || paramValues.contains("all")) { return true; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java b/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java index 4ed923a31a..d758704ba3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java @@ -211,7 +211,7 @@ public class JavaTokenizer implements Tokenizer { this.ignoreIdentifiers = ignoreIdentifiers; currentNestingLevel = 0; - classMembersIndentations = new LinkedList(); + classMembersIndentations = new LinkedList<>(); } public void processToken(Token currentToken) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java index 604de9f33f..02a55f36d2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java @@ -38,7 +38,7 @@ public class CommentDefaultAccessModifierRule extends AbstractIgnoredAnnotationR .desc("Regular expression").defaultValue("\\/\\*\\s+(default|package)\\s+\\*\\/").uiOrder(1.0f).build(); private static final String MESSAGE = "To avoid mistakes add a comment " + "at the beginning of the %s %s if you want a default access modifier"; - private final Set interestingLineNumberComments = new HashSet(); + private final Set interestingLineNumberComments = new HashSet<>(); public CommentDefaultAccessModifierRule() { definePropertyDescriptor(REGEX_DESCRIPTOR); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloneMethodMustImplementCloneableRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloneMethodMustImplementCloneableRule.java index e528fac6ac..beecbee439 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloneMethodMustImplementCloneableRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloneMethodMustImplementCloneableRule.java @@ -150,7 +150,7 @@ public class CloneMethodMustImplementCloneableRule extends AbstractJavaRule { private Set determineTopLevelCloneableClasses(final ASTClassOrInterfaceDeclaration currentClass) { final List classes = currentClass.getFirstParentOfType(ASTCompilationUnit.class) .findDescendantsOfType(ASTClassOrInterfaceDeclaration.class); - final Set classesNames = new HashSet(); + final Set classesNames = new HashSet<>(); for (final ASTClassOrInterfaceDeclaration c : classes) { if (!Objects.equals(c, currentClass) && extendsOrImplementsCloneable(c)) { classesNames.add(c.getImage()); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidSlf4jMessageFormatRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidSlf4jMessageFormatRule.java index 55d90ff474..0a5e1402c4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidSlf4jMessageFormatRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidSlf4jMessageFormatRule.java @@ -174,7 +174,7 @@ public class InvalidSlf4jMessageFormatRule extends AbstractJavaRule { final List fieldlist = node.getFirstParentOfType(ASTClassOrInterfaceBody.class) .findDescendantsOfType(ASTFieldDeclaration.class); // only look for ASTVariableDeclarator that are Fields - final List fields = new ArrayList(fieldlist.size()); + final List fields = new ArrayList<>(fieldlist.size()); for (final ASTFieldDeclaration astFieldDeclaration : fieldlist) { fields.add(astFieldDeclaration.getFirstChildOfType(ASTVariableDeclarator.class)); } From 9b1b1351d5fafed9d1695e371565a6de9b535f4b Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Wed, 21 Nov 2018 21:56:39 +0100 Subject: [PATCH 122/139] Update release notes, refs #1453, fixes #1440 --- docs/pages/release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 35e8909643..e0bc6cc22f 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -28,6 +28,7 @@ This is a {{ site.pmd.release_type }} release. * java-codestyle * [#1232](https://github.com/pmd/pmd/issues/1232): \[java] Detector for large numbers not separated by _ * [#1372](https://github.com/pmd/pmd/issues/1372): \[java] false positive for UselessQualifiedThis + * [#1440](https://github.com/pmd/pmd/issues/1440): \[java] CommentDefaultAccessModifierRule shows incorrect message ### API Changes @@ -37,6 +38,7 @@ This is a {{ site.pmd.release_type }} release. * [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007) * [#1428](https://github.com/pmd/pmd/pull/1428): \[core] Upgrading JCommander from 1.48 to 1.72 - [Thunderforge](https://github.com/Thunderforge) * [#1430](https://github.com/pmd/pmd/pull/1430): \[doc] Who really knows regex? - [Dem Pilafian](https://github.com/dpilafian) +* [#1453](https://github.com/pmd/pmd/pull/1453): \[java] Adding the fix for #1440. Showing correct message for CommentDefaultAccessmodifier. - [Rohit Kumar](https://github.com/stationeros) {% endtocmaker %} From 008963f6caeacc635b1d903389450184fee16d4f Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 22 Nov 2018 20:21:12 +0100 Subject: [PATCH 123/139] [doc] Add cheat sheet for custom liquid tags --- docs/_plugins/javadoc_tag.rb | 6 ----- docs/_plugins/jdoc_namespace_tag.rb | 8 ++++-- .../pmd/devdocs/writing_documentation.md | 26 +++++++++++++++++++ .../pmd/userdocs/extending/metrics_howto.md | 5 ++-- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb index 4149e6376d..dc68c67036 100644 --- a/docs/_plugins/javadoc_tag.rb +++ b/docs/_plugins/javadoc_tag.rb @@ -269,12 +269,6 @@ class JavadocTag < Liquid::Tag end - - Liquid::Template.register_tag('jdoc', JavadocTag) Liquid::Template.register_tag('jdoc_package', JavadocTag) Liquid::Template.register_tag('jdoc_old', JavadocTag) -Liquid::Template.register_tag('jdoc_nspace', JDocNamespaceDeclaration) - - - diff --git a/docs/_plugins/jdoc_namespace_tag.rb b/docs/_plugins/jdoc_namespace_tag.rb index 1c2ba22e20..019864de31 100644 --- a/docs/_plugins/jdoc_namespace_tag.rb +++ b/docs/_plugins/jdoc_namespace_tag.rb @@ -37,7 +37,6 @@ class JDocNamespaceDeclaration < Liquid::Tag end def render(var_ctx) - unless var_ctx[JDOC_NAMESPACE_MAP] var_ctx[JDOC_NAMESPACE_MAP] = JDocNamespaceDeclaration::make_base_namespaces #base namespace map end @@ -55,6 +54,9 @@ class JDocNamespaceDeclaration < Liquid::Tag # Parses a namespaced fqcn of the form nspace::a.b.c.Class into a tuple [artifactId, expandedFQCN] # If allow_sym is true, then the syntax :nspace is allowed as well def self.parse_fqcn(fqcn, var_ctx, allow_sym = true) + unless var_ctx[JDOC_NAMESPACE_MAP] + var_ctx[JDOC_NAMESPACE_MAP] = JDocNamespaceDeclaration::make_base_namespaces #base namespace map + end nspace = nil fqcn_suffix = "" @@ -107,4 +109,6 @@ class JDocNamespaceDeclaration < Liquid::Tag res end -end \ No newline at end of file +end + +Liquid::Template.register_tag('jdoc_nspace', JDocNamespaceDeclaration) diff --git a/docs/pages/pmd/devdocs/writing_documentation.md b/docs/pages/pmd/devdocs/writing_documentation.md index 1a02a2a8a3..da41c98748 100644 --- a/docs/pages/pmd/devdocs/writing_documentation.md +++ b/docs/pages/pmd/devdocs/writing_documentation.md @@ -60,6 +60,32 @@ all formatting inside the delimiters, and allow to write code samples without ``` +## Custom Liquid Tags + +We have some additional custom liquid tags that help in writing the documentation. + +Here's a short overview: + +| Liquid | Rendered as | +|:-------|:------------| +| `{% raw %}{% rule "java/codestyle/LinguisticNaming" %}{% endraw %}` | {% rule "java/codestyle/LinguisticNaming" %} | +| `{% raw %}{% jdoc core::Rule %}{% endraw %}` | {% jdoc core::Rule %} | +| `{% raw %}{% jdoc !q!core::Rule %}{% endraw %}` | {% jdoc !q!core::Rule %} | +| `{% raw %}{% jdoc core::Rule#setName(java.lang.String) %}{% endraw %}` | {% jdoc core::Rule#setName(java.lang.String) %} | +| `{% raw %}{% jdoc !c!core::Rule#setName(java.lang.String) %}{% endraw %}` | {% jdoc !c!core::Rule#setName(java.lang.String) %} | +| `{% raw %}{% jdoc !a!core::Rule#setName(java.lang.String) %}{% endraw %}` | {% jdoc !a!core::Rule#setName(java.lang.String) %} | +| `{% raw %}{% jdoc !ac!core::Rule#setName(java.lang.String) %}{% endraw %}` | {% jdoc !ac!core::Rule#setName(java.lang.String) %} | +| `{% raw %}{% jdoc core::properties.PropertyDescriptor %}{% endraw %}` | {% jdoc core::properties.PropertyDescriptor %} | +| `{% raw %}{% jdoc_nspace :jast java::lang.java.ast %}{% jdoc jast::ASTAnyTypeDeclaration %}{% endraw %}` | {% jdoc_nspace :jast java::lang.java.ast %}{% jdoc jast::ASTAnyTypeDeclaration %} | +| `{% raw %}{% jdoc_nspace :jast java::lang.java.ast %}{% jdoc_package :jast %}{% endraw %}` | {% jdoc_nspace :jast java::lang.java.ast %}{% jdoc_package :jast %} | +| `{% raw %}{% jdoc_nspace :PrD core::properties.PropertyDescriptor %}{% jdoc !ac!:PrD#uiOrder() %}{% endraw %}` | {% jdoc_nspace :PrD core::properties.PropertyDescriptor %}{% jdoc !ac!:PrD#uiOrder() %} | +| `{% raw %}{% jdoc_old core::Rule %}{% endraw %}` | {% jdoc_old core::Rule %} + +For the javadoc tags, the standard PMD maven modules are already defined as namespaces, e.g. `core`, `java`, `apex`, .... + +For the implementation of these tags, see the [_plugins](https://github.com/pmd/pmd/tree/master/docs/_plugins) folder. + + ## Building There are two ways, to execute jekyll: diff --git a/docs/pages/pmd/userdocs/extending/metrics_howto.md b/docs/pages/pmd/userdocs/extending/metrics_howto.md index 0b6708fc49..5320ca2580 100644 --- a/docs/pages/pmd/userdocs/extending/metrics_howto.md +++ b/docs/pages/pmd/userdocs/extending/metrics_howto.md @@ -39,8 +39,9 @@ which is the name of the metric key as defined in `JavaClassMetricKey` or `Java The function will throw an exception in the following cases: * The context node is neither an instance of {% jdoc jast::ASTAnyTypeDeclaration %} or {% jdoc jast::MethodLikeNode %}, that is, -it's not one of `ClassOrInterfaceDeclaration`, `EnumDeclaration`, `AnnotationDeclaration`, `MethodDeclaration`, -`ConstructorDeclaration`, or `LambdaExpression`. +it's not one of {% jdoc jast::ASTClassOrInterfaceDeclaration %}, {% jdoc jast::ASTEnumDeclaration}, +{% jdoc jast::ASTAnnotationDeclaration %}, {% jdoc jast::ASTMethodDeclaration %}, +{% jdoc jast::ASTConstructorDeclaration %}, or {% jdoc jast::ASTLambdaExpression %}. * The metric key does not exist (the name is case insensitive) or is not defined for the type of the context node. {%include note.html From 280f53d0b5b91af279b474a6e2a2d822a7a552b2 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 22 Nov 2018 20:21:25 +0100 Subject: [PATCH 124/139] [doc] update gems --- docs/Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index beeebfcad2..dd00f00f45 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -30,7 +30,7 @@ GEM ffi (1.9.25) forwardable-extended (2.6.0) gemoji (3.0.0) - github-pages (192) + github-pages (193) activesupport (= 4.2.10) github-pages-health-check (= 1.8.1) jekyll (= 3.7.4) @@ -38,7 +38,7 @@ GEM jekyll-coffeescript (= 1.1.1) jekyll-commonmark-ghpages (= 0.1.5) jekyll-default-layout (= 0.1.4) - jekyll-feed (= 0.10.0) + jekyll-feed (= 0.11.0) jekyll-gist (= 1.5.0) jekyll-github-metadata (= 2.9.4) jekyll-mentions (= 1.4.1) @@ -81,7 +81,7 @@ GEM octokit (~> 4.0) public_suffix (~> 2.0) typhoeus (~> 1.3) - html-pipeline (2.9.0) + html-pipeline (2.9.1) activesupport (>= 2) nokogiri (>= 1.4) http_parser.rb (0.6.0) @@ -114,7 +114,7 @@ GEM rouge (~> 2) jekyll-default-layout (0.1.4) jekyll (~> 3.0) - jekyll-feed (0.10.0) + jekyll-feed (0.11.0) jekyll (~> 3.3) jekyll-gist (1.5.0) octokit (~> 4.2) From 76e57ea2c7b8ec55b45dfceba93f9ba2ca97bb84 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 23 Nov 2018 20:25:04 +0100 Subject: [PATCH 125/139] Fix wrong issue link Co-Authored-By: oowekyala --- .../net/sourceforge/pmd/properties/PropertyDescriptor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java index 8c3dde160a..9cc323678c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyDescriptor.java @@ -16,7 +16,8 @@ import net.sourceforge.pmd.annotation.InternalApi; * any associated GUIs. While concrete descriptor instances are static and immutable they provide validation, * serialization, and default values for any specific datatypes. * - *

Upcoming API changes to the properties framework: see https://github.com/pmd/pmd/issues/1415

+ *

Upcoming API changes to the properties framework

+ * see pmd/pmd#1432 * * @param type of the property's value. This is a list type for multi-valued properties. * From ce83a875499e7510db080f4ae882e3b2e82d8222 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 23 Nov 2018 20:46:41 +0100 Subject: [PATCH 126/139] Fix outdated versions Co-Authored-By: oowekyala --- .../java/net/sourceforge/pmd/properties/PropertyBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java index 6cddaa50bd..3e60534f2b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java @@ -153,7 +153,7 @@ public abstract class PropertyBuilder, T> { * @param Type of values the property handles * * @author Clément Fournier - * @since 6.7.0 + * @since 6.10.0 */ // Note: we may keep some specialized property builders around to allow for some sugar, // e.g. specifying the default value of a regex property as a string, or like the collection one, @@ -254,7 +254,7 @@ public abstract class PropertyBuilder, T> { * @param Collection type for the property being built * * @author Clément Fournier - * @since 6.7.0 + * @since 6.10.0 */ public static final class GenericCollectionPropertyBuilder> extends PropertyBuilder, C> { private final ValueParser parser; From 1f76eb062c6a0d9e878b4bcb557db5c8b7c579e7 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 25 Nov 2018 14:35:52 +0100 Subject: [PATCH 127/139] Also checkout /sitemap.xml during release Fixes #1328 --- .travis/release.sh | 3 ++- docs/pages/release_notes.md | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis/release.sh b/.travis/release.sh index 9d468e4611..f11b56fdb7 100755 --- a/.travis/release.sh +++ b/.travis/release.sh @@ -77,7 +77,8 @@ mkdir pmd.github.io git config user.email "andreas.dangel+pmd-bot@adangel.org" git config core.sparsecheckout true git remote add origin git@github.com:pmd/pmd.github.io.git - echo "latest/" > .git/info/sparse-checkout + echo "/latest/" > .git/info/sparse-checkout + echo "/sitemap.xml" >> .git/info/sparse-checkout git pull --depth=1 origin master log_info "Copying documentation from ../docs/pmd-doc-${RELEASE_VERSION}/ to pmd-${RELEASE_VERSION}/ ..." rsync -ah --stats ../docs/pmd-doc-${RELEASE_VERSION}/ pmd-${RELEASE_VERSION}/ diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 0b69ed7ba4..f395d41ed8 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -29,6 +29,7 @@ This is a {{ site.pmd.release_type }} release. * all * [#1284](https://github.com/pmd/pmd/issues/1284): \[doc] Keep record of every currently deprecated API * [#1318](https://github.com/pmd/pmd/issues/1318): \[test] Kotlin DSL to ease test writing + * [#1328](https://github.com/pmd/pmd/issues/1328): \[ci] Building docs for release fails * [#1341](https://github.com/pmd/pmd/issues/1341): \[doc] Documentation Error with Regex Properties * java * [#1460](https://github.com/pmd/pmd/issues/1460): \[java] Intermittent PMD failure : PMD processing errors while no violations reported From e3ef72cc065487fc5f89cf5158fdc5c84d859756 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 25 Nov 2018 15:09:15 +0100 Subject: [PATCH 128/139] [ci] Do not use "sudo=false" for travis anymore See the following blog posts * https://blog.travis-ci.com/2018-10-04-combining-linux-infrastructures * https://blog.travis-ci.com/2018-11-19-required-linux-infrastructure-migration * https://changelog.travis-ci.com/linux-builds-run-on-vms-by-default-77106 --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9475419f49..f814e1b5c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,22 +21,18 @@ matrix: - name: "linux - mvn deploy" os: linux dist: trusty - sudo: false env: BUILD=deploy - name: "linux - build documentation" os: linux dist: trusty - sudo: false env: BUILD=doc - name: "linux - run sonar" os: linux dist: trusty - sudo: false env: BUILD=sonar - name: "linux - run coveralls" os: linux dist: trusty - sudo: false env: BUILD=coveralls - name: "macosx - mvn verify" os: osx From e735ee0f84268f038a52f62b8a39490db09740ae Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 25 Nov 2018 15:54:42 +0100 Subject: [PATCH 129/139] Dogfood - IdenticalCatchBranches, AvoidFileStream --- .../pmd/lang/apex/ast/AbstractApexNode.java | 5 +--- .../pmd/lang/apex/ast/ApexTreeBuilder.java | 8 ++----- .../java/net/sourceforge/pmd/RuleChain.java | 7 ++---- .../net/sourceforge/pmd/RuleSetFactory.java | 23 +++++-------------- .../net/sourceforge/pmd/ant/Formatter.java | 11 ++------- .../pmd/cpd/CPDCommandLineInterface.java | 6 +---- .../java/net/sourceforge/pmd/cpd/GUI.java | 5 +--- .../sourceforge/pmd/dcd/ClassLoaderUtil.java | 4 +--- .../pmd/renderers/RendererFactory.java | 9 ++++---- .../pmd/renderers/XSLTRenderer.java | 6 +---- .../pmd/util/designer/Designer.java | 12 ++-------- .../AvoidDuplicateLiteralsRule.java | 13 ++++++----- .../ecmascript/ast/EcmascriptTreeBuilder.java | 8 ++----- .../net/sourceforge/pmd/cli/BaseCLITest.java | 8 +++---- .../pmd/testframework/RuleTst.java | 8 ++----- .../fxdesigner/MainDesignerController.java | 4 ++-- .../util/beans/SettingsPersistenceUtil.java | 4 ++-- .../fxdesigner/util/beans/XmlInterface.java | 5 ++-- 18 files changed, 45 insertions(+), 101 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java index bc18a8d05d..a41d152456 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNode.java @@ -44,12 +44,9 @@ public abstract class AbstractApexNode extends AbstractApexNo return loc != null && Locations.isReal(loc); } catch (UnexpectedCodePathException e) { return false; - } catch (IndexOutOfBoundsException e) { + } catch (IndexOutOfBoundsException | NullPointerException e) { // bug in apex-jorje? happens on some ReferenceExpression nodes return false; - } catch (NullPointerException e) { - // bug in apex-jorje? - return false; } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index e55005d186..2aed66191a 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -211,9 +211,7 @@ public final class ApexTreeBuilder extends AstVisitor { private static void register(Class nodeType, Class> nodeAdapterType) { try { NODE_TYPE_TO_NODE_ADAPTER_TYPE.put(nodeType, nodeAdapterType.getConstructor(nodeType)); - } catch (SecurityException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { + } catch (SecurityException | NoSuchMethodException e) { throw new RuntimeException(e); } } @@ -248,9 +246,7 @@ public final class ApexTreeBuilder extends AstVisitor { "There is no Node adapter class registered for the Node class: " + node.getClass()); } return constructor.newInstance(node); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e.getTargetException()); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleChain.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleChain.java index fd86b9b8ae..02541f4b22 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleChain.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleChain.java @@ -74,11 +74,8 @@ public class RuleChain { if (visitor == null) { if (language.getRuleChainVisitorClass() != null) { try { - visitor = (RuleChainVisitor) language.getRuleChainVisitorClass().newInstance(); - } catch (InstantiationException e) { - throw new IllegalStateException( - "Failure to created RuleChainVisitor: " + language.getRuleChainVisitorClass(), e); - } catch (IllegalAccessException e) { + visitor = (RuleChainVisitor) language.getRuleChainVisitorClass().getConstructor().newInstance(); + } catch (ReflectiveOperationException | SecurityException | IllegalArgumentException e) { throw new IllegalStateException( "Failure to created RuleChainVisitor: " + language.getRuleChainVisitorClass(), e); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java index ec47ae5a54..b77a2d17f5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java @@ -380,18 +380,12 @@ public class RuleSetFactory { ruleSetBuilder.filterRulesByPriority(minimumPriority); return ruleSetBuilder.build(); - } catch (ClassNotFoundException cnfe) { - return classNotFoundProblem(cnfe); - } catch (InstantiationException ie) { - return classNotFoundProblem(ie); - } catch (IllegalAccessException iae) { - return classNotFoundProblem(iae); - } catch (ParserConfigurationException pce) { - return classNotFoundProblem(pce); - } catch (IOException ioe) { - return classNotFoundProblem(ioe); - } catch (SAXException se) { - return classNotFoundProblem(se); + } catch (ReflectiveOperationException ex) { + ex.printStackTrace(); + throw new RuntimeException("Couldn't find the class " + ex.getMessage(), ex); + } catch (ParserConfigurationException | IOException | SAXException ex) { + ex.printStackTrace(); + throw new RuntimeException("Couldn't read the ruleset " + ruleSetReferenceId + ": " + ex.getMessage(), ex); } } @@ -432,11 +426,6 @@ public class RuleSetFactory { return dbf.newDocumentBuilder(); } - private static RuleSet classNotFoundProblem(Exception ex) { - ex.printStackTrace(); - throw new RuntimeException("Couldn't find the class " + ex.getMessage()); - } - /** * Parse a rule node. * diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java b/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java index 140de7ef82..8a7e84c8d6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java @@ -13,7 +13,6 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -206,9 +205,7 @@ public class Formatter { if (res instanceof Charset) { return ((Charset) res).name(); } - } catch (NoSuchFieldException ignored) { - // fall-through - } catch (IllegalAccessException ignored) { + } catch (ReflectiveOperationException ignored) { // fall-through } return getNativeConsoleEncoding(); @@ -224,11 +221,7 @@ public class Formatter { if (res instanceof String) { return (String) res; } - } catch (NoSuchMethodException ignored) { - // fall-through - } catch (InvocationTargetException ignored) { - // fall-through - } catch (IllegalAccessException ignored) { + } catch (ReflectiveOperationException ignored) { // fall-through } return null; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java index 5a2f9d80fa..91aaba88df 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java @@ -173,12 +173,8 @@ public final class CPDCommandLineInterface { LOGGER.fine( String.format("Adding DBURI=%s with DBType=%s", dburi.toString(), dburi.getDbType().toString())); cpd.add(dburi); - } catch (IOException e) { + } catch (IOException | URISyntaxException e) { throw new IllegalStateException("uri=" + uri, e); - } catch (URISyntaxException ex) { - throw new IllegalStateException("uri=" + uri, ex); - } catch (Exception ex) { - throw new IllegalStateException("uri=" + uri, ex); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java index c6e7c4727b..7249c19a43 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java @@ -706,10 +706,7 @@ public class GUI implements CPDListener { } else { resultsTextArea.setText(report); } - } catch (IOException t) { - t.printStackTrace(); - JOptionPane.showMessageDialog(frame, "Halted due to " + t.getClass().getName() + "; " + t.getMessage()); - } catch (RuntimeException t) { + } catch (IOException | RuntimeException t) { t.printStackTrace(); JOptionPane.showMessageDialog(frame, "Halted due to " + t.getClass().getName() + "; " + t.getMessage()); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/ClassLoaderUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/ClassLoaderUtil.java index 9534861216..198d907971 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/dcd/ClassLoaderUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/dcd/ClassLoaderUtil.java @@ -31,9 +31,7 @@ public final class ClassLoaderUtil { public static Class getClass(String name) { try { return ClassLoaderUtil.class.getClassLoader().loadClass(name); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } catch (NoClassDefFoundError e) { + } catch (ClassNotFoundException | NoClassDefFoundError e) { throw new RuntimeException(e); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java index 48631ab33f..8c918c2093 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/RendererFactory.java @@ -80,13 +80,12 @@ public final class RendererFactory { } } } - } catch (InstantiationException e) { - throw new IllegalArgumentException("Unable to construct report renderer class: " + e.getLocalizedMessage()); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException("Unable to construct report renderer class: " + e.getLocalizedMessage()); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalArgumentException( + "Unable to construct report renderer class: " + e.getLocalizedMessage(), e); } catch (InvocationTargetException e) { throw new IllegalArgumentException( - "Unable to construct report renderer class: " + e.getTargetException().getLocalizedMessage()); + "Unable to construct report renderer class: " + e.getTargetException().getLocalizedMessage(), e); } // Warn about legacy report format usages if (REPORT_FORMAT_TO_RENDERER.containsKey(reportFormat) && !reportFormat.equals(renderer.getName())) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/XSLTRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/XSLTRenderer.java index 39e32c0de4..7c28598175 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/XSLTRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/XSLTRenderer.java @@ -142,11 +142,7 @@ public class XSLTRenderer extends XMLRenderer { try { DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); return parser.parse(new InputSource(new StringReader(xml))); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (SAXException e) { - e.printStackTrace(); - } catch (IOException e) { + } catch (ParserConfigurationException | SAXException | IOException e) { e.printStackTrace(); } return null; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/designer/Designer.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/designer/Designer.java index c3c683ec44..7d6b0dd3c7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/designer/Designer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/designer/Designer.java @@ -1015,11 +1015,7 @@ public class Designer implements ClipboardOwner { break; } } - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (SAXException e) { + } catch (ParserConfigurationException | IOException | SAXException e) { e.printStackTrace(); } } @@ -1056,11 +1052,7 @@ public class Designer implements ClipboardOwner { Source source = new DOMSource(document); Result result = new StreamResult(new FileWriter(new File(SETTINGS_FILE_NAME))); transformer.transform(source, result); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (TransformerException e) { + } catch (ParserConfigurationException | IOException | TransformerException e) { e.printStackTrace(); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java index 9fde3df4d5..e395d0e501 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidDuplicateLiteralsRule.java @@ -4,12 +4,11 @@ package net.sourceforge.pmd.lang.java.rule.errorprone; -import java.io.BufferedReader; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.IOException; import java.io.LineNumberReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -50,7 +49,8 @@ public class AvoidDuplicateLiteralsRule extends AbstractJavaRule { "Ignore list separator", ',', 4.0f); public static final FileProperty EXCEPTION_FILE_DESCRIPTOR = new FileProperty("exceptionfile", - "File containing strings to skip (one string per line), only used if ignore list is not set", null, 5.0f); + "File containing strings to skip (one string per line), only used if ignore list is not set. " + + "File must be UTF-8 encoded.", null, 5.0f); public static class ExceptionParser { @@ -102,8 +102,9 @@ public class AvoidDuplicateLiteralsRule extends AbstractJavaRule { definePropertyDescriptor(EXCEPTION_FILE_DESCRIPTOR); } - private LineNumberReader getLineReader() throws FileNotFoundException { - return new LineNumberReader(new BufferedReader(new FileReader(getProperty(EXCEPTION_FILE_DESCRIPTOR)))); + private LineNumberReader getLineReader() throws IOException { + return new LineNumberReader(Files.newBufferedReader(getProperty(EXCEPTION_FILE_DESCRIPTOR).toPath(), + StandardCharsets.UTF_8)); } @Override diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptTreeBuilder.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptTreeBuilder.java index 71695bbd32..4dadf80e8c 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptTreeBuilder.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptTreeBuilder.java @@ -145,9 +145,7 @@ public final class EcmascriptTreeBuilder implements NodeVisitor { Class> nodeAdapterType) { try { NODE_TYPE_TO_NODE_ADAPTER_TYPE.put(nodeType, nodeAdapterType.getConstructor(nodeType)); - } catch (SecurityException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { + } catch (SecurityException | NoSuchMethodException e) { throw new RuntimeException(e); } } @@ -164,9 +162,7 @@ public final class EcmascriptTreeBuilder implements NodeVisitor { "There is no Node adapter class registered for the Node class: " + node.getClass()); } return constructor.newInstance(node); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { + } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e.getTargetException()); diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/cli/BaseCLITest.java b/pmd-test/src/main/java/net/sourceforge/pmd/cli/BaseCLITest.java index ef7fd48918..bda1efb911 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/cli/BaseCLITest.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/cli/BaseCLITest.java @@ -8,9 +8,9 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintStream; +import java.nio.file.Files; import org.junit.After; import org.junit.Before; @@ -60,10 +60,10 @@ public abstract class BaseCLITest { protected void createTestOutputFile(String filename) { try { - PrintStream out = new PrintStream(new FileOutputStream(filename)); + PrintStream out = new PrintStream(Files.newOutputStream(new File(filename).toPath())); System.setOut(out); System.setErr(out); - } catch (FileNotFoundException e) { + } catch (IOException e) { fail("Can't create file " + filename + " for test."); } } diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java index 83030f7fe5..e5fe5685ab 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java @@ -334,12 +334,8 @@ public abstract class RuleTst { throw new RuntimeException("Couldn't find " + testXmlFileName); } doc = documentBuilder.parse(inputStream); - } catch (FactoryConfigurationError fce) { - throw new RuntimeException("Couldn't parse " + testXmlFileName + ", due to: " + fce, fce); - } catch (IOException ioe) { - throw new RuntimeException("Couldn't parse " + testXmlFileName + ", due to: " + ioe, ioe); - } catch (SAXException se) { - throw new RuntimeException("Couldn't parse " + testXmlFileName + ", due to: " + se, se); + } catch (FactoryConfigurationError | IOException | SAXException e) { + throw new RuntimeException("Couldn't parse " + testXmlFileName + ", due to: " + e, e); } return parseTests(rule, doc); diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/MainDesignerController.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/MainDesignerController.java index dca8575c5a..2f5f7fcd4b 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/MainDesignerController.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/MainDesignerController.java @@ -5,10 +5,10 @@ package net.sourceforge.pmd.util.fxdesigner; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -356,7 +356,7 @@ public class MainDesignerController implements Initializable, SettingsOwner { private void loadSourceFromFile(File file) { if (file != null) { try { - String source = IOUtils.toString(new FileInputStream(file), StandardCharsets.UTF_8); + String source = IOUtils.toString(Files.newInputStream(file.toPath()), StandardCharsets.UTF_8); sourceEditorController.setText(source); LanguageVersion guess = DesignerUtil.getLanguageVersionFromExtension(file.getName()); if (guess != null) { // guess the language from the extension diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/beans/SettingsPersistenceUtil.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/beans/SettingsPersistenceUtil.java index 22255494dc..beaaaffbac 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/beans/SettingsPersistenceUtil.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/beans/SettingsPersistenceUtil.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.util.fxdesigner.util.beans; import java.beans.PropertyDescriptor; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.ElementType; @@ -14,6 +13,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.InvocationTargetException; +import java.nio.file.Files; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; @@ -92,7 +92,7 @@ public final class SettingsPersistenceUtil { */ private static Optional getDocument(File file) { if (file.exists()) { - try (InputStream stream = new FileInputStream(file)) { + try (InputStream stream = Files.newInputStream(file.toPath())) { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document document = builder.parse(stream); return Optional.of(document); diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/beans/XmlInterface.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/beans/XmlInterface.java index 4667b4386b..53062ede1f 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/beans/XmlInterface.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/beans/XmlInterface.java @@ -5,8 +5,9 @@ package net.sourceforge.pmd.util.fxdesigner.util.beans; import java.io.File; -import java.io.FileWriter; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.Optional; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -109,7 +110,7 @@ public abstract class XmlInterface { Source source = new DOMSource(document); outputFile.getParentFile().mkdirs(); - Result result = new StreamResult(new FileWriter(outputFile)); + Result result = new StreamResult(Files.newBufferedWriter(outputFile.toPath(), StandardCharsets.UTF_8)); transformer.transform(source, result); } catch (TransformerException e) { throw new IOException("Failed to save settings", e); From b87df2203c66b65108ac5be7a3aa95e26cf94b43 Mon Sep 17 00:00:00 2001 From: "Travis CI (pmd-bot)" Date: Sun, 25 Nov 2018 15:22:15 +0000 Subject: [PATCH 130/139] Update documentation TRAVIS_JOB_NUMBER=3106.1 TRAVIS_COMMIT_RANGE=e3ef72cc0654...e735ee0f8426 --- docs/pages/pmd/rules/java/errorprone.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/pmd/rules/java/errorprone.md b/docs/pages/pmd/rules/java/errorprone.md index eefc198ef4..3c13244c37 100644 --- a/docs/pages/pmd/rules/java/errorprone.md +++ b/docs/pages/pmd/rules/java/errorprone.md @@ -381,7 +381,7 @@ private void buz(String x) {} |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|exceptionfile||File containing strings to skip (one string per line), only used if ignore list is not set|no| +|exceptionfile||File containing strings to skip (one string per line), only used if ignore list is not set. File must be UTF-8 encoded.|no| |separator|,|Ignore list separator|no| |exceptionList||Strings to ignore|no| |maxDuplicateLiterals|4|Max duplicate literals|no| From 1344b99f432248daf38a5612d547e404fb225b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 25 Nov 2018 22:34:24 +0100 Subject: [PATCH 131/139] Use Comparable for generic constraint --- .../pmd/properties/constraints/NumericConstraints.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java index 68ee5feafa..f9310baf20 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java @@ -26,19 +26,17 @@ public final class NumericConstraints { /** * Requires the number to be inside a range. - * The int values of the numbers are used so there - * may be some unexpected behaviour with decimal numbers. * * @param Type of number * * @return A range constraint */ - public static PropertyConstraint inRange(final N minInclusive, final N maxInclusive) { + public static > PropertyConstraint inRange(final N minInclusive, final N maxInclusive) { return ConstraintFactory.fromPredicate( new Predicate() { @Override public boolean test(N t) { - return minInclusive.intValue() <= t.intValue() && maxInclusive.intValue() >= t.intValue(); + return minInclusive.compareTo(t) >= 0 && maxInclusive.compareTo(t) <= 0; } }, "Should be between " + minInclusive + " and " + maxInclusive @@ -49,6 +47,9 @@ public final class NumericConstraints { /** * Requires the number to be strictly positive. + * The int values of the number is used for comparison + * so there may be some unexpected behaviour with decimal + * numbers. * * @param Type of number * @@ -64,6 +65,5 @@ public final class NumericConstraints { }, "Should be positive" ); - } } From bf8cb13cced1776f90a30b709b657c928b73471b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 25 Nov 2018 22:37:05 +0100 Subject: [PATCH 132/139] Remove ui order --- .../sourceforge/pmd/properties/PropertyBuilder.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java index 6cddaa50bd..ae106f8e21 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyBuilder.java @@ -37,7 +37,6 @@ public abstract class PropertyBuilder, T> { protected boolean isDefinedExternally; private String name; private String description; - private float uiOrder = 0f; private T defaultValue; @@ -69,12 +68,6 @@ public abstract class PropertyBuilder, T> { } - @Deprecated - float getUiOrder() { - return uiOrder; - } - - T getDefaultValue() { return defaultValue; } @@ -229,7 +222,7 @@ public abstract class PropertyBuilder, T> { return new GenericPropertyDescriptor<>( getName(), getDescription(), - getUiOrder(), + 0f, getDefaultValue(), getConstraints(), parser, @@ -358,7 +351,7 @@ public abstract class PropertyBuilder, T> { return (PropertyDescriptor) new GenericMultiValuePropertyDescriptor<>( getName(), getDescription(), - getUiOrder(), + 0f, getDefaultValue(), getConstraints(), parser, From 202a184366241b1cd9cc5e52d836d685db27e403 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 26 Nov 2018 12:11:18 +0100 Subject: [PATCH 133/139] Remove unnecessary PMD language module for kotlin --- .../pmd/lang/kotlin/KotlinLanguageModule.java | 26 ------------------ .../net.sourceforge.pmd.lang.Language | 1 - .../sourceforge/pmd/LanguageVersionTest.java | 27 ------------------- 3 files changed, 54 deletions(-) delete mode 100644 pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java delete mode 100644 pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language delete mode 100644 pmd-kotlin/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java diff --git a/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java b/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java deleted file mode 100644 index acfa4cbf0d..0000000000 --- a/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/KotlinLanguageModule.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.kotlin; - -import net.sourceforge.pmd.lang.BaseLanguageModule; - -/** - * Language Module for Kotlin - */ -public class KotlinLanguageModule extends BaseLanguageModule { - - /** The name. */ - public static final String NAME = "Kotlin"; - /** The terse name. */ - public static final String TERSE_NAME = "kotlin"; - - /** - * Create a new instance of Kotlin Language Module. - */ - public KotlinLanguageModule() { - super(NAME, null, TERSE_NAME, null, "kt"); - addVersion("1.3", null, true); - } -} diff --git a/pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language b/pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language deleted file mode 100644 index 78c4e9b40d..0000000000 --- a/pmd-kotlin/src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language +++ /dev/null @@ -1 +0,0 @@ -net.sourceforge.pmd.lang.kotlin.KotlinLanguageModule diff --git a/pmd-kotlin/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java b/pmd-kotlin/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java deleted file mode 100644 index a60ae63ecc..0000000000 --- a/pmd-kotlin/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import java.util.Arrays; -import java.util.Collection; - -import org.junit.runners.Parameterized.Parameters; - -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.kotlin.KotlinLanguageModule; - -public class LanguageVersionTest extends AbstractLanguageVersionTest { - - public LanguageVersionTest(String name, String terseName, String version, LanguageVersion expected) { - super(name, terseName, version, expected); - } - - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] { { KotlinLanguageModule.NAME, KotlinLanguageModule.TERSE_NAME, "1.3", - LanguageRegistry.getLanguage(KotlinLanguageModule.NAME).getDefaultVersion(), }, }); - } -} From 1cd90c66ecfa2eba27e5c16f980d8a75b9f946b4 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 26 Nov 2018 12:27:46 +0100 Subject: [PATCH 134/139] Update release notes, refs #1441 --- docs/pages/release_notes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 35e8909643..8eb38a34d9 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,6 +14,11 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### Kotlin support for CPD + +Thanks to [Maikel Steneker](https://github.com/maikelsteneker), CPD now supports [Kotlin](https://kotlinlang.org/). +This means, you can use CPD to find duplicated code in your Kotlin projects. + #### New Rules * The new Java rule {% rule "java/codestyle/UseUnderscoresInNumericLiterals" %} (`java-codestyle`) @@ -37,6 +42,7 @@ This is a {{ site.pmd.release_type }} release. * [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007) * [#1428](https://github.com/pmd/pmd/pull/1428): \[core] Upgrading JCommander from 1.48 to 1.72 - [Thunderforge](https://github.com/Thunderforge) * [#1430](https://github.com/pmd/pmd/pull/1430): \[doc] Who really knows regex? - [Dem Pilafian](https://github.com/dpilafian) +* [#1441](https://github.com/pmd/pmd/pull/1441): \[kotlin] [cpd] Added CPD support for Kotlin - [Maikel Steneker](https://github.com/maikelsteneker) {% endtocmaker %} From 167560328613db6ddf6d4a10f47a15c3ac62e966 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 26 Nov 2018 19:11:14 +0100 Subject: [PATCH 135/139] Update release notes, refs #1469 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 8b3fee5092..df621ab1f6 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -50,6 +50,7 @@ This is a {{ site.pmd.release_type }} release. * [#1430](https://github.com/pmd/pmd/pull/1430): \[doc] Who really knows regex? - [Dem Pilafian](https://github.com/dpilafian) * [#1434](https://github.com/pmd/pmd/pull/1434): \[java] JUnitTestsShouldIncludeAssert: Recognize AssertJ soft assertions as valid assert statements - [Loïc Ledoyen](https://github.com/ledoyen) * [#1464](https://github.com/pmd/pmd/pull/1464): \[doc] Fix XSS on documentation web page - [Maxime Robert](https://github.com/marob) +* [#1469](https://github.com/pmd/pmd/pull/1469): \[core] Configurable max loops in DAAPathFinder - [Alberto Fernández](https://github.com/albfernandez) {% endtocmaker %} From dedc68424ff3b171f736d66ef368d7b12bd80300 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 26 Nov 2018 19:51:26 +0100 Subject: [PATCH 136/139] Fix build - apparently the eclipse compiler needs some generic support Fix inRange property constraint --- .../constraints/ConstraintFactory.java | 2 +- .../constraints/NumericConstraints.java | 2 +- .../constraints/NumericConstraintsTest.java | 51 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/properties/constraints/NumericConstraintsTest.java diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java index 4aa0b5adc2..97f9f02e15 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/ConstraintFactory.java @@ -62,7 +62,7 @@ final class ConstraintFactory { @Override public PropertyConstraint> toCollectionConstraint() { final PropertyConstraint thisValidator = this; - return fromPredicate( + return ConstraintFactory.>fromPredicate( new Predicate>() { @Override public boolean test(Iterable us) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java index f9310baf20..4f8e8f0133 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/constraints/NumericConstraints.java @@ -36,7 +36,7 @@ public final class NumericConstraints { new Predicate() { @Override public boolean test(N t) { - return minInclusive.compareTo(t) >= 0 && maxInclusive.compareTo(t) <= 0; + return minInclusive.compareTo(t) <= 0 && maxInclusive.compareTo(t) >= 0; } }, "Should be between " + minInclusive + " and " + maxInclusive diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/constraints/NumericConstraintsTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/constraints/NumericConstraintsTest.java new file mode 100644 index 0000000000..a891a2c91a --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/constraints/NumericConstraintsTest.java @@ -0,0 +1,51 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.properties.constraints; + +import org.junit.Assert; +import org.junit.Test; + +public class NumericConstraintsTest { + + @Test + public void testInRangeInteger() { + PropertyConstraint constraint = NumericConstraints.inRange(1, 10); + Assert.assertTrue(constraint.test(1)); + Assert.assertTrue(constraint.test(5)); + Assert.assertTrue(constraint.test(10)); + Assert.assertFalse(constraint.test(0)); + Assert.assertFalse(constraint.test(-1)); + Assert.assertFalse(constraint.test(11)); + Assert.assertFalse(constraint.test(100)); + } + + @Test + public void testInRangeDouble() { + PropertyConstraint constraint = NumericConstraints.inRange(1.0, 10.0); + Assert.assertTrue(constraint.test(1.0)); + Assert.assertTrue(constraint.test(5.5)); + Assert.assertTrue(constraint.test(10.0)); + Assert.assertFalse(constraint.test(0.0)); + Assert.assertFalse(constraint.test(-1.0)); + Assert.assertFalse(constraint.test(11.1)); + Assert.assertFalse(constraint.test(100.0)); + } + + @Test + public void testPositive() { + PropertyConstraint constraint = NumericConstraints.positive(); + Assert.assertTrue(constraint.test(1)); + Assert.assertTrue(constraint.test(1.5f)); + Assert.assertTrue(constraint.test(1.5d)); + Assert.assertTrue(constraint.test(100)); + Assert.assertFalse(constraint.test(0)); + Assert.assertFalse(constraint.test(0.1f)); + Assert.assertFalse(constraint.test(0.9d)); + Assert.assertFalse(constraint.test(-1)); + Assert.assertFalse(constraint.test(-100)); + Assert.assertFalse(constraint.test(-0.1f)); + Assert.assertFalse(constraint.test(-0.1d)); + } +} From baf5c316d31d408b7092e89d169a04ada21c09ce Mon Sep 17 00:00:00 2001 From: "Travis CI (pmd-bot)" Date: Mon, 26 Nov 2018 19:14:36 +0000 Subject: [PATCH 137/139] Update documentation TRAVIS_JOB_NUMBER=3112.1 TRAVIS_COMMIT_RANGE=54c9f2e2a453...dedc68424ff3 --- docs/pages/pmd/rules/apex/design.md | 2 +- docs/pages/pmd/rules/java/codestyle.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/pmd/rules/apex/design.md b/docs/pages/pmd/rules/apex/design.md index a932f5aa0f..5a82766001 100644 --- a/docs/pages/pmd/rules/apex/design.md +++ b/docs/pages/pmd/rules/apex/design.md @@ -104,11 +104,11 @@ public class Complicated { |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|methodReportLevel|10|Cyclomatic complexity reporting threshold|no| |cc\_categories|Style|Code Climate Categories|yes. Delimiter is '\|'.| |cc\_remediation\_points\_multiplier|1|Code Climate Remediation Points multiplier|no| |cc\_block\_highlighting|false|Code Climate Block Highlighting|no| |classReportLevel|40|Total class complexity reporting threshold|no| +|methodReportLevel|10|Cyclomatic complexity reporting threshold|no| **Use this rule by referencing it:** ``` xml diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index fa2b23d8ce..7808bc0fc2 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -808,7 +808,7 @@ class Foo { |finalFieldPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to final field names|no| |staticFieldPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to static field names|no| |defaultFieldPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to field names|no| -|exclusions|serialVersionUID|Names of fields to whitelist.|yes. Delimiter is '\|'.| +|exclusions|serialVersionUID|Names of fields to whitelist.|yes. Delimiter is ''.| **Use this rule by referencing it:** ``` xml From 68cd02967206d07f8566589cf133c10051fd4d88 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 26 Nov 2018 20:11:38 +0100 Subject: [PATCH 138/139] Add default delimiter for multi/list properties --- .../net/sourceforge/pmd/properties/PropertyFactory.java | 6 +++--- .../lang/java/rule/codestyle/xml/FieldNamingConventions.xml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java index 723e5f4ed2..b76e7321d0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertyFactory.java @@ -34,7 +34,7 @@ public final class PropertyFactory { public static GenericCollectionPropertyBuilder> intListProperty(String name) { - return intProperty(name).toList(); + return intProperty(name).toList().delim(MultiValuePropertyDescriptor.DEFAULT_NUMERIC_DELIMITER); } @@ -44,7 +44,7 @@ public final class PropertyFactory { public static GenericCollectionPropertyBuilder> doubleListProperty(String name) { - return doubleProperty(name).toList(); + return doubleProperty(name).toList().delim(MultiValuePropertyDescriptor.DEFAULT_NUMERIC_DELIMITER); } @@ -54,7 +54,7 @@ public final class PropertyFactory { public static GenericCollectionPropertyBuilder> stringListProperty(String name) { - return stringProperty(name).toList(); + return stringProperty(name).toList().delim(MultiValuePropertyDescriptor.DEFAULT_DELIMITER); } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldNamingConventions.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldNamingConventions.xml index a6d343bcb6..6f17f54b5e 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldNamingConventions.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldNamingConventions.xml @@ -195,11 +195,11 @@ More exclusions can be configured - m$mangled + m$mangled|serialVersionUID 0 Date: Mon, 26 Nov 2018 19:39:18 +0000 Subject: [PATCH 139/139] Update documentation TRAVIS_JOB_NUMBER=3114.1 TRAVIS_COMMIT_RANGE=baf5c316d31d...68cd02967206 --- docs/pages/pmd/rules/java/codestyle.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index 7808bc0fc2..fa2b23d8ce 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -808,7 +808,7 @@ class Foo { |finalFieldPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to final field names|no| |staticFieldPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to static field names|no| |defaultFieldPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to field names|no| -|exclusions|serialVersionUID|Names of fields to whitelist.|yes. Delimiter is ''.| +|exclusions|serialVersionUID|Names of fields to whitelist.|yes. Delimiter is '\|'.| **Use this rule by referencing it:** ``` xml