diff --git a/docs/pages/7_0_0_release_notes.md b/docs/pages/7_0_0_release_notes.md index 85049d180b..ca506e93fa 100644 --- a/docs/pages/7_0_0_release_notes.md +++ b/docs/pages/7_0_0_release_notes.md @@ -40,6 +40,12 @@ Given the full Antlr support, PMD now fully supports Swift. We are pleased to an * {% rule "swift/bestpractices/UnavailableFunction" %} (`swift-bestpractices`) flags any function throwing a `fatalError` not marked as `@available(*, unavailable)` to ensure no calls are actually performed in the codebase. +#### XPath 3.1 support + +Support for XPath versions 1.0, 1.0-compatibility was removed, support for XPath 2.0 is deprecated. The default (and only) supported XPath version is now XPath 3.1. This version of the XPath language is mostly identical to XPath 2.0. Notable changes: + * The deprecated support for sequence-valued attributes is removed. Sequence-valued properties are still supported. + * Refer to [the Saxonica documentation](https://www.saxonica.com/html/documentation/expressions/xpath31new.html) for an introduction to new features in XPath 3.1. + #### Removed Rules The following previously deprecated rules have been finally removed: @@ -74,6 +80,11 @@ The following previously deprecated rules have been finally removed: The corresponding classes in packages `java.net.sourceforge.pmd.util.viewer` and `java.net.sourceforge.pmd.util.designer` have all been removed. +* All API related to XPath support has been moved to the package {% jdoc_package core::lang.rule.xpath %}. + This includes API that was previously dispersed over `net.sourceforge.pmd.lang`, `net.sourceforge.pmd.lang.ast.xpath`, + `net.sourceforge.pmd.lang.rule.xpath`, `net.sourceforge.pmd.lang.rule`, and various language-specific packages + (which were made internal). + #### Metrics framework * {% jdoc_old !!core::lang.metrics.MetricKeyUtil#of(java.lang.String, core::lang.metrics.Metric) %} is replaced with {% jdoc_old !!core::lang.metrics.MetricKey#of(java.lang.String, core::lang.metrics.Metric) %} diff --git a/docs/pages/pmd/userdocs/cli_reference.md b/docs/pages/pmd/userdocs/cli_reference.md index 743f5c3a15..2e6350ebc8 100644 --- a/docs/pages/pmd/userdocs/cli_reference.md +++ b/docs/pages/pmd/userdocs/cli_reference.md @@ -185,7 +185,7 @@ Example: * [apex](pmd_rules_apex.html) (Salesforce Apex) * [java](pmd_rules_java.html) * Supported Versions: 1.3, 1.4, 1.5, 5, 1.6, 6, 1.7, 7, 1.8, 8, 9, 1.9, 10, 1.10, 11, 12, - 13, 13-preview, 14 (default), 14-preview + 13, 14, 14-preview, 15 (default), 15-preview * [ecmascript](pmd_rules_ecmascript.html) (JavaScript) * [jsp](pmd_rules_jsp.html) * [modelica](pmd_rules_modelica.html) diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index 5b8f886623..68b7fe404b 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -21,23 +21,11 @@ also [the tutorial about how to write an XPath rule](pmd_userdocs_extending_your ## XPath version -PMD supports three XPath versions for now: 1.0, 2.0, and 1.0 compatibility mode. -The version can be specified with the `version` property in the rule definition, like so: +PMD uses XPath 3.1 for its XPath rules since PMD 7. Before then, the default version was XPath 1.0, with opt-in support for XPath 2.0. -```xml - -``` +See [the Saxonica documentation](https://www.saxonica.com/html/documentation/expressions/xpath31new.html) for an introduction to new features in XPath 3.1. -The default has always been version 1.0. - -**As of PMD version 6.22.0, XPath versions 1.0 and the 1.0 compatibility mode are -deprecated**. XPath 2.0 is superior in many ways, for example for its support for -type checking, sequence values, or quantified expressions. For a detailed -but approachable review of the features of XPath 2.0 and above, see [the Saxon documentation](https://www.saxonica.com/documentation/index.html#!expressions). - -It is recommended that you migrate to 2.0 before 7.0.0, but we expect -to be able to provide an automatic migration tool when releasing 7.0.0. -See [the migration guide](#migrating-from-10-to-20) below. +The property `version` of XPathRule is deprecated and will be removed. ## DOM representation of ASTs @@ -54,21 +42,7 @@ defined on. Concretely, this means: ### Value conversion -To represent attributes, we must map Java values to [XPath Data Model (XDM)](https://www.w3.org/TR/xpath-datamodel/) values. The conversion -depends on the XPath version used. - -#### XPath 1.0 - -On XPath 1.0 we map every Java value to an `xs:string` value by using the `toString` -of the object. Since XPath 1.0 allows many implicit conversions this works, but it -causes some incompatibilities with XPath 2.0 (see the section about migration further - down). - -#### XPath 2.0 - -XPath 2.0 is a strongly typed language, and so we use more precise type annotations. -In the following table we refer to the type conversion function as `conv`, a -function from Java types to XDM types. +To represent attributes, we must map Java values to [XPath Data Model (XDM)](https://www.w3.org/TR/xpath-datamodel/) values. In the following table we refer to the type conversion function as `conv`, a function from Java types to XDM types. | Java type `T` | XSD type `conv(T)` |-----------------|---------------------| @@ -80,22 +54,18 @@ function from Java types to XDM types. |`String` | `xs:string` |`Character` | `xs:string` |`Enum` | `xs:string` (uses `Object::toString`) -|`List` | `conv(E)*` (a sequence type)
⚠️ List support is deprecated with 6.25.0. See below. +|`List` | `conv(E)*` (a sequence type) The same `conv` function is used to translate rule property values to XDM values. -{% include warning.html content="Support for attributes of type `List` has been deprecated -with PMD 6.25.0 and will be removed completely with PMD 7. The reason is that newer Saxon -versions don't support sequences as attributes anymore. Lists are still possible in Java-based -rules but not with XPath. - -[Multivalued rule properties](pmd_userdocs_extending_defining_properties.html#multivalued-properties) -are still supported." %} +{% include warning.html content="Lists are only supported for rule properties, not attributes." %} ## Migrating from 1.0 to 2.0 + + XPath 1.0 and 2.0 have some incompatibilities. The [XPath 2.0 specification](https://www.w3.org/TR/xpath20/#id-incompat-in-false-mode) describes them precisely. Those are however mostly corner cases and XPath rules usually don't feature any of them. diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index be11faf83e..e157a33f71 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -19,6 +19,24 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### Java 15 Support + +This release of PMD brings support for Java 15. PMD can parse [Text Blocks](https://openjdk.java.net/jeps/378) +which have been promoted to be a standard language feature of Java. + +PMD also supports [Pattern Matching for instanceof](https://openjdk.java.net/jeps/375), +[Records](https://openjdk.java.net/jeps/384), and [Sealed Classes](https://openjdk.java.net/jeps/360). + +Note: The Pattern Matching for instanceof, Records, and Sealed Classes are all preview language features of OpenJDK 15 +and are not enabled by default. In order to +analyze a project with PMD that uses these language features, you'll need to enable it via the environment +variable `PMD_JAVA_OPTS` and select the new language version `15-preview`: + + export PMD_JAVA_OPTS=--enable-preview + ./run.sh pmd -language java -version 15-preview ... + +Note: Support for Java 13 preview language features have been removed. The version "13-preview" is no longer available. + #### Changes in how tab characters are handled In the past, tab characters in source files has been handled differently in different languages by PMD. @@ -65,6 +83,8 @@ See also [[all] Ensure PMD/CPD uses tab width of 1 for tabs consistently #2656]( * [#2653](https://github.com/pmd/pmd/issues/2653): \[lang-test] Upgrade kotlintest to Kotest * [#2656](https://github.com/pmd/pmd/pull/2656): \[all] Ensure PMD/CPD uses tab width of 1 for tabs consistently * [#2690](https://github.com/pmd/pmd/pull/2690): \[core] Fix java7 compatibility +* java + * [#2646](https://github.com/pmd/pmd/issues/2646): \[java] Support JDK 15 * java-bestpractices * [#2471](https://github.com/pmd/pmd/issues/2471): \[java] New Rule: AvoidReassigningCatchVariables * [#2663](https://github.com/pmd/pmd/issues/2663): \[java] NoClassDefFoundError on upgrade from 6.25.0 to 6.26.0 @@ -73,6 +93,7 @@ See also [[all] Ensure PMD/CPD uses tab width of 1 for tabs consistently #2656]( * [#2684](https://github.com/pmd/pmd/issues/2684): \[java] UnusedAssignment FP in try/catch * [#2686](https://github.com/pmd/pmd/issues/2686): \[java] UnusedAssignment must not flag abstract method parameters in interfaces and abstract classes * java-design + * [#2108](https://github.com/pmd/pmd/issues/2108): \[java] \[doc] ImmutableField rule: Description should clarify shallow immutability * [#2461](https://github.com/pmd/pmd/issues/2461): \[java] ExcessiveParameterListRule must ignore a private constructor * java-errorprone * [#2410](https://github.com/pmd/pmd/issues/2410): \[java] ProperCloneImplementation not valid for final class @@ -99,7 +120,7 @@ See also [[all] Ensure PMD/CPD uses tab width of 1 for tabs consistently #2656]( * {% jdoc !!core::Rule#getParserOptions() %} * {% jdoc !!core::lang.Parser#getParserOptions() %} -* {% jdoc !!core::lang.AbstractParser %} +* {% jdoc core::lang.AbstractParser %} * {% jdoc !!core::RuleContext#removeAttribute(java.lang.String) %} * {% jdoc !!core::RuleContext#getAttribute(java.lang.String) %} * {% jdoc !!core::RuleContext#setAttribute(java.lang.String, java.lang.Object) %} @@ -124,7 +145,21 @@ See also [[all] Ensure PMD/CPD uses tab width of 1 for tabs consistently #2656]( * {% jdoc_package core::lang.dfa %} * and the class {% jdoc plsql::lang.plsql.PLSQLDataFlowHandler %} -* {% jdoc !!visualforce::lang.vf.VfSimpleCharStream %} +* {% jdoc visualforce::lang.vf.VfSimpleCharStream %} + +* {% jdoc jsp::lang.jsp.ast.ASTJspDeclarations %} +* {% jdoc jsp::lang.jsp.ast.ASTJspDocument %} +* {% jdoc !!scala::lang.scala.ast.ScalaParserVisitorAdapter#zero() %} +* {% jdoc !!scala::lang.scala.ast.ScalaParserVisitorAdapter#combine(Object, Object) %} +* {% jdoc apex::lang.apex.ast.ApexParserVisitorReducedAdapter %} +* {% jdoc java::lang.java.ast.JavaParserVisitorReducedAdapter %} + +* {% jdoc java::lang.java.typeresolution.TypeHelper %} is deprecated in + favor of {% jdoc java::lang.java.types.TypeTestUtil %}, which has the +same functionality, but a slightly changed API. +* Many of the classes in {% jdoc_package java::lang.java.symboltable %} +are deprecated as internal API. + ### External Contributions @@ -140,6 +175,7 @@ See also [[all] Ensure PMD/CPD uses tab width of 1 for tabs consistently #2656]( * [#2697](https://github.com/pmd/pmd/pull/2697): \[java] ExcessiveParameterListRule must ignore a private constructor - [Mykhailo Palahuta](https://github.com/Drofff) * [#2699](https://github.com/pmd/pmd/pull/2699): \[java] ProperCloneImplementation not valid for final class - [Mykhailo Palahuta](https://github.com/Drofff) * [#2700](https://github.com/pmd/pmd/pull/2700): \[java] Fix OnlyOneReturn code example - [Jan-Lukas Else](https://github.com/jlelse) +* [#2722](https://github.com/pmd/pmd/pull/2722): \[doc] \[java] ImmutableField: extend description, fixes #2108 - [Mateusz Stefanski](https://github.com/mateusz-stefanski) {% endtocmaker %} diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index e9d667118e..d472d488a9 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -7219,7 +7219,7 @@ The binary package still contains all languages and can be used as usual. Have a Added - net.sourceforge.pmd.lang.LanguageVersion Added - net.sourceforge.pmd.lang.LanguageVersionDiscoverer Added - net.sourceforge.pmd.lang.LanguageVersionHandler - Added - net.sourceforge.pmd.lang.XPathHandler + Added - net.sourceforge.pmd.lang.rule.xpath.XPathHandler Added - net.sourceforge.pmd.lang.ast.xpath.AbstractASTXPathHandler Added - net.sourceforge.pmd.lang.xpath.Initializer Added - net.sourceforge.pmd.lang.ast.AbstractTokenManager @@ -7253,7 +7253,7 @@ The binary package still contains all languages and can be used as usual. Have a Renamed - net.sourceforge.pmd.stat.StatisticalRule to net.sourceforge.pmd.lang.rule.StatisticalRuleHelper Renamed - net.sourceforge.pmd.jaxen.TypeOfFunction to net.sourceforge.pmd.lang.java.xpath.TypeOfFunction Renamed - net.sourceforge.pmd.jaxen.MatchesFunction to net.sourceforge.pmd.lang.xpath.MatchesFunction - Renamed - net.sourceforge.pmd.jaxen.Attribute to net.sourceforge.pmd.lang.ast.xpath.Attribute + Renamed - net.sourceforge.pmd.jaxen.Attribute to net.sourceforge.pmd.lang.rule.xpath.Attribute Renamed - net.sourceforge.pmd.jaxen.AttributeAxisIterator to net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator Renamed - net.sourceforge.pmd.jaxen.DocumentNavigator to net.sourceforge.pmd.lang.ast.xpath.DocumentNavigator Renamed - net.sourceforge.pmd.jaxen.NodeIterator to net.sourceforge.pmd.lang.ast.xpath.NodeIterator diff --git a/javacc-wrapper.xml b/javacc-wrapper.xml index e340703084..f0e14fa6c7 100644 --- a/javacc-wrapper.xml +++ b/javacc-wrapper.xml @@ -479,10 +479,10 @@ public interface" /> - + + token="default Object visit(${node-name} node, Object data) { return visit${node-name}(node, data); }" + value="default Object visit${node-name}(${node-name} node, Object data) { for (int i = 0, len = node.getNumChildren(); i < len; i++) node.getChild(i).jjtAccept(this, data); return data; }"> @@ -497,7 +497,8 @@ public interface" /> - + 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 44ce1f2da1..a83622301c 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 @@ -12,8 +12,9 @@ public final class ASTAnnotation extends AbstractApexNode { super(annotation); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnnotationParameter.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnnotationParameter.java index e0f9f3be04..d06310df33 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnnotationParameter.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnnotationParameter.java @@ -13,8 +13,9 @@ public final class ASTAnnotationParameter extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnonymousClass.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnonymousClass.java index 4fe41057f0..1f700a7ba0 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnonymousClass.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAnonymousClass.java @@ -12,8 +12,9 @@ public final class ASTAnonymousClass extends AbstractApexNode { super(anonymousClass); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTApexFile.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTApexFile.java index 60a36dc523..315f746c7c 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTApexFile.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTApexFile.java @@ -51,8 +51,9 @@ public final class ASTApexFile extends AbstractApexNode implements Root return this; } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTArrayLoadExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTArrayLoadExpression.java index 2210b80ef0..92e6f3c8fe 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTArrayLoadExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTArrayLoadExpression.java @@ -12,8 +12,9 @@ public final class ASTArrayLoadExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTArrayStoreExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTArrayStoreExpression.java index 0095b44c0f..8ce5055555 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTArrayStoreExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTArrayStoreExpression.java @@ -12,8 +12,9 @@ public final class ASTArrayStoreExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAssignmentExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAssignmentExpression.java index 06a1b678e5..35563f7967 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAssignmentExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTAssignmentExpression.java @@ -13,8 +13,9 @@ public final class ASTAssignmentExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBinaryExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBinaryExpression.java index b0e1ea17fa..05cd60d30c 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBinaryExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBinaryExpression.java @@ -13,8 +13,9 @@ public final class ASTBinaryExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBindExpressions.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBindExpressions.java index 3cf24f5961..91e1d4f83f 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBindExpressions.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBindExpressions.java @@ -12,8 +12,9 @@ public final class ASTBindExpressions extends AbstractApexNode super(bindExpressions); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBlockStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBlockStatement.java index 602b0daa93..28e5a6d0cb 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBlockStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBlockStatement.java @@ -13,8 +13,9 @@ public final class ASTBlockStatement extends AbstractApexNode { super(blockStatement); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBooleanExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBooleanExpression.java index 39f0de59c5..e38030c72e 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBooleanExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBooleanExpression.java @@ -15,8 +15,9 @@ public final class ASTBooleanExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBreakStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBreakStatement.java index 00403caab5..9090c93b83 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBreakStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBreakStatement.java @@ -12,8 +12,9 @@ public final class ASTBreakStatement extends AbstractApexNode { super(breakStatement); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBridgeMethodCreator.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBridgeMethodCreator.java index ae5873c5cb..b6beacaa9d 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBridgeMethodCreator.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBridgeMethodCreator.java @@ -12,8 +12,9 @@ public final class ASTBridgeMethodCreator extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTCastExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTCastExpression.java index d1e77374f3..73ad77971d 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTCastExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTCastExpression.java @@ -12,8 +12,9 @@ public final class ASTCastExpression extends AbstractApexNode { super(node); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTCatchBlockStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTCatchBlockStatement.java index ef90488a5c..f880d83f3f 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTCatchBlockStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTCatchBlockStatement.java @@ -12,8 +12,9 @@ public final class ASTCatchBlockStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTClassRefExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTClassRefExpression.java index a4ef9c2cfa..e4e0bb3857 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTClassRefExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTClassRefExpression.java @@ -12,8 +12,9 @@ public final class ASTClassRefExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTConstructorPreamble.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTConstructorPreamble.java index b4aa92d69f..9a09657ed8 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTConstructorPreamble.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTConstructorPreamble.java @@ -12,8 +12,9 @@ public final class ASTConstructorPreamble extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTConstructorPreambleStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTConstructorPreambleStatement.java index c2cf6da3b8..0bca699653 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTConstructorPreambleStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTConstructorPreambleStatement.java @@ -12,8 +12,9 @@ public final class ASTConstructorPreambleStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTContinueStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTContinueStatement.java index ccd9678c2e..9af8ede32f 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTContinueStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTContinueStatement.java @@ -12,8 +12,9 @@ public final class ASTContinueStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlDeleteStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlDeleteStatement.java index 9b7915b62d..8bdadaa995 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlDeleteStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlDeleteStatement.java @@ -12,8 +12,9 @@ public final class ASTDmlDeleteStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlInsertStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlInsertStatement.java index 1ca21bf64d..97bdbc753e 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlInsertStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlInsertStatement.java @@ -12,8 +12,9 @@ public final class ASTDmlInsertStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlMergeStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlMergeStatement.java index c10b3fde78..b2bcc98732 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlMergeStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlMergeStatement.java @@ -12,8 +12,9 @@ public final class ASTDmlMergeStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUndeleteStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUndeleteStatement.java index 78d05fd29c..33520cc4fd 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUndeleteStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUndeleteStatement.java @@ -12,8 +12,9 @@ public final class ASTDmlUndeleteStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUpdateStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUpdateStatement.java index 53f14d833d..45ab8de03b 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUpdateStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUpdateStatement.java @@ -12,8 +12,9 @@ public final class ASTDmlUpdateStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUpsertStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUpsertStatement.java index 9b7a077c7f..b240fd7ea6 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUpsertStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDmlUpsertStatement.java @@ -12,8 +12,9 @@ public final class ASTDmlUpsertStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDoLoopStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDoLoopStatement.java index 18884f5b20..9e679cc4eb 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDoLoopStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTDoLoopStatement.java @@ -12,8 +12,9 @@ public final class ASTDoLoopStatement extends AbstractApexNode super(doLoopStatement); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTElseWhenBlock.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTElseWhenBlock.java index 4280a35355..b3a760ff89 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTElseWhenBlock.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTElseWhenBlock.java @@ -14,8 +14,9 @@ public final class ASTElseWhenBlock extends AbstractApexNode { } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTEmptyReferenceExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTEmptyReferenceExpression.java index 39ca6a6dd7..70b5f9eeb5 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTEmptyReferenceExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTEmptyReferenceExpression.java @@ -14,8 +14,9 @@ public final class ASTEmptyReferenceExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTExpression.java index 6803d8051b..eda90dfdf5 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTExpression.java @@ -12,8 +12,9 @@ public final class ASTExpression extends AbstractApexNode { super(expression); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTExpressionStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTExpressionStatement.java index ec3b32fee1..00b224ce64 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTExpressionStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTExpressionStatement.java @@ -12,8 +12,9 @@ public final class ASTExpressionStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTField.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTField.java index b6ba5286b9..e9bcfb717b 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTField.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTField.java @@ -12,8 +12,9 @@ public final class ASTField extends AbstractApexNode { super(field); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFieldDeclaration.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFieldDeclaration.java index e384d5e76a..c743b091b9 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFieldDeclaration.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFieldDeclaration.java @@ -12,8 +12,9 @@ public final class ASTFieldDeclaration extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFieldDeclarationStatements.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFieldDeclarationStatements.java index 463b74ca15..d97211d506 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFieldDeclarationStatements.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFieldDeclarationStatements.java @@ -20,8 +20,9 @@ public final class ASTFieldDeclarationStatements extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTForEachStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTForEachStatement.java index c85e497a99..cfd11facfd 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTForEachStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTForEachStatement.java @@ -12,8 +12,9 @@ public final class ASTForEachStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTForLoopStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTForLoopStatement.java index dce413e897..8f5e0eb81c 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTForLoopStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTForLoopStatement.java @@ -12,8 +12,9 @@ public final class ASTForLoopStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFormalComment.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFormalComment.java index 9fa419dc09..99cc7fa7f3 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFormalComment.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTFormalComment.java @@ -35,8 +35,9 @@ public final class ASTFormalComment extends AbstractApexNode { image = token; } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIdentifierCase.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIdentifierCase.java index dfd45cf184..7b6d8452a1 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIdentifierCase.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIdentifierCase.java @@ -14,8 +14,9 @@ public final class ASTIdentifierCase extends AbstractApexNode { } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfBlockStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfBlockStatement.java index 696de8314d..bb0daf7a68 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfBlockStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfBlockStatement.java @@ -12,8 +12,9 @@ public final class ASTIfBlockStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfElseBlockStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfElseBlockStatement.java index 12b9a39575..785dcfa7b0 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfElseBlockStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIfElseBlockStatement.java @@ -12,8 +12,9 @@ public final class ASTIfElseBlockStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIllegalStoreExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIllegalStoreExpression.java index a700b66cba..b0c1613bbb 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIllegalStoreExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIllegalStoreExpression.java @@ -12,8 +12,9 @@ public final class ASTIllegalStoreExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTInstanceOfExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTInstanceOfExpression.java index 909399734b..8c97871aca 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTInstanceOfExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTInstanceOfExpression.java @@ -12,8 +12,9 @@ public final class ASTInstanceOfExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTJavaMethodCallExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTJavaMethodCallExpression.java index b8fc594ef9..853d6f7822 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTJavaMethodCallExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTJavaMethodCallExpression.java @@ -12,8 +12,9 @@ public final class ASTJavaMethodCallExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTJavaVariableExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTJavaVariableExpression.java index d0bced4354..6d9f5a8902 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTJavaVariableExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTJavaVariableExpression.java @@ -12,8 +12,9 @@ public final class ASTJavaVariableExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralCase.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralCase.java index fc97e4bf9f..1873643e14 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralCase.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralCase.java @@ -14,8 +14,9 @@ public final class ASTLiteralCase extends AbstractApexNode { } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralExpression.java index ec970d6815..6513d0354e 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralExpression.java @@ -20,8 +20,9 @@ public final class ASTLiteralExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMapEntryNode.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMapEntryNode.java index d083227b71..306f74d40b 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMapEntryNode.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMapEntryNode.java @@ -12,8 +12,9 @@ public final class ASTMapEntryNode extends AbstractApexNode { super(mapEntryNode); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethod.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethod.java index 23f3f998b3..a781dc9fdd 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethod.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethod.java @@ -17,8 +17,9 @@ public final class ASTMethod extends AbstractApexNode implements ApexQua super(method); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodBlockStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodBlockStatement.java index 67ed3e3345..c180f6c3db 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodBlockStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodBlockStatement.java @@ -12,8 +12,9 @@ public final class ASTMethodBlockStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodCallExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodCallExpression.java index 7df2288128..ffe96cf907 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodCallExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethodCallExpression.java @@ -15,8 +15,9 @@ public final class ASTMethodCallExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifier.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifier.java index 26d2214d94..e898b9f5cc 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifier.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifier.java @@ -12,8 +12,9 @@ public final class ASTModifier extends AbstractApexNode { super(node); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierNode.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierNode.java index 8b051a3ee5..19a42c37c6 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierNode.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierNode.java @@ -13,8 +13,9 @@ public final class ASTModifierNode extends AbstractApexNode implem super(modifierNode); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierOrAnnotation.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierOrAnnotation.java index 73fa244bb3..612838d19f 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierOrAnnotation.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierOrAnnotation.java @@ -12,8 +12,9 @@ public final class ASTModifierOrAnnotation extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMultiStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMultiStatement.java index 926138ecec..28d8e73b92 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMultiStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMultiStatement.java @@ -12,8 +12,9 @@ public final class ASTMultiStatement extends AbstractApexNode { super(node); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNestedExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNestedExpression.java index 5b7511e479..7a1097d587 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNestedExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNestedExpression.java @@ -12,8 +12,9 @@ public final class ASTNestedExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNestedStoreExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNestedStoreExpression.java index 17021f8473..eea7eb98c0 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNestedStoreExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNestedStoreExpression.java @@ -12,8 +12,9 @@ public final class ASTNestedStoreExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewKeyValueObjectExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewKeyValueObjectExpression.java index b030b9d07c..a35c08e5f5 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewKeyValueObjectExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewKeyValueObjectExpression.java @@ -12,8 +12,9 @@ public final class ASTNewKeyValueObjectExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewListInitExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewListInitExpression.java index ccafcb77a8..98bcc7e22f 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewListInitExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewListInitExpression.java @@ -12,8 +12,9 @@ public final class ASTNewListInitExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewListLiteralExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewListLiteralExpression.java index c5ef851265..f46709ad0c 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewListLiteralExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewListLiteralExpression.java @@ -12,8 +12,9 @@ public final class ASTNewListLiteralExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewMapInitExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewMapInitExpression.java index 39f41712f1..e439f54fcd 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewMapInitExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewMapInitExpression.java @@ -12,8 +12,9 @@ public final class ASTNewMapInitExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewMapLiteralExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewMapLiteralExpression.java index 07e0d81370..41a176a2e8 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewMapLiteralExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewMapLiteralExpression.java @@ -12,8 +12,9 @@ public final class ASTNewMapLiteralExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewObjectExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewObjectExpression.java index cb0040091d..306712c328 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewObjectExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewObjectExpression.java @@ -12,8 +12,9 @@ public final class ASTNewObjectExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewSetInitExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewSetInitExpression.java index 454ba2351d..340b610499 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewSetInitExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewSetInitExpression.java @@ -12,8 +12,9 @@ public final class ASTNewSetInitExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewSetLiteralExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewSetLiteralExpression.java index daaef378b7..6e4e3833c3 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewSetLiteralExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTNewSetLiteralExpression.java @@ -12,8 +12,9 @@ public final class ASTNewSetLiteralExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPackageVersionExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPackageVersionExpression.java index 104fd7a9de..77426a863b 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPackageVersionExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPackageVersionExpression.java @@ -12,8 +12,9 @@ public final class ASTPackageVersionExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTParameter.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTParameter.java index dd50d716bd..af1a5f2f6b 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTParameter.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTParameter.java @@ -12,8 +12,9 @@ public final class ASTParameter extends AbstractApexNode { super(parameter); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPostfixExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPostfixExpression.java index 5633b383aa..09ab9ab8d3 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPostfixExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPostfixExpression.java @@ -15,8 +15,9 @@ public final class ASTPostfixExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPrefixExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPrefixExpression.java index ba6d285d22..4d98f6c22b 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPrefixExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTPrefixExpression.java @@ -13,8 +13,9 @@ public final class ASTPrefixExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTProperty.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTProperty.java index b7f2413733..e5ea37ead4 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTProperty.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTProperty.java @@ -12,8 +12,9 @@ public final class ASTProperty extends AbstractApexNode { super(property); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java index 51775542f4..8632675205 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReferenceExpression.java @@ -21,8 +21,9 @@ public final class ASTReferenceExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReturnStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReturnStatement.java index d1ec7a4d10..7ce9b3e420 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReturnStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTReturnStatement.java @@ -12,8 +12,9 @@ public final class ASTReturnStatement extends AbstractApexNode super(returnStatement); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTRunAsBlockStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTRunAsBlockStatement.java index 1b8b9d4fd0..b0114c7d35 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTRunAsBlockStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTRunAsBlockStatement.java @@ -12,8 +12,9 @@ public final class ASTRunAsBlockStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSoqlExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSoqlExpression.java index 6a8a67693e..d2f97c6d80 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSoqlExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSoqlExpression.java @@ -12,8 +12,9 @@ public final class ASTSoqlExpression extends AbstractApexNode { super(soqlExpression); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSoslExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSoslExpression.java index 58c1a99235..23c875c486 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSoslExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSoslExpression.java @@ -12,8 +12,9 @@ public final class ASTSoslExpression extends AbstractApexNode { super(soslExpression); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStandardCondition.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStandardCondition.java index 2d4a474762..06882577ab 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStandardCondition.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStandardCondition.java @@ -12,8 +12,9 @@ public final class ASTStandardCondition extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStatement.java index c0ea4d4325..40238de5a9 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStatement.java @@ -12,8 +12,9 @@ public final class ASTStatement extends AbstractApexNode { super(statement); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStatementExecuted.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStatementExecuted.java index 57dd9d61e6..0729577c71 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStatementExecuted.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTStatementExecuted.java @@ -12,8 +12,9 @@ public final class ASTStatementExecuted extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSuperMethodCallExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSuperMethodCallExpression.java index e567454be9..3acc7cfc83 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSuperMethodCallExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSuperMethodCallExpression.java @@ -12,8 +12,9 @@ public final class ASTSuperMethodCallExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSuperVariableExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSuperVariableExpression.java index 44dab15cb0..1aa9d33b21 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSuperVariableExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSuperVariableExpression.java @@ -12,8 +12,9 @@ public final class ASTSuperVariableExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatement.java index 10cc291e8c..c8f94419d5 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatement.java @@ -14,8 +14,9 @@ public final class ASTSwitchStatement extends AbstractApexNode } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTernaryExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTernaryExpression.java index ec8f8c3491..89aa84de64 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTernaryExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTernaryExpression.java @@ -12,8 +12,9 @@ public final class ASTTernaryExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThisMethodCallExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThisMethodCallExpression.java index b9d23b8b9a..25ad54f35f 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThisMethodCallExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThisMethodCallExpression.java @@ -12,8 +12,9 @@ public final class ASTThisMethodCallExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThisVariableExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThisVariableExpression.java index 6147d8429e..dbaff5e473 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThisVariableExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThisVariableExpression.java @@ -12,8 +12,9 @@ public final class ASTThisVariableExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThrowStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThrowStatement.java index f6ff5ee0f9..55c1b3c9a6 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThrowStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTThrowStatement.java @@ -12,8 +12,9 @@ public final class ASTThrowStatement extends AbstractApexNode { super(throwStatement); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTriggerVariableExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTriggerVariableExpression.java index 969327d952..2096ff0096 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTriggerVariableExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTriggerVariableExpression.java @@ -12,8 +12,9 @@ public final class ASTTriggerVariableExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTryCatchFinallyBlockStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTryCatchFinallyBlockStatement.java index 55344fb30b..0ad8b98358 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTryCatchFinallyBlockStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTryCatchFinallyBlockStatement.java @@ -14,8 +14,9 @@ public final class ASTTryCatchFinallyBlockStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTypeWhenBlock.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTypeWhenBlock.java index f568b9a012..89726babb0 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTypeWhenBlock.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTypeWhenBlock.java @@ -30,8 +30,9 @@ public final class ASTTypeWhenBlock extends AbstractApexNode { } } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClass.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClass.java index 9fa3a4b154..c21892095a 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClass.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClass.java @@ -20,8 +20,9 @@ public final class ASTUserClass extends AbstractApexNode implements A } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClassMethods.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClassMethods.java index c8e537dd25..01f5b58047 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClassMethods.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClassMethods.java @@ -12,8 +12,9 @@ public final class ASTUserClassMethods extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnum.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnum.java index 02a02a0bda..8a3b3849d2 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnum.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnum.java @@ -12,8 +12,9 @@ public final class ASTUserEnum extends AbstractApexNode { super(userEnum); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserExceptionMethods.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserExceptionMethods.java index 0924677183..df849d8f59 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserExceptionMethods.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserExceptionMethods.java @@ -12,8 +12,9 @@ public final class ASTUserExceptionMethods extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterface.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterface.java index 1068242a56..ac3ed5950a 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterface.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterface.java @@ -18,8 +18,9 @@ public final class ASTUserInterface extends AbstractApexNode impl super(userInterface); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserTrigger.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserTrigger.java index b3f88819bf..0d282d645d 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserTrigger.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserTrigger.java @@ -16,8 +16,9 @@ public final class ASTUserTrigger extends AbstractApexNode { super(userTrigger); } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTValueWhenBlock.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTValueWhenBlock.java index db976e06c4..475018e6f6 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTValueWhenBlock.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTValueWhenBlock.java @@ -14,8 +14,9 @@ public final class ASTValueWhenBlock extends AbstractApexNode { } + @Override - public Object jjtAccept(ApexParserVisitor visitor, Object data) { + protected R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableDeclaration.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableDeclaration.java index d5ecb141f5..9aeb6c641c 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableDeclaration.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableDeclaration.java @@ -12,8 +12,9 @@ public final class ASTVariableDeclaration extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableDeclarationStatements.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableDeclarationStatements.java index 795bb9a1e3..2fa2f4be33 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableDeclarationStatements.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableDeclarationStatements.java @@ -12,8 +12,9 @@ public final class ASTVariableDeclarationStatements extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableExpression.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableExpression.java index 40bc7d8e70..468b8500e2 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableExpression.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTVariableExpression.java @@ -12,8 +12,9 @@ public final class ASTVariableExpression extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTWhileLoopStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTWhileLoopStatement.java index aa37d08c59..4ffd18d269 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTWhileLoopStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTWhileLoopStatement.java @@ -12,8 +12,9 @@ public final class ASTWhileLoopStatement extends AbstractApexNode R acceptApexVisitor(ApexVisitor visitor, P data) { return visitor.visit(this, data); } } 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 a1a07aaf0e..8e94732e4b 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 @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.apex.ast; import org.checkerframework.checker.nullness.qual.NonNull; import net.sourceforge.pmd.annotation.InternalApi; +import net.sourceforge.pmd.lang.ast.AstVisitor; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.SourceCodePositioner; import net.sourceforge.pmd.lang.ast.impl.AbstractNodeWithTextCoordinates; @@ -40,6 +41,16 @@ abstract class AbstractApexNode extends AbstractNodeWithTextC super.setCoords(bline, bcol, eline, ecol); } + @Override + public final R acceptVisitor(AstVisitor visitor, P data) { + if (visitor instanceof ApexVisitor) { + return this.acceptApexVisitor((ApexVisitor) visitor, data); + } + return super.acceptVisitor(visitor, data); + } + + protected abstract R acceptApexVisitor(ApexVisitor visitor, P data); + @Override public @NonNull ASTApexFile getRoot() { return getParent().getRoot(); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexNode.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexNode.java index 902be330f1..28da54def5 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexNode.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexNode.java @@ -6,6 +6,8 @@ package net.sourceforge.pmd.lang.apex.ast; import org.checkerframework.checker.nullness.qual.NonNull; +import net.sourceforge.pmd.annotation.DeprecatedUntil700; +import net.sourceforge.pmd.lang.ast.AstVisitor; import net.sourceforge.pmd.lang.ast.impl.GenericNode; import apex.jorje.semantic.ast.AstNode; @@ -22,8 +24,14 @@ public interface ApexNode extends GenericNode> { /** * Accept the visitor. + * + * @deprecated Use {@link #acceptVisitor(AstVisitor, Object)} */ - Object jjtAccept(ApexParserVisitor visitor, Object data); + @Deprecated + @DeprecatedUntil700 + default Object jjtAccept(ApexParserVisitor visitor, Object data) { + return acceptVisitor(visitor, data); + } /** diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitor.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitor.java index 1585467daa..9913771b17 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitor.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitor.java @@ -4,199 +4,29 @@ package net.sourceforge.pmd.lang.apex.ast; -public interface ApexParserVisitor { +import net.sourceforge.pmd.annotation.DeprecatedUntil700; +import net.sourceforge.pmd.lang.ast.Node; + +@DeprecatedUntil700 +@Deprecated +public interface ApexParserVisitor extends ApexVisitor { + + @Override + default Object visitNode(Node node, Object param) { + for (Node child : node.children()) { + child.acceptVisitor(this, param); + } + return param; + } + + @Deprecated + default Object visit(ApexNode node, Object data) { + return visitNode(node, data); + } + + @Override + default Object visitApexNode(ApexNode node, Object data) { + return visit(node, data); // calls the overload above for compatibility + } - Object visit(ApexNode node, Object data); - - Object visit(ASTAnnotation node, Object data); - - Object visit(ASTAnnotationParameter node, Object data); - - Object visit(ASTAnonymousClass node, Object data); - - Object visit(ASTArrayLoadExpression node, Object data); - - Object visit(ASTArrayStoreExpression node, Object data); - - Object visit(ASTAssignmentExpression node, Object data); - - Object visit(ASTBinaryExpression node, Object data); - - Object visit(ASTBindExpressions node, Object data); - - Object visit(ASTBlockStatement node, Object data); - - Object visit(ASTBooleanExpression node, Object data); - - Object visit(ASTBreakStatement node, Object data); - - Object visit(ASTBridgeMethodCreator node, Object data); - - Object visit(ASTCastExpression node, Object data); - - Object visit(ASTCatchBlockStatement node, Object data); - - Object visit(ASTClassRefExpression node, Object data); - - Object visit(ASTConstructorPreamble node, Object data); - - Object visit(ASTConstructorPreambleStatement node, Object data); - - Object visit(ASTContinueStatement node, Object data); - - Object visit(ASTDmlDeleteStatement node, Object data); - - Object visit(ASTDmlInsertStatement node, Object data); - - Object visit(ASTDmlMergeStatement node, Object data); - - Object visit(ASTDmlUndeleteStatement node, Object data); - - Object visit(ASTDmlUpdateStatement node, Object data); - - Object visit(ASTDmlUpsertStatement node, Object data); - - Object visit(ASTDoLoopStatement node, Object data); - - Object visit(ASTExpression node, Object data); - - Object visit(ASTExpressionStatement node, Object data); - - Object visit(ASTField node, Object data); - - Object visit(ASTFieldDeclaration node, Object data); - - Object visit(ASTFieldDeclarationStatements node, Object data); - - Object visit(ASTFormalComment node, Object data); - - Object visit(ASTForEachStatement node, Object data); - - Object visit(ASTForLoopStatement node, Object data); - - Object visit(ASTIfBlockStatement node, Object data); - - Object visit(ASTIfElseBlockStatement node, Object data); - - Object visit(ASTIllegalStoreExpression node, Object data); - - Object visit(ASTInstanceOfExpression node, Object data); - - Object visit(ASTJavaMethodCallExpression node, Object data); - - Object visit(ASTJavaVariableExpression node, Object data); - - Object visit(ASTLiteralExpression node, Object data); - - Object visit(ASTMapEntryNode node, Object data); - - Object visit(ASTMethod node, Object data); - - Object visit(ASTMethodBlockStatement node, Object data); - - Object visit(ASTMethodCallExpression node, Object data); - - Object visit(ASTModifier node, Object data); - - Object visit(ASTModifierNode node, Object data); - - Object visit(ASTModifierOrAnnotation node, Object data); - - Object visit(ASTMultiStatement node, Object data); - - Object visit(ASTNestedExpression node, Object data); - - Object visit(ASTNestedStoreExpression node, Object data); - - Object visit(ASTNewKeyValueObjectExpression node, Object data); - - Object visit(ASTNewListInitExpression node, Object data); - - Object visit(ASTNewListLiteralExpression node, Object data); - - Object visit(ASTNewMapInitExpression node, Object data); - - Object visit(ASTNewMapLiteralExpression node, Object data); - - Object visit(ASTNewObjectExpression node, Object data); - - Object visit(ASTNewSetInitExpression node, Object data); - - Object visit(ASTNewSetLiteralExpression node, Object data); - - Object visit(ASTPackageVersionExpression node, Object data); - - Object visit(ASTParameter node, Object data); - - Object visit(ASTPostfixExpression node, Object data); - - Object visit(ASTPrefixExpression node, Object data); - - Object visit(ASTProperty node, Object data); - - Object visit(ASTReferenceExpression node, Object data); - - Object visit(ASTReturnStatement node, Object data); - - Object visit(ASTRunAsBlockStatement node, Object data); - - Object visit(ASTSoqlExpression node, Object data); - - Object visit(ASTSoslExpression node, Object data); - - Object visit(ASTStandardCondition node, Object data); - - Object visit(ASTStatement node, Object data); - - Object visit(ASTStatementExecuted node, Object data); - - Object visit(ASTSuperMethodCallExpression node, Object data); - - Object visit(ASTSuperVariableExpression node, Object data); - - Object visit(ASTTernaryExpression node, Object data); - - Object visit(ASTThisMethodCallExpression node, Object data); - - Object visit(ASTThisVariableExpression node, Object data); - - Object visit(ASTThrowStatement node, Object data); - - Object visit(ASTTriggerVariableExpression node, Object data); - - Object visit(ASTTryCatchFinallyBlockStatement node, Object data); - - Object visit(ASTUserClass node, Object data); - - Object visit(ASTUserClassMethods node, Object data); - - Object visit(ASTUserEnum node, Object data); - - Object visit(ASTUserExceptionMethods node, Object data); - - Object visit(ASTUserInterface node, Object data); - - Object visit(ASTUserTrigger node, Object data); - - Object visit(ASTVariableDeclaration node, Object data); - - Object visit(ASTVariableDeclarationStatements node, Object data); - - Object visit(ASTVariableExpression node, Object data); - - Object visit(ASTWhileLoopStatement node, Object data); - - Object visit(ASTSwitchStatement node, Object data); - - Object visit(ASTElseWhenBlock node, Object data); - - Object visit(ASTTypeWhenBlock node, Object data); - - Object visit(ASTValueWhenBlock node, Object data); - - Object visit(ASTLiteralCase node, Object data); - - Object visit(ASTIdentifierCase node, Object data); - - Object visit(ASTEmptyReferenceExpression node, Object data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorAdapter.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorAdapter.java index 2c869bdcaf..ef0be90e32 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorAdapter.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorAdapter.java @@ -4,493 +4,10 @@ package net.sourceforge.pmd.lang.apex.ast; -public class ApexParserVisitorAdapter implements ApexParserVisitor { +import net.sourceforge.pmd.annotation.DeprecatedUntil700; - @Override - public Object visit(ApexNode node, Object data) { - for (ApexNode child : node.children()) { - child.jjtAccept(this, data); - } - return data; - } +@Deprecated +@DeprecatedUntil700 +public class ApexParserVisitorAdapter extends ApexVisitorBase implements ApexParserVisitor { - @Override - public Object visit(ASTMethod node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserClass node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTModifierNode node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTParameter node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserClassMethods node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBridgeMethodCreator node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTReturnStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTConstructorPreambleStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserInterface node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserEnum node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTFieldDeclaration node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTWhileLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTryCatchFinallyBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTForLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIfElseBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIfBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTForEachStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTField node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBreakStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThrowStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDoLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTernaryExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSoqlExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBooleanExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAnnotation node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAnonymousClass node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTArrayLoadExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTArrayStoreExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAssignmentExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBinaryExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBindExpressions node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTCatchBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTClassRefExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTContinueStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlDeleteStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlInsertStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlMergeStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUndeleteStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUpdateStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUpsertStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTExpressionStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTFieldDeclarationStatements node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTInstanceOfExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTJavaMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTJavaVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMapEntryNode node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTModifierOrAnnotation node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewListInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewListLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewMapInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewMapLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewObjectExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewSetInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewSetLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPackageVersionExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPostfixExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPrefixExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTProperty node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTReferenceExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTRunAsBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSoslExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTStandardCondition node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSuperMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSuperVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThisMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThisVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTriggerVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserExceptionMethods node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserTrigger node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableDeclaration node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableDeclarationStatements node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAnnotationParameter node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTCastExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTConstructorPreamble node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIllegalStoreExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMethodBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTModifier node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMultiStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNestedExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNestedStoreExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewKeyValueObjectExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTStatementExecuted node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTFormalComment node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSwitchStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTElseWhenBlock node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTypeWhenBlock node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTValueWhenBlock node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIdentifierCase node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTLiteralCase node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTEmptyReferenceExpression node, Object data) { - return visit((ApexNode) node, data); - } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorReducedAdapter.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorReducedAdapter.java deleted file mode 100644 index 1a55a5f148..0000000000 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParserVisitorReducedAdapter.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.ast; - -/** - * @author Clément Fournier - */ -public class ApexParserVisitorReducedAdapter extends ApexParserVisitorAdapter { - - - @Override - public final Object visit(ASTUserInterface node, Object data) { - return visit((ASTUserClassOrInterface) node, data); - } - - - @Override - public final Object visit(ASTUserClass node, Object data) { - return visit((ASTUserClassOrInterface) node, data); - } - - - public Object visit(ASTUserClassOrInterface node, Object data) { - return visit((ApexNode) node, data); - } - -} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexVisitor.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexVisitor.java new file mode 100644 index 0000000000..7b1fd0879d --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexVisitor.java @@ -0,0 +1,406 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import net.sourceforge.pmd.lang.ast.AstVisitor; + +public interface ApexVisitor extends AstVisitor { + + /** + * The default visit method, to which other methods delegate. + */ + default R visitApexNode(ApexNode node, P data) { + return visitNode(node, data); + } + + + default R visit(ASTApexFile node, P data) { + return visitNode(node, data); + } + + default R visit(ASTAnnotation node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTAnnotationParameter node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTAnonymousClass node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTArrayLoadExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTArrayStoreExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTAssignmentExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTBinaryExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTBindExpressions node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTBlockStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTBooleanExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTBreakStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTBridgeMethodCreator node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTCastExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTCatchBlockStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTClassRefExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTConstructorPreamble node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTConstructorPreambleStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTContinueStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTDmlDeleteStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTDmlInsertStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTDmlMergeStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTDmlUndeleteStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTDmlUpdateStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTDmlUpsertStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTDoLoopStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTExpressionStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTField node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTFieldDeclaration node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTFieldDeclarationStatements node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTFormalComment node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTForEachStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTForLoopStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTIfBlockStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTIfElseBlockStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTIllegalStoreExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTInstanceOfExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTJavaMethodCallExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTJavaVariableExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTLiteralExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTMapEntryNode node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTMethod node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTMethodBlockStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTMethodCallExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTModifier node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTModifierNode node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTModifierOrAnnotation node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTMultiStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTNestedExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTNestedStoreExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTNewKeyValueObjectExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTNewListInitExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTNewListLiteralExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTNewMapInitExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTNewMapLiteralExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTNewObjectExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTNewSetInitExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTNewSetLiteralExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTPackageVersionExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTParameter node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTPostfixExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTPrefixExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTProperty node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTReferenceExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTReturnStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTRunAsBlockStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTSoqlExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTSoslExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTStandardCondition node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTStatementExecuted node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTSuperMethodCallExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTSuperVariableExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTTernaryExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTThisMethodCallExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTThisVariableExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTThrowStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTTriggerVariableExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTTryCatchFinallyBlockStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTUserClass node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTUserClassMethods node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTUserEnum node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTUserExceptionMethods node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTUserInterface node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTUserTrigger node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTVariableDeclaration node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTVariableDeclarationStatements node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTVariableExpression node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTWhileLoopStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTSwitchStatement node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTElseWhenBlock node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTTypeWhenBlock node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTValueWhenBlock node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTLiteralCase node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTIdentifierCase node, P data) { + return visitApexNode(node, data); + } + + default R visit(ASTEmptyReferenceExpression node, P data) { + return visitApexNode(node, data); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexVisitorBase.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexVisitorBase.java new file mode 100644 index 0000000000..ff76e12b40 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexVisitorBase.java @@ -0,0 +1,25 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import net.sourceforge.pmd.lang.ast.AstVisitorBase; + +public abstract class ApexVisitorBase extends AstVisitorBase implements ApexVisitor { + + @Override + public R visit(ASTUserInterface node, P data) { + return visitTypeDecl(node, data); + } + + @Override + public R visit(ASTUserClass node, P data) { + return visitTypeDecl(node, data); + } + + public R visitTypeDecl(ASTUserClassOrInterface node, P data) { + return visitApexNode(node, data); + } + +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityMetric.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityMetric.java index 740bfd29bb..ce508231a5 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityMetric.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityMetric.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.apex.metrics.impl; import net.sourceforge.pmd.lang.apex.ast.ASTMethod; import net.sourceforge.pmd.lang.apex.metrics.impl.visitors.CognitiveComplexityVisitor; +import net.sourceforge.pmd.lang.apex.metrics.impl.visitors.CognitiveComplexityVisitor.State; import net.sourceforge.pmd.lang.metrics.MetricOptions; /** @@ -18,7 +19,8 @@ import net.sourceforge.pmd.lang.metrics.MetricOptions; public class CognitiveComplexityMetric extends AbstractApexOperationMetric { @Override public double computeFor(ASTMethod node, MetricOptions options) { - CognitiveComplexityVisitor.State resultingState = (CognitiveComplexityVisitor.State) node.jjtAccept(new CognitiveComplexityVisitor(), new CognitiveComplexityVisitor.State()); - return resultingState.getComplexity(); + State state = new State(); + node.acceptVisitor(CognitiveComplexityVisitor.INSTANCE, state); + return state.getComplexity(); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/CycloMetric.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/CycloMetric.java index 6e60120f87..da9d0483e9 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/CycloMetric.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/CycloMetric.java @@ -27,7 +27,9 @@ public class CycloMetric extends AbstractApexOperationMetric { @Override public double computeFor(ASTMethod node, MetricOptions options) { - return ((MutableInt) node.jjtAccept(new StandardCycloVisitor(), new MutableInt(1))).doubleValue(); + MutableInt result = new MutableInt(1); + node.acceptVisitor(new StandardCycloVisitor(), result); + return result.doubleValue(); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/visitors/CognitiveComplexityVisitor.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/visitors/CognitiveComplexityVisitor.java index 79fdeae1c6..3653ce4517 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/visitors/CognitiveComplexityVisitor.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/visitors/CognitiveComplexityVisitor.java @@ -20,7 +20,8 @@ import net.sourceforge.pmd.lang.apex.ast.ASTSwitchStatement; import net.sourceforge.pmd.lang.apex.ast.ASTTernaryExpression; import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement; import net.sourceforge.pmd.lang.apex.ast.ApexNode; -import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitorAdapter; +import net.sourceforge.pmd.lang.apex.ast.ApexVisitorBase; +import net.sourceforge.pmd.lang.apex.metrics.impl.visitors.CognitiveComplexityVisitor.State; import apex.jorje.data.ast.BooleanOp; import apex.jorje.data.ast.PrefixOp; @@ -28,8 +29,12 @@ import apex.jorje.data.ast.PrefixOp; /** * @author Gwilym Kuiper */ -public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { +public class CognitiveComplexityVisitor extends ApexVisitorBase { + + public static final CognitiveComplexityVisitor INSTANCE = new CognitiveComplexityVisitor(); + public static class State { + private int complexity = 0; private int nestingLevel = 0; @@ -80,8 +85,7 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { } @Override - public Object visit(ASTIfElseBlockStatement node, Object data) { - State state = (State) data; + public Void visit(ASTIfElseBlockStatement node, State state) { boolean hasElseStatement = node.hasElseStatement(); for (ApexNode child : node.children()) { @@ -91,156 +95,135 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { } state.increaseNestingLevel(); - super.visit(child, data); + child.acceptVisitor(this, state); state.decreaseNestingLevel(); } - return data; + return null; } @Override - public Object visit(ASTForLoopStatement node, Object data) { - State state = (State) data; + public Void visit(ASTForLoopStatement node, State state) { state.increaseNestingLevel(); - super.visit(node, data); + super.visit(node, state); state.decreaseNestingLevel(); - return data; + return null; } @Override - public Object visit(ASTForEachStatement node, Object data) { - State state = (State) data; - + public Void visit(ASTForEachStatement node, State state) { state.increaseNestingLevel(); - super.visit(node, data); + super.visit(node, state); state.decreaseNestingLevel(); - return data; + return null; } @Override - public Object visit(ASTContinueStatement node, Object data) { - State state = (State) data; - + public Void visit(ASTContinueStatement node, State state) { state.structureComplexity(); - return super.visit(node, data); + return super.visit(node, state); } @Override - public Object visit(ASTBreakStatement node, Object data) { - State state = (State) data; - + public Void visit(ASTBreakStatement node, State state) { state.structureComplexity(); - return super.visit(node, data); + return super.visit(node, state); } @Override - public Object visit(ASTWhileLoopStatement node, Object data) { - State state = (State) data; - + public Void visit(ASTWhileLoopStatement node, State state) { state.increaseNestingLevel(); - super.visit(node, data); + super.visit(node, state); state.decreaseNestingLevel(); - return data; + return null; } @Override - public Object visit(ASTCatchBlockStatement node, Object data) { - State state = (State) data; - + public Void visit(ASTCatchBlockStatement node, State state) { state.increaseNestingLevel(); - super.visit(node, data); + super.visit(node, state); state.decreaseNestingLevel(); - return data; + return null; } @Override - public Object visit(ASTDoLoopStatement node, Object data) { - State state = (State) data; + public Void visit(ASTDoLoopStatement node, State state) { state.increaseNestingLevel(); - super.visit(node, data); + super.visit(node, state); state.decreaseNestingLevel(); - return data; + return null; } @Override - public Object visit(ASTTernaryExpression node, Object data) { - State state = (State) data; + public Void visit(ASTTernaryExpression node, State state) { state.increaseNestingLevel(); - super.visit(node, data); + super.visit(node, state); state.decreaseNestingLevel(); - return data; + return null; } @Override - public Object visit(ASTBooleanExpression node, Object data) { - State state = (State) data; + public Void visit(ASTBooleanExpression node, State state) { BooleanOp op = node.getOperator(); if (op == BooleanOp.AND || op == BooleanOp.OR) { state.booleanOperation(op); } - return super.visit(node, data); + return super.visit(node, state); } @Override - public Object visit(ASTPrefixExpression node, Object data) { - State state = (State) data; + public Void visit(ASTPrefixExpression node, State state) { PrefixOp op = node.getOperator(); if (op == PrefixOp.NOT) { state.booleanOperation(null); } - return super.visit(node, data); + return super.visit(node, state); } @Override - public Object visit(ASTBlockStatement node, Object data) { - State state = (State) data; + public Void visit(ASTBlockStatement node, State state) { for (ApexNode child : node.children()) { - child.jjtAccept(this, data); + child.acceptVisitor(this, state); // This needs to happen because the current 'run' of boolean operations is terminated // once we finish a statement. state.booleanOperation(null); } - return data; + return null; } @Override - public Object visit(ASTMethod node, Object data) { - State state = (State) data; + public Void visit(ASTMethod node, State state) { state.setMethodName(node.getCanonicalName()); - return super.visit(node, data); + return super.visit(node, state); } @Override - public Object visit(ASTMethodCallExpression node, Object data) { - State state = (State) data; + public Void visit(ASTMethodCallExpression node, State state) { state.methodCall(node.getMethodName()); - return super.visit(node, data); + return super.visit(node, state); } @Override - public Object visit(ASTSwitchStatement node, Object data) { - State state = (State) data; - + public Void visit(ASTSwitchStatement node, State state) { state.increaseNestingLevel(); - super.visit(node, data); + super.visit(node, state); state.decreaseNestingLevel(); - - return state; + return null; } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/visitors/StandardCycloVisitor.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/visitors/StandardCycloVisitor.java index 001fda93d0..462aa48107 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/visitors/StandardCycloVisitor.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/visitors/StandardCycloVisitor.java @@ -16,85 +16,76 @@ import net.sourceforge.pmd.lang.apex.ast.ASTStandardCondition; import net.sourceforge.pmd.lang.apex.ast.ASTTernaryExpression; import net.sourceforge.pmd.lang.apex.ast.ASTThrowStatement; import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement; -import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitorAdapter; +import net.sourceforge.pmd.lang.apex.ast.ApexVisitorBase; import net.sourceforge.pmd.lang.apex.metrics.impl.CycloMetric; /** * @author Clément Fournier */ -public class StandardCycloVisitor extends ApexParserVisitorAdapter { +public class StandardCycloVisitor extends ApexVisitorBase { @Override - public Object visit(ASTMethod node, Object data) { + public Void visit(ASTMethod node, MutableInt data) { return super.visit(node, data); } @Override - public Object visit(ASTIfBlockStatement node, Object data) { - ((MutableInt) data).add( - 1 + CycloMetric.booleanExpressionComplexity(node.getFirstDescendantOfType(ASTStandardCondition.class))); - super.visit(node, data); - return data; + public Void visit(ASTIfBlockStatement node, MutableInt data) { + data.add(1 + CycloMetric.booleanExpressionComplexity(node.getFirstDescendantOfType(ASTStandardCondition.class))); + return super.visit(node, data); } @Override - public Object visit(ASTCatchBlockStatement node, Object data) { - ((MutableInt) data).increment(); - super.visit(node, data); - return data; + public Void visit(ASTCatchBlockStatement node, MutableInt data) { + data.increment(); + return super.visit(node, data); } @Override - public Object visit(ASTForLoopStatement node, Object data) { - ((MutableInt) data).add( - 1 + CycloMetric.booleanExpressionComplexity(node.getFirstDescendantOfType(ASTStandardCondition.class))); - super.visit(node, data); - return data; + public Void visit(ASTForLoopStatement node, MutableInt data) { + data.add( + 1 + CycloMetric.booleanExpressionComplexity(node.getFirstDescendantOfType(ASTStandardCondition.class))); + return super.visit(node, data); } @Override - public Object visit(ASTForEachStatement node, Object data) { - ((MutableInt) data).increment(); - super.visit(node, data); - return data; + public Void visit(ASTForEachStatement node, MutableInt data) { + data.increment(); + return super.visit(node, data); } @Override - public Object visit(ASTThrowStatement node, Object data) { - ((MutableInt) data).increment(); - super.visit(node, data); - return data; + public Void visit(ASTThrowStatement node, MutableInt data) { + data.increment(); + return super.visit(node, data); } @Override - public Object visit(ASTWhileLoopStatement node, Object data) { - ((MutableInt) data).add( - 1 + CycloMetric.booleanExpressionComplexity(node.getFirstDescendantOfType(ASTStandardCondition.class))); - super.visit(node, data); - return data; + public Void visit(ASTWhileLoopStatement node, MutableInt data) { + data.add( + 1 + CycloMetric.booleanExpressionComplexity(node.getFirstDescendantOfType(ASTStandardCondition.class))); + return super.visit(node, data); } @Override - public Object visit(ASTDoLoopStatement node, Object data) { - ((MutableInt) data).add( - 1 + CycloMetric.booleanExpressionComplexity(node.getFirstDescendantOfType(ASTStandardCondition.class))); - super.visit(node, data); - return data; + public Void visit(ASTDoLoopStatement node, MutableInt data) { + data.add( + 1 + CycloMetric.booleanExpressionComplexity(node.getFirstDescendantOfType(ASTStandardCondition.class))); + return super.visit(node, data); } @Override - public Object visit(ASTTernaryExpression node, Object data) { - ((MutableInt) data).add( - 1 + CycloMetric.booleanExpressionComplexity(node.getFirstDescendantOfType(ASTStandardCondition.class))); - super.visit(node, data); - return data; + public Void visit(ASTTernaryExpression node, MutableInt data) { + data.add( + 1 + CycloMetric.booleanExpressionComplexity(node.getFirstDescendantOfType(ASTStandardCondition.class))); + return super.visit(node, data); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitor.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitor.java index e24af12287..c450836a28 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitor.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitor.java @@ -10,12 +10,12 @@ import net.sourceforge.pmd.lang.apex.ast.ASTMethod; import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface; import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; import net.sourceforge.pmd.lang.apex.ast.ASTUserTrigger; -import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitorReducedAdapter; +import net.sourceforge.pmd.lang.apex.ast.ApexVisitorBase; /** * @author Clément Fournier */ -public class ApexMultifileVisitor extends ApexParserVisitorReducedAdapter { +public class ApexMultifileVisitor extends ApexVisitorBase { private final ApexProjectMirror mirror; @@ -28,28 +28,28 @@ public class ApexMultifileVisitor extends ApexParserVisitorReducedAdapter { @Override - public Object visit(ASTUserClassOrInterface node, Object data) { + public Void visitTypeDecl(ASTUserClassOrInterface node, Void data) { stack.push(mirror.getClassStats(node.getQualifiedName(), true)); - super.visit(node, data); + super.visitTypeDecl(node, data); stack.pop(); return data; } @Override - public Object visit(ASTUserTrigger node, Object data) { + public Void visit(ASTUserTrigger node, Void data) { return data; // ignore } @Override - public Object visit(ASTUserEnum node, Object data) { + public Void visit(ASTUserEnum node, Void data) { return data; // ignore } @Override - public Object visit(ASTMethod node, Object data) { + public Void visit(ASTMethod node, Void data) { stack.peek().addOperation(node.getQualifiedName().getOperation(), node.getSignature()); return data; } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitorFacade.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitorFacade.java index dfea0a69f3..bcbcdf69be 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitorFacade.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitorFacade.java @@ -5,16 +5,15 @@ package net.sourceforge.pmd.lang.apex.multifile; import net.sourceforge.pmd.lang.apex.ast.ApexNode; -import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitorAdapter; /** * @author Clément Fournier */ -public class ApexMultifileVisitorFacade extends ApexParserVisitorAdapter { +public class ApexMultifileVisitorFacade { public void initializeWith(ApexNode rootNode) { ApexMultifileVisitor visitor = new ApexMultifileVisitor(ApexProjectMirror.INSTANCE); - rootNode.jjtAccept(visitor, null); + rootNode.acceptVisitor(visitor, null); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRule.java index 74fc94fa53..b6f5883189 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRule.java @@ -9,103 +9,6 @@ import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.apex.ApexLanguageModule; import net.sourceforge.pmd.lang.apex.ApexParserOptions; -import net.sourceforge.pmd.lang.apex.ast.ASTAnnotation; -import net.sourceforge.pmd.lang.apex.ast.ASTAnnotationParameter; -import net.sourceforge.pmd.lang.apex.ast.ASTAnonymousClass; -import net.sourceforge.pmd.lang.apex.ast.ASTArrayLoadExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTArrayStoreExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTAssignmentExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTBinaryExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTBindExpressions; -import net.sourceforge.pmd.lang.apex.ast.ASTBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTBooleanExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTBreakStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTBridgeMethodCreator; -import net.sourceforge.pmd.lang.apex.ast.ASTCastExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTCatchBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTClassRefExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTConstructorPreamble; -import net.sourceforge.pmd.lang.apex.ast.ASTConstructorPreambleStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTContinueStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlDeleteStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlInsertStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlMergeStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlUndeleteStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpdateStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpsertStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTDoLoopStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTElseWhenBlock; -import net.sourceforge.pmd.lang.apex.ast.ASTEmptyReferenceExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTExpressionStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTField; -import net.sourceforge.pmd.lang.apex.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.apex.ast.ASTFieldDeclarationStatements; -import net.sourceforge.pmd.lang.apex.ast.ASTForEachStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTForLoopStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTFormalComment; -import net.sourceforge.pmd.lang.apex.ast.ASTIdentifierCase; -import net.sourceforge.pmd.lang.apex.ast.ASTIfBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTIfElseBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTIllegalStoreExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTInstanceOfExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTJavaMethodCallExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTJavaVariableExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTLiteralCase; -import net.sourceforge.pmd.lang.apex.ast.ASTLiteralExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTMapEntryNode; -import net.sourceforge.pmd.lang.apex.ast.ASTMethod; -import net.sourceforge.pmd.lang.apex.ast.ASTMethodBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTMethodCallExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTModifier; -import net.sourceforge.pmd.lang.apex.ast.ASTModifierNode; -import net.sourceforge.pmd.lang.apex.ast.ASTModifierOrAnnotation; -import net.sourceforge.pmd.lang.apex.ast.ASTMultiStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTNestedExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNestedStoreExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewKeyValueObjectExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewListInitExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewListLiteralExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewMapInitExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewMapLiteralExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewObjectExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewSetInitExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTNewSetLiteralExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTPackageVersionExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTParameter; -import net.sourceforge.pmd.lang.apex.ast.ASTPostfixExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTPrefixExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTProperty; -import net.sourceforge.pmd.lang.apex.ast.ASTReferenceExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTRunAsBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTSoqlExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTSoslExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTStandardCondition; -import net.sourceforge.pmd.lang.apex.ast.ASTStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTStatementExecuted; -import net.sourceforge.pmd.lang.apex.ast.ASTSuperMethodCallExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTSuperVariableExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTSwitchStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTTernaryExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTThisMethodCallExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTThisVariableExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTThrowStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTTriggerVariableExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTTryCatchFinallyBlockStatement; -import net.sourceforge.pmd.lang.apex.ast.ASTTypeWhenBlock; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClassMethods; -import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; -import net.sourceforge.pmd.lang.apex.ast.ASTUserExceptionMethods; -import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; -import net.sourceforge.pmd.lang.apex.ast.ASTUserTrigger; -import net.sourceforge.pmd.lang.apex.ast.ASTValueWhenBlock; -import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclaration; -import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclarationStatements; -import net.sourceforge.pmd.lang.apex.ast.ASTVariableExpression; -import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement; -import net.sourceforge.pmd.lang.apex.ast.ApexNode; import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitor; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.rule.AbstractRule; @@ -125,494 +28,7 @@ public abstract class AbstractApexRule extends AbstractRule @Override public void apply(Node target, RuleContext ctx) { - ((ApexNode) target).jjtAccept(this, ctx); + target.acceptVisitor(this, ctx); } - @Override - public Object visit(ApexNode node, Object data) { - for (ApexNode child : node.children()) { - child.jjtAccept(this, data); - } - return data; - } - - @Override - public Object visit(ASTMethod node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserClass node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTModifierNode node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTParameter node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserClassMethods node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBridgeMethodCreator node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTReturnStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTConstructorPreambleStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserInterface node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserEnum node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTFieldDeclaration node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTWhileLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTryCatchFinallyBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTForLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIfElseBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIfBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTForEachStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTField node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBreakStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThrowStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDoLoopStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTernaryExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSoqlExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBooleanExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAnnotation node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAnonymousClass node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTArrayLoadExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTArrayStoreExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAssignmentExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBinaryExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTBindExpressions node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTCatchBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTClassRefExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTContinueStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlDeleteStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlInsertStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlMergeStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUndeleteStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUpdateStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTDmlUpsertStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTExpressionStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTFieldDeclarationStatements node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTInstanceOfExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTJavaMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTJavaVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMapEntryNode node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTModifierOrAnnotation node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewListInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewListLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewMapInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewMapLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewObjectExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewSetInitExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewSetLiteralExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPackageVersionExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPostfixExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTPrefixExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTProperty node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTReferenceExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTRunAsBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSoslExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTStandardCondition node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSuperMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSuperVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThisMethodCallExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTThisVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTriggerVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserExceptionMethods node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTUserTrigger node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableDeclaration node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableDeclarationStatements node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTVariableExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTAnnotationParameter node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTCastExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTConstructorPreamble node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIllegalStoreExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMethodBlockStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTModifier node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTMultiStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNestedExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNestedStoreExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTNewKeyValueObjectExpression node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTStatementExecuted node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTFormalComment node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTSwitchStatement node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTElseWhenBlock node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTTypeWhenBlock node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTValueWhenBlock node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTIdentifierCase node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTLiteralCase node, Object data) { - return visit((ApexNode) node, data); - } - - @Override - public Object visit(ASTEmptyReferenceExpression node, Object data) { - return visit((ApexNode) node, data); - } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexXPathRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexXPathRule.java deleted file mode 100644 index 76973aacf4..0000000000 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/ApexXPathRule.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule; - -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.apex.ApexLanguageModule; -import net.sourceforge.pmd.lang.apex.ApexParserOptions; -import net.sourceforge.pmd.lang.rule.XPathRule; - -/** - * @deprecated Will be removed with PMD 7. The only reason for this class were the code climate properties, - * which are already deprecated. - */ -@Deprecated -public class ApexXPathRule extends XPathRule { - - public ApexXPathRule() { - super.setLanguage(LanguageRegistry.getLanguage(ApexLanguageModule.NAME)); - } - - @Override - public ParserOptions getParserOptions() { - return new ApexParserOptions(); - } -} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/AbstractNcssCountRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/AbstractNcssCountRule.java index 7303592c7c..13c00dce13 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/AbstractNcssCountRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/AbstractNcssCountRule.java @@ -24,8 +24,9 @@ import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement; import net.sourceforge.pmd.lang.apex.ast.ApexNode; -import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitorAdapter; +import net.sourceforge.pmd.lang.apex.ast.ApexVisitorBase; import net.sourceforge.pmd.lang.apex.rule.internal.AbstractCounterCheckRule; +import net.sourceforge.pmd.lang.ast.Node; /** * Abstract superclass for NCSS counting methods. Counts tokens according to @@ -51,16 +52,28 @@ public abstract class AbstractNcssCountRule> extends Abstr @Override protected int getMetric(T node) { - return (Integer) new NcssVisitor().visit(node, null) + 1; + return node.acceptVisitor(NcssVisitor.INSTANCE, null) + 1; } - private static class NcssVisitor extends ApexParserVisitorAdapter { + private static class NcssVisitor extends ApexVisitorBase { + // todo this would be better with a signature + + static final NcssVisitor INSTANCE = new NcssVisitor(); @Override - public Object visit(ApexNode node, Object data) { + public Integer visitApexNode(ApexNode node, Void data) { return countNodeChildren(node, data); } + @Override + protected Integer visitChildren(Node node, Void data) { + int v = 0; + for (Node child : node.children()) { + v += child.acceptVisitor(this, data); + } + return v; + } + /** * Count the number of children of the given node. Adds one to count the * node itself. @@ -70,101 +83,97 @@ public abstract class AbstractNcssCountRule> extends Abstr * * @return count of the number of children of the node, plus one */ - protected Integer countNodeChildren(ApexNode node, Object data) { - int nodeCount = 0; - for (int i = 0; i < node.getNumChildren(); i++) { - nodeCount += (Integer) node.getChild(i).jjtAccept(this, data); - } - return nodeCount; + protected Integer countNodeChildren(ApexNode node, Void data) { + return visitChildren(node, data); } @Override - public Object visit(ASTForLoopStatement node, Object data) { + public Integer visit(ASTForLoopStatement node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTForEachStatement node, Object data) { + public Integer visit(ASTForEachStatement node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTDoLoopStatement node, Object data) { + public Integer visit(ASTDoLoopStatement node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTIfBlockStatement node, Object data) { + public Integer visit(ASTIfBlockStatement node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTIfElseBlockStatement node, Object data) { + public Integer visit(ASTIfElseBlockStatement node, Void data) { return countNodeChildren(node, data) + 2; } @Override - public Object visit(ASTWhileLoopStatement node, Object data) { + public Integer visit(ASTWhileLoopStatement node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTBreakStatement node, Object data) { + public Integer visit(ASTBreakStatement node, Void data) { return 1; } @Override - public Object visit(ASTTryCatchFinallyBlockStatement node, Object data) { + public Integer visit(ASTTryCatchFinallyBlockStatement node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTContinueStatement node, Object data) { + public Integer visit(ASTContinueStatement node, Void data) { return 1; } @Override - public Object visit(ASTReturnStatement node, Object data) { + public Integer visit(ASTReturnStatement node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTThrowStatement node, Object data) { + public Integer visit(ASTThrowStatement node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTStatement node, Object data) { + public Integer visit(ASTStatement node, Void data) { return 1; } @Override - public Object visit(ASTMethodCallExpression node, Object data) { + public Integer visit(ASTMethodCallExpression node, Void data) { return 1; } @Override - public Object visit(ASTMethod node, Object data) { + public Integer visit(ASTMethod node, Void data) { return node.isSynthetic() ? 0 : countNodeChildren(node, data); } @Override - public Object visit(ASTUserClass node, Object data) { + public Integer visit(ASTUserClass node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTUserEnum node, Object data) { + public Integer visit(ASTUserEnum node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTUserInterface node, Object data) { + public Integer visit(ASTUserInterface node, Void data) { return countNodeChildren(node, data) + 1; } @Override - public Object visit(ASTFieldDeclaration node, Object data) { + public Integer visit(ASTFieldDeclaration node, Void data) { return 1; } } diff --git a/pmd-apex/src/main/resources/category/apex/bestpractices.xml b/pmd-apex/src/main/resources/category/apex/bestpractices.xml index 5c13033efc..351f932d98 100644 --- a/pmd-apex/src/main/resources/category/apex/bestpractices.xml +++ b/pmd-apex/src/main/resources/category/apex/bestpractices.xml @@ -179,7 +179,7 @@ trigger Accounts on Account (before insert, before update, before delete, after since="6.18.0" language="apex" message="Calls to System.debug should specify a logging level." - class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule" + class="net.sourceforge.pmd.lang.rule.XPathRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_bestpractices.html#debugsshoulduselogginglevel"> The first parameter of System.debug, when using the signature with two parameters, is a LoggingLevel enum. @@ -189,7 +189,6 @@ Having the Logging Level specified provides a cleaner log, and improves readabil 3 - Avoid using if..else statements without using surrounding braces. If the code formatting @@ -46,7 +46,6 @@ from the rest. 3 - Avoid using if statements without using braces to surround the code block. If the code @@ -84,7 +83,6 @@ controlled from the rest. 3 - Avoid using 'for' statements without using surrounding braces. If the code formatting or @@ -167,7 +165,6 @@ from the rest. 3 - Apex allows the use of several variables declaration of the same type on one line. However, it @@ -281,7 +278,6 @@ can lead to quite messy code. This rule looks for several declarations on the sa 1 - - @@ -342,7 +337,7 @@ public class Foo { language="apex" since="5.6.0" message="Avoid using 'while' statements without curly braces" - class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule" + class="net.sourceforge.pmd.lang.rule.XPathRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#whileloopsmustusebraces"> Avoid using 'while' statements without using braces to surround the code block. If the code @@ -351,7 +346,6 @@ controlled from the rest. 3 - Avoid directly accessing Trigger.old and Trigger.new as it can lead to a bug. Triggers should be bulkified and iterate through the map to handle the actions for each item separately. 3 - Empty Catch Block finds instances where an exception is caught, but nothing is done. @@ -124,7 +123,6 @@ or reported. 3 - Empty If Statement finds instances where a condition is checked but nothing is done about it. 3 - Empty block statements serve no purpose and should be removed. 3 - Avoid empty try or finally blocks - what's the point? 3 - Empty While Statement finds all instances where a while statement does nothing. @@ -275,7 +270,6 @@ a while loop that does a lot in the exit expression, rewrite it to make it clear 3 - Test methods marked as a testMethod or annotated with @IsTest, @@ -357,7 +351,6 @@ public class MyClass { 3 - suppressions = rpt.getSuppressedRuleViolations(); + List suppressions = rpt.getSuppressedViolations(); assertEquals(1, suppressions.size()); } @@ -158,9 +158,9 @@ public class SuppressWarningsTest extends RuleTst { Report rpt = new Report(); runTestFromString(TEST15, new FooRule(), rpt, LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getDefaultVersion()); - assertEquals(0, rpt.size()); + assertEquals(0, rpt.getViolations().size()); - List suppressions = rpt.getSuppressedRuleViolations(); + List suppressions = rpt.getSuppressedViolations(); assertEquals(1, suppressions.size()); Report.SuppressedViolation suppression = suppressions.get(0); diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirrorTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirrorTest.java index 978791f688..655b4fcb8e 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirrorTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirrorTest.java @@ -19,7 +19,7 @@ import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface; import net.sourceforge.pmd.lang.apex.ast.ApexNode; import net.sourceforge.pmd.lang.apex.ast.ApexParserTestBase; -import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitorAdapter; +import net.sourceforge.pmd.lang.apex.ast.ApexVisitorBase; import net.sourceforge.pmd.lang.apex.metrics.impl.AbstractApexClassMetric; import net.sourceforge.pmd.lang.apex.metrics.impl.AbstractApexOperationMetric; import net.sourceforge.pmd.lang.metrics.MetricKey; @@ -72,24 +72,24 @@ public class ApexProjectMirrorTest extends ApexParserTestBase { private List visitWith(ApexNode acu, final boolean force) { final List result = new ArrayList<>(); - acu.jjtAccept(new ApexParserVisitorAdapter() { + acu.acceptVisitor(new ApexVisitorBase, Void>() { @Override - public Object visit(ASTMethod node, Object data) { + public Void visit(ASTMethod node, List result) { if (opMetricKey.supports(node)) { result.add((int) MetricsUtil.computeMetric(opMetricKey, node, MetricOptions.emptyOptions(), force)); } - return super.visit(node, data); + return super.visit(node, result); } @Override - public Object visit(ASTUserClass node, Object data) { + public Void visit(ASTUserClass node, List result) { if (classMetricKey.supports(node)) { result.add((int) MetricsUtil.computeMetric(classMetricKey, node, MetricOptions.emptyOptions(), force)); } - return super.visit(node, data); + return super.visit(node, result); } - }, null); + }, result); return result; } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitorTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitorTest.java index bc87f5bb0b..a563b20469 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitorTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileVisitorTest.java @@ -14,7 +14,7 @@ import org.junit.Test; import net.sourceforge.pmd.lang.apex.ast.ASTMethod; import net.sourceforge.pmd.lang.apex.ast.ApexNode; import net.sourceforge.pmd.lang.apex.ast.ApexParserTestBase; -import net.sourceforge.pmd.lang.apex.ast.ApexParserVisitorAdapter; +import net.sourceforge.pmd.lang.apex.ast.ApexVisitorBase; import net.sourceforge.pmd.lang.apex.metrics.ApexSignatureMatcher; import net.sourceforge.pmd.lang.apex.metrics.signature.ApexOperationSigMask; @@ -40,14 +40,14 @@ public class ApexMultifileVisitorTest extends ApexParserTestBase { final ApexOperationSigMask opMask = new ApexOperationSigMask(); // We could parse qnames from string but probably simpler to do that - acu.jjtAccept(new ApexParserVisitorAdapter() { + acu.acceptVisitor(new ApexVisitorBase() { @Override - public Object visit(ASTMethod node, Object data) { + public Void visit(ASTMethod node, Void data1) { if (!node.isSynthetic()) { assertTrue(toplevel.hasMatchingSig(node.getQualifiedName(), opMask)); } - return data; + return data1; } }, null); } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRuleTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRuleTest.java index 20e5799d6a..ab46471221 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRuleTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/AbstractApexRuleTest.java @@ -47,7 +47,7 @@ public class AbstractApexRuleTest extends ApexParserTestBase { ctx.setLanguageVersion(apex.getDefaultVersion()); TopLevelRule rule = new TopLevelRule(); rule.apply(node, ctx); - assertEquals(1, ctx.getReport().size()); + assertEquals(1, ctx.getReport().getViolations().size()); } private static class TopLevelRule extends AbstractApexRule { diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index 030e789e56..5446e92b60 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -61,34 +61,6 @@ pmd-core-checkstyle-suppressions.xml - - - org.apache.maven.plugins - maven-shade-plugin - - - jaxen:jaxen - - - - jaxen:jaxen - - org/jaxen/** - - - org/w3c/dom/** - - - - - - - - shade - - - - @@ -115,23 +87,10 @@ commons-io commons-io - - jaxen - jaxen - - true - - net.sourceforge.saxon - saxon + net.sf.saxon + Saxon-HE org.apache.commons @@ -154,15 +113,6 @@ org.checkerframework checker-qual - 2.5.2 - - - - - net.sourceforge.saxon - saxon - dom - runtime @@ -201,45 +151,4 @@ test - - - - m2e - - - - m2e.version - - - - - - jaxen - jaxen - false - - - - - idea - - - - - idea.maven.embedder.version - - - - - jaxen - jaxen - false - - - - diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/Report.java b/pmd-core/src/main/java/net/sourceforge/pmd/Report.java index 5de0f14057..15508e1c0a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/Report.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/Report.java @@ -10,41 +10,23 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; import java.util.List; -import java.util.Map; -import org.apache.commons.lang3.StringUtils; - -import net.sourceforge.pmd.lang.dfa.report.ReportTree; import net.sourceforge.pmd.renderers.AbstractAccumulatingRenderer; -import net.sourceforge.pmd.util.DateTimeUtil; -import net.sourceforge.pmd.util.NumericConstants; /** * A {@link Report} collects all informations during a PMD execution. This * includes violations, suppressed violations, metrics, error during processing * and configuration errors. */ -public class Report implements Iterable { +public class Report { - /* - * The idea is to store the violations in a tree instead of a list, to do - * better and faster sort and filter mechanism and to visualize the result - * as tree. (ide plugins). - */ - private final ReportTree violationTree = new ReportTree(); - - // Note that this and the above data structure are both being maintained for - // a bit - private final List violations = new ArrayList<>(); private final List listeners = new ArrayList<>(); + + private final List violations = new ArrayList<>(); + private final List suppressedRuleViolations = new ArrayList<>(); private final List errors = new ArrayList<>(); private final List configErrors = new ArrayList<>(); - private long start; - private long end; - private final List suppressedRuleViolations = new ArrayList<>(); /** * Creates a new, initialized, empty report for the given file name. @@ -66,36 +48,6 @@ public class Report implements Iterable { return report; } - /** - * Represents a duration. Useful for reporting processing time. - * - * @deprecated Not used within PMD. Rendering durations is format-specific. - */ - @Deprecated - public static class ReadableDuration { - private final long duration; - - /** - * Creates a new duration. - * - * @param duration - * the duration in milliseconds. - */ - public ReadableDuration(long duration) { - this.duration = duration; - } - - /** - * Gets a human readable representation of the duration, such as "1h 3m - * 5s". - * - * @return human readable representation of the duration - */ - public String getTime() { - return DateTimeUtil.asHoursMinutesSeconds(duration); - } - } - /** * Represents a configuration error. */ @@ -179,83 +131,8 @@ public class Report implements Iterable { } } - - private static String keyFor(RuleViolation rv) { - - return StringUtils.isNotBlank(rv.getPackageName()) ? rv.getPackageName() + '.' + rv.getClassName() : ""; - } - - /** - * Calculate a summary of violation counts per fully classified class name. - * - * @return violations per class name - * - * @deprecated This is too specific. Not every violation has a qualified name. - */ - @Deprecated - public Map getCountSummary() { - Map summary = new HashMap<>(); - for (RuleViolation rv : violationTree) { - String key = keyFor(rv); - Integer o = summary.get(key); - summary.put(key, o == null ? NumericConstants.ONE : o + 1); - } - return summary; - } - - /** - * @deprecated The {@link ReportTree} is deprecated - */ - @Deprecated - public ReportTree getViolationTree() { - return this.violationTree; - } - - /** - * Calculate a summary of violations per rule. - * - * @return a Map summarizing the Report: String (rule name) -> Integer (count - * of violations) - * - * @deprecated This is too specific, only used by one renderer. - */ - @Deprecated - public Map getSummary() { - Map summary = new HashMap<>(); - for (RuleViolation rv : violations) { - String name = rv.getRule().getName(); - if (!summary.containsKey(name)) { - summary.put(name, NumericConstants.ZERO); - } - Integer count = summary.get(name); - summary.put(name, count + 1); - } - return summary; - } - - /** - * Registers a report listener - * - * @param listener - * the listener - */ - public void addListener(ThreadSafeReportListener listener) { - listeners.add(listener); - } - - /** - * Returns the suppressed violations. - * - * @deprecated Use {@link #getSuppressedViolations()} (be aware, that that method returns an unmodifiable list) - */ - @Deprecated - public List getSuppressedRuleViolations() { - return suppressedRuleViolations; - } - /** * Represents a violation, that has been suppressed. - * TODO this should implement RuleViolation */ public static class SuppressedViolation { private final RuleViolation rv; @@ -288,31 +165,39 @@ public class Report implements Iterable { } } - - public void addSuppressedViolation(SuppressedViolation sv) { - suppressedRuleViolations.add(sv); + /** + * Registers a report listener + * + * @param listener the listener + */ + public void addListener(ThreadSafeReportListener listener) { + listeners.add(listener); } /** * Adds a new rule violation to the report and notify the listeners. * - * @param violation - * the violation to add + * @param violation the violation to add */ public void addRuleViolation(RuleViolation violation) { int index = Collections.binarySearch(violations, violation, RuleViolationComparator.INSTANCE); violations.add(index < 0 ? -index - 1 : index, violation); - violationTree.addRuleViolation(violation); for (ThreadSafeReportListener listener : listeners) { listener.ruleViolationAdded(violation); } } + /** + * Adds a new suppressed violation. + */ + public void addSuppressedViolation(SuppressedViolation sv) { + suppressedRuleViolations.add(sv); + } + /** * Adds a new configuration error to the report. * - * @param error - * the error to add + * @param error the error to add */ public void addConfigError(ConfigurationError error) { configErrors.add(error); @@ -345,83 +230,10 @@ public class Report implements Iterable { for (RuleViolation violation : r.getViolations()) { int index = Collections.binarySearch(violations, violation, RuleViolationComparator.INSTANCE); violations.add(index < 0 ? -index - 1 : index, violation); - violationTree.addRuleViolation(violation); } } - /** - * Checks whether there are no violations and no processing errors. - * That means, that PMD analysis yielded nothing to worry about. - * - * @deprecated Use {@link #getViolations()} or {@link #getProcessingErrors()} - */ - @Deprecated - public boolean isEmpty() { - return !violations.iterator().hasNext() && !hasErrors(); - } - - /** - * Checks whether any processing errors have been reported. - * - * @return true if there were any processing errors, - * false otherwise - * - * @deprecated Use {@link #getProcessingErrors()}.isEmpty() - */ - @Deprecated - public boolean hasErrors() { - return !getProcessingErrors().isEmpty(); - } - - /** - * Checks whether any configuration errors have been reported. - * - * @return true if there were any configuration errors, - * false otherwise - * - * @deprecated Use {@link #getConfigurationErrors()}.isEmpty() - */ - @Deprecated - public boolean hasConfigErrors() { - return !getConfigurationErrors().isEmpty(); - } - - /** - * Checks whether no violations have been reported. - * - * @return true if no violations have been reported, - * false otherwise - * - * @deprecated The {@link ReportTree} is deprecated, use {@link #getViolations()}.isEmpty() instead. - */ - @Deprecated - public boolean treeIsEmpty() { - return !violationTree.iterator().hasNext(); - } - - /** - * Returns an iteration over the reported violations. - * - * @return an iterator - * - * @deprecated The {@link ReportTree} is deprecated - */ - @Deprecated - public Iterator treeIterator() { - return violationTree.iterator(); - } - - /** - * @deprecated Use {@link #getViolations()} - */ - @Deprecated - @Override - public Iterator iterator() { - return violations.iterator(); - } - - /** * Returns an unmodifiable list of violations that were suppressed. */ @@ -458,85 +270,6 @@ public class Report implements Iterable { } - /** - * Returns an iterator of the reported processing errors. - * - * @return the iterator - * - * @deprecated Use {@link #getProcessingErrors()} - */ - @Deprecated - public Iterator errors() { - return getProcessingErrors().iterator(); - } - - /** - * Returns an iterator of the reported configuration errors. - * - * @return the iterator - * @deprecated Use {@link #getConfigurationErrors()} - */ - @Deprecated - public Iterator configErrors() { - return getConfigurationErrors().iterator(); - } - - /** - * The number of violations. - * - * @return number of violations. - * - * @deprecated The {@link ReportTree} is deprecated - */ - @Deprecated - public int treeSize() { - return violationTree.size(); - } - - /** - * The number of violations. - * - * @return number of violations. - * - * @deprecated Use {@link #getViolations()} - */ - @Deprecated - public int size() { - return violations.size(); - } - - /** - * Mark the start time of the report. This is used to get the elapsed time - * in the end. - * - * @see #getElapsedTimeInMillis() - * - * @deprecated Not used, {@link #getElapsedTimeInMillis()} will be removed - */ - @Deprecated - public void start() { - start = System.currentTimeMillis(); - } - - /** - * Mark the end time of the report. This is ued to get the elapsed time. - * - * @see #getElapsedTimeInMillis() - * @deprecated Not used, {@link #getElapsedTimeInMillis()} will be removed - */ - @Deprecated - public void end() { - end = System.currentTimeMillis(); - } - - /** - * @deprecated Unused - */ - @Deprecated - public long getElapsedTimeInMillis() { - return end - start; - } - public List getListeners() { return listeners; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java b/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java index 28b6d8b090..b0127e5ba4 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/SourceCodeProcessor.java @@ -19,7 +19,6 @@ import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.RootNode; -import net.sourceforge.pmd.lang.xpath.Initializer; public class SourceCodeProcessor { @@ -79,9 +78,6 @@ public class SourceCodeProcessor { public void processSourceCode(Reader sourceCode, RuleSets ruleSets, RuleContext ctx) throws PMDException { determineLanguage(ctx); - // make sure custom XPath functions are initialized - Initializer.initialize(); - // Coarse check to see if any RuleSet applies to file, will need to do a finer RuleSet specific check later if (ruleSets.applies(ctx.getSourceCodeFile())) { if (isCacheUpToDate(ctx)) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/ViolationSuppressor.java b/pmd-core/src/main/java/net/sourceforge/pmd/ViolationSuppressor.java index 6537e125d9..a88f0568f2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/ViolationSuppressor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/ViolationSuppressor.java @@ -14,6 +14,9 @@ import net.sourceforge.pmd.Report.SuppressedViolation; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.RootNode; import net.sourceforge.pmd.lang.rule.RuleViolationFactory; +import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; +import net.sourceforge.pmd.lang.rule.xpath.internal.DeprecatedAttrLogger; +import net.sourceforge.pmd.lang.rule.xpath.internal.SaxonXPathRuleQuery; /** * An object that suppresses rule violations. Suppressors are used by @@ -55,8 +58,24 @@ public interface ViolationSuppressor { @Override public @Nullable SuppressedViolation suppressOrNull(RuleViolation rv, @NonNull Node node) { - String xpath = rv.getRule().getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR); - if (xpath != null && node.hasDescendantMatchingXPath(xpath)) { + // todo this should not be implemented via a rule property + // because the parsed xpath expression should be stored, not a random string + // this needs to be checked to be a valid xpath expression in the ruleset, + // not at the time it is evaluated, and also parsed by the XPath parser only once + Rule rule = rv.getRule(); + String xpath = rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR); + if (xpath == null) { + return null; + } + SaxonXPathRuleQuery rq = new SaxonXPathRuleQuery( + xpath, + XPathVersion.DEFAULT, + rule.getPropertiesByPropertyDescriptor(), + // todo version should be carried around by the node + rule.getLanguage().getDefaultVersion().getLanguageVersionHandler().getXPathHandler(), + DeprecatedAttrLogger.createForSuppression(rv.getRule()) + ); + if (!rq.evaluate(node).isEmpty()) { return new SuppressedViolation(rv, this, xpath); } return null; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java b/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java index 8ca5bd6e17..f60d1093bf 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java @@ -170,7 +170,7 @@ public class PMDTaskImpl { @Override public void renderFileReport(Report r) { - int size = r.size(); + int size = r.getViolations().size(); if (size > 0) { reportSize.addAndGet(size); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/Benchmark.java b/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/Benchmark.java deleted file mode 100644 index 7cf422214a..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/Benchmark.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.benchmark; - -/** - * Represents an execution phase for benchmarking purposes. - * - * @author Brian Remedios - */ -@Deprecated -public enum Benchmark { - // The constants must be sorted in execution order, - // the index is derived from the ordinal of the constant - Rule(null), - RuleChainRule(null), - CollectFiles("Collect files"), - LoadRules("Load rules"), - Parser("Parser"), - QualifiedNameResolution("Qualified name resolution"), - SymbolTable("Symbol table"), - DFA("DFA"), - TypeResolution("Type resolution"), - RuleChainVisit("RuleChain visit"), - Multifile("Multifile analysis"), - Reporting("Reporting"), - RuleTotal("Rule total"), - RuleChainTotal("Rule chain rule total"), - MeasuredTotal("Measured total"), - NonMeasuredTotal("Non-measured total"), - TotalPMD("Total PMD"); - - public final int index = ordinal(); - public final String name; - - - Benchmark(String theName) { - name = theName; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/BenchmarkReport.java b/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/BenchmarkReport.java deleted file mode 100644 index c0cdb123b0..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/BenchmarkReport.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.benchmark; - -import java.io.PrintStream; -import java.util.Map; -import java.util.Set; - -/** - * - * @author Brian Remedios - */ -@Deprecated -public interface BenchmarkReport { - - /** - * - * @param stressResults the durations from the stress test run - * @param stream the report is written into this stream - */ - void generate(Set stressResults, PrintStream stream); - - /** - * - * @param benchmarksByName - * @param stream the report is written into this stream - */ - void generate(Map benchmarksByName, PrintStream stream); -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/BenchmarkResult.java b/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/BenchmarkResult.java deleted file mode 100644 index 5f929eda3f..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/BenchmarkResult.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.benchmark; - -@Deprecated -class BenchmarkResult implements Comparable { - - public final Benchmark type; - public final String name; - private long time; - private long count; - - BenchmarkResult(Benchmark type, String name) { - this.type = type; - this.name = name; - } - - BenchmarkResult(Benchmark type, long time, long count) { - this(type, type.name); - this.time = time; - this.count = count; - } - - public long getTime() { - return time; - } - - public long getCount() { - return count; - } - - public void update(long time, long count) { - this.time += time; - this.count += count; - } - - @Override - public int compareTo(BenchmarkResult benchmarkResult) { - int cmp = Integer.compare(type.index, benchmarkResult.type.index); - if (cmp == 0) { - cmp = Long.compare(this.time, benchmarkResult.time); - } - return cmp; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/Benchmarker.java b/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/Benchmarker.java deleted file mode 100644 index 42baa667b6..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/Benchmarker.java +++ /dev/null @@ -1,254 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.benchmark; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - -import org.apache.commons.lang3.StringUtils; - -import net.sourceforge.pmd.PMD; -import net.sourceforge.pmd.PMDConfiguration; -import net.sourceforge.pmd.PMDException; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleSet; -import net.sourceforge.pmd.RuleSetFactory; -import net.sourceforge.pmd.RuleSetNotFoundException; -import net.sourceforge.pmd.RuleSets; -import net.sourceforge.pmd.RulesetsFactoryUtils; -import net.sourceforge.pmd.SourceCodeProcessor; -import net.sourceforge.pmd.lang.Language; -import net.sourceforge.pmd.lang.LanguageFilenameFilter; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.lang.Parser; -import net.sourceforge.pmd.util.FileUtil; -import net.sourceforge.pmd.util.datasource.DataSource; - -/** - * @deprecated use {@link TimeTracker} instead - */ -@Deprecated -public final class Benchmarker { - - private static final Map BENCHMARKS_BY_NAME = new HashMap<>(); - - private Benchmarker() { } - - /** - * @param args - * String[] - * @param name - * String - * @return boolean - */ - private static boolean findBooleanSwitch(String[] args, String name) { - for (int i = 0; i < args.length; i++) { - if (args[i].equals(name)) { - return true; - } - } - return false; - } - - /** - * - * @param args - * String[] - * @param name - * String - * @param defaultValue - * String - * @return String - */ - private static String findOptionalStringValue(String[] args, String name, String defaultValue) { - for (int i = 0; i < args.length; i++) { - if (args[i].equals(name)) { - return args[i + 1]; - } - } - return defaultValue; - } - - /** - * - * @param args - * String[] - * @throws RuleSetNotFoundException - * @throws IOException - * @throws PMDException - */ - public static void main(String[] args) throws RuleSetNotFoundException, IOException, PMDException { - - String targetjdk = findOptionalStringValue(args, "--targetjdk", "1.4"); - Language language = LanguageRegistry.getLanguage("Java"); - LanguageVersion languageVersion = language.getVersion(targetjdk); - if (languageVersion == null) { - languageVersion = language.getDefaultVersion(); - } - - String srcDir = findOptionalStringValue(args, "--source-directory", "/usr/local/java/src/java/lang/"); - List dataSources = FileUtil.collectFiles(srcDir, new LanguageFilenameFilter(language)); - - boolean debug = findBooleanSwitch(args, "--debug"); - boolean parseOnly = findBooleanSwitch(args, "--parse-only"); - - if (debug) { - System.out.println("Using " + language.getName() + " " + languageVersion.getVersion()); - } - if (parseOnly) { - Parser parser = PMD.parserFor(languageVersion, null); - parseStress(parser, dataSources, debug); - } else { - String ruleset = findOptionalStringValue(args, "--ruleset", ""); - if (debug) { - System.out.println("Checking directory " + srcDir); - } - Set results = new TreeSet<>(); - RuleSetFactory factory = RulesetsFactoryUtils.defaultFactory(); - if (StringUtils.isNotBlank(ruleset)) { - stress(languageVersion, factory.createRuleSet(ruleset), dataSources, results, debug); - } else { - Iterator i = factory.getRegisteredRuleSets(); - while (i.hasNext()) { - stress(languageVersion, i.next(), dataSources, results, debug); - } - } - - TextReport report = new TextReport(); - report.generate(results, System.err); - } - } - - /** - * @param parser - * Parser - * @param dataSources - * List - * @param debug - * boolean - * @throws IOException - */ - private static void parseStress(Parser parser, List dataSources, boolean debug) throws IOException { - - long start = System.currentTimeMillis(); - - for (DataSource ds : dataSources) { - try (DataSource dataSource = ds; InputStreamReader reader = new InputStreamReader(dataSource.getInputStream())) { - parser.parse(dataSource.getNiceFileName(false, null), reader); - } - } - - if (debug) { - long end = System.currentTimeMillis(); - long elapsed = end - start; - System.out.println("That took " + elapsed + " ms"); - } - } - - /** - * @param languageVersion - * LanguageVersion - * @param ruleSet - * RuleSet - * @param dataSources - * List - * @param results - * Set - * @param debug - * boolean - * @throws PMDException - * @throws IOException - */ - private static void stress(LanguageVersion languageVersion, RuleSet ruleSet, List dataSources, - Set results, boolean debug) throws PMDException, IOException { - - final RuleSetFactory factory = RulesetsFactoryUtils.defaultFactory(); - for (Rule rule: ruleSet.getRules()) { - if (debug) { - System.out.println("Starting " + rule.getName()); - } - - final RuleSet working = factory.createSingleRuleRuleSet(rule); - RuleSets ruleSets = new RuleSets(working); - - PMDConfiguration config = new PMDConfiguration(); - config.setDefaultLanguageVersion(languageVersion); - - RuleContext ctx = new RuleContext(); - long start = System.currentTimeMillis(); - for (DataSource ds : dataSources) { - try (DataSource dataSource = ds; InputStream stream = new BufferedInputStream(dataSource.getInputStream())) { - ctx.setSourceCodeFile(new File(dataSource.getNiceFileName(false, null))); - new SourceCodeProcessor(config).processSourceCode(stream, ruleSets, ctx); - } - } - long end = System.currentTimeMillis(); - long elapsed = end - start; - results.add(new RuleDuration(elapsed, rule)); - if (debug) { - System.out.println("Done timing " + rule.getName() + "; elapsed time was " + elapsed); - } - } - } - - /** - * @param type - * Benchmark - * @param time - * long - * @param count - * long - */ - public static void mark(Benchmark type, long time, long count) { - mark(type, null, time, count); - } - - /** - * - * @param type - * Benchmark - * @param name - * String - * @param time - * long - * @param count - * long - */ - public static synchronized void mark(Benchmark type, String name, long time, long count) { - String typeName = type.name; - if (typeName != null && name != null) { - throw new IllegalArgumentException("Name cannot be given for type: " + type); - } else if (typeName == null && name == null) { - throw new IllegalArgumentException("Name is required for type: " + type); - } else if (typeName == null) { - typeName = name; - } - BenchmarkResult benchmarkResult = BENCHMARKS_BY_NAME.get(typeName); - if (benchmarkResult == null) { - benchmarkResult = new BenchmarkResult(type, typeName); - BENCHMARKS_BY_NAME.put(typeName, benchmarkResult); - } - benchmarkResult.update(time, count); - } - - public static void reset() { - BENCHMARKS_BY_NAME.clear(); - } - - public static Map values() { - return BENCHMARKS_BY_NAME; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/RuleDuration.java b/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/RuleDuration.java deleted file mode 100644 index 35e2e6affa..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/RuleDuration.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.benchmark; - -import net.sourceforge.pmd.Rule; - -@Deprecated -public class RuleDuration implements Comparable { - - public Rule rule; - public long time; - - public RuleDuration(long elapsed, Rule rule) { - this.rule = rule; - this.time = elapsed; - } - - @Override - public int compareTo(RuleDuration other) { - if (other.time < time) { - return -1; - } else if (other.time > time) { - return 1; - } - - return rule.getName().compareTo(other.rule.getName()); - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/StringBuilderCR.java b/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/StringBuilderCR.java deleted file mode 100644 index 36cab0443e..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/StringBuilderCR.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.benchmark; - -/** - * A wrapped StringBuilder that appends a variable number of text segments - * efficiently and always appends the specified carriage return terminator. - * - * @author Brian Remedios - */ -@Deprecated -public class StringBuilderCR { - - private final String cr; - private final StringBuilder sb = new StringBuilder(); - - public StringBuilderCR(String theCR) { - cr = theCR; - } - - public StringBuilderCR(String initialText, String theCR) { - this(theCR); - appendLn(initialText); - } - - public void appendLn(String... chunks) { - - for (String chunk : chunks) { - sb.append(chunk); - } - sb.append(cr); - } - - @Override - public String toString() { - return sb.toString(); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/TextReport.java b/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/TextReport.java deleted file mode 100644 index 2488106790..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/benchmark/TextReport.java +++ /dev/null @@ -1,159 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.benchmark; - -import java.io.PrintStream; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.lang3.StringUtils; - -import net.sourceforge.pmd.PMD; - -/** - * - * - */ -@Deprecated -public class TextReport implements BenchmarkReport { - - private static final int TIME_COLUMN = 48; - private static final int NAME_COLUMN_WIDTH = 50; - private static final int VALUE_COLUMN_WIDTH = 8; - - @Override - public void generate(Set stressResults, PrintStream stream) { - - stream.println("========================================================="); - stream.println("Rule\t\t\t\t\t\tTime in ms"); - stream.println("========================================================="); - - for (RuleDuration result : stressResults) { - StringBuilder buffer = new StringBuilder(result.rule.getName()); - while (buffer.length() < TIME_COLUMN) { - buffer.append(' '); - } - buffer.append(result.time); - stream.println(stream.toString()); - } - - stream.println("========================================================="); - } - - public void report(Map benchmarksByName) { - generate(benchmarksByName, System.out); - } - - @Override - public void generate(Map benchmarksByName, PrintStream stream) { - - List results = new ArrayList<>(benchmarksByName.values()); - - long[] totalTime = new long[Benchmark.TotalPMD.index + 1]; - long[] totalCount = new long[Benchmark.TotalPMD.index + 1]; - - for (BenchmarkResult benchmarkResult : results) { - totalTime[benchmarkResult.type.index] += benchmarkResult.getTime(); - totalCount[benchmarkResult.type.index] += benchmarkResult.getCount(); - if (benchmarkResult.type.index < Benchmark.MeasuredTotal.index) { - totalTime[Benchmark.MeasuredTotal.index] += benchmarkResult.getTime(); - } - } - results.add(new BenchmarkResult(Benchmark.RuleTotal, totalTime[Benchmark.RuleTotal.index], 0)); - results.add(new BenchmarkResult(Benchmark.RuleChainTotal, totalTime[Benchmark.RuleChainTotal.index], 0)); - results.add(new BenchmarkResult(Benchmark.MeasuredTotal, totalTime[Benchmark.MeasuredTotal.index], 0)); - results.add(new BenchmarkResult(Benchmark.NonMeasuredTotal, - totalTime[Benchmark.TotalPMD.index] - totalTime[Benchmark.MeasuredTotal.index], 0)); - Collections.sort(results); - - StringBuilderCR buf = new StringBuilderCR(PMD.EOL); - boolean writeRuleHeader = true; - boolean writeRuleChainRuleHeader = true; - long ruleCount = 0; - long ruleChainCount = 0; - - for (BenchmarkResult benchmarkResult : results) { - StringBuilder buf2 = new StringBuilder(benchmarkResult.name); - buf2.append(':'); - while (buf2.length() <= NAME_COLUMN_WIDTH) { - buf2.append(' '); - } - String result = MessageFormat.format("{0,number,0.000}", - Double.valueOf(benchmarkResult.getTime() / 1000000000.0)); - buf2.append(StringUtils.leftPad(result, VALUE_COLUMN_WIDTH)); - if (benchmarkResult.type.index <= Benchmark.RuleChainRule.index) { - buf2.append(StringUtils - .leftPad(MessageFormat.format("{0,number,###,###,###,###,###}", benchmarkResult.getCount()), 20)); - } - switch (benchmarkResult.type) { - case Rule: - if (writeRuleHeader) { - writeRuleHeader = false; - buf.appendLn(); - buf.appendLn("---------------------------------<<< Rules >>>---------------------------------"); - buf.appendLn("Rule name Time (secs) # of Evaluations"); - buf.appendLn(); - } - ruleCount++; - break; - case RuleChainRule: - if (writeRuleChainRuleHeader) { - writeRuleChainRuleHeader = false; - buf.appendLn(); - buf.appendLn("----------------------------<<< RuleChain Rules >>>----------------------------"); - buf.appendLn("Rule name Time (secs) # of Visits"); - buf.appendLn(); - } - ruleChainCount++; - break; - case CollectFiles: - buf.appendLn(); - buf.appendLn("--------------------------------<<< Summary >>>--------------------------------"); - buf.appendLn("Segment Time (secs)"); - buf.appendLn(); - break; - case MeasuredTotal: - String s = MessageFormat.format("{0,number,###,###,###,###,###}", ruleCount); - String t = MessageFormat.format("{0,number,0.000}", - ruleCount == 0 ? 0 : total(totalTime, Benchmark.Rule, ruleCount)); - buf.appendLn("Rule Average (", s, " rules):", StringUtils.leftPad(t, 37 - s.length())); - s = MessageFormat.format("{0,number,###,###,###,###,###}", ruleChainCount); - t = MessageFormat.format("{0,number,0.000}", - ruleChainCount == 0 ? 0 : total(totalTime, Benchmark.RuleChainRule, ruleChainCount)); - buf.appendLn("RuleChain Average (", s, " rules):", StringUtils.leftPad(t, 32 - s.length())); - - buf.appendLn(); - buf.appendLn("-----------------------------<<< Final Summary >>>-----------------------------"); - buf.appendLn("Total Time (secs)"); - buf.appendLn(); - break; - default: - // Do nothing - break; - } - buf.appendLn(buf2.toString()); - } - - stream.print(buf.toString()); - } - - /** - * - * @param timeTotals - * long[] - * @param index - * Benchmark - * @param count - * long - * @return double - */ - private static double total(long[] timeTotals, Benchmark index, long count) { - return timeTotals[index.index] / 1000000000.0d / count; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java index fada9e28eb..16b0e724ae 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/LanguageVersionHandler.java @@ -9,10 +9,10 @@ import java.util.List; import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.lang.ast.AstProcessingStage; -import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler; import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider; import net.sourceforge.pmd.lang.rule.RuleViolationFactory; import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory; +import net.sourceforge.pmd.lang.rule.xpath.impl.XPathHandler; import net.sourceforge.pmd.util.designerbindings.DesignerBindings; import net.sourceforge.pmd.util.designerbindings.DesignerBindings.DefaultDesignerBindings; @@ -30,7 +30,7 @@ public interface LanguageVersionHandler { * Get the XPathHandler. */ default XPathHandler getXPathHandler() { - return new DefaultASTXPathHandler(); + return XPathHandler.noFunctionDefinitions(); } 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 deleted file mode 100644 index 064a65b215..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/XPathHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -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; - -/** - * Interface for performing Language specific XPath handling, such as - * initialization and navigation. - */ -@InternalApi -@Deprecated -public interface XPathHandler { - - /** - * Initialize. This is intended to be called by {@link Initializer} to - * perform Language specific initialization. - */ - void initialize(); - - /** - * Initialize. This is intended to be called by {@link Initializer} to - * perform Language specific initialization for Saxon. - */ - void initialize(IndependentContext context); - - /** - * 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. This isn't used - * anymore - */ - @Deprecated - Navigator getNavigator(); -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AstVisitorBase.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AstVisitorBase.java index b2fc648550..08a6f529f0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AstVisitorBase.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AstVisitorBase.java @@ -7,32 +7,17 @@ package net.sourceforge.pmd.lang.ast; /** * Base implementation of {@link AstVisitor}, that performs a top-down * (preorder) visit and may accumulate a result. + * + *

Note that if you care about the result ({@code }), then you need + * to override {@link #visitChildren(Node, Object) visitChildren} to implement + * the logic that combines values from children, if any. */ public abstract class AstVisitorBase implements AstVisitor { - /** Initial value when combining values returned by children. */ - protected R zero() { - return null; - } - - /** - * Merge two values of type R, used to combine values returned by children. - * - * @param acc Current accumulated value for the previous siblings - * (or {@link #zero()} if the child is the first child) - * @param childValue Value for the new child - * - * @return New accumulated value to use for the next sibling - */ - protected R combine(R acc, R childValue) { - return acc; - } - /** * Visit the children. By default the data parameter is passed unchanged - * to all descendants. The {@link #zero() zero} and {@link #combine(Object, Object) combine} - * functions should be implemented if this is to return something else - * than null. + * to all descendants, and null is returned. Override this method to customize + * this behavior. * * @param node Node whose children should be visited * @param data Parameter of the visit @@ -41,12 +26,10 @@ public abstract class AstVisitorBase implements AstVisitor { */ // kept separate from super.visit for clarity protected R visitChildren(Node node, P data) { - R result = zero(); for (Node child : node.children()) { - R r1 = child.acceptVisitor(this, data); - result = combine(result, r1); + child.acceptVisitor(this, data); } - return result; + return null; } @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java index 5170c91a13..d20e8dc8eb 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java @@ -4,22 +4,23 @@ package net.sourceforge.pmd.lang.ast; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Objects; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import org.jaxen.BaseXPath; -import org.jaxen.JaxenException; import net.sourceforge.pmd.lang.ast.NodeStream.DescendantNodeStream; import net.sourceforge.pmd.lang.ast.internal.StreamImpl; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; -import net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator; -import net.sourceforge.pmd.lang.ast.xpath.internal.ContextualizedNavigator; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttrLogger; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute; +import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; +import net.sourceforge.pmd.lang.rule.xpath.impl.AttributeAxisIterator; +import net.sourceforge.pmd.lang.rule.xpath.impl.XPathHandler; +import net.sourceforge.pmd.lang.rule.xpath.internal.DeprecatedAttrLogger; +import net.sourceforge.pmd.lang.rule.xpath.internal.SaxonXPathRuleQuery; import net.sourceforge.pmd.util.DataMap; import net.sourceforge.pmd.util.DataMap.DataKey; @@ -215,35 +216,21 @@ public interface Node { * * @param xpathString the expression to check * @return List of all matching nodes. Returns an empty list if none found. - * @throws JaxenException if the xpath is incorrect or fails altogether - * * @deprecated This is very inefficient and should not be used in new code. PMD 7.0.0 will remove * support for this method. */ @Deprecated - @SuppressWarnings("unchecked") - default List findChildNodesWithXPath(String xpathString) throws JaxenException { - return new BaseXPath(xpathString, new ContextualizedNavigator(DeprecatedAttrLogger.createAdHocLogger())) - .selectNodes(this); + default List findChildNodesWithXPath(String xpathString) { + return new SaxonXPathRuleQuery( + xpathString, + XPathVersion.DEFAULT, + Collections.emptyMap(), + XPathHandler.noFunctionDefinitions(), + // since this method will be removed, we don't log anything anymore + DeprecatedAttrLogger.noop() + ).evaluate(this); } - /** - * Checks whether at least one descendant matches the xpath expression. - * - * @param xpathString the expression to check - * @return true if there is a match - * - * @deprecated This is very inefficient and should not be used in new code. PMD 7.0.0 will remove - * support for this method. - */ - @Deprecated - default boolean hasDescendantMatchingXPath(String xpathString) { - try { - return !findChildNodesWithXPath(xpathString).isEmpty(); - } catch (final JaxenException e) { - throw new RuntimeException("XPath expression " + xpathString + " failed: " + e.getLocalizedMessage(), e); - } - } /** @@ -321,7 +308,8 @@ public interface Node { /** - * Returns an iterator enumerating all the attributes that are available from XPath for this node. + * Returns an iterator enumerating all the attributes that are available + * from XPath for this node. * * @return An attribute iterator for this node */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TextAvailableNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TextAvailableNode.java index d24bf1f977..8e9c55c020 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TextAvailableNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/TextAvailableNode.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.lang.ast; -import net.sourceforge.pmd.lang.ast.xpath.NoAttribute; +import net.sourceforge.pmd.lang.rule.xpath.NoAttribute; /** * Refinement of {@link Node} for nodes that can provide the underlying diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrNode.java index be9147822c..c71bde3868 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrNode.java @@ -36,6 +36,11 @@ import net.sourceforge.pmd.util.DataMap.DataKey; public abstract class BaseAntlrNode, N extends AntlrNode> implements AntlrNode { private DataMap> userMap; + + /** + * The only node for which this is not overwritten is the root node, for + * which by contract, this is -1. + */ private int indexInParent = -1; protected BaseAntlrNode() { @@ -97,7 +102,7 @@ public abstract class BaseAntlrNode, N e @Override public int getIndexInParent() { - assert indexInParent >= 0 : "Index not set"; + assert getParent() == null || indexInParent >= 0 : "Index not set"; return indexInParent; } 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 deleted file mode 100644 index eb470c94bd..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AbstractASTXPathHandler.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -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 - public Navigator getNavigator() { - return new DocumentNavigator(); - } - - public void initialize(IndependentContext context, Language language, Class functionsClass) { - context.declareNamespace("pmd-" + language.getTerseName(), "java:" + functionsClass.getName()); - } - - @Override - public void initialize() { - // override if needed - } - - @Override - public void initialize(IndependentContext context) { - // override if needed - } -} 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 deleted file mode 100644 index 3fa844f28a..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DefaultASTXPathHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -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() { - // override if needed - } - - @Override - public void initialize(IndependentContext context) { - // override if needed - } -} 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 deleted file mode 100644 index b6fe8eef08..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/DocumentNavigator.java +++ /dev/null @@ -1,373 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -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; - -/** - * Navigator used for XPath 1.0 (Jaxen) queries. - */ -@Deprecated -@InternalApi -public class DocumentNavigator extends DefaultNavigator { - - private static final Iterator EMPTY_ITERATOR = new ArrayList().iterator(); - - @Override - public String getAttributeName(Object arg0) { - return ((Attribute) arg0).getName(); - } - - @Override - public String getAttributeNamespaceUri(Object arg0) { - return ""; - } - - @Override - public String getAttributeQName(Object arg0) { - return ((Attribute) arg0).getName(); - } - - @Override - public String getAttributeStringValue(Object arg0) { - return ((Attribute) arg0).getStringValue(); - } - - @Override - public String getCommentStringValue(Object arg0) { - return ""; - } - - @Override - public String getElementName(Object node) { - return ((Node) node).getXPathNodeName(); - } - - @Override - public String getElementNamespaceUri(Object arg0) { - return ""; - } - - @Override - public String getElementQName(Object arg0) { - return getElementName(arg0); - } - - @Override - public String getElementStringValue(Object arg0) { - return ""; - } - - @Override - public String getNamespacePrefix(Object arg0) { - return ""; - } - - @Override - public String getNamespaceStringValue(Object arg0) { - return ""; - } - - @Override - public String getTextStringValue(Object arg0) { - return ""; - } - - @Override - public boolean isAttribute(Object arg0) { - return arg0 instanceof Attribute; - } - - @Override - public boolean isComment(Object arg0) { - return false; - } - - @Override - public boolean isDocument(Object arg0) { - return arg0 instanceof RootNode; - } - - @Override - public boolean isElement(Object arg0) { - return arg0 instanceof Node; - } - - @Override - public boolean isNamespace(Object arg0) { - return false; - } - - @Override - public boolean isProcessingInstruction(Object arg0) { - return false; - } - - @Override - public boolean isText(Object arg0) { - return false; - } - - @Override - public XPath parseXPath(String arg0) { - return null; - } - - @Override - public Object getParentNode(Object arg0) { - if (arg0 instanceof Node) { - return ((Node) arg0).getParent(); - } - if (arg0 instanceof Attribute) { - return ((Attribute) arg0).getParent(); - } - // can't navigate to parent node... - return null; - } - - @Override - public Iterator getAttributeAxisIterator(final Object arg0) { - // for XPath 1.0, we don't return any attributes, that are lists. XPath 1.0 - // has no good support for lists/sequences and the value would only be available - // as a simple string. - return new ListFilteringAttributeIterator(((Node) arg0).getXPathAttributesIterator()); - } - - private static class ListFilteringAttributeIterator implements Iterator { - private final Iterator baseIterator; - private Attribute current; - - ListFilteringAttributeIterator(Iterator baseIterator) { - this.baseIterator = baseIterator; - this.current = getNextAttribute(); - } - - @Override - public boolean hasNext() { - return current != null; - } - - @Override - public Attribute next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - Attribute result = current; - current = getNextAttribute(); - return result; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - private Attribute getNextAttribute() { - Attribute result = null; - while (baseIterator.hasNext() && result == null) { - Attribute candidate = baseIterator.next(); - // Calling getValue() here would break laziness - if (!List.class.isAssignableFrom(candidate.getType())) { - result = candidate; - } - } - return result; - } - } - - /** - * Get an iterator over all of this node's children. - * - * @param contextNode - * The context node for the child axis. - * @return A possibly-empty iterator (not null). - */ - @Override - public Iterator getChildAxisIterator(Object contextNode) { - return new NodeIterator((Node) contextNode) { - @Override - protected Node getFirstNode(Node node) { - return getFirstChild(node); - } - - @Override - protected Node getNextNode(Node node) { - return getNextSibling(node); - } - }; - } - - /** - * Get a (single-member) iterator over this node's parent. - * - * @param contextNode - * the context node for the parent axis. - * @return A possibly-empty iterator (not null). - */ - @Override - public Iterator getParentAxisIterator(Object contextNode) { - if (isAttribute(contextNode)) { - return new SingleObjectIterator(((Attribute) contextNode).getParent()); - } - Node parent = ((Node) contextNode).getParent(); - if (parent != null) { - return new SingleObjectIterator(parent); - } else { - return EMPTY_ITERATOR; - } - } - - /** - * Get an iterator over all following siblings. - * - * @param contextNode - * the context node for the sibling iterator. - * @return A possibly-empty iterator (not null). - */ - @Override - public Iterator getFollowingSiblingAxisIterator(Object contextNode) { - return new NodeIterator((Node) contextNode) { - @Override - protected Node getFirstNode(Node node) { - return getNextNode(node); - } - - @Override - protected Node getNextNode(Node node) { - return getNextSibling(node); - } - }; - } - - /** - * Get an iterator over all preceding siblings. - * - * @param contextNode - * The context node for the preceding sibling axis. - * @return A possibly-empty iterator (not null). - */ - @Override - public Iterator getPrecedingSiblingAxisIterator(Object contextNode) { - return new NodeIterator((Node) contextNode) { - @Override - protected Node getFirstNode(Node node) { - return getNextNode(node); - } - - @Override - protected Node getNextNode(Node node) { - return getPreviousSibling(node); - } - }; - } - - /** - * Get an iterator over all following nodes, depth-first. - * - * @param contextNode - * The context node for the following axis. - * @return A possibly-empty iterator (not null). - */ - @Override - public Iterator getFollowingAxisIterator(Object contextNode) { - return new NodeIterator((Node) contextNode) { - @Override - protected Node getFirstNode(Node node) { - if (node == null) { - return null; - } else { - Node sibling = getNextSibling(node); - if (sibling == null) { - return getFirstNode(node.getParent()); - } else { - return sibling; - } - } - } - - @Override - protected Node getNextNode(Node node) { - if (node == null) { - return null; - } else { - Node n = getFirstChild(node); - if (n == null) { - n = getNextSibling(node); - } - if (n == null) { - return getFirstNode(node.getParent()); - } else { - return n; - } - } - } - }; - } - - /** - * Get an iterator over all preceding nodes, depth-first. - * - * @param contextNode - * The context node for the preceding axis. - * @return A possibly-empty iterator (not null). - */ - @Override - public Iterator getPrecedingAxisIterator(Object contextNode) { - return new NodeIterator((Node) contextNode) { - @Override - protected Node getFirstNode(Node node) { - if (node == null) { - return null; - } else { - Node sibling = getPreviousSibling(node); - if (sibling == null) { - return getFirstNode(node.getParent()); - } else { - return sibling; - } - } - } - - @Override - protected Node getNextNode(Node node) { - if (node == null) { - return null; - } else { - Node n = getLastChild(node); - if (n == null) { - n = getPreviousSibling(node); - } - if (n == null) { - return getFirstNode(node.getParent()); - } else { - return n; - } - } - } - }; - } - - @Override - public Object getDocumentNode(Object contextNode) { - if (isDocument(contextNode)) { - return contextNode; - } - if (null == contextNode) { - throw new RuntimeException("contextNode may not be null"); - } - return getDocumentNode(getParentNode(contextNode)); - } -} 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 deleted file mode 100644 index cde536b42e..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NodeIterator.java +++ /dev/null @@ -1,90 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -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; - -/** - * Base class for node iterators used to implement XPath axis - * iterators for Jaxen. - * - * @author daniels - */ -@Deprecated -@InternalApi -public abstract class NodeIterator implements Iterator { - - private Node node; - - protected NodeIterator(Node contextNode) { - this.node = getFirstNode(contextNode); - } - - @Override - public boolean hasNext() { - return node != null; - } - - @Override - public Node next() { - if (node == null) { - throw new NoSuchElementException(); - } - Node ret = node; - node = getNextNode(node); - return ret; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - protected abstract Node getFirstNode(Node contextNode); - - protected abstract Node getNextNode(Node contextNode); - - protected Node getPreviousSibling(Node contextNode) { - Node parentNode = contextNode.getParent(); - if (parentNode != null) { - int prevPosition = contextNode.getIndexInParent() - 1; - if (prevPosition >= 0) { - return parentNode.getChild(prevPosition); - } - } - return null; - } - - protected Node getNextSibling(Node contextNode) { - Node parentNode = contextNode.getParent(); - if (parentNode != null) { - int nextPosition = contextNode.getIndexInParent() + 1; - if (nextPosition < parentNode.getNumChildren()) { - return parentNode.getChild(nextPosition); - } - } - return null; - } - - protected Node getFirstChild(Node contextNode) { - if (contextNode.getNumChildren() > 0) { - return contextNode.getChild(0); - } else { - return null; - } - } - - protected Node getLastChild(Node contextNode) { - if (contextNode.getNumChildren() > 0) { - return contextNode.getChild(contextNode.getNumChildren() - 1); - } else { - return null; - } - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/ContextualizedNavigator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/ContextualizedNavigator.java deleted file mode 100644 index 358d7d7ce7..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/ContextualizedNavigator.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.internal; - -import net.sourceforge.pmd.lang.ast.xpath.Attribute; -import net.sourceforge.pmd.lang.ast.xpath.DocumentNavigator; - -/** - * Navigator that records attribute usages. - */ -public class ContextualizedNavigator extends DocumentNavigator { - - private final DeprecatedAttrLogger ctx; - - public ContextualizedNavigator(DeprecatedAttrLogger ctx) { - this.ctx = ctx; - } - - @Override - public String getAttributeStringValue(Object arg0) { - Attribute attr = (Attribute) arg0; - ctx.recordUsageOf(attr); - return attr.getStringValue(); - } -} 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 deleted file mode 100644 index 822bb9d797..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AbstractNodeInfo.java +++ /dev/null @@ -1,283 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -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; -import net.sf.saxon.om.AxisIterator; -import net.sf.saxon.om.DocumentInfo; -import net.sf.saxon.om.FastStringBuffer; -import net.sf.saxon.om.NamePool; -import net.sf.saxon.om.Navigator.AxisFilter; -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.om.SequenceIterator; -import net.sf.saxon.om.SiblingCountingNode; -import net.sf.saxon.om.VirtualNode; -import net.sf.saxon.pattern.NodeTest; -import net.sf.saxon.trans.XPathException; -import net.sf.saxon.value.Value; - -/** - * This is a basic implementation of the Saxon NodeInfo and related interfaces. - * Most methods are trivial implementations which immediately throw - * {@link UnsupportedOperationException}. A few of the methods actually have - * useful implementations, such as {@link #iterateAxis(byte, NodeTest)} and - * {@link #isSameNodeInfo(NodeInfo)}. - */ -@Deprecated -@InternalApi -public class AbstractNodeInfo implements VirtualNode, SiblingCountingNode { - @Override - public String getSystemId() { - throw createUnsupportedOperationException("Source.getSystemId()"); - } - - @Override - public void setSystemId(String systemId) { - throw createUnsupportedOperationException("Source.setSystemId(String)"); - } - - @Override - public String getStringValue() { - throw createUnsupportedOperationException("ValueRepresentation.getStringValue()"); - } - - @Override - public CharSequence getStringValueCS() { - throw createUnsupportedOperationException("ValueRepresentation.getStringValueCS()"); - } - - @Override - public SequenceIterator getTypedValue() throws XPathException { - throw createUnsupportedOperationException("Item.getTypedValue()"); - } - - @Override - public Object getUnderlyingNode() { - throw createUnsupportedOperationException("VirtualNode.getUnderlyingNode()"); - } - - @Override - public int getSiblingPosition() { - throw createUnsupportedOperationException("SiblingCountingNode.getSiblingPosition()"); - } - - @Override - public Value atomize() throws XPathException { - throw createUnsupportedOperationException("NodeInfo.atomize()"); - } - - @Override - public int compareOrder(NodeInfo other) { - throw createUnsupportedOperationException("NodeInfo.compareOrder(NodeInfo)"); - } - - @Override - public void copy(Receiver receiver, int whichNamespaces, boolean copyAnnotations, int locationId) - throws XPathException { - throw createUnsupportedOperationException("ValueRepresentation.copy(Receiver, int, boolean, int)"); - } - - /** - * This implementation considers to NodeInfo objects to be equal, if their - * underlying nodes are equal. - * - * {@inheritDoc} - */ - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (other instanceof ElementNode) { - return this.getUnderlyingNode() == ((ElementNode) other).getUnderlyingNode(); - } - return false; - } - - @Override - public int hashCode() { - if (this.getUnderlyingNode() != null) { - return super.hashCode() + 31 * this.getUnderlyingNode().hashCode(); - } else { - return super.hashCode(); - } - } - - @Override - public void generateId(FastStringBuffer buffer) { - throw createUnsupportedOperationException("NodeInfo.generateId(FastStringBuffer)"); - } - - @Override - public String getAttributeValue(int fingerprint) { - throw createUnsupportedOperationException("NodeInfo.getAttributeValue(int)"); - } - - @Override - public String getBaseURI() { - throw createUnsupportedOperationException("NodeInfo.getBaseURI()"); - } - - @Override - public int getColumnNumber() { - throw createUnsupportedOperationException("NodeInfo.getColumnNumber()"); - } - - @Override - public Configuration getConfiguration() { - throw createUnsupportedOperationException("NodeInfo.getConfiguration()"); - } - - @Override - public int[] getDeclaredNamespaces(int[] buffer) { - throw createUnsupportedOperationException("NodeInfo.getDeclaredNamespaces(int[])"); - } - - @Override - public String getDisplayName() { - throw createUnsupportedOperationException("NodeInfo.getDisplayName()"); - } - - /** - * This implementation always returns 0. - * - * {@inheritDoc} - */ - @Override - public int getDocumentNumber() { - return 0; - } - - @Override - public DocumentInfo getDocumentRoot() { - throw createUnsupportedOperationException("NodeInfo.getDocumentRoot()"); - } - - @Override - public int getFingerprint() { - throw createUnsupportedOperationException("NodeInfo.getFingerprint()"); - } - - @Override - public int getLineNumber() { - throw createUnsupportedOperationException("NodeInfo.getLineNumber()"); - } - - @Override - public String getLocalPart() { - throw createUnsupportedOperationException("NodeInfo.getLocalPart()"); - } - - @Override - public int getNameCode() { - throw createUnsupportedOperationException("NodeInfo.getNameCode()"); - } - - @Override - public NamePool getNamePool() { - throw createUnsupportedOperationException("NodeInfo.getNamePool()"); - } - - @Override - public int getNodeKind() { - throw createUnsupportedOperationException("NodeInfo.getNodeKind()"); - } - - @Override - public NodeInfo getParent() { - throw createUnsupportedOperationException("NodeInfo.getParent()"); - } - - @Override - public String getPrefix() { - throw createUnsupportedOperationException("NodeInfo.getPrefix()"); - } - - @Override - public NodeInfo getRoot() { - throw createUnsupportedOperationException("NodeInfo.getRoot()"); - } - - @Override - public int getTypeAnnotation() { - throw createUnsupportedOperationException("NodeInfo.getTypeAnnotation()"); - } - - @Override - public String getURI() { - throw createUnsupportedOperationException("NodeInfo.getURI()"); - } - - @Override - public boolean hasChildNodes() { - throw createUnsupportedOperationException("NodeInfo.hasChildNodes()"); - } - - @Override - public boolean isId() { - throw createUnsupportedOperationException("NodeInfo.isId()"); - } - - @Override - public boolean isIdref() { - throw createUnsupportedOperationException("NodeInfo.isIdref()"); - } - - @Override - public boolean isNilled() { - throw createUnsupportedOperationException("NodeInfo.isNilled()"); - } - - /** - * This implementation delegates to {@link #equals(Object)}, per the Saxon - * documentation's description of this method's behavior. - * - * {@inheritDoc} - */ - @Override - public boolean isSameNodeInfo(NodeInfo other) { - return this.equals(other); - } - - @Override - public AxisIterator iterateAxis(byte axisNumber) { - throw createUnsupportedOperationException( - "NodeInfo.iterateAxis(byte) for axis '" + Axis.axisName[axisNumber] + "'"); - } - - /** - * This implementation calls {@link #iterateAxis(byte)} to get an - * {@link AxisIterator} which is then optionally filtered using - * {@link AxisFilter}. - * - * {@inheritDoc} - */ - @Override - public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { - return filter(iterateAxis(axisNumber), nodeTest); - } - - protected static AxisIterator filter(AxisIterator axisIterator, NodeTest nodeTest) { - return nodeTest != null ? new AxisFilter(axisIterator, nodeTest) : axisIterator; - } - - /** - * Used to create a customized instance of UnsupportedOperationException. - * The caller of this method is intended to throw the - * exception. - * - * @param name - * Method name that is not supported. - * @return A UnsupportedOperationException indicated the method is not - * supported by the implementation class. - */ - protected UnsupportedOperationException createUnsupportedOperationException(String name) { - return new UnsupportedOperationException(name + " is not implemented by " + this.getClass().getName()); - } -} 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 deleted file mode 100644 index d22adb33ab..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeAxisIterator.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -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; -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; - protected final Iterator iterator; - - /** - * Create an iterator over the Attribute axis for the given ElementNode. - * - * @see net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator - */ - public AttributeAxisIterator(ElementNode startNodeInfo) { - this.startNodeInfo = startNodeInfo; - this.iterator = startNodeInfo.node.getXPathAttributesIterator(); - } - - @Override - public SequenceIterator getAnother() { - return new AttributeAxisIterator(startNodeInfo); - } - - @Override - public void advance() { - if (this.iterator.hasNext()) { - Attribute attribute = this.iterator.next(); - super.current = new AttributeNode(startNodeInfo, attribute, super.position()); - } else { - super.current = null; - } - } -} 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 deleted file mode 100644 index 7a919967ef..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/AttributeNode.java +++ /dev/null @@ -1,85 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.saxon; - -import java.util.List; - -import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttrLogger; -import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery; - -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.om.SequenceIterator; -import net.sf.saxon.trans.XPathException; -import net.sf.saxon.type.Type; -import net.sf.saxon.value.Value; - -/** - * A Saxon OM Attribute node for an AST Node Attribute. - * Belongs to an {@link ElementNode}, and wraps an - * {@link Attribute}. - */ -@Deprecated -@InternalApi -public class AttributeNode extends BaseNodeInfo { - - protected final Attribute attribute; - protected final int id; - protected Value value; - - - /** - * Creates a new AttributeNode from a PMD Attribute. - * - * @param parent Parent elemtn - * @param id The index within the attribute order - */ - public AttributeNode(ElementNode parent, Attribute attribute, int id) { - super(Type.ATTRIBUTE, parent.getNamePool(), attribute.getName(), parent); - this.attribute = attribute; - this.id = id; - } - - @Override - public String getLocalPart() { - return attribute.getName(); - } - - private DeprecatedAttrLogger getAttrCtx() { - return parent == null ? DeprecatedAttrLogger.noop() - : parent.document.getAttrCtx(); - } - - @Override - public Value atomize() { - getAttrCtx().recordUsageOf(attribute); - if (value == null) { - Object data = attribute.getValue(); - if (data instanceof List) { - value = SaxonXPathRuleQuery.getSequenceRepresentation((List) data); - } else { - value = SaxonXPathRuleQuery.getAtomicRepresentation(attribute.getValue()); - } - } - return value; - } - - @Override - public CharSequence getStringValueCS() { - return attribute.getStringValue(); - } - - @Override - public SequenceIterator getTypedValue() throws XPathException { - return atomize().iterate(); - } - - @Override - public int compareOrder(NodeInfo other) { - - return Integer.signum(this.id - ((AttributeNode) other).id); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/BaseNodeInfo.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/BaseNodeInfo.java deleted file mode 100644 index ea6e4477ac..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/BaseNodeInfo.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.saxon; - - -import net.sf.saxon.om.FingerprintedNode; -import net.sf.saxon.om.NamePool; -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.om.SiblingCountingNode; -import net.sf.saxon.om.VirtualNode; - -abstract class BaseNodeInfo extends AbstractNodeInfo implements VirtualNode, SiblingCountingNode, FingerprintedNode { - - // It's important that all our NodeInfo implementations share the - // same getNodeKind implementation, otherwise NameTest spends a lot - // of time in virtual dispatch - private final int nodeKind; - private final NamePool namePool; - private final int fingerprint; - - protected final ElementNode parent; - - BaseNodeInfo(int nodeKind, NamePool namePool, String localName, ElementNode parent) { - this.nodeKind = nodeKind; - this.namePool = namePool; - this.fingerprint = namePool.allocate("", "", localName) & NamePool.FP_MASK; - this.parent = parent; - } - - @Override - public final String getURI() { - return ""; - } - - @Override - public final String getBaseURI() { - return ""; - } - - @Override - public String getPrefix() { - return ""; - } - - @Override - public final NodeInfo getParent() { - return parent; - } - - @Override - public int getNameCode() { - // note: the nameCode is only equal to the fingerprint because - // this implementation does not use namespace prefixes - // if we change that (eg for embedded language support) then - // we'll need to worry about this. See NamePool.FP_MASK - return fingerprint; - } - - @Override - public final int getFingerprint() { - return fingerprint; - } - - @Override - public final NamePool getNamePool() { - return namePool; - } - - @Override - public final int getNodeKind() { - return nodeKind; - } - -} 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 deleted file mode 100644 index d91f1828a6..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/DocumentNode.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.saxon; - -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.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttrLogger; -import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery; - -import net.sf.saxon.om.Axis; -import net.sf.saxon.om.AxisIterator; -import net.sf.saxon.om.DocumentInfo; -import net.sf.saxon.om.NamePool; -import net.sf.saxon.om.Navigator; -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.om.SingleNodeIterator; -import net.sf.saxon.type.Type; - -/** - * A Saxon OM Document node for an AST Node. - */ -@Deprecated -@InternalApi -public class DocumentNode extends BaseNodeInfo implements DocumentInfo { - - /** - * The root ElementNode of the DocumentNode. - */ - protected final ElementNode rootNode; - - /** - * Mapping from AST Node to corresponding ElementNode. - */ - public final Map nodeToElementNode = new HashMap<>(); - - private DeprecatedAttrLogger attrCtx; - - /** - * Construct a DocumentNode, with the given AST Node serving as the root - * ElementNode. - * - * @param node The root AST Node. - * @param namePool Pool to share names - * - * @see ElementNode - */ - public DocumentNode(Node node, NamePool namePool) { - super(Type.DOCUMENT, namePool, "", null); - this.rootNode = new ElementNode(this, new IdGenerator(), null, node, -1, namePool); - } - - @Deprecated - public DocumentNode(Node node) { - this(node, SaxonXPathRuleQuery.getNamePool()); - } - - @Override - public String[] getUnparsedEntity(String name) { - throw createUnsupportedOperationException("DocumentInfo.getUnparsedEntity(String)"); - } - - @Override - public Iterator getUnparsedEntityNames() { - throw createUnsupportedOperationException("DocumentInfo.getUnparsedEntityNames()"); - } - - @Override - public NodeInfo selectID(String id) { - throw createUnsupportedOperationException("DocumentInfo.selectID(String)"); - } - - @Override - public DocumentInfo getDocumentRoot() { - return this; - } - - @Override - public boolean hasChildNodes() { - return true; - } - - @Override - public AxisIterator iterateAxis(byte axisNumber) { - switch (axisNumber) { - case Axis.DESCENDANT: - return new Navigator.DescendantEnumeration(this, false, true); - case Axis.DESCENDANT_OR_SELF: - return new Navigator.DescendantEnumeration(this, true, true); - case Axis.CHILD: - return SingleNodeIterator.makeIterator(rootNode); - default: - return super.iterateAxis(axisNumber); - } - } - - public DeprecatedAttrLogger getAttrCtx() { - return attrCtx == null ? DeprecatedAttrLogger.noop() : attrCtx; - } - - public void setAttrCtx(DeprecatedAttrLogger attrCtx) { - this.attrCtx = attrCtx; - } -} 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 deleted file mode 100644 index 6db157eac4..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/ElementNode.java +++ /dev/null @@ -1,267 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath.saxon; - -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.sourceforge.pmd.lang.ast.xpath.Attribute; -import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery; - -import net.sf.saxon.om.Axis; -import net.sf.saxon.om.AxisIterator; -import net.sf.saxon.om.DocumentInfo; -import net.sf.saxon.om.EmptyIterator; -import net.sf.saxon.om.NamePool; -import net.sf.saxon.om.Navigator; -import net.sf.saxon.om.Navigator.BaseEnumeration; -import net.sf.saxon.om.NodeArrayIterator; -import net.sf.saxon.om.NodeInfo; -import net.sf.saxon.om.SequenceIterator; -import net.sf.saxon.om.SingleNodeIterator; -import net.sf.saxon.om.SingletonIterator; -import net.sf.saxon.pattern.NameTest; -import net.sf.saxon.pattern.NodeTest; -import net.sf.saxon.type.Type; -import net.sf.saxon.value.AtomicValue; -import net.sf.saxon.value.StringValue; -import net.sf.saxon.value.UntypedAtomicValue; -import net.sf.saxon.value.Value; - -/** - * A Saxon OM Element type node for an AST Node. - */ -@Deprecated -@InternalApi -public class ElementNode extends BaseNodeInfo { - - protected final DocumentNode document; - protected final ElementNode parent; - protected final Node node; - protected final int id; - protected final int siblingPosition; - protected final NodeInfo[] children; - - private Map attributes; - - @Deprecated - public ElementNode(DocumentNode document, IdGenerator idGenerator, ElementNode parent, Node node, int siblingPosition) { - this(document, idGenerator, parent, node, siblingPosition, SaxonXPathRuleQuery.getNamePool()); - } - - public ElementNode(DocumentNode document, - IdGenerator idGenerator, - ElementNode parent, - Node node, - int siblingPosition, - NamePool namePool) { - super(Type.ELEMENT, namePool, node.getXPathNodeName(), parent); - - this.document = document; - this.parent = parent; - this.node = node; - this.id = idGenerator.getNextId(); - this.siblingPosition = siblingPosition; - - if (node.getNumChildren() > 0) { - this.children = new NodeInfo[node.getNumChildren()]; - for (int i = 0; i < children.length; i++) { - children[i] = new ElementNode(document, idGenerator, this, node.getChild(i), i, namePool); - } - } else { - this.children = null; - } - document.nodeToElementNode.put(node, this); - } - - private Map getAttributes() { - if (attributes == null) { - attributes = new HashMap<>(); - Iterator iter = node.getXPathAttributesIterator(); - int idx = 0; - while (iter.hasNext()) { - Attribute next = iter.next(); - AttributeNode attrNode = new AttributeNode(this, next, idx++); - attributes.put(attrNode.getFingerprint(), attrNode); - } - } - return attributes; - } - - @Override - public Object getUnderlyingNode() { - return node; - } - - @Override - public int getSiblingPosition() { - return siblingPosition; - } - - @Override - public int getColumnNumber() { - return node.getBeginColumn(); - } - - @Override - public int getLineNumber() { - return node.getBeginLine(); - } - - @Override - public boolean hasChildNodes() { - return children != null; - } - - @Override - public DocumentInfo getDocumentRoot() { - return document; - } - - @Override - public String getLocalPart() { - return node.getXPathNodeName(); - } - - - @Override - public SequenceIterator getTypedValue() { - return SingletonIterator.makeIterator((AtomicValue) atomize()); - } - - @Override - public Value atomize() { - switch (getNodeKind()) { - case Type.COMMENT: - case Type.PROCESSING_INSTRUCTION: - return new StringValue(getStringValueCS()); - default: - return new UntypedAtomicValue(getStringValueCS()); - } - } - - @Override - public CharSequence getStringValueCS() { - return ""; - } - - @Override - public int compareOrder(NodeInfo other) { - int result; - if (this.isSameNodeInfo(other)) { - result = 0; - } else { - result = Integer.signum(this.getLineNumber() - other.getLineNumber()); - if (result == 0) { - result = Integer.signum(this.getColumnNumber() - other.getColumnNumber()); - } - if (result == 0) { - if (this.getParent().equals(other.getParent())) { - result = Integer.signum(this.getSiblingPosition() - ((ElementNode) other).getSiblingPosition()); - } else { - // we must not return 0 here, otherwise the node might be removed as duplicate when creating - // a union set. The the nodes are definitively different nodes (isSameNodeInfo == false). - result = 1; - } - } - } - return result; - } - - - @Override - public String getDisplayName() { - return getLocalPart(); - } - - - @Override - public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) { - if (axisNumber == Axis.ATTRIBUTE) { - if (nodeTest instanceof NameTest) { - if ((nodeTest.getNodeKindMask() & (1 << Type.ATTRIBUTE)) == 0) { - return EmptyIterator.getInstance(); - } else { - int fp = nodeTest.getFingerprint(); - if (fp != -1) { - return SingleNodeIterator.makeIterator(getAttributes().get(fp)); - } - } - } - } - return super.iterateAxis(axisNumber, nodeTest); - } - - @SuppressWarnings("PMD.MissingBreakInSwitch") - @Override - public AxisIterator iterateAxis(final byte axisNumber) { - switch (axisNumber) { - case Axis.ANCESTOR: - return new Navigator.AncestorEnumeration(this, false); - case Axis.ANCESTOR_OR_SELF: - return new Navigator.AncestorEnumeration(this, true); - case Axis.ATTRIBUTE: - return new AttributeEnumeration(); - case Axis.CHILD: - if (children == null) { - return EmptyIterator.getInstance(); - } else { - return new NodeArrayIterator(children); - } - case Axis.DESCENDANT: - return new Navigator.DescendantEnumeration(this, false, true); - case Axis.DESCENDANT_OR_SELF: - return new Navigator.DescendantEnumeration(this, true, true); - case Axis.FOLLOWING: - return new Navigator.FollowingEnumeration(this); - case Axis.FOLLOWING_SIBLING: - if (parent == null || siblingPosition == parent.children.length - 1) { - return EmptyIterator.getInstance(); - } else { - return new NodeArrayIterator(parent.children, siblingPosition + 1, parent.children.length); - } - case Axis.NAMESPACE: - return super.iterateAxis(axisNumber); - case Axis.PARENT: - return SingleNodeIterator.makeIterator(parent); - case Axis.PRECEDING: - return new Navigator.PrecedingEnumeration(this, false); - case Axis.PRECEDING_SIBLING: - if (parent == null || siblingPosition == 0) { - return EmptyIterator.getInstance(); - } else { - return new NodeArrayIterator(parent.children, 0, siblingPosition); - } - case Axis.SELF: - return SingleNodeIterator.makeIterator(this); - case Axis.PRECEDING_OR_ANCESTOR: - return new Navigator.PrecedingEnumeration(this, true); - default: - return super.iterateAxis(axisNumber); - } - } - - private class AttributeEnumeration extends BaseEnumeration { - - private final Iterator iter = getAttributes().values().iterator(); - - @Override - public void advance() { - if (iter.hasNext()) { - current = iter.next(); - } else { - current = null; - } - } - - @Override - public SequenceIterator getAnother() { - return new AttributeEnumeration(); - } - } -} 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 deleted file mode 100644 index afb0886811..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/saxon/IdGenerator.java +++ /dev/null @@ -1,21 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -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; - - public int getNextId() { - return id++; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/AbstractReportNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/AbstractReportNode.java deleted file mode 100644 index bcf8866405..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/AbstractReportNode.java +++ /dev/null @@ -1,124 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.dfa.report; - -import java.util.ArrayList; -import java.util.List; - -@Deprecated // will be removed with PMD 7.0.0 without replacement. See net.sourceforge.pmd.lang.dfa.report.ReportTree for details. -public abstract class AbstractReportNode { - private List childNodes = new ArrayList<>(); - private AbstractReportNode parentNode = null; - - /* - * Number of all RuleViolations down to this node. At the moment it will - * only be calculated by running the ReportHTMLPrintVisitor. - */ - private int numberOfViolations; - - /** - * Should compare to nodes of the tree. - */ - public abstract boolean equalsNode(AbstractReportNode arg0); - - /** - * @return null If there isn't any child. - */ - public AbstractReportNode getFirstChild() { - if (this.isLeaf()) { - return null; - } - return this.childNodes.get(0); - } - - /** - * @return null If there isn't any sibling. - */ - public AbstractReportNode getNextSibling() { - if (parentNode == null) { - return null; - } - int index = parentNode.getChildIndex(this); - if (index < 0) { - return null; - } - if (index >= parentNode.childNodes.size() - 1) { - return null; - } - return parentNode.childNodes.get(index + 1); - } - - /** - * @return index The index of the x-th child of his parent. - */ - private int getChildIndex(AbstractReportNode child) { - for (int i = 0; i < childNodes.size(); i++) { - if (childNodes.get(i).equals(child)) { - return i; - } - } - return -1; - } - - /** - * Adds the child in front of any other childs. - */ - public void addFirst(AbstractReportNode child) { - childNodes.add(0, child); - child.parentNode = this; - } - - /** - * Adds the child at the end. - */ - public void add(AbstractReportNode child) { - childNodes.add(child); - child.parentNode = this; - } - - public void addNumberOfViolation(int number) { - numberOfViolations += number; - } - - /** - * @return The number of all violations downside the node. - */ - public int getNumberOfViolations() { - return numberOfViolations; - } - - // ---------------------------------------------------------------------------- - // visitor methods - public void childrenAccept(ReportVisitor visitor) { - for (int i = 0; i < childNodes.size(); i++) { - AbstractReportNode node = childNodes.get(i); - node.accept(visitor); - } - } - - public void accept(ReportVisitor visitor) { - visitor.visit(this); - } - - public AbstractReportNode getChildAt(int arg0) { - if (arg0 >= 0 && arg0 <= childNodes.size() - 1) { - return childNodes.get(arg0); - } - return null; - } - - public int getChildCount() { - return childNodes.size(); - } - - public AbstractReportNode getParent() { - return parentNode; - } - - public boolean isLeaf() { - return childNodes.isEmpty(); - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ClassNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ClassNode.java deleted file mode 100644 index eb6ec4d588..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ClassNode.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.dfa.report; - -@Deprecated // will be removed with PMD 7.0.0 without replacement. See net.sourceforge.pmd.lang.dfa.report.ReportTree for details. -public class ClassNode extends AbstractReportNode { - - private String className; - - public ClassNode(String className) { - this.className = className; - } - - public String getClassName() { - return className; - } - - @Override - public boolean equalsNode(AbstractReportNode arg0) { - if (!(arg0 instanceof ClassNode)) { - return false; - } - return ((ClassNode) arg0).getClassName().equals(className); - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/PackageNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/PackageNode.java deleted file mode 100644 index 8ba7c1ba4c..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/PackageNode.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.dfa.report; - -@Deprecated // will be removed with PMD 7.0.0 without replacement. See net.sourceforge.pmd.lang.dfa.report.ReportTree for details. -public class PackageNode extends AbstractReportNode { - - private String packageName; - - public PackageNode(String packageName) { - this.packageName = packageName; - } - - public String getPackageName() { - return this.packageName; - } - - @Override - public boolean equalsNode(AbstractReportNode arg0) { - if (!(arg0 instanceof PackageNode)) { - return false; - } - - return ((PackageNode) arg0).getPackageName().equals(this.packageName); - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ReportHTMLPrintVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ReportHTMLPrintVisitor.java deleted file mode 100644 index 682dbbc587..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ReportHTMLPrintVisitor.java +++ /dev/null @@ -1,178 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.dfa.report; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; - -import org.apache.commons.lang3.StringUtils; - -import net.sourceforge.pmd.PMD; -import net.sourceforge.pmd.RuleViolation; - -/** - * Uses the generated result tree instead of the result list. The - * visitor traverses the tree and creates several html files. The - * "package view" file (index.html) displays an overview of packages, - * classes and the number of * rule violations they contain. All the - * other html files represent a class * and show detailed information - * about the violations. - * - * @author raik - */ -@Deprecated // will be removed with PMD 7.0.0 without replacement. See net.sourceforge.pmd.lang.dfa.report.ReportTree for details. -public class ReportHTMLPrintVisitor extends ReportVisitor { - - @SuppressWarnings("PMD.AvoidStringBufferField") - private StringBuilder packageBuf = new StringBuilder(30); - @SuppressWarnings("PMD.AvoidStringBufferField") - private StringBuilder classBuf = new StringBuilder(60); - private int length; - private String baseDir; - - private static final String FILE_SEPARATOR = System.getProperty("file.separator"); - - public ReportHTMLPrintVisitor(String baseDir) { - this.baseDir = baseDir; - } - - /** - * Writes the buffer to file. - */ - private void write(String filename, StringBuilder buf) throws IOException { - try (BufferedWriter bw = Files.newBufferedWriter(new File(baseDir + FILE_SEPARATOR + filename).toPath(), - StandardCharsets.UTF_8)) { - bw.write(buf.toString(), 0, buf.length()); - } - } - - /** - * Generates a html table with violation information. - */ - private String displayRuleViolation(RuleViolation vio) { - - StringBuilder sb = new StringBuilder(200); - sb.append(""); - renderViolationRow(sb, "Rule:", vio.getRule().getName()); - renderViolationRow(sb, "Description:", vio.getDescription()); - - if (StringUtils.isNotBlank(vio.getVariableName())) { - renderViolationRow(sb, "Variable:", vio.getVariableName()); - } - - if (vio.getEndLine() > 0) { - renderViolationRow(sb, "Line:", vio.getEndLine() + " and " + vio.getBeginLine()); - } else { - renderViolationRow(sb, "Line:", Integer.toString(vio.getBeginLine())); - } - - sb.append("
"); - return sb.toString(); - } - - // TODO - join the 21st century, include CSS attributes :) - private void renderViolationRow(StringBuilder sb, String fieldName, String fieldData) { - sb.append("").append(fieldName).append("").append(fieldData).append(""); - } - - /** - * The visit method (Visitor Pattern). There are 3 types of ReportNodes: - * RuleViolation - contains a RuleViolation, Class - represents a class and - * contains the name of the class, Package - represents a package and - * contains the name(s) of the package. - */ - @Override - public void visit(AbstractReportNode node) { - - /* - * The first node of result tree. - */ - if (node.getParent() == null) { - packageBuf.insert(0, - "" + PMD.EOL - + "" + " " + PMD.EOL + " " + PMD.EOL - + " PMD" + " " + " " + PMD.EOL - + "

Package View

" - + "" + " " - + PMD.EOL + "" + "" + "" + " " + PMD.EOL); - - length = packageBuf.length(); - } - - super.visit(node); - - if (node instanceof ViolationNode) { - renderViolation((ViolationNode) node); - } - if (node instanceof ClassNode) { - renderClass((ClassNode) node); - } - if (node instanceof PackageNode) { - renderPackage((PackageNode) node); - } - - // The first node of result tree. - if (node.getParent() == null) { - packageBuf.append("
PackageClass#
"); - try { - write("index.html", packageBuf); - } catch (Exception e) { - throw new RuntimeException("Error while writing HTML report: " + e.getMessage()); - } - } - } - - private void renderViolation(ViolationNode vnode) { - - vnode.getParent().addNumberOfViolation(1); - RuleViolation vio = vnode.getRuleViolation(); - classBuf.append("" + " " + vio.getMethodName() + "" + " " + this.displayRuleViolation(vio) - + "" + ""); - } - - private void renderPackage(PackageNode pnode) { - - String str; - - // rootNode - if (pnode.getParent() == null) { - str = "Aggregate"; - } else { // all the other nodes - str = pnode.getPackageName(); - pnode.getParent().addNumberOfViolation(pnode.getNumberOfViolations()); - } - - packageBuf.insert(length, "" + str + "" + " -" + " " - + pnode.getNumberOfViolations() + "" + "" + PMD.EOL); - } - - private void renderClass(ClassNode cnode) { - - String str = cnode.getClassName(); - - classBuf.insert(0, - "" + PMD.EOL - + "PMD - " + str + "" + PMD.EOL + "

Class View

" - + "

Class: " + str + "

" - + "" + " " + PMD.EOL - + "" + "" + " " + PMD.EOL); - - classBuf.append("
MethodViolation
" + " " + ""); - - try { - write(str + ".html", classBuf); - } catch (Exception e) { - throw new RuntimeException("Error while writing HTML report: " + e.getMessage()); - } - classBuf = new StringBuilder(); - - packageBuf.insert(this.length, "" + " -" + "
" + str + "" - + " " + cnode.getNumberOfViolations() + "" + "" + PMD.EOL); - cnode.getParent().addNumberOfViolation(cnode.getNumberOfViolations()); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ReportTree.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ReportTree.java deleted file mode 100644 index 988a29e21d..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ReportTree.java +++ /dev/null @@ -1,209 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.dfa.report; - -import java.util.Iterator; - -import net.sourceforge.pmd.RuleViolation; - -/** - * - * @deprecated This class will be removed with PMD 7.0.0 without replacement. - * It is very specific for Java as it tries to recreate the package hierarchy - * of the analyzed classes and put the found violations in there. - * So it is of limited use for any other language. - */ -@Deprecated // will be removed with PMD 7.0.0 without replacement -public class ReportTree implements Iterable { - - private PackageNode rootNode = new PackageNode(""); - private AbstractReportNode level; - - private class TreeIterator implements Iterator { - - private AbstractReportNode iterNode = rootNode; - private boolean hasNextFlag; - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean hasNext() { - hasNextFlag = true; - return getNext() != null; - } - - @Override - public RuleViolation next() { - if (!hasNextFlag) { - getNext(); - } else { - hasNextFlag = false; - } - - if (iterNode instanceof ViolationNode) { - return ((ViolationNode) iterNode).getRuleViolation(); - } - return null; - } - - /** - * It's some kind of left-right-middle search (postorder). It always - * returns only leafs. The first node he returns is the most left handed - * leaf he can found. Now he's looking for siblings and if there are - * any, he starts searching for the next most left handed leaf. If there - * are no siblings he goes up to his parent and starts looking for - * siblings. If there are any he starts searching for the next most left - * handed leaf again. And so on ... until he wants to get the parent of - * the root node. Because there is no one, the search stops. - */ - - private AbstractReportNode getNext() { - AbstractReportNode node; - - while (true) { - if (iterNode.isLeaf()) { - - while ((node = iterNode.getNextSibling()) == null) { - - node = iterNode.getParent(); - if (node == null) { - return null; - } else { - iterNode = node; - } - } - - iterNode = node; - if (iterNode.isLeaf()) { - return iterNode; - } else { - continue; - } - } else { - iterNode = iterNode.getFirstChild(); - if (iterNode.isLeaf()) { - return iterNode; - } else { - continue; - } - } - } - } - } - - @Override - public Iterator iterator() { - return new TreeIterator(); - } - - public int size() { - int count = 0; - for (Iterator i = iterator(); i.hasNext();) { - i.next(); - count++; - } - return count; - } - - public AbstractReportNode getRootNode() { - return rootNode; - } - - /** - * Adds the RuleViolation to the tree. Splits the package name. Each - * package, class and violation gets there own tree node. - */ - public void addRuleViolation(RuleViolation violation) { - String packageName = violation.getPackageName(); - if (packageName == null) { - packageName = ""; - } - - level = rootNode; - - int endIndex = packageName.indexOf('.'); - while (true) { - String parentPackage; - if (endIndex < 0) { - parentPackage = packageName; - } else { - parentPackage = packageName.substring(0, endIndex); - } - - if (!isStringInLevel(parentPackage)) { - PackageNode node = new PackageNode(parentPackage); - level.addFirst(node); - // gotoLevel - level = node; - } - - if (endIndex < 0) { - break; - } - endIndex = packageName.indexOf('.', endIndex + 1); - } - - String cl = violation.getClassName(); - - if (!isStringInLevel(cl)) { - ClassNode node = new ClassNode(cl); - level.addFirst(node); - // gotoLevel - level = node; - } - - /* - * Filters duplicated rule violations. Like the comparator in - * RuleViolation if he already exists. - */ - ViolationNode tmp = new ViolationNode(violation); - if (!equalsNodeInLevel(level, tmp)) { - level.add(tmp); - } - } - - /** - * Checks if node is a child of the level node. - */ - private boolean equalsNodeInLevel(AbstractReportNode level, AbstractReportNode node) { - for (int i = 0; i < level.getChildCount(); i++) { - if (level.getChildAt(i).equalsNode(node)) { - return true; - } - } - return false; - } - - /** - * Checks if the packageName or the className is a child of the current - * (this.level) node. If it's true, the current node changes to the child - * node. - */ - private boolean isStringInLevel(String str) { - - for (int i = 0; i < level.getChildCount(); i++) { - final AbstractReportNode child = level.getChildAt(i); - final String tmp; - if (child instanceof PackageNode) { - tmp = ((PackageNode) child).getPackageName(); - } else if (child instanceof ClassNode) { - tmp = ((ClassNode) child).getClassName(); - } else { - return false; - } - - if (tmp != null && tmp.equals(str)) { - // goto level - level = child; - return true; - } - } - return false; - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ReportVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ReportVisitor.java deleted file mode 100644 index 0794187d13..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ReportVisitor.java +++ /dev/null @@ -1,14 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.dfa.report; - -@Deprecated // will be removed with PMD 7.0.0 without replacement. See net.sourceforge.pmd.lang.dfa.report.ReportTree for details. -public abstract class ReportVisitor { - - public void visit(AbstractReportNode node) { - node.childrenAccept(this); - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ViolationNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ViolationNode.java deleted file mode 100644 index 4b0c7cb683..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/dfa/report/ViolationNode.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.dfa.report; - -import net.sourceforge.pmd.RuleViolation; - -@Deprecated // will be removed with PMD 7.0.0 without replacement. See net.sourceforge.pmd.lang.dfa.report.ReportTree for details. -public class ViolationNode extends AbstractReportNode { - - private RuleViolation ruleViolation; - - public ViolationNode(RuleViolation violation) { - this.ruleViolation = violation; - } - - public RuleViolation getRuleViolation() { - return ruleViolation; - } - - @Override - public boolean equalsNode(AbstractReportNode arg0) { - if (!(arg0 instanceof ViolationNode)) { - return false; - } - - RuleViolation rv = ((ViolationNode) arg0).getRuleViolation(); - - return rv.getFilename().equals(getRuleViolation().getFilename()) - && rv.getBeginLine() == getRuleViolation().getBeginLine() - && rv.getBeginColumn() == getRuleViolation().getBeginColumn() - && rv.getEndLine() == getRuleViolation().getEndLine() - && rv.getEndColumn() == getRuleViolation().getEndColumn() - && rv.getVariableName().equals(getRuleViolation().getVariableName()); - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractDelegateRule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractDelegateRule.java index 5244eb6b6c..f34e442045 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractDelegateRule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractDelegateRule.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.rule; import java.util.List; import java.util.Map; -import java.util.Set; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; @@ -93,11 +92,6 @@ public abstract class AbstractDelegateRule implements Rule { return rule.dysfunctionReason(); } - @Override - public Set> ignoredProperties() { - return rule.ignoredProperties(); - } - @Override public String getName() { return rule.getName(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ParametricRuleViolation.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ParametricRuleViolation.java index 8e8073aced..285d27ae8b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ParametricRuleViolation.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/ParametricRuleViolation.java @@ -11,7 +11,6 @@ import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.properties.PropertyDescriptor; -import net.sourceforge.pmd.util.StringUtil; public class ParametricRuleViolation implements RuleViolation { @@ -66,19 +65,15 @@ public class ParametricRuleViolation implements RuleViolation { final int endIndex = buf.indexOf("}", startIndex); if (endIndex >= 0) { final String name = buf.substring(startIndex + 2, endIndex); - if (isVariable(name)) { - buf.replace(startIndex, endIndex + 1, getVariableValue(name)); + String variableValue = getVariableValue(name); + if (variableValue != null) { + buf.replace(startIndex, endIndex + 1, variableValue); } } } return buf.toString(); } - protected boolean isVariable(String name) { - return StringUtil.isAnyOf(name, "variableName", "methodName", "className", "packageName") - || rule.getPropertyDescriptor(name) != null; - } - protected String getVariableValue(String name) { if ("variableName".equals(name)) { return variableName; @@ -90,7 +85,7 @@ public class ParametricRuleViolation implements RuleViolation { return packageName; } else { final PropertyDescriptor propertyDescriptor = rule.getPropertyDescriptor(name); - return String.valueOf(rule.getProperty(propertyDescriptor)); + return propertyDescriptor == null ? null : String.valueOf(rule.getProperty(propertyDescriptor)); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleReference.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleReference.java index e3086542b3..29dec60d4c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleReference.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/RuleReference.java @@ -349,42 +349,6 @@ public class RuleReference extends AbstractDelegateRule { return propertyValues != null && propertyValues.containsKey(descriptor); } - @Override - @Deprecated - public boolean usesDefaultValues() { - - List> descriptors = getOverriddenPropertyDescriptors(); - if (!descriptors.isEmpty()) { - return false; - } - - for (PropertyDescriptor desc : descriptors) { - if (!Objects.equals(desc.defaultValue(), getProperty(desc))) { - return false; - } - } - - return getRule().usesDefaultValues(); - } - - @Override - @Deprecated - public void useDefaultValueFor(PropertyDescriptor desc) { - - // not sure if we should go all the way through to the real thing? - getRule().useDefaultValueFor(desc); - - if (propertyValues == null) { - return; - } - - propertyValues.remove(desc); - - if (propertyDescriptors != null) { - propertyDescriptors.remove(desc); - } - } - @Override public Rule deepCopy() { return new RuleReference(this); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/XPathRule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/XPathRule.java index e2d5a51890..eef4f999b6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/XPathRule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/XPathRule.java @@ -4,10 +4,6 @@ package net.sourceforge.pmd.lang.rule; -import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_1_0; -import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_1_0_COMPATIBILITY; -import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_2_0; - import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -21,23 +17,25 @@ import org.checkerframework.checker.nullness.qual.NonNull; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.annotation.DeprecatedUntil700; import net.sourceforge.pmd.lang.ast.AstProcessingStage; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttrLogger; -import net.sourceforge.pmd.lang.rule.xpath.JaxenXPathRuleQuery; -import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery; -import net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery; import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; +import net.sourceforge.pmd.lang.rule.xpath.internal.DeprecatedAttrLogger; +import net.sourceforge.pmd.lang.rule.xpath.internal.SaxonXPathRuleQuery; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; + /** * Rule that tries to match an XPath expression against a DOM view of an AST. */ -public class XPathRule extends AbstractRule { +public final class XPathRule extends AbstractRule { private static final Logger LOG = Logger.getLogger(XPathRule.class.getName()); + // TODO move to XPath subpackage + /** * @deprecated Use {@link #XPathRule(XPathVersion, String)} */ @@ -48,55 +46,38 @@ public class XPathRule extends AbstractRule { .defaultValue("") .build(); - private static final Map XPATH_VERSIONS; - - static { - Map tmp = new HashMap<>(); - tmp.put(XPATH_1_0, XPATH_1_0); - tmp.put(XPATH_1_0_COMPATIBILITY, XPATH_1_0_COMPATIBILITY); - tmp.put(XPATH_2_0, XPATH_2_0); - XPATH_VERSIONS = Collections.unmodifiableMap(tmp); - } - - /** * @deprecated Use {@link #XPathRule(XPathVersion, String)} */ @Deprecated - public static final PropertyDescriptor VERSION_DESCRIPTOR = - PropertyFactory.enumProperty("version", XPATH_VERSIONS) + @DeprecatedUntil700 + public static final PropertyDescriptor VERSION_DESCRIPTOR = + PropertyFactory.enumProperty("version", getXPathVersions()) .desc("XPath specification version") - .defaultValue(XPATH_1_0) + .defaultValue(XPathVersion.DEFAULT) .build(); /** - * This is initialized only once when calling {@link #evaluate(Node, RuleContext)} {@link #getTargetSelector()}. + * This is initialized only once when calling {@link #apply(Node, RuleContext)} or {@link #getTargetSelector()}. */ - private XPathRuleQuery xpathRuleQuery; + private SaxonXPathRuleQuery xpathRuleQuery; + // this is shared with rules forked by deepCopy, used by the XPathRuleQuery private DeprecatedAttrLogger attrLogger = DeprecatedAttrLogger.create(this); + /** - * Creates a new XPathRule without the corresponding XPath query. - * - * @deprecated Use {@link #XPathRule(XPathVersion, String)} + * @deprecated This is now only used by the ruleset loader. When + * we have syntactic sugar for XPath rules in the XML, we won't + * need this anymore. */ + @Deprecated public XPathRule() { definePropertyDescriptor(XPATH_DESCRIPTOR); definePropertyDescriptor(VERSION_DESCRIPTOR); } - /** - * Creates a new XPathRule and associates the XPath query. - * - * @deprecated Use {@link #XPathRule(XPathVersion, String)} - */ - public XPathRule(final String xPath) { - this(); - setXPath(xPath); - } - /** * Make a new XPath rule with the given version + expression * @@ -107,10 +88,12 @@ public class XPathRule extends AbstractRule { */ public XPathRule(XPathVersion version, String expression) { this(); + Objects.requireNonNull(version, "XPath version is null"); Objects.requireNonNull(expression, "XPath expression is null"); - setXPath(expression); - setVersion(version.getXmlName()); + + setProperty(XPathRule.XPATH_DESCRIPTOR, expression); + setProperty(XPathRule.VERSION_DESCRIPTOR, XPathVersion.ofId(version.getXmlName())); } @@ -126,7 +109,7 @@ public class XPathRule extends AbstractRule { * set or invalid. */ public XPathVersion getVersion() { - return XPathVersion.ofId(getProperty(VERSION_DESCRIPTOR)); + return getProperty(VERSION_DESCRIPTOR); } /** @@ -136,49 +119,20 @@ public class XPathRule extends AbstractRule { return getProperty(XPATH_DESCRIPTOR); } - /** - * @deprecated Use the constructor {@link #XPathRule(XPathVersion, String)}, - * don't set the expression after the fact. - */ - @Deprecated - public void setXPath(final String xPath) { - setProperty(XPathRule.XPATH_DESCRIPTOR, xPath); - } - - /** - * @deprecated Use the constructor {@link #XPathRule(XPathVersion, String)}, - * don't set the version after the fact. - */ - @Deprecated - public void setVersion(final String version) { - setProperty(XPathRule.VERSION_DESCRIPTOR, version); - } @Override public void apply(Node target, RuleContext ctx) { - evaluate(target, ctx); - } - - /** - * Evaluate the XPath query with the AST node. All matches are reported as violations. - * - * @param node The Node that to be checked. - * @param data The RuleContext. - * - * @deprecated Use {@link #apply(Node, RuleContext)} - */ - @Deprecated - public void evaluate(final Node node, final RuleContext data) { if (xPathRuleQueryNeedsInitialization()) { initXPathRuleQuery(); } - List nodesWithViolation = xpathRuleQuery.evaluate(node, data); + List nodesWithViolation = xpathRuleQuery.evaluate(target); for (Node nodeWithViolation : nodesWithViolation) { - addViolation(data, nodeWithViolation, nodeWithViolation.getImage()); + addViolation(ctx, nodeWithViolation, nodeWithViolation.getImage()); } } + /** * Initializes {@link #xpathRuleQuery} iff {@link #xPathRuleQueryNeedsInitialization()} is true. To select the * engine in which the query will be run it looks at the XPath version. @@ -191,17 +145,14 @@ public class XPathRule extends AbstractRule { throw new IllegalStateException("Invalid XPath version, should have been caught by Rule::dysfunctionReason"); } - if (version == XPathVersion.XPATH_1_0) { - xpathRuleQuery = new JaxenXPathRuleQuery(attrLogger); - } else { - xpathRuleQuery = new SaxonXPathRuleQuery(attrLogger); - } - - xpathRuleQuery.setXPath(xpath); - xpathRuleQuery.setVersion(version.getXmlName()); - xpathRuleQuery.setProperties(getPropertiesByPropertyDescriptor()); + xpathRuleQuery = new SaxonXPathRuleQuery(xpath, + version, + getPropertiesByPropertyDescriptor(), + getLanguage().getDefaultVersion().getLanguageVersionHandler().getXPathHandler(), + attrLogger); } + /** * Checks if the {@link #xpathRuleQuery} is null and therefore requires initialization. * @@ -235,6 +186,7 @@ public class XPathRule extends AbstractRule { } } + @Override public String dysfunctionReason() { if (getVersion() == null) { @@ -245,10 +197,17 @@ public class XPathRule extends AbstractRule { return null; } - @Override public boolean dependsOn(AstProcessingStage stage) { // FIXME must be made language-specific return true; } + + private static Map getXPathVersions() { + Map tmp = new HashMap<>(); + for (XPathVersion v : XPathVersion.values()) { + tmp.put(v.getXmlName(), v); + } + return Collections.unmodifiableMap(tmp); + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/AbstractXPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/AbstractXPathRuleQuery.java deleted file mode 100644 index 5647fb9ec8..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/AbstractXPathRuleQuery.java +++ /dev/null @@ -1,82 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.properties.PropertyDescriptor; - -/** - * This implementation of XPathRuleQuery provides support for RuleChain visits. - * - * @deprecated Internal API - */ -@Deprecated -@InternalApi -public abstract class AbstractXPathRuleQuery implements XPathRuleQuery { - - /** - * The XPath query string. - */ - protected String xpath; - - /** - * The XPath version; - */ - protected String version; - - /** - * The properties. - */ - protected Map, Object> properties; - - /** - * Subclasses can manage RuleChain visits via this list. - */ - protected final List ruleChainVisits = new ArrayList<>(); - - @Override - public void setXPath(final String xpath) { - this.xpath = xpath; - } - - @Override - public void setVersion(String version) throws UnsupportedOperationException { - if (!isSupportedVersion(version)) { - throw new UnsupportedOperationException( - this.getClass().getSimpleName() + " does not support XPath version: " + version); - } - this.version = version; - } - - /** - * Subclasses should implement to indicate whether an XPath version is - * supported. - * - * @param version - * The XPath version. - * @return true if the XPath version is supported, - * false otherwise. - */ - protected abstract boolean isSupportedVersion(String version); - - @Override - public void setProperties(Map, Object> properties) { - this.properties = properties; - } - - @Override - public List getRuleChainVisits() { - return ruleChainVisits; - } - - @Override - public abstract List evaluate(Node node, RuleContext data); -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/Attribute.java similarity index 90% rename from pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java rename to pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/Attribute.java index b357987ece..6353d17a20 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/Attribute.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/Attribute.java @@ -1,19 +1,22 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.ast.xpath; +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.Collections; import java.util.List; import java.util.Objects; -import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; /** * Represents an XPath attribute of a specific node. @@ -50,6 +53,18 @@ public class Attribute { } + + /** + * Gets the generic type of the value of this attribute. + */ + public Type getType() { + return method == null ? String.class : method.getGenericReturnType(); + } + + public Class getErasedType() { + return method == null ? String.class : method.getReturnType(); + } + public String getName() { return name; } @@ -59,12 +74,6 @@ public class Attribute { return parent; } - /** Returns the most general type that the value may be. */ - @Experimental - public Class getType() { - return method == null ? String.class : method.getReturnType(); - } - /** * Returns null for "not deprecated", empty string for "deprecated without replacement", * otherwise name of replacement attribute. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/DeprecatedAttribute.java similarity index 87% rename from pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java rename to pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/DeprecatedAttribute.java index 430cf5dd73..0e9657a27f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttribute.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/DeprecatedAttribute.java @@ -2,7 +2,11 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.ast.xpath.internal; +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQuery.java deleted file mode 100644 index 4ef992f19d..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQuery.java +++ /dev/null @@ -1,282 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.jaxen.BaseXPath; -import org.jaxen.JaxenException; -import org.jaxen.Navigator; -import org.jaxen.SimpleVariableContext; -import org.jaxen.XPath; -import org.jaxen.expr.AllNodeStep; -import org.jaxen.expr.DefaultXPathFactory; -import org.jaxen.expr.Expr; -import org.jaxen.expr.LocationPath; -import org.jaxen.expr.NameStep; -import org.jaxen.expr.Predicate; -import org.jaxen.expr.Step; -import org.jaxen.expr.UnionExpr; -import org.jaxen.expr.XPathFactory; -import org.jaxen.saxpath.Axis; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.internal.ContextualizedNavigator; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttrLogger; -import net.sourceforge.pmd.properties.PropertyDescriptor; - -/** - * This is a Jaxen based XPathRule query. - * - * @deprecated Internal API - */ -@Deprecated -@InternalApi -public class JaxenXPathRuleQuery extends AbstractXPathRuleQuery { - - private static final Logger LOG = Logger.getLogger(JaxenXPathRuleQuery.class.getName()); - - static final String AST_ROOT = "_AST_ROOT_"; - - private InitializationStatus initializationStatus = InitializationStatus.NONE; - // Mapping from Node name to applicable XPath queries - Map> nodeNameToXPaths; - - private final DeprecatedAttrLogger attrCtx; - - public JaxenXPathRuleQuery() { - this(DeprecatedAttrLogger.noop()); - } - - public JaxenXPathRuleQuery(DeprecatedAttrLogger attrCtx) { - this.attrCtx = attrCtx; - } - - @Override - public boolean isSupportedVersion(String version) { - return XPATH_1_0.equals(version); - } - - @Override - public List evaluate(final Node node, final RuleContext data) { - final List results = new ArrayList<>(); - - try { - initializeExpressionIfStatusIsNoneOrPartial(new ContextualizedNavigator(attrCtx)); - - List xPaths = getXPathsForNodeOrDefault(node.getXPathNodeName()); - for (XPath xpath : xPaths) { - @SuppressWarnings("unchecked") - final List matchedNodes = xpath.selectNodes(node); - results.addAll(matchedNodes); - } - } catch (final JaxenException e) { - throw new RuntimeException(e); - } - return results; - } - - /** - * Get the XPath queries associated with the node name. If there are none, the XPath queries for the {@link #AST_ROOT} - * are obtained. - * - * @param nodeName the id of the node - * @return the list of XPath queries that match the node name - */ - private List getXPathsForNodeOrDefault(final String nodeName) { - List xPaths = nodeNameToXPaths.get(nodeName); - if (xPaths == null) { - xPaths = nodeNameToXPaths.get(AST_ROOT); - } - return xPaths; - } - - @Override - public List getRuleChainVisits() { - try { - // No Navigator available in this context - initializeExpressionIfStatusIsNoneOrPartial(null); - return super.getRuleChainVisits(); - } catch (final JaxenException ex) { - throw new RuntimeException(ex); - } - } - - /** - * - * @param navigator the navigator which is required to be non-null if the {@link #initializationStatus} is PARTIAL. - * @throws JaxenException - */ - @SuppressWarnings("unchecked") - private void initializeExpressionIfStatusIsNoneOrPartial(final Navigator navigator) throws JaxenException { - if (initializationStatus == InitializationStatus.FULL) { - return; - } - if (initializationStatus == InitializationStatus.PARTIAL && navigator == null) { - LOG.severe("XPathRule is not initialized because no navigator was provided. " - + "Please make sure to implement getXPathHandler in the handler of the language. " - + "See also AbstractLanguageVersionHandler."); - return; - } - initializeXPathExpression(navigator); - } - - private void initializeXPathExpression(final Navigator navigator) throws JaxenException { - /* - Attempt to use the RuleChain with this XPath query. - - To do so, the queries should generally look like //TypeA or //TypeA | //TypeB. We will look at the parsed XPath - AST using the Jaxen APIs to make this determination. - - If the query is not exactly what we are looking for, do not use the - RuleChain. - */ - nodeNameToXPaths = new HashMap<>(); - - final BaseXPath originalXPath = createXPath(xpath, navigator); - addQueryToNode(originalXPath, AST_ROOT); - - boolean useRuleChain = true; - final Deque pending = new ArrayDeque<>(); - pending.push(originalXPath.getRootExpr()); - while (!pending.isEmpty()) { - final Expr node = pending.pop(); - - // Need to prove we can handle this part of the query - boolean valid = false; - - // Must be a LocationPath... that is something like //Type - if (node instanceof LocationPath) { - final LocationPath locationPath = (LocationPath) node; - if (locationPath.isAbsolute()) { - // Should be at least two steps - @SuppressWarnings("unchecked") - final List steps = locationPath.getSteps(); - - if (steps.size() >= 2) { - final Step step1 = steps.get(0); - final Step step2 = steps.get(1); - // First step should be an AllNodeStep using the - // descendant or self axis - if (step1 instanceof AllNodeStep - && step1.getAxis() == Axis.DESCENDANT_OR_SELF) { - // Second step should be a NameStep using the child - // axis. - if (step2 instanceof NameStep && step2.getAxis() == Axis.CHILD) { - // Construct a new expression that is - // appropriate for RuleChain use - final XPathFactory xpathFactory = new DefaultXPathFactory(); - - // Instead of an absolute location path, we'll - // be using a relative path - final LocationPath relativeLocationPath = xpathFactory.createRelativeLocationPath(); - // The first step will be along the self axis - final Step allNodeStep = xpathFactory.createAllNodeStep(Axis.SELF); - // Retain all predicates from the original name - // step - @SuppressWarnings("unchecked") - final List predicates = step2.getPredicates(); - - for (Predicate predicate : predicates) { - allNodeStep.addPredicate(predicate); - } - relativeLocationPath.addStep(allNodeStep); - - // Retain the remaining steps from the original - // location path - for (int i = 2; i < steps.size(); i++) { - relativeLocationPath.addStep(steps.get(i)); - } - - final BaseXPath xpath = createXPath(relativeLocationPath.getText(), navigator); - addQueryToNode(xpath, ((NameStep) step2).getLocalName()); - valid = true; - } - } - } - } - } else if (node instanceof UnionExpr) { // Or a UnionExpr, that is - // something like //TypeA | - // //TypeB - UnionExpr unionExpr = (UnionExpr) node; - pending.push(unionExpr.getLHS()); - pending.push(unionExpr.getRHS()); - valid = true; - } - if (!valid) { - useRuleChain = false; - break; - } - } - - if (useRuleChain) { - // Use the RuleChain for all the nodes extracted from the xpath - // queries - super.ruleChainVisits.addAll(nodeNameToXPaths.keySet()); - } else { - // Use original XPath if we cannot use the RuleChain - nodeNameToXPaths.clear(); - addQueryToNode(originalXPath, AST_ROOT); - if (LOG.isLoggable(Level.FINE)) { - LOG.log(Level.FINE, "Unable to use RuleChain for XPath: " + xpath); - } - } - - if (navigator == null) { - this.initializationStatus = InitializationStatus.PARTIAL; - // Clear the node data, because we did not have a Navigator - nodeNameToXPaths = null; - } else { - this.initializationStatus = InitializationStatus.FULL; - } - } - - /** - * Relates an XPath query to a node by adding the query to the {@link #nodeNameToXPaths}. - * - * @param xPath the query to do over a node - * @param nodeName the node on which to do the query - */ - private void addQueryToNode(final XPath xPath, final String nodeName) { - List xPathsForNode = nodeNameToXPaths.get(nodeName); - if (xPathsForNode == null) { - xPathsForNode = new ArrayList<>(); - nodeNameToXPaths.put(nodeName, xPathsForNode); - } - xPathsForNode.add(xPath); - } - - private BaseXPath createXPath(final String xpathQueryString, final Navigator navigator) throws JaxenException { - final BaseXPath xpath = new BaseXPath(xpathQueryString, navigator); - - if (properties.size() > 1) { - final SimpleVariableContext vc = new SimpleVariableContext(); - for (Entry, Object> e : properties.entrySet()) { - final String propName = e.getKey().name(); - if (!"xpath".equals(propName)) { - final Object value = e.getValue(); - vc.setVariableValue(propName, value != null ? value.toString() : null); - } - } - xpath.setVariableContext(vc); - } - return xpath; - } - - - private enum InitializationStatus { - NONE, PARTIAL, FULL - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NoAttribute.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/NoAttribute.java similarity index 92% rename from pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NoAttribute.java rename to pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/NoAttribute.java index a359b844f0..651569027c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/NoAttribute.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/NoAttribute.java @@ -1,8 +1,12 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.ast.xpath; +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java deleted file mode 100644 index 4bcb8f7423..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQuery.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Pattern; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttrLogger; -import net.sourceforge.pmd.lang.ast.xpath.saxon.DocumentNode; -import net.sourceforge.pmd.lang.ast.xpath.saxon.ElementNode; -import net.sourceforge.pmd.lang.rule.xpath.internal.RuleChainAnalyzer; -import net.sourceforge.pmd.lang.xpath.Initializer; -import net.sourceforge.pmd.properties.PropertyDescriptor; -import net.sourceforge.pmd.util.DataMap; -import net.sourceforge.pmd.util.DataMap.DataKey; -import net.sourceforge.pmd.util.DataMap.SimpleDataKey; - -import net.sf.saxon.expr.Expression; -import net.sf.saxon.om.Item; -import net.sf.saxon.om.NamePool; -import net.sf.saxon.om.NamespaceConstant; -import net.sf.saxon.om.SequenceIterator; -import net.sf.saxon.om.ValueRepresentation; -import net.sf.saxon.sxpath.AbstractStaticContext; -import net.sf.saxon.sxpath.IndependentContext; -import net.sf.saxon.sxpath.XPathDynamicContext; -import net.sf.saxon.sxpath.XPathEvaluator; -import net.sf.saxon.sxpath.XPathExpression; -import net.sf.saxon.sxpath.XPathStaticContext; -import net.sf.saxon.sxpath.XPathVariable; -import net.sf.saxon.trans.XPathException; -import net.sf.saxon.value.AtomicValue; -import net.sf.saxon.value.BigIntegerValue; -import net.sf.saxon.value.BooleanValue; -import net.sf.saxon.value.DoubleValue; -import net.sf.saxon.value.EmptySequence; -import net.sf.saxon.value.FloatValue; -import net.sf.saxon.value.Int64Value; -import net.sf.saxon.value.SequenceExtent; -import net.sf.saxon.value.StringValue; -import net.sf.saxon.value.UntypedAtomicValue; -import net.sf.saxon.value.Value; - -/** - * This is a Saxon based XPathRule query. - * - * @deprecated Internal API - */ -@Deprecated -@InternalApi -public class SaxonXPathRuleQuery extends AbstractXPathRuleQuery { - - /** - * Special nodeName that references the root expression. - */ - static final String AST_ROOT = "_AST_ROOT_"; - - private static final Logger LOG = Logger.getLogger(SaxonXPathRuleQuery.class.getName()); - - private static final NamePool NAME_POOL = new NamePool(); - - /** Cache key for the wrapped tree for saxon. */ - private static final SimpleDataKey SAXON_TREE_CACHE_KEY = DataMap.simpleDataKey("saxon.tree"); - - /** - * Contains for each nodeName a sub expression, used for implementing rule chain. - */ - Map> nodeNameToXPaths = new HashMap<>(); - - /** - * Representation of an XPath query, created at {@link #initializeXPathExpression()} using {@link #xpath}. - */ - XPathExpression xpathExpression; - - /** - * Holds the static context later used to match the variables in the dynamic context in - * {@link #createDynamicContext(ElementNode)}. Created at {@link #initializeXPathExpression()} - * using the properties descriptors in {@link #properties}. - */ - private List xpathVariables; - - private final DeprecatedAttrLogger attrCtx; - - @Deprecated - public SaxonXPathRuleQuery() { - this(DeprecatedAttrLogger.noop()); - } - - public SaxonXPathRuleQuery(DeprecatedAttrLogger attrCtx) { - this.attrCtx = attrCtx; - } - - @Override - public boolean isSupportedVersion(String version) { - return XPATH_1_0_COMPATIBILITY.equals(version) || XPATH_2_0.equals(version); - } - - @Override - public List evaluate(final Node node, final RuleContext data) { - initializeXPathExpression(); - - try { - final DocumentNode documentNode = getDocumentNodeForRootNode(node); - documentNode.setAttrCtx(attrCtx); // - - // Map AST Node -> Saxon Node - final ElementNode rootElementNode = documentNode.nodeToElementNode.get(node); - assert rootElementNode != null : "Cannot find " + node; - final XPathDynamicContext xpathDynamicContext = createDynamicContext(rootElementNode); - - final List nodes = new LinkedList<>(); - List expressions = getXPathExpressionForNodeOrDefault(node.getXPathNodeName()); - for (Expression expression : expressions) { - SequenceIterator iterator = expression.iterate(xpathDynamicContext.getXPathContextObject()); - Item current = iterator.next(); - while (current != null) { - nodes.add((ElementNode) current); - current = iterator.next(); - } - } - - /* - Map List of Saxon Nodes -> List of AST Nodes, which were detected to match the XPath expression - (i.e. violation found) - */ - final List results = new ArrayList<>(nodes.size()); - for (final ElementNode elementNode : nodes) { - results.add((Node) elementNode.getUnderlyingNode()); - } - Collections.sort(results, RuleChainAnalyzer.documentOrderComparator()); - return results; - } catch (final XPathException e) { - throw new RuntimeException(super.xpath + " had problem: " + e.getMessage(), e); - } - } - - private List getXPathExpressionForNodeOrDefault(String nodeName) { - if (nodeNameToXPaths.containsKey(nodeName)) { - return nodeNameToXPaths.get(nodeName); - } - return nodeNameToXPaths.get(AST_ROOT); - } - - /** - * Attempt to create a dynamic context on which to evaluate the {@link #xpathExpression}. - * - * @param elementNode the node on which to create the context; generally this node is the root node of the Saxon - * Tree - * @return the dynamic context on which to run the query - * @throws XPathException if the supplied value does not conform to the required type of the - * variable, when setting up the dynamic context; or if the supplied value contains a node that does not belong to - * this Configuration (or another Configuration that shares the same namePool) - */ - private XPathDynamicContext createDynamicContext(final ElementNode elementNode) throws XPathException { - final XPathDynamicContext dynamicContext = xpathExpression.createDynamicContext(elementNode); - - // Set variable values on the dynamic context - for (final XPathVariable xpathVariable : xpathVariables) { - final String variableName = xpathVariable.getVariableQName().getLocalName(); - for (final Map.Entry, Object> entry : super.properties.entrySet()) { - if (variableName.equals(entry.getKey().name())) { - final ValueRepresentation valueRepresentation = getRepresentation(entry.getKey(), entry.getValue()); - dynamicContext.setVariable(xpathVariable, valueRepresentation); - } - } - } - return dynamicContext; - } - - - private ValueRepresentation getRepresentation(final PropertyDescriptor descriptor, final Object value) { - if (descriptor.isMultiValue()) { - return getSequenceRepresentation((List) value); - } else { - return getAtomicRepresentation(value); - } - } - - /** - * Gets the DocumentNode representation for the whole AST in which the node is, that is, if the node is not the root - * of the AST, then the AST is traversed all the way up until the root node is found. If the DocumentNode was - * cached because this method was previously called, then a new DocumentNode will not be instanced. - * - * @param node the node from which the root node will be looked for. - * @return the DocumentNode representing the whole AST - */ - private DocumentNode getDocumentNodeForRootNode(final Node node) { - final Node root = getRootNode(node); - - DataMap> userMap = root.getUserMap(); - DocumentNode docNode = userMap.get(SAXON_TREE_CACHE_KEY); - if (docNode == null) { - docNode = new DocumentNode(root, getNamePool()); - userMap.set(SAXON_TREE_CACHE_KEY, docNode); - } - return docNode; - } - - /** - * Traverse the AST until the root node is found. - * - * @param node the node from where to start traversing the tree - * @return the root node - */ - private Node getRootNode(final Node node) { - Node root = node; - while (root.getParent() != null) { - root = root.getParent(); - } - return root; - } - - private void addExpressionForNode(String nodeName, Expression expression) { - if (!nodeNameToXPaths.containsKey(nodeName)) { - nodeNameToXPaths.put(nodeName, new LinkedList()); - } - nodeNameToXPaths.get(nodeName).add(expression); - } - - /** - * Initialize the {@link #xpathExpression} and the {@link #xpathVariables}. - */ - private void initializeXPathExpression() { - if (xpathExpression != null) { - return; - } - try { - final XPathEvaluator xpathEvaluator = new XPathEvaluator(); - final XPathStaticContext xpathStaticContext = xpathEvaluator.getStaticContext(); - xpathStaticContext.getConfiguration().setNamePool(getNamePool()); - - // Enable XPath 1.0 compatibility - if (XPATH_1_0_COMPATIBILITY.equals(version)) { - ((AbstractStaticContext) xpathStaticContext).setBackwardsCompatibilityMode(true); - } - - ((IndependentContext) xpathStaticContext).declareNamespace("fn", NamespaceConstant.FN); - - // Register PMD functions - Initializer.initialize((IndependentContext) xpathStaticContext); - - /* - Create XPathVariables for later use. It is a Saxon quirk that XPathVariables must be defined on the - static context, and reused later to associate an actual value on the dynamic context creation, in - createDynamicContext(ElementNode). - */ - xpathVariables = new ArrayList<>(); - for (final PropertyDescriptor propertyDescriptor : super.properties.keySet()) { - final String name = propertyDescriptor.name(); - if (!"xpath".equals(name)) { - final XPathVariable xpathVariable = xpathStaticContext.declareVariable(null, name); - xpathVariables.add(xpathVariable); - } - } - - xpathExpression = xpathEvaluator.createExpression(super.xpath); - analyzeXPathForRuleChain(xpathEvaluator); - } catch (final XPathException e) { - throw new RuntimeException(e); - } - } - - private void analyzeXPathForRuleChain(final XPathEvaluator xpathEvaluator) { - final Expression expr = xpathExpression.getInternalExpression(); - - boolean useRuleChain = true; - - // First step: Split the union venn expressions into single expressions - Iterable subexpressions = RuleChainAnalyzer.splitUnions(expr); - - // Second step: Analyze each expression separately - for (Expression subexpression : subexpressions) { - RuleChainAnalyzer rca = new RuleChainAnalyzer(xpathEvaluator.getConfiguration()); - Expression modified = rca.visit(subexpression); - - if (rca.getRootElement() != null) { - addExpressionForNode(rca.getRootElement(), modified); - } else { - // couldn't find a root element for the expression, that means, we can't use rule chain at all - // even though, it would be possible for part of the expression. - useRuleChain = false; - break; - } - } - - if (useRuleChain) { - super.ruleChainVisits.addAll(nodeNameToXPaths.keySet()); - } else { - nodeNameToXPaths.clear(); - if (LOG.isLoggable(Level.FINE)) { - LOG.log(Level.FINE, "Unable to use RuleChain for XPath: " + xpath); - } - } - - // always add fallback expression - addExpressionForNode(AST_ROOT, xpathExpression.getInternalExpression()); - } - - /** - * Gets the Saxon representation of the parameter, if its type corresponds - * to an XPath 2.0 atomic datatype. - * - * @param value The value to convert - * - * @return The converted AtomicValue - */ - public static AtomicValue getAtomicRepresentation(final Object value) { - - /* - FUTURE When supported, we should consider refactor this implementation to use Pattern Matching - (see http://openjdk.java.net/jeps/305) so that it looks clearer. - */ - if (value == null) { - return UntypedAtomicValue.ZERO_LENGTH_UNTYPED; - } else if (value instanceof Enum) { - // enums use their toString - return new StringValue(value.toString()); - } else if (value instanceof String) { - return new StringValue((String) value); - } else if (value instanceof Boolean) { - return BooleanValue.get((Boolean) value); - } else if (value instanceof Integer) { - return Int64Value.makeIntegerValue((Integer) value); - } else if (value instanceof Long) { - return new BigIntegerValue((Long) value); - } else if (value instanceof Double) { - return new DoubleValue((Double) value); - } else if (value instanceof Character) { - return new StringValue(value.toString()); - } else if (value instanceof Float) { - return new FloatValue((Float) value); - } else if (value instanceof Pattern) { - return new StringValue(String.valueOf(value)); - } else { - // We could maybe use UntypedAtomicValue - throw new RuntimeException("Unable to create ValueRepresentation for value of type: " + value.getClass()); - } - } - - public static Value getSequenceRepresentation(List list) { - if (list == null || list.isEmpty()) { - return EmptySequence.getInstance(); - } - final Item[] converted = new Item[list.size()]; - for (int i = 0; i < list.size(); i++) { - converted[i] = getAtomicRepresentation(list.get(i)); - } - return new SequenceExtent(converted); - } - - @Override - public List getRuleChainVisits() { - initializeXPathExpression(); - return super.getRuleChainVisits(); - } - - public static NamePool getNamePool() { - return NAME_POOL; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathRuleQuery.java deleted file mode 100644 index cd1d36c32f..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathRuleQuery.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath; - -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.properties.PropertyDescriptor; - -/** - * This interface captures the logic needed by XPathRule to implement an XPath - * based query on an AST Node. - * - *

- * Implementations of this class do not need to be thread-safe, but they will be - * reused to query against different AST Nodes. Therefore, internal state should - * be maintained in a fashion consistent with reuse. Further, implementations - * are recommended to manage internal state that is invariant over AST Nodes in - * a fashion which facilities high performance (e.g. caching). - *

- * - * @deprecated This will be internalized in 7.0.0. - */ -@InternalApi -@Deprecated -public interface XPathRuleQuery { - - /** - * XPath 1.0 version. - * - * @deprecated Use {@link XPathVersion} - */ - @Deprecated - String XPATH_1_0 = "1.0"; - - /** - * XPath 1.0 compatibility version. - * - * @deprecated Use {@link XPathVersion} - */ - @Deprecated - String XPATH_1_0_COMPATIBILITY = "1.0 compatibility"; - - /** - * XPath 2.0 version. - * - * @deprecated Use {@link XPathVersion} - */ - @Deprecated - String XPATH_2_0 = "2.0"; - - - /** - * Set the XPath query string to be used. - * - * @param xpath - * The XPath query string. - */ - void setXPath(String xpath); - - /** - * Set the XPath version to be used. - * - * @param version - * The XPath version. - * @throws UnsupportedOperationException - * if the version cannot be handled. - */ - void setVersion(String version) throws UnsupportedOperationException; - - /** - * Set the properties to use during the XPath query. - */ - void setProperties(Map, Object> properties); - - /** - * Indicates which AST Nodes (if any) should be used with the RuleChain. Use - * of the RuleChain will allow the query execute on a targed sub-tree of the - * AST, instead of the entire AST from the root. This can result in great - * performance benefits. - */ - List getRuleChainVisits(); - - /** - * Evaluate the XPath query against the given Node. - * - * @param node - * The Node. - * @param data - * The RuleContext. - * @return The matching Nodes. - */ - List evaluate(Node node, RuleContext data); -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathVersion.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathVersion.java index 7177afa443..0c2d428636 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathVersion.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/XPathVersion.java @@ -14,21 +14,34 @@ public enum XPathVersion { /** * XPath 1.0. * - * @deprecated Will become unsupported in 7.0.0 + * @deprecated not supported anymore */ @Deprecated - XPATH_1_0(XPathRuleQuery.XPATH_1_0), - + XPATH_1_0("1.0"), /** * XPath 1.0 compatibility mode. * - * @deprecated Will become unsupported in 7.0.0 + * @deprecated Not supported any more. */ @Deprecated - XPATH_1_0_COMPATIBILITY(XPathRuleQuery.XPATH_1_0_COMPATIBILITY), + XPATH_1_0_COMPATIBILITY("1.0 compatibility"), - /** XPath 2.0. */ - XPATH_2_0(XPathRuleQuery.XPATH_2_0); + /** + * XPath 2.0. + * + * @deprecated Technically still supported, use 3.1 instead. There + * are no known incompatibilities. + */ + @Deprecated + XPATH_2_0("2.0"), + /** XPath 3.1. */ + XPATH_3_1("3.1"); + + + /** + * The default XPath version for XPath queries. + */ + public static final XPathVersion DEFAULT = XPATH_3_1; private static final Map BY_NAME = new HashMap<>(); private final String version; @@ -55,6 +68,10 @@ public enum XPathVersion { return version; } + @Override + public String toString() { + return getXmlName(); + } /** * Gets an XPath version from the string used to represent diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/AbstractXPathFunctionDef.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/AbstractXPathFunctionDef.java new file mode 100644 index 0000000000..47a2d86815 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/AbstractXPathFunctionDef.java @@ -0,0 +1,32 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath.impl; + +import net.sf.saxon.lib.ExtensionFunctionDefinition; +import net.sf.saxon.om.StructuredQName; + + +/** + * Base impl for an XPath function definition. + * This uses Saxon API. + * + * @since 7.0.0 + */ +public abstract class AbstractXPathFunctionDef extends ExtensionFunctionDefinition { + + private static final String PMD_URI_PREFIX = "http://pmd.sourceforge.net/"; + private final StructuredQName qname; + + protected AbstractXPathFunctionDef(String localName, String languageTerseName) { + String namespacePrefix = "pmd-" + languageTerseName; + String uri = PMD_URI_PREFIX + namespacePrefix; + this.qname = new StructuredQName(namespacePrefix, uri, localName); + } + + @Override + public final StructuredQName getFunctionQName() { + return qname; + } +} 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/rule/xpath/impl/AttributeAxisIterator.java similarity index 84% rename from pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java rename to pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIterator.java index 9207d29b19..43f1380c81 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/rule/xpath/impl/AttributeAxisIterator.java @@ -1,12 +1,10 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.ast.xpath; +package net.sourceforge.pmd.lang.rule.xpath.impl; import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; @@ -16,11 +14,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; -import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.impl.AbstractNode; import net.sourceforge.pmd.lang.ast.impl.AbstractNodeWithTextCoordinates; -import net.sourceforge.pmd.lang.ast.xpath.NoAttribute.NoAttrScope; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.NoAttribute; +import net.sourceforge.pmd.lang.rule.xpath.NoAttribute.NoAttrScope; /** @@ -28,11 +27,7 @@ import net.sourceforge.pmd.lang.ast.xpath.NoAttribute.NoAttrScope; * 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. */ @@ -89,27 +84,10 @@ public class AttributeAxisIterator implements Iterator { } private boolean isConsideredReturnType(Method method) { - return isSimpleType(method.getReturnType()) || isSequence(method.getGenericReturnType()); - } - - private boolean isSimpleType(Class klass) { + Class klass = method.getReturnType(); return CONSIDERED_RETURN_TYPES.contains(klass) || klass.isEnum(); } - // Note: Lists are deprecated with 6.25.0, see #2451 - // we still allow them here for compatibility, but this can be removed with PMD 7. - @Deprecated - private boolean isSequence(Type returnType) { - if (returnType instanceof ParameterizedType && ((ParameterizedType) returnType).getRawType() == List.class) { - Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments(); - return actualTypeArguments.length == 1 - && actualTypeArguments[0] instanceof Class - && isSimpleType((Class) actualTypeArguments[0]); - } - return false; - } - - private boolean isIgnored(Class nodeClass, Method method) { Class declaration = method.getDeclaringClass(); if (method.isAnnotationPresent(NoAttribute.class)) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/XPathHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/XPathHandler.java new file mode 100644 index 0000000000..3e048f3adb --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/XPathHandler.java @@ -0,0 +1,40 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath.impl; + +import java.util.Collections; +import java.util.Set; + +import net.sourceforge.pmd.util.CollectionUtil; + +import net.sf.saxon.lib.ExtensionFunctionDefinition; + + +/** + * Interface for performing Language specific XPath handling, such as + * initialization and navigation. + */ +public interface XPathHandler { + + /** + * Returns the set of extension functions for this language module. + * These are the additional functions available in XPath queries. + */ + Set getRegisteredExtensionFunctions(); + + + static XPathHandler noFunctionDefinitions() { + return Collections::emptySet; + } + + + /** + * Returns a default XPath handler. + */ + static XPathHandler getHandlerForFunctionDefs(ExtensionFunctionDefinition first, ExtensionFunctionDefinition... defs) { + Set set = CollectionUtil.setOf(first, defs); + return () -> set; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstAttributeNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstAttributeNode.java new file mode 100644 index 0000000000..6195e129c9 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstAttributeNode.java @@ -0,0 +1,115 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath.internal; + +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; + +import net.sourceforge.pmd.lang.rule.xpath.Attribute; + +import net.sf.saxon.om.AtomicSequence; +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.tree.iter.AxisIterator; +import net.sf.saxon.tree.iter.EmptyIterator; +import net.sf.saxon.tree.util.FastStringBuffer; +import net.sf.saxon.tree.util.Navigator; +import net.sf.saxon.tree.wrapper.SiblingCountingNode; +import net.sf.saxon.type.SchemaType; +import net.sf.saxon.type.Type; + + +/** + * @since 7.0.0 + */ +class AstAttributeNode extends BaseNodeInfo implements SiblingCountingNode { + + + private final Attribute attribute; + private AtomicSequence value; + private final SchemaType schemaType; + private final int siblingPosition; + + + AstAttributeNode(AstElementNode parent, Attribute attribute, int siblingPosition) { + super(Type.ATTRIBUTE, parent.getNamePool(), attribute.getName(), parent); + this.attribute = attribute; + this.schemaType = DomainConversion.buildType(attribute.getType()); + this.siblingPosition = siblingPosition; + this.treeInfo = parent.getTreeInfo(); + } + + @Override + List getChildren() { + return Collections.emptyList(); + } + + @Override + public int getSiblingPosition() { + return siblingPosition; + } + + + @Override + protected AxisIterator iterateAttributes(Predicate nodeTest) { + return EmptyIterator.ofNodes(); + } + + @Override + protected AxisIterator iterateChildren(Predicate nodeTest) { + return EmptyIterator.ofNodes(); + } + + @Override + protected AxisIterator iterateSiblings(Predicate nodeTest, boolean forwards) { + return EmptyIterator.ofNodes(); + } + + @Override + public AtomicSequence atomize() { + if (value == null) { + value = DomainConversion.convert(attribute.getValue()); + } + return value; + } + + @Override + public SchemaType getSchemaType() { + return schemaType; + } + + + @Override + public Attribute getUnderlyingNode() { + return attribute; + } + + @Override + public int compareOrder(NodeInfo other) { + if (other instanceof SiblingCountingNode) { + return Navigator.compareOrder(this, (SiblingCountingNode) other); + } + throw new UnsupportedOperationException(); + } + + + @Override + public String getLocalPart() { + return attribute.getName(); + } + + + @Override + public void generateId(FastStringBuffer buffer) { + buffer.append(Integer.toString(hashCode())); + } + + + @Override + public CharSequence getStringValueCS() { + getTreeInfo().getLogger().recordUsageOf(attribute); + return attribute.getStringValue(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstDocumentNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstDocumentNode.java new file mode 100644 index 0000000000..b13587fe99 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstDocumentNode.java @@ -0,0 +1,93 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath.internal; + +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; + +import org.apache.commons.lang3.mutable.MutableInt; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.RootNode; + +import net.sf.saxon.Configuration; +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.tree.iter.AxisIterator; +import net.sf.saxon.tree.iter.EmptyIterator; +import net.sf.saxon.tree.util.FastStringBuffer; +import net.sf.saxon.type.Type; + +/** + * See {@link AstTreeInfo#getRootNode()}. + */ +class AstDocumentNode extends BaseNodeInfo { + + private final AstElementNode rootElement; + private final List children; + + AstDocumentNode(AstTreeInfo document, + MutableInt idGenerator, + RootNode wrappedNode, + Configuration configuration) { + super(Type.DOCUMENT, configuration.getNamePool(), "", null); + this.rootElement = new AstElementNode(document, idGenerator, this, wrappedNode, configuration); + this.children = Collections.singletonList(rootElement); + } + + @Override + List getChildren() { + return children; + } + + public AstElementNode getRootElement() { + return rootElement; + } + + @Override + protected AxisIterator iterateAttributes(Predicate nodeTest) { + return EmptyIterator.ofNodes(); + } + + @Override + protected AxisIterator iterateChildren(Predicate nodeTest) { + return filter(nodeTest, iterateList(children)); + } + + @Override + protected AxisIterator iterateSiblings(Predicate nodeTest, boolean forwards) { + return EmptyIterator.ofNodes(); + } + + @Override + public int getSiblingPosition() { + return 0; + } + + @Override + public Node getUnderlyingNode() { + return rootElement.getUnderlyingNode(); + } + + @Override + public int compareOrder(NodeInfo other) { + return other == this ? 0 : -1; + } + + @Override + public String getLocalPart() { + return ""; + } + + @Override + public void generateId(FastStringBuffer buffer) { + buffer.append("0"); + } + + @Override + public CharSequence getStringValueCS() { + return ""; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java new file mode 100644 index 0000000000..b5debaa918 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java @@ -0,0 +1,235 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath.internal; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +import org.apache.commons.lang3.mutable.MutableInt; +import org.checkerframework.checker.nullness.qual.Nullable; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.RootNode; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; +import net.sourceforge.pmd.util.CollectionUtil; + +import net.sf.saxon.Configuration; +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.pattern.NameTest; +import net.sf.saxon.tree.iter.AxisIterator; +import net.sf.saxon.tree.iter.EmptyIterator; +import net.sf.saxon.tree.iter.LookaheadIterator; +import net.sf.saxon.tree.iter.SingleNodeIterator; +import net.sf.saxon.tree.util.FastStringBuffer; +import net.sf.saxon.tree.util.Navigator; +import net.sf.saxon.tree.wrapper.SiblingCountingNode; +import net.sf.saxon.type.Type; + + +/** + * A wrapper for Saxon around a Node. Note: the {@link RootNode} of a tree + * corresponds to both a document node and an element node that is its child. + */ +public final class AstElementNode extends BaseNodeInfo implements SiblingCountingNode { + + private final Node wrappedNode; + /** The index of the node in the tree according to document order */ + private final int id; + + private final List children; + private @Nullable Map attributes; + + + AstElementNode(AstTreeInfo document, + MutableInt idGenerator, + BaseNodeInfo parent, + Node wrappedNode, + Configuration configuration) { + super(Type.ELEMENT, configuration.getNamePool(), wrappedNode.getXPathNodeName(), parent); + + this.treeInfo = document; + this.wrappedNode = wrappedNode; + this.id = idGenerator.getAndIncrement(); + + this.children = new ArrayList<>(wrappedNode.getNumChildren()); + + for (int i = 0; i < wrappedNode.getNumChildren(); i++) { + children.add(new AstElementNode(document, idGenerator, this, wrappedNode.getChild(i), configuration)); + } + } + + public Map makeAttributes(Node wrappedNode) { + Map atts = new HashMap<>(); + Iterator it = wrappedNode.getXPathAttributesIterator(); + + int attrIdx = 0; + while (it.hasNext()) { + Attribute next = it.next(); + atts.put(next.getName(), new AstAttributeNode(this, next, attrIdx++)); + } + + return atts; + } + + public Map getAttributes() { + if (attributes == null) { + attributes = makeAttributes(getUnderlyingNode()); + } + return attributes; + } + + @Override + List getChildren() { + return children; + } + + @Override + public Node getUnderlyingNode() { + return wrappedNode; + } + + @Override + public int getColumnNumber() { + return wrappedNode.getBeginColumn(); + } + + @Override + public int getSiblingPosition() { + BaseNodeInfo parent = getParent(); + return !(parent instanceof AstElementNode) ? 0 + : id - ((AstElementNode) parent).id; + } + + @Override + public int compareOrder(NodeInfo other) { + if (other instanceof AstElementNode) { + return Integer.compare(this.id, ((AstElementNode) other).id); + } else if (other instanceof SiblingCountingNode) { + return Navigator.compareOrder(this, (SiblingCountingNode) other); + } + throw new UnsupportedOperationException(); + } + + @Override + protected AxisIterator iterateAttributes(Predicate predicate) { + if (predicate instanceof NameTest) { + String local = ((NameTest) predicate).getLocalPart(); + return SingleNodeIterator.makeIterator(getAttributes().get(local)); + } + + return filter(predicate, new IteratorAdapter(getAttributes().values().iterator())); + } + + @Override + protected AxisIterator iterateChildren(Predicate nodeTest) { + return filter(nodeTest, iterateList(children)); + } + + @Override // this excludes self + protected AxisIterator iterateSiblings(Predicate nodeTest, boolean forwards) { + if (parent == null) { + return EmptyIterator.ofNodes(); + } + + List siblingsList = + forwards ? CollectionUtil.drop(parent.getChildren(), wrappedNode.getIndexInParent() + 1) + : CollectionUtil.take(parent.getChildren(), wrappedNode.getIndexInParent()); + + return filter(nodeTest, iterateList(siblingsList, forwards)); + } + + + @Override + public String getAttributeValue(String uri, String local) { + AstAttributeNode attributeWrapper = getAttributes().get(local); + + return attributeWrapper == null ? null : attributeWrapper.getStringValue(); + } + + + @Override + public int getLineNumber() { + return wrappedNode.getBeginLine(); + } + + + @Override + public NodeInfo getRoot() { + return getTreeInfo().getRootNode(); + } + + + @Override + public void generateId(FastStringBuffer buffer) { + buffer.append(Integer.toString(id)); + } + + @Override + public String getLocalPart() { + return wrappedNode.getXPathNodeName(); + } + + + @Override + public CharSequence getStringValueCS() { + // https://www.w3.org/TR/xpath-datamodel-31/#ElementNode + // The string-value property of an Element Node must be the + // concatenation of the string-values of all its Text Node + // descendants in document order or, if the element has no such + // descendants, the zero-length string. + + // Since we represent all our Nodes as elements, there are no + // text nodes + return ""; + } + + @Override + public boolean hasFingerprint() { + return true; + } + + @Override + public String toString() { + return "Wrapper[" + getLocalPart() + "]@" + hashCode(); + } + + + + private static class IteratorAdapter implements AxisIterator, LookaheadIterator { + + private static final EnumSet PROPERTIES = EnumSet.of(Property.LOOKAHEAD); + private final Iterator it; + + IteratorAdapter(Iterator it) { + this.it = it; + } + + @Override + public boolean hasNext() { + return it.hasNext(); + } + + @Override + public NodeInfo next() { + return it.hasNext() ? it.next() : null; + } + + @Override + public void close() { + // nothing to do + } + + + @Override + public EnumSet getProperties() { + return PROPERTIES; + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstTreeInfo.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstTreeInfo.java new file mode 100644 index 0000000000..386fa630b0 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstTreeInfo.java @@ -0,0 +1,81 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath.internal; + +import java.util.List; + +import org.apache.commons.lang3.mutable.MutableInt; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.RootNode; + +import net.sf.saxon.Configuration; +import net.sf.saxon.om.GenericTreeInfo; + + +/** + * A wrapper around the root node of an AST, implementing {@link net.sf.saxon.om.TreeInfo}. + */ +public final class AstTreeInfo extends GenericTreeInfo { + + private DeprecatedAttrLogger logger; + + /** + * Builds an AstDocument, with the given node as the root. + * + * @param node The root AST Node. + * @param configuration Configuration of the run + * + * @see AstElementNode + */ + public AstTreeInfo(RootNode node, Configuration configuration) { + super(configuration); + MutableInt idGenerator = new MutableInt(1); // 0 is taken by the document node + setRootNode(new AstDocumentNode(this, idGenerator, node, configuration)); + } + + public AstElementNode findWrapperFor(Node node) { + // for the RootNode, this returns the document node + List indices = node.ancestorsOrSelf().toList(Node::getIndexInParent); + AstElementNode cur = getRootNode().getRootElement(); + + // this is a quick but possibly expensive check + assert cur.getUnderlyingNode() == node.getRoot() : "Node is not in this tree"; + + // note we skip the first, who is the root + for (int i = indices.size() - 2; i >= 0; i--) { + Integer idx = indices.get(i); + if (idx >= cur.getChildren().size()) { + throw new IllegalArgumentException("Node is not part of this tree " + node); + } + + cur = cur.getChildren().get(idx); + } + if (cur.getUnderlyingNode() != node) { + // may happen with the root + throw new IllegalArgumentException("Node is not part of this tree " + node); + } + return cur; + } + + /** + * Returns the document node of the tree. Note that this has a single + * child of element type. Both the document and this element child have + * the {@link RootNode} as {@link AstElementNode#getUnderlyingNode()}. + */ + @Override + public AstDocumentNode getRootNode() { + return (AstDocumentNode) super.getRootNode(); + } + + + public void setAttrCtx(DeprecatedAttrLogger attrCtx) { + this.logger = attrCtx; + } + + public DeprecatedAttrLogger getLogger() { + return logger == null ? DeprecatedAttrLogger.noop() : logger; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/BaseNodeInfo.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/BaseNodeInfo.java new file mode 100644 index 0000000000..0823b3c61f --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/BaseNodeInfo.java @@ -0,0 +1,101 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath.internal; + + +import java.util.List; +import java.util.function.Predicate; + +import net.sf.saxon.om.NamePool; +import net.sf.saxon.om.NodeInfo; +import net.sf.saxon.pattern.AnyNodeTest; +import net.sf.saxon.tree.iter.AxisIterator; +import net.sf.saxon.tree.iter.ListIterator; +import net.sf.saxon.tree.iter.ReverseListIterator; +import net.sf.saxon.tree.util.Navigator.AxisFilter; +import net.sf.saxon.tree.wrapper.AbstractNodeWrapper; +import net.sf.saxon.tree.wrapper.SiblingCountingNode; + +abstract class BaseNodeInfo extends AbstractNodeWrapper implements SiblingCountingNode { + + // It's important that all our NodeInfo implementations share the + // same getNodeKind implementation, otherwise NameTest spends a lot + // of time in virtual dispatch + private final int nodeKind; + private final NamePool namePool; + private final int fingerprint; + + protected final BaseNodeInfo parent; + + BaseNodeInfo(int nodeKind, NamePool namePool, String localName, BaseNodeInfo parent) { + this.nodeKind = nodeKind; + this.namePool = namePool; + this.fingerprint = namePool.allocateFingerprint("", localName) & NamePool.FP_MASK; + this.parent = parent; + } + + abstract List getChildren(); + + @Override + public AstTreeInfo getTreeInfo() { + return (AstTreeInfo) treeInfo; + } + + @Override + public final String getURI() { + return ""; + } + + @Override + public final String getBaseURI() { + return ""; + } + + @Override + public String getPrefix() { + return ""; + } + + @Override + public final BaseNodeInfo getParent() { + return parent; + } + + @Override + public final int getFingerprint() { + return fingerprint; + } + + @Override + public final NamePool getNamePool() { + return namePool; + } + + @Override + public final int getNodeKind() { + return nodeKind; + } + + protected static AxisIterator filter(Predicate nodeTest, AxisIterator iter) { + return nodeTest == null || (nodeTest instanceof AnyNodeTest) ? iter : new AxisFilter(iter, nodeTest); + } + + + static AxisIterator iterateList(List nodes) { + return iterateList(nodes, true); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + static AxisIterator iterateList(List nodes, boolean forwards) { + return forwards ? new ListIterator.OfNodes((List) nodes) + : new RevListAxisIterator((List) nodes); + } + + private static class RevListAxisIterator extends ReverseListIterator implements AxisIterator { + RevListAxisIterator(List list) { + super(list); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttrLogger.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DeprecatedAttrLogger.java similarity index 81% rename from pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttrLogger.java rename to pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DeprecatedAttrLogger.java index e6c2358a06..4f8c7d65b1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/internal/DeprecatedAttrLogger.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DeprecatedAttrLogger.java @@ -2,15 +2,16 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.ast.xpath.internal; +package net.sourceforge.pmd.lang.rule.xpath.internal; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; import java.util.logging.Logger; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.lang.rule.XPathRule; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; /** * Records usages of deprecated attributes in XPath rules. This needs @@ -28,8 +29,16 @@ public abstract class DeprecatedAttrLogger { * if the warnings would be ignored anyway. */ public static DeprecatedAttrLogger create(XPathRule rule) { + return doCreate(rule, false); + } + + public static DeprecatedAttrLogger createForSuppression(Rule rule) { + return doCreate(rule, true); + } + + private static DeprecatedAttrLogger doCreate(Rule rule, boolean isSuppressionQuery) { if (LOG.isLoggable(Level.WARNING)) { - return new AttrLoggerImpl(rule); + return new AttrLoggerImpl(rule, isSuppressionQuery); } else { return noop(); } @@ -64,10 +73,12 @@ public abstract class DeprecatedAttrLogger { private static class AttrLoggerImpl extends DeprecatedAttrLogger { private final ConcurrentMap deprecated = new ConcurrentHashMap<>(); - private final XPathRule rule; + private final Rule rule; + private final boolean isSuppressionQuery; - private AttrLoggerImpl(XPathRule rule) { + private AttrLoggerImpl(Rule rule, boolean isSuppressionQuery) { this.rule = rule; + this.isSuppressionQuery = isSuppressionQuery; } @Override @@ -78,7 +89,10 @@ public abstract class DeprecatedAttrLogger { Boolean b = deprecated.putIfAbsent(name, Boolean.TRUE); if (b == null) { // this message needs to be kept in sync with PMDCoverageTest / BinaryDistributionIT - String msg = "Use of deprecated attribute '" + name + "' by XPath rule " + ruleToString(); + + String user = isSuppressionQuery ? "violationSuppressXPath for rule " + ruleToString() + : "XPath rule " + ruleToString(); + String msg = "Use of deprecated attribute '" + name + "' by " + user; if (!replacement.isEmpty()) { msg += ", please use " + replacement + " instead"; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DomainConversion.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DomainConversion.java new file mode 100644 index 0000000000..58a3bf13da --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DomainConversion.java @@ -0,0 +1,157 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.regex.Pattern; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import net.sf.saxon.om.AtomicArray; +import net.sf.saxon.om.AtomicSequence; +import net.sf.saxon.om.EmptyAtomicSequence; +import net.sf.saxon.type.BuiltInAtomicType; +import net.sf.saxon.type.SchemaType; +import net.sf.saxon.value.AtomicValue; +import net.sf.saxon.value.BigIntegerValue; +import net.sf.saxon.value.BooleanValue; +import net.sf.saxon.value.DoubleValue; +import net.sf.saxon.value.FloatValue; +import net.sf.saxon.value.Int64Value; +import net.sf.saxon.value.SequenceType; +import net.sf.saxon.value.StringValue; +import net.sf.saxon.value.UntypedAtomicValue; + + +/** + * Converts Java values into XPath values. + */ +public final class DomainConversion { + + private DomainConversion() { + + } + + + public static SchemaType buildType(java.lang.reflect.Type type) { + switch (type.getTypeName()) { + case "java.lang.Integer": + case "java.lang.Long": + return BuiltInAtomicType.INTEGER; + case "java.lang.Double": + case "java.lang.Float": + return BuiltInAtomicType.DOUBLE; + case "java.lang.String": + case "java.lang.Character": + case "java.lang.Class": + case "java.util.regex.Pattern": + return BuiltInAtomicType.STRING; + default: + return BuiltInAtomicType.UNTYPED_ATOMIC; + } + } + + @NonNull + public static AtomicSequence convert(Object obj) { + if (obj instanceof Collection) { + return getSequenceRepresentation((Collection) obj); + } + return getAtomicRepresentation(obj); + } + + public static SequenceType typeOf(Object obj) { + if (obj instanceof Collection) { + if (((Collection) obj).isEmpty()) { + return SequenceType.EMPTY_SEQUENCE; + } + return SequenceType.NON_EMPTY_SEQUENCE; + } else if (obj instanceof String) { + return SequenceType.SINGLE_STRING; + } else if (obj instanceof Boolean) { + return SequenceType.SINGLE_BOOLEAN; + } else if (obj instanceof Integer) { + return SequenceType.SINGLE_INTEGER; + } else if (obj instanceof Float) { + return SequenceType.SINGLE_FLOAT; + } else if (obj instanceof Long) { + return SequenceType.SINGLE_INTEGER; + } else if (obj instanceof Double) { + return SequenceType.SINGLE_DOUBLE; + } else if (obj instanceof Number) { + return SequenceType.SINGLE_NUMERIC; + } else if (obj instanceof Enum) { + return SequenceType.SINGLE_STRING; + } else if (obj instanceof Character) { + return SequenceType.SINGLE_STRING; + } else if (obj instanceof Pattern) { + return SequenceType.SINGLE_STRING; + } + return SequenceType.SINGLE_ITEM; + } + + public static AtomicSequence getSequenceRepresentation(Collection list) { + if (list == null || list.isEmpty()) { + return EmptyAtomicSequence.getInstance(); + } + List vs = new ArrayList<>(list.size()); + flattenInto(list, vs); + return new AtomicArray(vs); + } + + // sequences cannot be nested, this takes care of list of lists, + // just in case + private static void flattenInto(Collection list, List values) { + for (Object o : list) { + if (o instanceof Collection) { + flattenInto((Collection) o, values); + } else { + values.add(getAtomicRepresentation(o)); + } + } + } + + + /** + * Gets the Saxon representation of the parameter, if its type corresponds + * to an XPath 2.0 atomic datatype. + * + * @param value The value to convert + * + * @return The converted AtomicValue + */ + @NonNull + public static AtomicValue getAtomicRepresentation(final Object value) { + + /* + FUTURE When supported, we should consider refactor this implementation to use Pattern Matching + (see http://openjdk.java.net/jeps/305) so that it looks clearer. + */ + if (value == null) { + return UntypedAtomicValue.ZERO_LENGTH_UNTYPED; + + } else if (value instanceof String) { + return new StringValue((String) value); + } else if (value instanceof Boolean) { + return BooleanValue.get((Boolean) value); + } else if (value instanceof Integer) { + return Int64Value.makeIntegerValue((Integer) value); + } else if (value instanceof Long) { + return new BigIntegerValue((Long) value); + } else if (value instanceof Double) { + return new DoubleValue((Double) value); + } else if (value instanceof Character) { + return new StringValue(value.toString()); + } else if (value instanceof Float) { + return new FloatValue((Float) value); + } else if (value instanceof Pattern || value instanceof Enum) { + return new StringValue(String.valueOf(value)); + } else { + // We could maybe use UntypedAtomicValue + throw new RuntimeException("Unable to create ValueRepresentation for value of type: " + value.getClass()); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/ExpressionPrinter.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/ExpressionPrinter.java index 7719642a03..ef20dd376d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/ExpressionPrinter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/ExpressionPrinter.java @@ -7,9 +7,9 @@ package net.sourceforge.pmd.lang.rule.xpath.internal; import net.sf.saxon.expr.AxisExpression; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.RootExpression; -import net.sf.saxon.expr.Token; import net.sf.saxon.expr.VennExpression; -import net.sf.saxon.om.Axis; +import net.sf.saxon.expr.parser.Token; +import net.sf.saxon.om.AxisInfo; /** * Simple printer for saxon expressions. Might be useful for debugging / during development. @@ -32,7 +32,7 @@ public class ExpressionPrinter extends SaxonExprVisitor { @Override public Expression visit(AxisExpression e) { - print("axis=" + Axis.axisName[e.getAxis()] + "(test=" + e.getNodeTest() + ")"); + print("axis=" + AxisInfo.axisName[e.getAxis()] + "(test=" + e.getNodeTest() + ")"); return super.visit(e); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DocumentSorter.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/PmdDocumentSorter.java similarity index 76% rename from pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DocumentSorter.java rename to pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/PmdDocumentSorter.java index 920ee61324..0b1356b1aa 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DocumentSorter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/PmdDocumentSorter.java @@ -12,11 +12,12 @@ import net.sourceforge.pmd.lang.ast.Node; /** * Sorts nodes by document order. */ -final class DocumentSorter implements Comparator { +// renamed because it conflicts with a Saxon node +final class PmdDocumentSorter implements Comparator { - public static final DocumentSorter INSTANCE = new DocumentSorter(); + public static final PmdDocumentSorter INSTANCE = new PmdDocumentSorter(); - private DocumentSorter() { + private PmdDocumentSorter() { } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/RuleChainAnalyzer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/RuleChainAnalyzer.java index e093c07dd7..100a5eb613 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/RuleChainAnalyzer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/RuleChainAnalyzer.java @@ -4,8 +4,11 @@ package net.sourceforge.pmd.lang.rule.xpath.internal; +import static net.sourceforge.pmd.util.CollectionUtil.listOf; + import java.util.Collections; import java.util.Comparator; +import java.util.List; import net.sourceforge.pmd.lang.ast.Node; @@ -13,17 +16,18 @@ import net.sf.saxon.Configuration; import net.sf.saxon.expr.AxisExpression; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.FilterExpression; -import net.sf.saxon.expr.LazyExpression; -import net.sf.saxon.expr.PathExpression; +import net.sf.saxon.expr.LetExpression; import net.sf.saxon.expr.RootExpression; -import net.sf.saxon.om.Axis; +import net.sf.saxon.expr.SlashExpression; +import net.sf.saxon.expr.VennExpression; +import net.sf.saxon.expr.sort.DocumentSorter; +import net.sf.saxon.om.AxisInfo; import net.sf.saxon.pattern.NameTest; -import net.sf.saxon.sort.DocumentSorter; import net.sf.saxon.type.Type; /** * Analyzes the xpath expression to find the root path selector for a element. If found, - * the element name is available via {@link RuleChainAnalyzer#getRootElement()} and the + * the element name is available via {@link RuleChainAnalyzer#getRootElements()} and the * expression is rewritten to start at "node::self()" instead. * *

It uses a visitor to visit all the different expressions. @@ -35,21 +39,22 @@ import net.sf.saxon.type.Type; * after all (sub)expressions have been executed. */ public class RuleChainAnalyzer extends SaxonExprVisitor { + private final Configuration configuration; - private String rootElement; + private List rootElement; private boolean rootElementReplaced; - private boolean insideLazyExpression; - private boolean foundPathInsideLazy; + private boolean insideExpensiveExpr; + private boolean foundPathInsideExpensive; public RuleChainAnalyzer(Configuration currentConfiguration) { this.configuration = currentConfiguration; } - public String getRootElement() { - if (!foundPathInsideLazy && rootElementReplaced) { - return rootElement; + public List getRootElements() { + if (!foundPathInsideExpensive && rootElementReplaced) { + return rootElement == null ? Collections.emptyList() : rootElement; } - return null; + return Collections.emptyList(); } @Override @@ -59,33 +64,59 @@ public class RuleChainAnalyzer extends SaxonExprVisitor { return result.getBaseExpression(); } + public Expression visitSlashPreserveRootElement(SlashExpression e) { + Expression start = visit(e.getStart()); + + // save state + List elt = rootElement; + boolean replaced = rootElementReplaced; + + Expression step = visit(e.getStep()); + + if (!(e.getStart() instanceof RootExpression)) { + // restore + rootElement = elt; + rootElementReplaced = replaced; + } + + return new SlashExpression(start, step); + } + @Override - public Expression visit(PathExpression e) { - if (!insideLazyExpression && rootElement == null) { - Expression result = super.visit(e); + public Expression visit(SlashExpression e) { + if (!insideExpensiveExpr && rootElement == null) { + Expression result = visitSlashPreserveRootElement(e); if (rootElement != null && !rootElementReplaced) { - if (result instanceof PathExpression) { - PathExpression newPath = (PathExpression) result; - Expression step = newPath.getStepExpression(); + if (result instanceof SlashExpression) { + SlashExpression newPath = (SlashExpression) result; + Expression step = newPath.getStep(); if (step instanceof FilterExpression) { - FilterExpression filterExpression = (FilterExpression) newPath.getStepExpression(); - result = new FilterExpression(new AxisExpression(Axis.SELF, null), filterExpression.getFilter()); + FilterExpression filterExpression = (FilterExpression) step; + result = new FilterExpression(new AxisExpression(AxisInfo.SELF, null), filterExpression.getFilter()); rootElementReplaced = true; } else if (step instanceof AxisExpression) { - if (newPath.getStartExpression() instanceof RootExpression) { - result = new AxisExpression(Axis.SELF, null); - rootElementReplaced = true; + Expression start = newPath.getStart(); + if (start instanceof RootExpression) { + result = new AxisExpression(AxisInfo.SELF, null); + } else if (start instanceof VennExpression) { + // abort, set rootElementReplaced so that the + // nodes above won't try to replace themselves + rootElement = null; + result = e; + } else { + result = new SlashExpression(start, new AxisExpression(AxisInfo.SELF, null)); } + rootElementReplaced = true; } } else { - result = new AxisExpression(Axis.DESCENDANT_OR_SELF, null); + result = new AxisExpression(AxisInfo.DESCENDANT_OR_SELF, null); rootElementReplaced = true; } } return result; } else { - if (insideLazyExpression) { - foundPathInsideLazy = true; + if (insideExpensiveExpr) { + foundPathInsideExpensive = true; } return super.visit(e); } @@ -95,26 +126,47 @@ public class RuleChainAnalyzer extends SaxonExprVisitor { public Expression visit(AxisExpression e) { if (rootElement == null && e.getNodeTest() instanceof NameTest) { NameTest test = (NameTest) e.getNodeTest(); - if (test.getPrimitiveType() == Type.ELEMENT && e.getAxis() == Axis.DESCENDANT) { - rootElement = configuration.getNamePool().getClarkName(test.getFingerprint()); - } else if (test.getPrimitiveType() == Type.ELEMENT && e.getAxis() == Axis.CHILD) { - rootElement = configuration.getNamePool().getClarkName(test.getFingerprint()); + if (test.getPrimitiveType() == Type.ELEMENT && e.getAxis() == AxisInfo.DESCENDANT) { + rootElement = listOf(configuration.getNamePool().getClarkName(test.getFingerprint())); + } else if (test.getPrimitiveType() == Type.ELEMENT && e.getAxis() == AxisInfo.CHILD) { + rootElement = listOf(configuration.getNamePool().getClarkName(test.getFingerprint())); } } return super.visit(e); } @Override - public Expression visit(LazyExpression e) { - boolean prevCtx = insideLazyExpression; - insideLazyExpression = true; - Expression result = super.visit(e); - insideLazyExpression = prevCtx; - return result; + public Expression visit(LetExpression e) { + // lazy expressions are not a thing in saxon HE + // instead saxon hoists expensive subexpressions into LetExpressions + // Eg //A[//B] + // is transformed to let bs := //B in //A + // so that the //B is done only once. + + // The cost of an expr is an abstract measure of its expensiveness, + // Eg the cost of //A or //* is 40, the cost of //A//B is 820 + // (a path expr multiplies the cost of its lhs and rhs) + + if (e.getSequence().getCost() >= 20) { + boolean prevCtx = insideExpensiveExpr; + insideExpensiveExpr = true; + Expression result = super.visit(e); + insideExpensiveExpr = prevCtx; + return result; + } else { + return super.visit(e); + } + } + + @Override + public Expression visit(VennExpression e) { + // stop visiting subtree. We assume all unions were at the root + // and flattened, here we find one that couldn't be flattened + return e; } public static Comparator documentOrderComparator() { - return net.sourceforge.pmd.lang.rule.xpath.internal.DocumentSorter.INSTANCE; + return PmdDocumentSorter.INSTANCE; } /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonExprVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonExprVisitor.java index d1dc8dd873..8a55cd1309 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonExprVisitor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonExprVisitor.java @@ -4,17 +4,19 @@ package net.sourceforge.pmd.lang.rule.xpath.internal; +import net.sf.saxon.expr.AndExpression; import net.sf.saxon.expr.AxisExpression; +import net.sf.saxon.expr.BinaryExpression; import net.sf.saxon.expr.BooleanExpression; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.FilterExpression; -import net.sf.saxon.expr.LazyExpression; import net.sf.saxon.expr.LetExpression; -import net.sf.saxon.expr.PathExpression; +import net.sf.saxon.expr.OrExpression; import net.sf.saxon.expr.QuantifiedExpression; import net.sf.saxon.expr.RootExpression; +import net.sf.saxon.expr.SlashExpression; import net.sf.saxon.expr.VennExpression; -import net.sf.saxon.sort.DocumentSorter; +import net.sf.saxon.expr.sort.DocumentSorter; abstract class SaxonExprVisitor { public Expression visit(DocumentSorter e) { @@ -22,10 +24,10 @@ abstract class SaxonExprVisitor { return new DocumentSorter(base); } - public Expression visit(PathExpression e) { - Expression start = visit(e.getStartExpression()); - Expression step = visit(e.getStepExpression()); - return new PathExpression(start, step); + public Expression visit(SlashExpression e) { + Expression start = visit(e.getStart()); + Expression step = visit(e.getStep()); + return new SlashExpression(start, step); } public Expression visit(RootExpression e) { @@ -37,18 +39,24 @@ abstract class SaxonExprVisitor { } public Expression visit(VennExpression e) { - final Expression[] operands = e.getOperands(); - Expression operand0 = visit(operands[0]); - Expression operand1 = visit(operands[1]); + Expression operand0 = visit(e.getLhsExpression()); + Expression operand1 = visit(e.getRhsExpression()); return new VennExpression(operand0, e.getOperator(), operand1); } public Expression visit(FilterExpression e) { - Expression base = visit(e.getBaseExpression()); + Expression base = visit(e.getLhsExpression()); Expression filter = visit(e.getFilter()); return new FilterExpression(base, filter); } + public Expression visit(BinaryExpression e) { + Expression base = visit(e.getLhsExpression()); + Expression filter = visit(e.getRhsExpression()); + + return new FilterExpression(base, filter); + } + public Expression visit(QuantifiedExpression e) { return e; } @@ -65,24 +73,20 @@ abstract class SaxonExprVisitor { return result; } - public Expression visit(LazyExpression e) { - Expression base = visit(e.getBaseExpression()); - return LazyExpression.makeLazyExpression(base); - } - public Expression visit(BooleanExpression e) { - final Expression[] operands = e.getOperands(); - Expression operand0 = visit(operands[0]); - Expression operand1 = visit(operands[1]); - return new BooleanExpression(operand0, e.getOperator(), operand1); + Expression operand0 = visit(e.getLhsExpression()); + Expression operand1 = visit(e.getRhsExpression()); + + return e instanceof AndExpression ? new AndExpression(operand0, operand1) + : new OrExpression(operand0, operand1); } public Expression visit(Expression expr) { Expression result; if (expr instanceof DocumentSorter) { result = visit((DocumentSorter) expr); - } else if (expr instanceof PathExpression) { - result = visit((PathExpression) expr); + } else if (expr instanceof SlashExpression) { + result = visit((SlashExpression) expr); } else if (expr instanceof RootExpression) { result = visit((RootExpression) expr); } else if (expr instanceof AxisExpression) { @@ -95,8 +99,6 @@ abstract class SaxonExprVisitor { result = visit((QuantifiedExpression) expr); } else if (expr instanceof LetExpression) { result = visit((LetExpression) expr); - } else if (expr instanceof LazyExpression) { - result = visit((LazyExpression) expr); } else if (expr instanceof BooleanExpression) { result = visit((BooleanExpression) expr); } else { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQuery.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQuery.java new file mode 100644 index 0000000000..150589ee98 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQuery.java @@ -0,0 +1,292 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath.internal; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.RootNode; +import net.sourceforge.pmd.lang.rule.XPathRule; +import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; +import net.sourceforge.pmd.lang.rule.xpath.impl.XPathHandler; +import net.sourceforge.pmd.properties.PropertyDescriptor; +import net.sourceforge.pmd.util.DataMap; +import net.sourceforge.pmd.util.DataMap.DataKey; +import net.sourceforge.pmd.util.DataMap.SimpleDataKey; + +import net.sf.saxon.Configuration; +import net.sf.saxon.expr.Expression; +import net.sf.saxon.expr.LocalVariableReference; +import net.sf.saxon.lib.ExtensionFunctionDefinition; +import net.sf.saxon.lib.NamespaceConstant; +import net.sf.saxon.om.AtomicSequence; +import net.sf.saxon.om.Item; +import net.sf.saxon.om.NamePool; +import net.sf.saxon.om.SequenceIterator; +import net.sf.saxon.om.StructuredQName; +import net.sf.saxon.sxpath.IndependentContext; +import net.sf.saxon.sxpath.XPathDynamicContext; +import net.sf.saxon.sxpath.XPathEvaluator; +import net.sf.saxon.sxpath.XPathExpression; +import net.sf.saxon.sxpath.XPathVariable; +import net.sf.saxon.trans.XPathException; + + +/** + * This is a Saxon based XPathRule query. + */ +public class SaxonXPathRuleQuery { + + /** + * Special nodeName that references the root expression. + */ + static final String AST_ROOT = "_AST_ROOT_"; + + private static final Logger LOG = Logger.getLogger(SaxonXPathRuleQuery.class.getName()); + + private static final NamePool NAME_POOL = new NamePool(); + + /** Cache key for the wrapped tree for saxon. */ + private static final SimpleDataKey SAXON_TREE_CACHE_KEY = DataMap.simpleDataKey("saxon.tree"); + + private final String xpathExpr; + @SuppressWarnings("PMD") // may be useful later, idk + private final XPathVersion version; + private final Map, Object> properties; + private final XPathHandler xPathHandler; + private final List rulechainQueries = new ArrayList<>(); + private Configuration configuration; + + /** + * Contains for each nodeName a sub expression, used for implementing rule chain. + */ + Map> nodeNameToXPaths = new HashMap<>(); + + /** + * Representation of an XPath query, created at {@link #ensureInitialized()} using {@link #xpathExpr}. + */ + XPathExpression xpathExpression; + + private final DeprecatedAttrLogger attrCtx; + + + public SaxonXPathRuleQuery(String xpathExpr, + XPathVersion version, + Map, Object> properties, + XPathHandler xPathHandler, + DeprecatedAttrLogger logger) { + this.xpathExpr = xpathExpr; + this.version = version; + this.properties = properties; + this.xPathHandler = xPathHandler; + this.attrCtx = logger; + } + + + public String getXpathExpression() { + return xpathExpr; + } + + + public List getRuleChainVisits() { + ensureInitialized(); + return rulechainQueries; + } + + + public List evaluate(final Node node) { + ensureInitialized(); + + final AstTreeInfo documentNode = getDocumentNodeForRootNode(node); + documentNode.setAttrCtx(attrCtx); + try { + + // Map AST Node -> Saxon Node + final XPathDynamicContext xpathDynamicContext = xpathExpression.createDynamicContext(documentNode.findWrapperFor(node)); + + // XPath 2.0 sequences may contain duplicates + final Set results = new LinkedHashSet<>(); + List expressions = getExpressionsForLocalNameOrDefault(node.getXPathNodeName()); + for (Expression expression : expressions) { + @SuppressWarnings("PMD.CloseResource") + SequenceIterator iterator = expression.iterate(xpathDynamicContext.getXPathContextObject()); + Item current = iterator.next(); + while (current != null) { + if (current instanceof AstElementNode) { + results.add(((AstElementNode) current).getUnderlyingNode()); + } + current = iterator.next(); + } + } + + /* + Map List of Saxon Nodes -> List of AST Nodes, which were detected to match the XPath expression + (i.e. violation found) + */ + final List sortedRes = new ArrayList<>(results); + sortedRes.sort(RuleChainAnalyzer.documentOrderComparator()); + return sortedRes; + } catch (final XPathException e) { + throw new RuntimeException(xpathExpr + " had problem: " + e.getMessage(), e); + } finally { + documentNode.setAttrCtx(DeprecatedAttrLogger.noop()); + } + } + + // test only + List getExpressionsForLocalNameOrDefault(String nodeName) { + ensureInitialized(); + List expressions = nodeNameToXPaths.get(nodeName); + if (expressions != null) { + return expressions; + } + return nodeNameToXPaths.get(AST_ROOT); + } + + // test only + Expression getFallbackExpr() { + ensureInitialized(); + return nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0); + } + + + /** + * Gets the DocumentNode representation for the whole AST in which the node is, that is, if the node is not the root + * of the AST, then the AST is traversed all the way up until the root node is found. If the DocumentNode was + * cached because this method was previously called, then a new DocumentNode will not be instanced. + * + * @param node the node from which the root node will be looked for. + * + * @return the DocumentNode representing the whole AST + */ + private AstTreeInfo getDocumentNodeForRootNode(final Node node) { + final RootNode root = node.getRoot(); + + DataMap> userMap = root.getUserMap(); + AstTreeInfo docNode = userMap.get(SAXON_TREE_CACHE_KEY); + if (docNode == null) { + docNode = new AstTreeInfo(root, configuration); + userMap.set(SAXON_TREE_CACHE_KEY, docNode); + } + return docNode; + } + + + private void addExpressionForNode(String nodeName, Expression expression) { + nodeNameToXPaths.computeIfAbsent(nodeName, n -> new ArrayList<>(2)).add(expression); + } + + private void ensureInitialized() { + if (xpathExpression != null) { + return; + } + try { + this.configuration = Configuration.newConfiguration(); + this.configuration.setNamePool(getNamePool()); + + StaticContextWithProperties staticCtx = new StaticContextWithProperties(this.configuration); + staticCtx.setXPathLanguageLevel(version == XPathVersion.XPATH_3_1 ? 31 : 20); + staticCtx.declareNamespace("fn", NamespaceConstant.FN); + + for (final PropertyDescriptor propertyDescriptor : properties.keySet()) { + final String name = propertyDescriptor.name(); + if (!"xpath".equals(name) && !XPathRule.VERSION_DESCRIPTOR.name().equals(name)) { + staticCtx.declareProperty(propertyDescriptor); + } + } + + for (ExtensionFunctionDefinition fun : xPathHandler.getRegisteredExtensionFunctions()) { + StructuredQName qname = fun.getFunctionQName(); + staticCtx.declareNamespace(qname.getPrefix(), qname.getURI()); + this.configuration.registerExtensionFunction(fun); + } + + final XPathEvaluator xpathEvaluator = new XPathEvaluator(configuration); + xpathEvaluator.setStaticContext(staticCtx); + + xpathExpression = xpathEvaluator.createExpression(xpathExpr); + analyzeXPathForRuleChain(xpathEvaluator); + } catch (final XPathException e) { + throw new RuntimeException(e); + } + } + + private void analyzeXPathForRuleChain(final XPathEvaluator xpathEvaluator) { + final Expression expr = xpathExpression.getInternalExpression(); + + boolean useRuleChain = true; + + // First step: Split the union venn expressions into single expressions + Iterable subexpressions = RuleChainAnalyzer.splitUnions(expr); + + // Second step: Analyze each expression separately + for (Expression subexpression : subexpressions) { + RuleChainAnalyzer rca = new RuleChainAnalyzer(xpathEvaluator.getConfiguration()); + Expression modified = rca.visit(subexpression); + + if (!rca.getRootElements().isEmpty()) { + rca.getRootElements().forEach(it -> addExpressionForNode(it, modified)); + } else { + // couldn't find a root element for the expression, that means, we can't use rule chain at all + // even though, it would be possible for part of the expression. + useRuleChain = false; + break; + } + } + + if (useRuleChain) { + rulechainQueries.addAll(nodeNameToXPaths.keySet()); + } else { + nodeNameToXPaths.clear(); + if (LOG.isLoggable(Level.FINE)) { + LOG.log(Level.FINE, "Unable to use RuleChain for XPath: " + xpathExpr); + } + } + + // always add fallback expression + addExpressionForNode(AST_ROOT, xpathExpression.getInternalExpression()); + } + + public static NamePool getNamePool() { + return NAME_POOL; + } + + + final class StaticContextWithProperties extends IndependentContext { + + private final Map> propertiesByName = new HashMap<>(); + + StaticContextWithProperties(Configuration config) { + super(config); + } + + public void declareProperty(PropertyDescriptor prop) { + XPathVariable var = declareVariable(null, prop.name()); + propertiesByName.put(var.getVariableQName(), prop); + } + + @Override + public Expression bindVariable(StructuredQName qName) throws XPathException { + LocalVariableReference local = (LocalVariableReference) super.bindVariable(qName); + PropertyDescriptor prop = propertiesByName.get(qName); + if (prop == null || prop.defaultValue() == null) { + return local; + } + + // TODO Saxon optimizer bug (js/codestyle.xml/AssignmentInOperand) + Object actualValue = properties.getOrDefault(prop, prop.defaultValue()); + AtomicSequence converted = DomainConversion.convert(actualValue); + local.setStaticType(null, converted, 0); + return local; + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SplitUnions.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SplitUnions.java index 7d45b544b3..3d70db5d19 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SplitUnions.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/SplitUnions.java @@ -5,12 +5,15 @@ package net.sourceforge.pmd.lang.rule.xpath.internal; +import static net.sourceforge.pmd.util.CollectionUtil.listOf; + import java.util.ArrayList; import java.util.List; import net.sf.saxon.expr.Expression; -import net.sf.saxon.expr.Token; import net.sf.saxon.expr.VennExpression; +import net.sf.saxon.expr.parser.Token; +import net.sf.saxon.expr.sort.DocumentSorter; /** * Splits a venn expression with the union operator into single expressions. @@ -18,12 +21,13 @@ import net.sf.saxon.expr.VennExpression; *

E.g. "//A | //B | //C" will result in 3 expressions "//A", "//B", and "//C". */ class SplitUnions extends SaxonExprVisitor { - private List expressions = new ArrayList<>(); + + private final List expressions = new ArrayList<>(); @Override public Expression visit(VennExpression e) { if (e.getOperator() == Token.UNION) { - for (Expression operand : e.getOperands()) { + for (Expression operand : listOf(e.getLhsExpression(), e.getRhsExpression())) { if (operand instanceof VennExpression) { visit(operand); } else { @@ -34,6 +38,16 @@ class SplitUnions extends SaxonExprVisitor { return e; } + @Override + public Expression visit(Expression e) { + // only flatten toplevel unions + if (e instanceof VennExpression || e instanceof DocumentSorter) { + return super.visit(e); + } else { + return e; + } + } + public List getExpressions() { return expressions; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/Applier.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/Applier.java index e8c93403db..e42b0cc8c0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/Applier.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/Applier.java @@ -5,8 +5,7 @@ package net.sourceforge.pmd.lang.symboltable; import java.util.Iterator; - -import net.sourceforge.pmd.util.SearchFunction; +import java.util.function.Predicate; public final class Applier { @@ -14,8 +13,8 @@ public final class Applier { // utility class } - public static void apply(SearchFunction f, Iterator i) { - while (i.hasNext() && f.applyTo(i.next())) { + public static void apply(Predicate f, Iterator i) { + while (i.hasNext() && f.test(i.next())) { // Nothing to do } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/ImageFinderFunction.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/ImageFinderFunction.java index b9e14141a5..5b8dcfd944 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/ImageFinderFunction.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/symboltable/ImageFinderFunction.java @@ -8,10 +8,9 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Predicate; -import net.sourceforge.pmd.util.SearchFunction; - -public class ImageFinderFunction implements SearchFunction { +public class ImageFinderFunction implements Predicate { private final Set images; private NameDeclaration decl; @@ -25,7 +24,7 @@ public class ImageFinderFunction implements SearchFunction { } @Override - public boolean applyTo(NameDeclaration nameDeclaration) { + public boolean test(NameDeclaration nameDeclaration) { if (images.contains(nameDeclaration.getImage())) { decl = nameDeclaration; return false; 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 deleted file mode 100644 index c73ef828a7..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/Initializer.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -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; -import net.sourceforge.pmd.lang.LanguageVersionHandler; - -import net.sf.saxon.sxpath.IndependentContext; - -/** - * This class serves as the means to perform XPath related static - * 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() { } - - /** - * Perform all initialization. - */ - public static void initialize() { - // noop as initialization is done in static block below - } - - /** - * Perform all initialization. - */ - public static void initialize(IndependentContext context) { - context.declareNamespace("pmd", "java:" + PMDFunctions.class.getName()); - for (Language language : LanguageRegistry.getLanguages()) { - for (LanguageVersion languageVersion : language.getVersions()) { - LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler(); - if (languageVersionHandler != null) { - languageVersionHandler.getXPathHandler().initialize(context); - } - } - } - } - - static { - initializeGlobal(); - initializeLanguages(); - } - - private static void initializeGlobal() { - MatchesFunction.registerSelfInSimpleContext(); - } - - private static void initializeLanguages() { - for (Language language : LanguageRegistry.getLanguages()) { - for (LanguageVersion languageVersion : language.getVersions()) { - LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler(); - if (languageVersionHandler != null) { - languageVersionHandler.getXPathHandler().initialize(); - } - } - } - } -} 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 deleted file mode 100644 index 252ed9bdec..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/MatchesFunction.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.xpath; - -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.jaxen.Context; -import org.jaxen.Function; -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() { - // see http://jaxen.org/extensions.html - ((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "matches", - new MatchesFunction()); - } - - @Override - public Object call(Context context, List args) throws FunctionCallException { - if (args.isEmpty()) { - return Boolean.FALSE; - } - List attributes = (List) args.get(0); - Attribute attr = (Attribute) attributes.get(0); - - for (int i = 1; i < args.size(); i++) { - Pattern check = Pattern.compile((String) args.get(i)); - Matcher matcher = check.matcher(attr.getStringValue()); - if (matcher.find()) { - return context.getNodeSet(); - } - } - return Boolean.FALSE; - } - - public static boolean matches(String s, String... patterns) { - for (String pattern : patterns) { - Pattern check = Pattern.compile(pattern); - Matcher matcher = check.matcher(s); - if (matcher.find()) { - return true; - } - } - return false; - } -} 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 deleted file mode 100644 index 5a26e7b75c..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/xpath/PMDFunctions.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.xpath; - -import net.sourceforge.pmd.annotation.InternalApi; - - -@InternalApi -@Deprecated -public final class PMDFunctions { - private PMDFunctions() { } - - public static boolean matches(String s, String pattern1) { - return MatchesFunction.matches(s, pattern1); - } - - public static boolean matches(String s, String pattern1, String pattern2) { - return MatchesFunction.matches(s, pattern1, pattern2); - } - - public static boolean matches(String s, String pattern1, String pattern2, String pattern3) { - return MatchesFunction.matches(s, pattern1, pattern2, pattern3); - } - - public static boolean matches(String s, String pattern1, String pattern2, String pattern3, String pattern4) { - return MatchesFunction.matches(s, pattern1, pattern2, pattern3, pattern4); - } - - public static boolean matches(String s, String pattern1, String pattern2, String pattern3, String pattern4, - String pattern5) { - return MatchesFunction.matches(s, pattern1, pattern2, pattern3, pattern4, pattern5); - } - - public static boolean matches(String s, String pattern1, String pattern2, String pattern3, String pattern4, - String pattern5, String pattern6) { - return MatchesFunction.matches(s, pattern1, pattern2, pattern3, pattern4, pattern5, pattern6); - } -} 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 deleted file mode 100644 index 31882c325e..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractMultiPackagedProperty.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties; - -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.properties.modules.PackagedPropertyModule; - - -/** - * Multi-valued property restricting the type of its values to some packages. - * - * @param The type of the values - * - * @author Brian Remedios - * @author Clément Fournier - * @version Refactored June 2017 (6.0.0) - */ -@Deprecated -/* default */ abstract class AbstractMultiPackagedProperty extends AbstractMultiValueProperty - implements PackagedPropertyDescriptor> { - - - protected final PackagedPropertyModule module; - - - /** - * Create a packaged property. - * - * @param theName Name - * @param theDescription Description - * @param theDefault Default value - * @param theUIOrder UI order - * @param module - * - * @throws IllegalArgumentException - */ - protected AbstractMultiPackagedProperty(String theName, String theDescription, List theDefault, - float theUIOrder, boolean isDefinedExternally, - PackagedPropertyModule module) { - super(theName, theDescription, theDefault, theUIOrder, MULTI_VALUE_DELIMITER, isDefinedExternally); - this.module = module; - } - - - @Override - protected void addAttributesTo(Map attributes) { - super.addAttributesTo(attributes); - module.addAttributesTo(attributes); - } - - - @Override - protected String valueErrorFor(T value) { - if (value == null) { - String err = super.valueErrorFor(null); - if (err != null) { - return err; - } - } - - return module.valueErrorFor(value); - } - - - @Override - public String[] legalPackageNames() { - return module.legalPackageNames(); - } - - - protected String[] packageNamesIn(Map params) { - return module.packageNamesIn(params); - } -} 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 deleted file mode 100644 index 94921e7eae..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/AbstractPackagedProperty.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties; - -import java.util.Map; - -import net.sourceforge.pmd.properties.modules.PackagedPropertyModule; - - -/** - * Property which restricts the type of its values to some packages. If the legalPackageNames value is set to null then - * no restrictions are made. - * - * @param The type of the values - * - * @author Brian Remedios - * @author Clément Fournier - * @version Refactored June 2017 (6.0.0) - */ -@Deprecated -/* default */ abstract class AbstractPackagedProperty extends AbstractSingleValueProperty - implements PackagedPropertyDescriptor { - - protected final PackagedPropertyModule module; - - - /** - * Create a packaged property. - * - * @param theName Name - * @param theDescription Description - * @param theDefault Default value - * @param theUIOrder UI order - * @param module - * - * @throws IllegalArgumentException - */ - protected AbstractPackagedProperty(String theName, String theDescription, T theDefault, - float theUIOrder, boolean isDefinedExternally, - PackagedPropertyModule module) { - super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally); - this.module = module; - } - - - @Override - protected void addAttributesTo(Map attributes) { - super.addAttributesTo(attributes); - module.addAttributesTo(attributes); - } - - - @Override - protected String valueErrorFor(T value) { - return module.valueErrorFor(value); - } - - - @Override - public String[] legalPackageNames() { - return module.legalPackageNames(); - } - - - protected String[] packageNamesIn(Map params) { - return module.packageNamesIn(params); - } - -} 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 71463940cf..3d7d7a3c95 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 @@ -10,10 +10,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import net.sourceforge.pmd.util.CollectionUtil; /** @@ -81,12 +77,6 @@ public abstract class AbstractPropertySource implements PropertySource { return new HashMap<>(propertyValuesByDescriptor); } - @Override - @Deprecated - public Set> ignoredProperties() { - return Collections.emptySet(); - } - @Override public void definePropertyDescriptor(PropertyDescriptor propertyDescriptor) { @@ -210,32 +200,6 @@ public abstract class AbstractPropertySource implements PropertySource { } - @Override - @Deprecated - public boolean usesDefaultValues() { - - Map, Object> valuesByProperty = getPropertiesByPropertyDescriptor(); - if (valuesByProperty.isEmpty()) { - return true; - } - - for (Entry, Object> entry : valuesByProperty.entrySet()) { - if (!CollectionUtil.areEqual(entry.getKey().defaultValue(), entry.getValue())) { - return false; - } - } - - return true; - } - - - @Override - @Deprecated - public void useDefaultValueFor(PropertyDescriptor desc) { - propertyValuesByDescriptor.remove(desc); - } - - // todo Java 8 move up to interface @Override public String dysfunctionReason() { 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 deleted file mode 100644 index 8c2c3d2a6e..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodMultiProperty.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties; - -import static net.sourceforge.pmd.properties.ValueParserConstants.METHOD_PARSER; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; - -import net.sourceforge.pmd.properties.builders.MultiPackagedPropertyBuilder; -import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilderConversionWrapper; -import net.sourceforge.pmd.properties.modules.MethodPropertyModule; - - -/** - * Defines a property type that can specify multiple methods to use as part of a rule. - * - * 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" ]. - * - * @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 { - - - /** - * Constructor for MethodMultiProperty using an array of defaults. - * - * @param theName String - * @param theDescription String - * @param theDefaults Method[] - * @param legalPackageNames String[] - * @param theUIOrder float - */ - public MethodMultiProperty(String theName, String theDescription, Method[] theDefaults, - String[] legalPackageNames, float theUIOrder) { - this(theName, theDescription, Arrays.asList(theDefaults), legalPackageNames, theUIOrder); - } - - - /** - * Constructor for MethodProperty using a list of defaults. - * - * @param theName String - * @param theDescription String - * @param theDefaults Method[] - * @param legalPackageNames String[] - * @param theUIOrder float - * - * @throws IllegalArgumentException - */ - public MethodMultiProperty(String theName, String theDescription, List theDefaults, - String[] legalPackageNames, float theUIOrder) { - this(theName, theDescription, theDefaults, legalPackageNames, theUIOrder, false); - } - - - /** Master constructor. */ - private MethodMultiProperty(String theName, String theDescription, List theDefaults, - String[] legalPackageNames, float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, theDefaults, theUIOrder, isDefinedExternally, - new MethodPropertyModule(legalPackageNames, theDefaults)); - } - - - /** - * Constructor for MethodProperty. - * - * @param theName String - * @param theDescription String - * @param methodDefaults String - * @param legalPackageNames String[] - * @param theUIOrder float - * - * @throws IllegalArgumentException - * @deprecated will be removed in 7.O.O - */ - public MethodMultiProperty(String theName, String theDescription, String methodDefaults, - String[] legalPackageNames, float theUIOrder) { - this(theName, theDescription, - methodsFrom(methodDefaults), - legalPackageNames, theUIOrder, - false); - } - - - @Override - public String asString(Method value) { - return MethodPropertyModule.asString(value); - } - - - @Override - protected Method createFrom(String toParse) { - return METHOD_PARSER.valueOf(toParse); - } - - - @Override - public Class type() { - return Method.class; - } - - - @Override - public List valueFrom(String valueString) throws IllegalArgumentException { - return methodsFrom(valueString); - } - - - private static List methodsFrom(String valueString) { - return ValueParserConstants.parsePrimitives(valueString, MULTI_VALUE_DELIMITER, METHOD_PARSER); - } - - - static PropertyDescriptorBuilderConversionWrapper.MultiValue.Packaged extractor() { - return new PropertyDescriptorBuilderConversionWrapper.MultiValue.Packaged(Method.class, ValueParserConstants.METHOD_PARSER) { - @Override - protected MethodMultiPBuilder newBuilder(String name) { - return new MethodMultiPBuilder(name); - } - }; - } - - - public static MethodMultiPBuilder named(String name) { - return new MethodMultiPBuilder(name); - } - - - public static final class MethodMultiPBuilder extends MultiPackagedPropertyBuilder { - private MethodMultiPBuilder(String name) { - super(name); - } - - - @Override - public MethodMultiProperty build() { - return new MethodMultiProperty(name, description, defaultValues, legalPackageNames, uiOrder, isDefinedInXML); - } - } - -} 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 deleted file mode 100644 index f42768eedb..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/MethodProperty.java +++ /dev/null @@ -1,120 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties; - - -import static net.sourceforge.pmd.properties.ValueParserConstants.METHOD_PARSER; - -import java.lang.reflect.Method; -import java.util.Collections; - -import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilderConversionWrapper; -import net.sourceforge.pmd.properties.builders.SinglePackagedPropertyBuilder; -import net.sourceforge.pmd.properties.modules.MethodPropertyModule; - - -/** - * Defines a property type that can specify a single method to use as part of a rule. - * - *

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 Will be removed with 7.0.0 with no scheduled replacement - */ -@Deprecated -public final class MethodProperty extends AbstractPackagedProperty { - - - /** - * Constructor for MethodProperty. - * - * @param theName Name of the property - * @param theDescription Description - * @param theDefault Default value - * @param legalPackageNames Legal packages - * @param theUIOrder UI order - */ - public MethodProperty(String theName, String theDescription, Method theDefault, String[] legalPackageNames, - float theUIOrder) { - this(theName, theDescription, theDefault, legalPackageNames, theUIOrder, false); - } - - - /** Master constructor. */ - private MethodProperty(String theName, String theDescription, Method theDefault, String[] legalPackageNames, - float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally, - new MethodPropertyModule(legalPackageNames, Collections.singletonList(theDefault))); - } - - - /** - * Constructor for MethodProperty using a string as a default value. - * - * @param theName Name of the property - * @param theDescription Description - * @param defaultMethodStr Default value, that will be parsed into a Method object - * @param legalPackageNames Legal packages - * @param theUIOrder UI order - * - * @deprecated will be removed in 7.0.0 - */ - public MethodProperty(String theName, String theDescription, String defaultMethodStr, String[] legalPackageNames, - float theUIOrder) { - this(theName, theDescription, METHOD_PARSER.valueOf(defaultMethodStr), - legalPackageNames, theUIOrder, false); - } - - - @Override - protected String asString(Method value) { - return MethodPropertyModule.asString(value); - } - - - @Override - public Class type() { - return Method.class; - } - - - @Override - public Method createFrom(String valueString) throws IllegalArgumentException { - return METHOD_PARSER.valueOf(valueString); - } - - - static PropertyDescriptorBuilderConversionWrapper.SingleValue.Packaged extractor() { - return new PropertyDescriptorBuilderConversionWrapper.SingleValue.Packaged(Method.class, ValueParserConstants.METHOD_PARSER) { - @Override - protected MethodPBuilder newBuilder(String name) { - return new MethodPBuilder(name); - } - }; - } - - - public static MethodPBuilder named(String name) { - return new MethodPBuilder(name); - } - - - public static final class MethodPBuilder extends SinglePackagedPropertyBuilder { - private MethodPBuilder(String name) { - super(name); - } - - - @Override - public MethodProperty build() { - return new MethodProperty(name, description, defaultValue, legalPackageNames, uiOrder, isDefinedInXML); - } - } - - -} 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 deleted file mode 100644 index e650d9a9b9..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PackagedPropertyDescriptor.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties; - -/** - * Defines a property descriptor type whose values can be described by qualified names and thus restricted to only some - * packages. These typically use values such as {@link Class} and {@link java.lang.reflect.Method}. - * - * @param type of the property value - * - * @author Clément Fournier - */ -@Deprecated -public interface PackagedPropertyDescriptor extends PropertyDescriptor { - - /** Delimiter used to separate package names. */ - char PACKAGE_NAME_DELIMITER = ' '; - /** Delimiter used to separate multiple values if this descriptor is multi valued. */ - char MULTI_VALUE_DELIMITER = '|'; - - - /** - * Returns the legal package names. - * - * @return The legal package names - */ - String[] legalPackageNames(); -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertySource.java b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertySource.java index 7a516714bd..66c9251299 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertySource.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/properties/PropertySource.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.properties; import java.util.List; import java.util.Map; -import java.util.Set; /** @@ -154,39 +153,6 @@ public interface PropertySource { boolean hasDescriptor(PropertyDescriptor descriptor); - /** - * Returns whether this Rule uses default values for properties. - * - * @return boolean true if the properties all have default values, false otherwise. - * - * @deprecated Has no real utility, will be removed by 7.0.0 - */ - @Deprecated - boolean usesDefaultValues(); - - - /** - * Clears out any user-specified value for the property allowing it to use the default value in the descriptor. - * - * @param desc the property to clear out - * - * @deprecated Has no real utility, and the name is confusing, will be removed by 7.0.0 - */ - @Deprecated - void useDefaultValueFor(PropertyDescriptor desc); - - - /** - * Return the properties that are effectively ignored due to the configuration of the rule and values held by other - * properties. This can be used to disable corresponding widgets in a UI. - * - * @return the properties that are ignored - * @deprecated Has no real utility, will be removed by 7.0.0 - */ - @Deprecated - Set> ignoredProperties(); - - /** * Returns a description of why the receiver may be dysfunctional. * Usually due to missing property values or some kind of conflict 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 f6984d9efa..7122fbb28a 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 @@ -54,13 +54,7 @@ public enum PropertyTypeId { @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); + DOUBLE_LIST("List[Double]", DoubleMultiProperty.extractor(), ValueParserConstants.DOUBLE_PARSER); private static final Map CONSTANTS_BY_MNEMONIC; @@ -119,19 +113,6 @@ public enum PropertyTypeId { } - /** - * Returns true if the property corresponding to this factory is packaged, - * which means it can be safely cast to a {@link PackagedPropertyDescriptor}. - * - * @return whether the property is packaged - */ - @Deprecated - public boolean isPropertyPackaged() { - return factory instanceof PropertyDescriptorBuilderConversionWrapper.SingleValue.Packaged - || factory instanceof PropertyDescriptorBuilderConversionWrapper.MultiValue.Packaged; - } - - /** * Returns true if the property corresponding to this factory takes * lists of values as its value. 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 deleted file mode 100644 index 9899e00538..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeMultiProperty.java +++ /dev/null @@ -1,127 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties; - -import java.util.List; - -import net.sourceforge.pmd.properties.builders.MultiPackagedPropertyBuilder; -import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilderConversionWrapper; -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 Will be removed with 7.0.0 with no scheduled replacement yet - * @author Brian Remedios - */ -@Deprecated -public final class TypeMultiProperty extends AbstractMultiPackagedProperty { - - - /** - * Constructor for TypeProperty. - * - * @param theName String - * @param theDescription String - * @param theDefaults Class[] - * @param legalPackageNames String[] - * @param theUIOrder float - * - * @throws IllegalArgumentException - */ - public TypeMultiProperty(String theName, String theDescription, List theDefaults, - String[] legalPackageNames, float theUIOrder) { - this(theName, theDescription, theDefaults, legalPackageNames, theUIOrder, false); - - } - - - /** Master constructor. */ - private TypeMultiProperty(String theName, String theDescription, List theTypeDefaults, - String[] legalPackageNames, float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, theTypeDefaults, theUIOrder, isDefinedExternally, - new TypePropertyModule(legalPackageNames, theTypeDefaults)); - } - - - /** - * Constructor for TypeProperty. - * - * @param theName String - * @param theDescription String - * @param theTypeDefaults String - * @param legalPackageNames String[] - * @param theUIOrder float - * - * @throws IllegalArgumentException - */ - public TypeMultiProperty(String theName, String theDescription, String theTypeDefaults, - String[] legalPackageNames, float theUIOrder) { - this(theName, theDescription, typesFrom(theTypeDefaults), - legalPackageNames, - theUIOrder, false); - - } - - - @Override - public Class type() { - return Class.class; - } - - - @Override - public String asString(Class value) { - return value == null ? "" : value.getName(); - } - - - @Override - protected Class createFrom(String toParse) { - return ValueParserConstants.CLASS_PARSER.valueOf(toParse); - } - - - @Override - public List valueFrom(String valueString) { - return typesFrom(valueString); - } - - - private static List typesFrom(String valueString) { - return ValueParserConstants.parsePrimitives(valueString, MULTI_VALUE_DELIMITER, ValueParserConstants.CLASS_PARSER); - } - - - public static PropertyDescriptorBuilderConversionWrapper.MultiValue.Packaged extractor() { - return new PropertyDescriptorBuilderConversionWrapper.MultiValue.Packaged(Class.class, ValueParserConstants.CLASS_PARSER) { - @Override - protected TypeMultiPBuilder newBuilder(String name) { - return new TypeMultiPBuilder(name); - } - }; - } - - - public static TypeMultiPBuilder named(String name) { - return new TypeMultiPBuilder(name); - } - - - public static final class TypeMultiPBuilder extends MultiPackagedPropertyBuilder { - - private TypeMultiPBuilder(String name) { - super(name); - } - - - @Override - public TypeMultiProperty build() { - return new TypeMultiProperty(name, description, defaultValues, legalPackageNames, uiOrder, isDefinedInXML); - } - } -} 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 deleted file mode 100644 index 9b6cfc1113..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/TypeProperty.java +++ /dev/null @@ -1,111 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties; - -import java.util.Collections; - -import net.sourceforge.pmd.properties.builders.PropertyDescriptorBuilderConversionWrapper; -import net.sourceforge.pmd.properties.builders.SinglePackagedPropertyBuilder; -import net.sourceforge.pmd.properties.modules.TypePropertyModule; - - -/** - * Defines a property that supports single class types, even for primitive values! - * - * TODO - untested for array types - * - * @author Brian Remedios - * @deprecated Will be removed with 7.0.0 with no scheduled replacement yet - */ -@Deprecated -public final class TypeProperty extends AbstractPackagedProperty { - - /** - * Constructor for TypeProperty using a string as default value. - * - * @param theName String - * @param theDescription String - * @param defaultTypeStr String - * @param legalPackageNames String[] - * @param theUIOrder float - * - * @throws IllegalArgumentException if the default string could not be parsed into a Class - * @deprecated will be removed in 7.0.0 - */ - public TypeProperty(String theName, String theDescription, String defaultTypeStr, String[] legalPackageNames, - float theUIOrder) { - this(theName, theDescription, ValueParserConstants.CLASS_PARSER.valueOf(defaultTypeStr), legalPackageNames, theUIOrder, false); - } - - - /** Master constructor. */ - private TypeProperty(String theName, String theDescription, Class theDefault, String[] legalPackageNames, - float theUIOrder, boolean isDefinedExternally) { - super(theName, theDescription, theDefault, theUIOrder, isDefinedExternally, - new TypePropertyModule(legalPackageNames, Collections.singletonList(theDefault))); - } - - - /** - * Constructor for TypeProperty. - * - * @param theName String - * @param theDescription String - * @param theDefault Class - * @param legalPackageNames String[] - * @param theUIOrder float - */ - public TypeProperty(String theName, String theDescription, Class theDefault, String[] legalPackageNames, - float theUIOrder) { - this(theName, theDescription, theDefault, legalPackageNames, theUIOrder, false); - } - - - @Override - public Class type() { - return Class.class; - } - - - @Override - protected String asString(Class value) { - return value == null ? "" : value.getName(); - } - - - @Override - public Class createFrom(String valueString) { - return ValueParserConstants.CLASS_PARSER.valueOf(valueString); - } - - - static PropertyDescriptorBuilderConversionWrapper.SingleValue.Packaged extractor() { - return new PropertyDescriptorBuilderConversionWrapper.SingleValue.Packaged(Class.class, ValueParserConstants.CLASS_PARSER) { - @Override - protected TypePBuilder newBuilder(String name) { - return new TypePBuilder(name); - } - }; - } - - - public static TypePBuilder named(String name) { - return new TypePBuilder(name); - } - - - public static final class TypePBuilder extends SinglePackagedPropertyBuilder { - private TypePBuilder(String name) { - super(name); - } - - - @Override - public TypeProperty build() { - return new TypeProperty(name, description, defaultValue, legalPackageNames, uiOrder, isDefinedInXML); - } - } - -} 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 17b18c5db7..8884cb156a 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 @@ -4,14 +4,7 @@ package net.sourceforge.pmd.properties; -import static net.sourceforge.pmd.properties.modules.MethodPropertyModule.ARRAY_FLAG; -import static net.sourceforge.pmd.properties.modules.MethodPropertyModule.CLASS_METHOD_DELIMITER; -import static net.sourceforge.pmd.properties.modules.MethodPropertyModule.METHOD_ARG_DELIMITER; -import static net.sourceforge.pmd.properties.modules.MethodPropertyModule.METHOD_GROUP_DELIMITERS; - import java.io.File; -import java.lang.reflect.Array; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -21,7 +14,6 @@ import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.util.ClassUtil; /** @@ -37,114 +29,6 @@ import net.sourceforge.pmd.util.ClassUtil; public final class ValueParserConstants { - /** Extracts methods. */ - static final ValueParser METHOD_PARSER = new ValueParser() { - @Override - public Method valueOf(String value) throws IllegalArgumentException { - return methodFrom(value, CLASS_METHOD_DELIMITER, METHOD_ARG_DELIMITER); - } - - - /** - * Returns the method specified within the string argument after parsing out - * its source class and any optional arguments. Callers need to specify the - * delimiters expected between the various elements. I.e.: - * - *

"String#isEmpty()" "String#indexOf(int)" "String#substring(int,int)" - * - *

If a method isn't part of the specified class we will walk up any - * superclasses to Object to try and find it. - * - *

If the classes are listed in the ClassUtil class within in Typemaps then - * you likely can avoid specifying fully-qualified class names per the above - * example. - * - *

Returns null if a matching method cannot be found. - * - * @param methodNameAndArgTypes Method name (with its declaring class and arguments) - * @param classMethodDelimiter Delimiter between the class and method names - * @param methodArgDelimiter Method arguments delimiter - * - * @return Method - */ - Method methodFrom(String methodNameAndArgTypes, char classMethodDelimiter, char methodArgDelimiter) { - - // classname#methodname(arg1,arg2) - // 0 1 2 - - int delimPos0 = -1; - if (methodNameAndArgTypes != null) { - delimPos0 = methodNameAndArgTypes.indexOf(classMethodDelimiter); - } else { - return null; - } - - if (delimPos0 < 0) { - return null; - } - - String className = methodNameAndArgTypes.substring(0, delimPos0); - Class type = ClassUtil.getTypeFor(className); - if (type == null) { - return null; - } - - int delimPos1 = methodNameAndArgTypes.indexOf(METHOD_GROUP_DELIMITERS[0]); - if (delimPos1 < 0) { - String methodName = methodNameAndArgTypes.substring(delimPos0 + 1); - return ClassUtil.methodFor(type, methodName, ClassUtil.EMPTY_CLASS_ARRAY); - } - - String methodName = methodNameAndArgTypes.substring(delimPos0 + 1, delimPos1); - if (StringUtils.isBlank(methodName)) { - return null; - } // missing method name? - - int delimPos2 = methodNameAndArgTypes.indexOf(METHOD_GROUP_DELIMITERS[1]); - if (delimPos2 < 0) { - return null; - } // error! - - String argTypesStr = methodNameAndArgTypes.substring(delimPos1 + 1, delimPos2); - if (StringUtils.isBlank(argTypesStr)) { - return ClassUtil.methodFor(type, methodName, ClassUtil.EMPTY_CLASS_ARRAY); - } // no arg(s) - - String[] argTypeNames = StringUtils.split(argTypesStr, methodArgDelimiter); - Class[] argTypes = new Class[argTypeNames.length]; - for (int i = 0; i < argTypes.length; i++) { - argTypes[i] = typeFor(argTypeNames[i]); - } - - return ClassUtil.methodFor(type, methodName, argTypes); - } - - - private Class typeFor(String typeName) { - - Class type; - - if (typeName.endsWith(ARRAY_FLAG)) { - String arrayTypeName = typeName.substring(0, typeName.length() - ARRAY_FLAG.length()); - type = typeFor(arrayTypeName); // recurse - return Array.newInstance(type, 0).getClass(); // TODO is there a - // better way to get - // an array type? - } - - type = ClassUtil.getTypeFor(typeName); // try shortcut first - if (type != null) { - return type; - } - - try { - return Class.forName(typeName); - } catch (ClassNotFoundException ex) { - return null; - } - } - - }; /** Extracts characters. */ static final ValueParser CHARACTER_PARSER = new ValueParser() { @Override @@ -213,27 +97,6 @@ public final class ValueParserConstants { } }; - /** Extract classes. */ - static final ValueParser CLASS_PARSER = new ValueParser() { - @Override - public Class valueOf(String value) throws IllegalArgumentException { - if (StringUtils.isBlank(value)) { - return null; - } - - Class cls = ClassUtil.getTypeFor(value); - if (cls != null) { - return cls; - } - - try { - return Class.forName(value); - } catch (ClassNotFoundException ex) { - throw new IllegalArgumentException(value); - } - } - }; - private ValueParserConstants() { 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 deleted file mode 100644 index bbca8d8a02..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/MethodPropertyModule.java +++ /dev/null @@ -1,113 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.modules; - -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; - -import net.sourceforge.pmd.util.ClassUtil; - - -/** - * Factorises common functionality for method properties. - * - * @author Clément Fournier - */ -@Deprecated -public class MethodPropertyModule extends PackagedPropertyModule { - - public static final char CLASS_METHOD_DELIMITER = '#'; - public static final char METHOD_ARG_DELIMITER = ','; - public static final char[] METHOD_GROUP_DELIMITERS = {'(', ')'}; - public static final String ARRAY_FLAG = "[]"; - private static final Map, String> TYPE_SHORTCUTS = ClassUtil.getClassShortNames(); - - - public MethodPropertyModule(String[] legalPackageNames, List defaults) { - super(legalPackageNames, defaults); - } - - - @Override - protected String packageNameOf(Method method) { - return method.getDeclaringClass().getName() + '.' + method.getName(); - } - - - @Override - protected String itemTypeName() { - return "method"; - } - - - public static String asString(Method method) { - return method == null ? "" : asStringFor(method); - } - - - /** - * Return the value of `method' as a string that can be easily recognized and parsed when we see it again. - * - * @param method the method to convert - * - * @return the string value - */ - private static String asStringFor(Method method) { - StringBuilder sb = new StringBuilder(); - asStringOn(method, sb); - return sb.toString(); - } - - - /** - * Serializes the method signature onto the specified buffer. - * - * @param method Method - * @param sb StringBuilder - */ - private static void asStringOn(Method method, StringBuilder sb) { - - Class clazz = method.getDeclaringClass(); - - sb.append(shortestNameFor(clazz)); - sb.append(CLASS_METHOD_DELIMITER); - sb.append(method.getName()); - - sb.append(METHOD_GROUP_DELIMITERS[0]); - - Class[] argTypes = method.getParameterTypes(); - if (argTypes.length == 0) { - sb.append(METHOD_GROUP_DELIMITERS[1]); - return; - } - - serializedTypeIdOn(argTypes[0], sb); - for (int i = 1; i < argTypes.length; i++) { - sb.append(METHOD_ARG_DELIMITER); - serializedTypeIdOn(argTypes[i], sb); - } - sb.append(METHOD_GROUP_DELIMITERS[1]); - } - - - private static String shortestNameFor(Class cls) { - String compactName = TYPE_SHORTCUTS.get(cls); - return compactName == null ? cls.getName() : compactName; - } - - - private static void serializedTypeIdOn(Class type, StringBuilder sb) { - - Class arrayType = type.getComponentType(); - if (arrayType == null) { - sb.append(shortestNameFor(type)); - return; - } - sb.append(shortestNameFor(arrayType)).append(ARRAY_FLAG); - } - - -} 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 deleted file mode 100644 index 5e90f6f4cc..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/PackagedPropertyModule.java +++ /dev/null @@ -1,181 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.modules; - -import static net.sourceforge.pmd.properties.PackagedPropertyDescriptor.PACKAGE_NAME_DELIMITER; -import static net.sourceforge.pmd.properties.PropertyDescriptorField.LEGAL_PACKAGES; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; - -import net.sourceforge.pmd.properties.PropertyDescriptorField; - - -/** - * Factorises common functionality for packaged properties. - * - * @author Clément Fournier - */ -@Deprecated -public abstract class PackagedPropertyModule { - - private static final Pattern PACKAGE_NAME_PATTERN = Pattern.compile("(\\w+)(\\.\\w+)*"); - - private final String[] legalPackageNames; - - - public PackagedPropertyModule(String[] legalPackageNames, List defaults) { - - checkValidPackages(legalPackageNames); - checkValidDefaults(defaults, legalPackageNames); - - this.legalPackageNames = legalPackageNames; - } - - - /** - * Checks that the legal packages are okay. - * - * @param legalNamePrefixes Prefixes to check. Can be null, but not contain null - * - * @throws IllegalArgumentException If the prefixes contain null - * @throws IllegalArgumentException If one name that does not look like a package name - */ - private void checkValidPackages(String[] legalNamePrefixes) throws IllegalArgumentException { - if (legalNamePrefixes == null) { - return; - } - - for (String name : legalNamePrefixes) { - if (name == null) { - throw new IllegalArgumentException("Null is not allowed in the legal package names:" - + Arrays.toString(legalNamePrefixes)); - } else if (!PACKAGE_NAME_PATTERN.matcher(name).matches()) { - throw new IllegalArgumentException("One name is not a package: '" + name + "'"); - - } - } - } - - - /** - * Evaluates the names of the items against the allowable name prefixes. If one or more do not have valid prefixes - * then an exception will be thrown. - * - * @param items Items to check - * @param legalNamePrefixes Legal name prefixes - * - * @throws IllegalArgumentException if some items are not allowed - */ - private void checkValidDefaults(List items, String[] legalNamePrefixes) { - - if (legalNamePrefixes == null) { // valid value, matches everything - return; - } - - Set nameSet = new HashSet<>(); - - for (T item : items) { - if (item == null) { - continue; - } - nameSet.add(packageNameOf(item)); - } - - Set notAllowed = new HashSet<>(nameSet); - - - for (String name : nameSet) { - for (String prefix : legalNamePrefixes) { - if (name.startsWith(prefix)) { - notAllowed.remove(name); - break; - } - } - } - - if (notAllowed.isEmpty()) { - return; - } - - throw new IllegalArgumentException("Invalid items: " + notAllowed); - } - - - /** - * Returns the package name of the item. - * - * @param item Item (not null) - * - * @return Package name of the item - */ - protected abstract String packageNameOf(T item); - - - public String valueErrorFor(T value) { - - if (legalPackageNames == null) { - return null; // no restriction - } - - String name = packageNameOf(value); - - for (int i = 0; i < legalPackageNames.length; i++) { - if (name.startsWith(legalPackageNames[i])) { - return null; - } - } - - return "Disallowed " + itemTypeName() + ": " + name; - } - - - /** - * Returns the name of the type of item. - * - * @return The name of the type of item - */ - protected abstract String itemTypeName(); - - - public String[] legalPackageNames() { - return Arrays.copyOf(legalPackageNames, legalPackageNames.length); - } - - - public void addAttributesTo(Map attributes) { - attributes.put(LEGAL_PACKAGES, delimitedPackageNames()); - } - - - private String delimitedPackageNames() { - - if (legalPackageNames == null || legalPackageNames.length == 0) { - return ""; - } - if (legalPackageNames.length == 1) { - return legalPackageNames[0]; - } - - StringBuilder sb = new StringBuilder(); - sb.append(legalPackageNames[0]); - for (int i = 1; i < legalPackageNames.length; i++) { - sb.append(PACKAGE_NAME_DELIMITER).append(legalPackageNames[i]); - } - return sb.toString(); - } - - - public String[] packageNamesIn(Map params) { - return StringUtils.split(params.get(LEGAL_PACKAGES), PACKAGE_NAME_DELIMITER); - } - -} 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 deleted file mode 100644 index 52e4f5d87f..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/properties/modules/TypePropertyModule.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties.modules; - -import java.util.List; - - -/** - * Factorises common functionality for type properties. - * - * @author Clément Fournier - */ -@Deprecated -public class TypePropertyModule extends PackagedPropertyModule { - - public TypePropertyModule(String[] legalPackageNames, List defaults) { - super(legalPackageNames, defaults); - } - - - @Override - protected String packageNameOf(Class item) { - return item.getName(); - } - - - @Override - protected String itemTypeName() { - return "type"; - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractIncrementingRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractIncrementingRenderer.java index 1580e8eefb..3cb2edad5d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractIncrementingRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractIncrementingRenderer.java @@ -57,22 +57,18 @@ public abstract class AbstractIncrementingRenderer extends AbstractRenderer { @Override public void renderFileReport(Report report) throws IOException { - Iterator violations = report.iterator(); + Iterator violations = report.getViolations().iterator(); if (violations.hasNext()) { renderFileViolations(violations); getWriter().flush(); } - for (Iterator i = report.errors(); i.hasNext();) { - errors.add(i.next()); - } + errors.addAll(report.getProcessingErrors()); - for (Iterator i = report.configErrors(); i.hasNext();) { - configErrors.add(i.next()); - } + configErrors.addAll(report.getConfigurationErrors()); if (showSuppressedViolations) { - suppressed.addAll(report.getSuppressedRuleViolations()); + suppressed.addAll(report.getSuppressedViolations()); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/TextColorRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/TextColorRenderer.java index 198d38cb6c..d39f46eac9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/TextColorRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/TextColorRenderer.java @@ -11,11 +11,15 @@ import java.io.IOException; import java.io.Reader; import java.nio.charset.Charset; import java.nio.file.Files; -import java.util.Iterator; +import java.util.HashMap; import java.util.Map; +import org.apache.commons.lang3.StringUtils; + import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.Report; +import net.sourceforge.pmd.Report.ConfigurationError; +import net.sourceforge.pmd.Report.ProcessingError; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; @@ -123,10 +127,9 @@ public class TextColorRenderer extends AbstractAccumulatingRenderer { int numberOfErrors = 0; int numberOfWarnings = 0; - for (Iterator i = report.iterator(); i.hasNext();) { + for (RuleViolation rv : report.getViolations()) { buf.setLength(0); numberOfWarnings++; - RuleViolation rv = i.next(); String nextFile = determineFileName(rv.getFilename()); if (!nextFile.equals(lastFile)) { lastFile = nextFile; @@ -145,18 +148,16 @@ public class TextColorRenderer extends AbstractAccumulatingRenderer { } writer.write(PMD.EOL + PMD.EOL); writer.write("Summary:" + PMD.EOL + PMD.EOL); - Map summary = report.getCountSummary(); - for (Map.Entry entry : summary.entrySet()) { + for (Map.Entry entry : getCountSummary(report).entrySet()) { buf.setLength(0); String key = entry.getKey(); buf.append(key).append(" : ").append(entry.getValue()).append(PMD.EOL); writer.write(buf.toString()); } - for (Iterator i = report.errors(); i.hasNext();) { + for (ProcessingError error : report.getProcessingErrors()) { buf.setLength(0); numberOfErrors++; - Report.ProcessingError error = i.next(); String nextFile = determineFileName(error.getFile()); if (!nextFile.equals(lastFile)) { lastFile = nextFile; @@ -168,10 +169,9 @@ public class TextColorRenderer extends AbstractAccumulatingRenderer { writer.write(buf.toString()); } - for (Iterator i = report.configErrors(); i.hasNext();) { + for (ConfigurationError error : report.getConfigurationErrors()) { buf.setLength(0); numberOfErrors++; - Report.ConfigurationError error = i.next(); buf.append(this.redBold + "*" + this.colorReset + " rule: " + this.whiteBold + error.rule().getName() + this.colorReset + PMD.EOL); buf.append(this.green + " err: " + this.cyan + error.issue() + this.colorReset + PMD.EOL + PMD.EOL); @@ -187,6 +187,30 @@ public class TextColorRenderer extends AbstractAccumulatingRenderer { + this.colorReset + PMD.EOL); } + + /** + * Calculate a summary of violation counts per fully classified class name. + * + * @return violations per class name + */ + private static Map getCountSummary(Report report) { + Map summary = new HashMap<>(); + for (RuleViolation rv : report.getViolations()) { + String key = keyFor(rv); + if (key.isEmpty()) { + continue; + } + Integer o = summary.get(key); + summary.put(key, o == null ? 1 : o + 1); + } + return summary; + } + + private static String keyFor(RuleViolation rv) { + return StringUtils.isNotBlank(rv.getPackageName()) ? rv.getPackageName() + '.' + rv.getClassName() : ""; + } + + /** * Retrieves the requested line from the specified file. * @@ -194,6 +218,7 @@ public class TextColorRenderer extends AbstractAccumulatingRenderer { * the java or cpp source file * @param line * line number to extract + * * @return a trimmed line of source code */ private String getLine(String sourceFile, int line) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/YAHTMLRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/YAHTMLRenderer.java index cb1d4ed34c..1e2309ea38 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/YAHTMLRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/YAHTMLRenderer.java @@ -9,7 +9,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.SortedMap; @@ -92,9 +91,8 @@ public class YAHTMLRenderer extends AbstractAccumulatingRenderer { public void end() throws IOException { String outputDir = getProperty(OUTPUT_DIR); - Iterator violations = report.iterator(); - while (violations.hasNext()) { - addViolation(violations.next()); + for (RuleViolation ruleViolation : report.getViolations()) { + addViolation(ruleViolation); } renderIndex(outputDir); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/ClassUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/ClassUtil.java deleted file mode 100644 index 3e7ea1eb37..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/ClassUtil.java +++ /dev/null @@ -1,185 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Various class-related utility methods intended for mapping common java.lang - * types to their short short forms allowing end users to enter these names in - * UIs without the package prefixes. - * - * @author Brian Remedios - * @deprecated Is internal API - */ -@Deprecated -public final class ClassUtil { - - public static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - - @SuppressWarnings("PMD.AvoidUsingShortType") - private static final TypeMap PRIMITIVE_TYPE_NAMES = new TypeMap(new Class[] { int.class, byte.class, long.class, - short.class, float.class, double.class, char.class, boolean.class, }); - - private static final TypeMap TYPES_BY_NAME = new TypeMap( - new Class[] { Integer.class, Byte.class, Long.class, Short.class, Float.class, Double.class, - Character.class, Boolean.class, BigDecimal.class, String.class, Object.class, Class.class, }); - - private static final Map, String> SHORT_NAMES_BY_TYPE = computeClassShortNames(); - - private ClassUtil() { - } - - /** - * Returns the type(class) for the name specified or null if not found. - * - * @param name - * String - * @return Class - */ - public static Class getPrimitiveTypeFor(String name) { - return PRIMITIVE_TYPE_NAMES.typeFor(name); - } - - /** - * Return a map of all the short names of classes we maintain mappings for. - * The names are keyed by the classes themselves. - * - * @return Map - */ - private static Map, String> computeClassShortNames() { - - Map, String> map = new HashMap<>(); - map.putAll(PRIMITIVE_TYPE_NAMES.asInverseWithShortName()); - map.putAll(TYPES_BY_NAME.asInverseWithShortName()); - return map; - } - - public static Map, String> getClassShortNames() { - return SHORT_NAMES_BY_TYPE; - } - - /** - * Attempt to determine the actual class given the short name. - * - * @param shortName - * String - * @return Class - */ - public static Class getTypeFor(String shortName) { - Class type = TYPES_BY_NAME.typeFor(shortName); - if (type != null) { - return type; - } - - type = PRIMITIVE_TYPE_NAMES.typeFor(shortName); - if (type != null) { - return type; - } - - return CollectionUtil.getCollectionTypeFor(shortName); - } - - /** - * Return the name of the type in its short form if its known to us - * otherwise return its name fully packaged. - * - * @param type - * @return String - */ - public static String asShortestName(Class type) { - - String name = SHORT_NAMES_BY_TYPE.get(type); - return name == null ? type.getName() : name; - } - - /** - * Returns the abbreviated name of the type, without the package name - * - * @param fullTypeName - * @return String - */ - - public static String withoutPackageName(String fullTypeName) { - int dotPos = fullTypeName.lastIndexOf('.'); - return dotPos > 0 ? fullTypeName.substring(dotPos + 1) : fullTypeName; - } - - /** - * Attempts to return the specified method from the class provided but will - * walk up its superclasses until it finds a match. Returns null if it - * doesn't. - * - * @param clasz - * Class - * @param methodName - * String - * @param paramTypes - * Class[] - * @return Method - */ - public static Method methodFor(Class clasz, String methodName, Class[] paramTypes) { - Method method = null; - Class current = clasz; - while (current != Object.class) { - try { - method = current.getDeclaredMethod(methodName, paramTypes); - } catch (NoSuchMethodException ex) { - current = current.getSuperclass(); - } - if (method != null) { - return method; - } - } - return null; - } - - /** - * Return the methods as a map keyed by their common declaration types. - * - * @param methods - * @return methods grouped by declaring type name - */ - public static Map> asMethodGroupsByTypeName(Method[] methods) { - - Map> methodGroups = new HashMap<>(methods.length); - - for (int i = 0; i < methods.length; i++) { - String clsName = asShortestName(methods[i].getDeclaringClass()); - if (!methodGroups.containsKey(clsName)) { - methodGroups.put(clsName, new ArrayList()); - } - methodGroups.get(clsName).add(methods[i]); - } - return methodGroups; - } - - - /** - * Return the methods as a map keyed by their common declaration types. - * - * @param methods - * - * @return methods grouped by declaring type name - */ - public static Map> asMethodGroupsByTypeName(List methods) { - - Map> methodGroups = new HashMap<>(methods.size()); - - for (Method m : methods) { - String clsName = asShortestName(m.getDeclaringClass()); - if (!methodGroups.containsKey(clsName)) { - methodGroups.put(clsName, new ArrayList()); - } - methodGroups.get(clsName).add(m); - } - return methodGroups; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java index a4c09d873c..505ab7f624 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java @@ -8,7 +8,6 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; -import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -19,7 +18,6 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Function; @@ -54,55 +52,28 @@ public final class CollectionUtil { private static final int UNKNOWN_SIZE = -1; @SuppressWarnings("PMD.UnnecessaryFullyQualifiedName") - public static final TypeMap COLLECTION_INTERFACES_BY_NAMES = new TypeMap(List.class, Collection.class, Map.class, Set.class); + public static final Set COLLECTION_INTERFACES_BY_NAMES = collectionTypes(List.class, Collection.class, Map.class, Set.class); - @SuppressWarnings({"PMD.LooseCoupling", "PMD.UnnecessaryFullyQualifiedName" }) - public static final TypeMap COLLECTION_CLASSES_BY_NAMES - = new TypeMap(ArrayList.class, java.util.LinkedList.class, java.util.Vector.class, HashMap.class, - java.util.LinkedHashMap.class, java.util.TreeMap.class, java.util.TreeSet.class, - HashSet.class, java.util.LinkedHashSet.class, java.util.Hashtable.class); + @SuppressWarnings({"PMD.LooseCoupling", "PMD.UnnecessaryFullyQualifiedName"}) + public static final Set COLLECTION_CLASSES_BY_NAMES + = collectionTypes(ArrayList.class, java.util.LinkedList.class, java.util.Vector.class, HashMap.class, + java.util.LinkedHashMap.class, java.util.TreeMap.class, java.util.TreeSet.class, + HashSet.class, java.util.LinkedHashSet.class, java.util.Hashtable.class); private CollectionUtil() { } - /** - * Add elements from the source to the target as long as they don't already - * exist there. Return the number of items actually added. - * - * @param source - * @param target - * @return int - */ - public static int addWithoutDuplicates(Collection source, Collection target) { + private static Set collectionTypes(Class... types) { + Set set = new HashSet<>(); - int added = 0; - - for (T item : source) { - if (target.contains(item)) { - continue; + for (Class type : types) { + if (!set.add(type.getSimpleName()) || !set.add(type.getName())) { + throw new IllegalArgumentException("Duplicate or name collision for " + type); } - target.add(item); - added++; } - return added; - } - - /** - * Returns the collection type if we recognize it by its short name. - * - * @param shortName - * String - * @return Class - */ - public static Class getCollectionTypeFor(String shortName) { - Class cls = COLLECTION_CLASSES_BY_NAMES.typeFor(shortName); - if (cls != null) { - return cls; - } - - return COLLECTION_INTERFACES_BY_NAMES.typeFor(shortName); + return set; } /** @@ -114,7 +85,10 @@ public final class CollectionUtil { * @param includeInterfaces * boolean * @return boolean + * + * @deprecated Will be replaced with type resolution */ + @Deprecated public static boolean isCollectionType(String typeName, boolean includeInterfaces) { if (COLLECTION_CLASSES_BY_NAMES.contains(typeName)) { @@ -124,37 +98,6 @@ public final class CollectionUtil { return includeInterfaces && COLLECTION_INTERFACES_BY_NAMES.contains(typeName); } - /** - * Return whether we can identify the typeName as a java.util collection - * class or interface as specified. - * - * @param clazzType - * Class - * @param includeInterfaces - * boolean - * @return boolean - */ - public static boolean isCollectionType(Class clazzType, boolean includeInterfaces) { - - if (COLLECTION_CLASSES_BY_NAMES.contains(clazzType)) { - return true; - } - - return includeInterfaces && COLLECTION_INTERFACES_BY_NAMES.contains(clazzType); - } - - /** - * Returns the items as a populated set. - * - * @param items - * Object[] - * @return Set - */ - public static Set asSet(T[] items) { - - return new HashSet<>(Arrays.asList(items)); - } - /** * Creates and returns a map populated with the keyValuesSets where the * value held by the tuples are they key and value in that order. @@ -164,7 +107,10 @@ public final class CollectionUtil { * @param values * V[] * @return Map + * + * @deprecated Used by deprecated property types */ + @Deprecated public static Map mapFrom(K[] keys, V[] values) { if (keys.length != values.length) { throw new RuntimeException("mapFrom keys and values arrays have different sizes"); @@ -182,7 +128,10 @@ public final class CollectionUtil { * @param source * Map * @return Map + * + * @deprecated Used by deprecated property types */ + @Deprecated public static Map invertedMapFrom(Map source) { Map map = new HashMap<>(source.size()); for (Map.Entry entry : source.entrySet()) { @@ -192,124 +141,6 @@ public final class CollectionUtil { } - /** - * Consumes all the elements of the iterator and - * returns a list containing them. The iterator is - * then unusable - * - * @param it An iterator - * - * @return a list containing the elements remaining - * on the iterator - */ - public static List toList(Iterator it) { - List list = new ArrayList<>(); - while (it.hasNext()) { - list.add(it.next()); - } - return list; - } - - /** - * Returns true if the objects are array instances and each of their - * elements compares via equals as well. - * - * @param value - * Object - * @param otherValue - * Object - * @return boolean - * @deprecated {@link Objects#deepEquals(Object, Object)} - */ - @Deprecated - public static boolean arraysAreEqual(Object value, Object otherValue) { - if (value instanceof Object[]) { - if (otherValue instanceof Object[]) { - return valuesAreTransitivelyEqual((Object[]) value, (Object[]) otherValue); - } - return false; - } - return false; - } - - /** - * Returns whether the arrays are equal by examining each of their elements, - * even if they are arrays themselves. - * - * @param thisArray - * Object[] - * @param thatArray - * Object[] - * @return boolean - * @deprecated {@link Arrays#deepEquals(Object[], Object[])} - */ - @Deprecated - public static boolean valuesAreTransitivelyEqual(Object[] thisArray, Object[] thatArray) { - if (thisArray == thatArray) { - return true; - } - if (thisArray == null || thatArray == null) { - return false; - } - if (thisArray.length != thatArray.length) { - return false; - } - for (int i = 0; i < thisArray.length; i++) { - if (!areEqual(thisArray[i], thatArray[i])) { - return false; // recurse if req'd - } - } - return true; - } - - /** - * A comprehensive isEqual method that handles nulls and arrays safely. - * - * @param value - * Object - * @param otherValue - * Object - * @return boolean - * @deprecated {@link Objects#deepEquals(Object, Object)} - */ - @Deprecated - @SuppressWarnings("PMD.CompareObjectsWithEquals") - public static boolean areEqual(Object value, Object otherValue) { - if (value == otherValue) { - return true; - } - if (value == null) { - return false; - } - if (otherValue == null) { - return false; - } - - if (value.getClass().getComponentType() != null) { - return arraysAreEqual(value, otherValue); - } - return value.equals(otherValue); - } - - /** - * Returns whether the items array is null or has zero length. - * - * @param items - * @return boolean - */ - public static boolean isEmpty(Object[] items) { - return items == null || items.length == 0; - } - - /** - * Returns whether the items array is non-null and has at least one entry. - * - * @return boolean - */ - public static boolean isNotEmpty(Object[] items) { - return !isEmpty(items); - } - /** * Returns a list view that pretends it is the concatenation of @@ -333,6 +164,7 @@ public final class CollectionUtil { } } + /** * Returns the set union of the given collections. * @@ -683,95 +515,6 @@ public final class CollectionUtil { : list.subList(0, n); } - /** - * Returns true if both arrays are if both are null or have zero-length, - * otherwise return the false if their respective elements are not equal by - * position. - * - * @param - * @param a - * @param b - * @return boolean - * @deprecated {@link Arrays#deepEquals(Object[], Object[])} - */ - @Deprecated - public static boolean areSemanticEquals(T[] a, T[] b) { - if (a == null) { - return b == null || b.length == 0; - } - if (b == null) { - return a.length == 0; - } - - if (a.length != b.length) { - return false; - } - - for (int i = 0; i < a.length; i++) { - if (!areEqual(a[i], b[i])) { - return false; - } - } - - return true; - } - - - /** - * If the newValue is already held within the values array then the values - * array is returned, otherwise a new array is created appending the - * newValue to the end. - * - * @param - * @param values - * @param newValue - * @return an array containing the union of values and newValue - */ - @Deprecated - public static T[] addWithoutDuplicates(T[] values, T newValue) { - - for (T value : values) { - if (value.equals(newValue)) { - return values; - } - } - - T[] largerOne = (T[]) Array.newInstance(values.getClass().getComponentType(), values.length + 1); - System.arraycopy(values, 0, largerOne, 0, values.length); - largerOne[values.length] = newValue; - return largerOne; - } - - /** - * Returns an array of values as a union set of the two input arrays. - * - * @param - * @param values - * @param newValues - * @return the union of the two arrays - */ - @Deprecated - public static T[] addWithoutDuplicates(T[] values, T[] newValues) { - - Set originals = new HashSet<>(values.length); - for (T value : values) { - originals.add(value); - } - List newOnes = new ArrayList<>(newValues.length); - for (T value : newValues) { - if (originals.contains(value)) { - continue; - } - newOnes.add(value); - } - - T[] largerOne = (T[]) Array.newInstance(values.getClass().getComponentType(), values.length + newOnes.size()); - System.arraycopy(values, 0, largerOne, 0, values.length); - for (int i = values.length; i < largerOne.length; i++) { - largerOne[i] = newOnes.get(i - values.length); - } - return largerOne; - } public static List listOfNotNull(T t) { return t == null ? emptyList() : singletonList(t); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/DateTimeUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/DateTimeUtil.java deleted file mode 100644 index 4a374ce3a1..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/DateTimeUtil.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -import net.sourceforge.pmd.annotation.InternalApi; - -/** - * - * @author Brian Remedios - */ -@InternalApi -@Deprecated -public final class DateTimeUtil { - - private DateTimeUtil() { - } - - /** - * - * @param milliseconds - * @return String - */ - public static String asHoursMinutesSeconds(long milliseconds) { - - if (milliseconds < 0) { - throw new IllegalArgumentException(); - } - - long seconds = 0; - long minutes = 0; - long hours = 0; - - if (milliseconds > 1000) { - seconds = milliseconds / 1000; - } - - if (seconds > 60) { - minutes = seconds / 60; - seconds = seconds % 60; - } - - if (minutes > 60) { - hours = minutes / 60; - minutes = minutes % 60; - } - - StringBuilder res = new StringBuilder(); - if (hours > 0) { - res.append(hours).append("h "); - } - if (hours > 0 || minutes > 0) { - res.append(minutes).append("m "); - } - res.append(seconds).append('s'); - return res.toString(); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/FileIterable.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/FileIterable.java deleted file mode 100644 index fdd4a1f8f3..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/FileIterable.java +++ /dev/null @@ -1,88 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -import java.io.File; -import java.io.IOException; -import java.io.LineNumberReader; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Iterator; - -/** - * - *

- * Handy class to easily iterate over a file, line by line, using a Java 5 for - * loop. - *

- * - * @author Romain Pelisse <belaran@gmail.com> - * @deprecated Just use {@link Files#readAllLines(Path, Charset)} or {@code lines} on Java 8 - */ -@Deprecated -public class FileIterable implements Iterable { - - private LineNumberReader lineReader = null; - - public FileIterable(File file) { - try { - lineReader = new LineNumberReader(Files.newBufferedReader(file.toPath(), Charset.defaultCharset())); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - @Override - protected void finalize() throws Throwable { - try { - if (lineReader != null) { - lineReader.close(); - } - } catch (IOException e) { - throw new IllegalStateException(e); - } - super.finalize(); - } - - @Override - public Iterator iterator() { - return new FileIterator(); - } - - class FileIterator implements Iterator { - - private boolean hasNext = true; - - @Override - public boolean hasNext() { - return hasNext; - } - - @Override - public String next() { - String line = null; - try { - if (hasNext) { - line = lineReader.readLine(); - if (line == null) { - hasNext = false; - line = ""; - } - } - return line; - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void remove() { - throw new UnsupportedOperationException("remove is not supported by " + this.getClass().getName()); - } - - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/NumericConstants.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/NumericConstants.java deleted file mode 100644 index fc37a21165..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/NumericConstants.java +++ /dev/null @@ -1,21 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -/** - * @deprecated These constants were only useful before autoboxing was - * introduced, just use a literal or define your own constants - */ -@Deprecated -public final class NumericConstants { - - public static final Integer ZERO = 0; - - public static final Integer ONE = 1; - - public static final Float FLOAT_ZERO = 0.0f; - - private NumericConstants() { } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/SearchFunction.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/SearchFunction.java deleted file mode 100644 index 709aa57325..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/SearchFunction.java +++ /dev/null @@ -1,18 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -/** - * @deprecated Will be replaced with standard java.util.function.Predicate with 7.0.0 - */ -@Deprecated -public interface SearchFunction { - /** - * Applies the search function over a single element. - * @param o The element to analyze. - * @return True if the search should continue, false otherwhise. - */ - boolean applyTo(E o); -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java index fbd517c405..4d533b4a32 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java @@ -4,9 +4,6 @@ package net.sourceforge.pmd.util; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; @@ -180,44 +177,6 @@ public final class StringUtil { } - /** - * Return whether the non-null text arg starts with any of the prefix - * values. - * - * @return boolean - * - * @deprecated {@link StringUtils#startsWithAny(CharSequence, CharSequence...)} - */ - @Deprecated - public static boolean startsWithAny(String text, String... prefixes) { - - for (String prefix : prefixes) { - if (text.startsWith(prefix)) { - return true; - } - } - - return false; - } - - - /** - * Returns whether the non-null text arg matches any of the test values. - * - * @return boolean - */ - public static boolean isAnyOf(String text, String... tests) { - - for (String test : tests) { - if (text.equals(test)) { - return true; - } - } - - return false; - } - - /** * Checks for the existence of any of the listed prefixes on the non-null * text and removes them. @@ -236,100 +195,6 @@ public final class StringUtil { } - /** - * @param value String - * - * @return boolean - * - * @deprecated {@link StringUtils#isNotBlank(CharSequence)} - */ - @Deprecated - public static boolean isNotEmpty(String value) { - return !isEmpty(value); - } - - - /** - * Returns true if the value arg is either null, empty, or full of - * whitespace characters. More efficient that calling - * (string).trim().length() == 0. - * - * @param value String to test - * - * @return true if the value is empty, false otherwise. - * - * @deprecated {@link StringUtils#isBlank(CharSequence)} - */ - @Deprecated - public static boolean isEmpty(String value) { - return StringUtils.isBlank(value); - } - - - /** - * Returns true if the argument is null or the empty string. - * - * @param value String to test - * - * @return True if the argument is null or the empty string - * - * @deprecated {@link StringUtils#isEmpty(CharSequence)} - */ - @Deprecated - public static boolean isMissing(String value) { - return StringUtils.isEmpty(value); - } - - - /** - * Returns true if both strings are effectively null or whitespace, returns - * false otherwise if they have actual text that differs. - * - * @return boolean - */ - @Deprecated - public static boolean areSemanticEquals(String a, String b) { - - if (a == null) { - return isEmpty(b); - } - if (b == null) { - return isEmpty(a); - } - - return a.equals(b); - } - - - /** - * @param original String - * @param oldString String - * @param newString String - * - * @return String - * - * @deprecated {@link StringUtils#replace(String, String, String)} - */ - @Deprecated - public static String replaceString(final String original, final String oldString, final String newString) { - int index = original.indexOf(oldString); - if (index < 0) { - return original; - } else { - final String replace = newString == null ? "" : newString; - final StringBuilder buf = new StringBuilder(Math.max(16, original.length() + replace.length())); - int last = 0; - while (index != -1) { - buf.append(original.substring(last, index)); - buf.append(replace); - last = index + oldString.length(); - index = original.indexOf(oldString, last); - } - buf.append(original.substring(last)); - return buf.toString(); - } - } - /** * @param supportUTF8 override the default setting, whether special characters should be replaced with entities ( * false) or should be included as is ( true). @@ -402,174 +267,6 @@ public final class StringUtil { return s; } - /** - * @param original String - * @param oldChar char - * @param newString String - * - * @return String - * - * @deprecated {@link StringUtils#replace(String, String, String)} or {@link StringUtils#replaceChars(String, char, char)} - */ - @Deprecated - public static String replaceString(final String original, char oldChar, final String newString) { - int index = original.indexOf(oldChar); - if (index < 0) { - return original; - } else { - final String replace = newString == null ? "" : newString; - final StringBuilder buf = new StringBuilder(Math.max(16, original.length() + replace.length())); - int last = 0; - while (index != -1) { - buf.append(original.substring(last, index)); - buf.append(replace); - last = index + 1; - index = original.indexOf(oldChar, last); - } - buf.append(original.substring(last)); - return buf.toString(); - } - } - - - /** - * Parses the input source using the delimiter specified. This method is - * much faster than using the StringTokenizer or String.split(char) approach - * and serves as a replacement for String.split() for JDK1.3 that doesn't - * have it. - * - * @param source String - * @param delimiter char - * - * @return String[] - * - * @deprecated {@link StringUtils#split(String, char)} - */ - @Deprecated - public static String[] substringsOf(String source, char delimiter) { - - if (source == null || source.length() == 0) { - return EMPTY_STRINGS; - } - - int delimiterCount = 0; - int length = source.length(); - char[] chars = source.toCharArray(); - - for (int i = 0; i < length; i++) { - if (chars[i] == delimiter) { - delimiterCount++; - } - } - - if (delimiterCount == 0) { - return new String[] {source}; - } - - String[] results = new String[delimiterCount + 1]; - - int i = 0; - int offset = 0; - - while (offset <= length) { - int pos = source.indexOf(delimiter, offset); - if (pos < 0) { - pos = length; - } - results[i++] = pos == offset ? "" : source.substring(offset, pos); - offset = pos + 1; - } - - return results; - } - - - /** - * Much more efficient than StringTokenizer. - * - * @param str String - * @param separator char - * - * @return String[] - * - * @deprecated {@link StringUtils#split(String, String)} - */ - @Deprecated - public static String[] substringsOf(String str, String separator) { - - if (str == null || str.length() == 0) { - return EMPTY_STRINGS; - } - - int index = str.indexOf(separator); - if (index == -1) { - return new String[] {str}; - } - - List list = new ArrayList<>(); - int currPos = 0; - int len = separator.length(); - while (index != -1) { - list.add(str.substring(currPos, index)); - currPos = index + len; - index = str.indexOf(separator, currPos); - } - list.add(str.substring(currPos)); - return list.toArray(new String[0]); - } - - - /** - * Copies the elements returned by the iterator onto the string buffer each - * delimited by the separator. - * - * @param sb StringBuffer - * @param iter Iterator - * @param separator String - * - * @deprecated {@link StringUtils#join(Iterator, String)} - */ - @Deprecated - public static void asStringOn(StringBuffer sb, Iterator iter, String separator) { - - if (!iter.hasNext()) { - return; - } - - sb.append(iter.next()); - - while (iter.hasNext()) { - sb.append(separator); - sb.append(iter.next()); - } - } - - - /** - * Copies the array items onto the string builder each delimited by the - * separator. Does nothing if the array is null or empty. - * - * @param sb StringBuilder - * @param items Object[] - * @param separator String - * - * @deprecated {@link StringUtils#join(Iterable, String)} - */ - @Deprecated - public static void asStringOn(StringBuilder sb, Object[] items, String separator) { - - if (items == null || items.length == 0) { - return; - } - - sb.append(items[0]); - - for (int i = 1; i < items.length; i++) { - sb.append(separator); - sb.append(items[i]); - } - } - /** * Determine the maximum number of common leading whitespace characters the @@ -577,9 +274,7 @@ public final class StringUtil { * leading characters can be removed to shift all the text in the strings to * the left without misaligning them. * - * @param strings String[] - * - * @return int + * @throws NullPointerException If the parameter is null */ public static int maxCommonLeadingWhitespaceForAll(String[] strings) { @@ -590,14 +285,12 @@ public final class StringUtil { char[] matches = new char[shortest]; - String str; for (int m = 0; m < matches.length; m++) { matches[m] = strings[0].charAt(m); if (!Character.isWhitespace(matches[m])) { return m; } - for (int i = 0; i < strings.length; i++) { - str = strings[i]; + for (String str : strings) { if (str.charAt(m) != matches[m]) { return m; } @@ -612,13 +305,11 @@ public final class StringUtil { * Return the length of the shortest string in the array. If the collection * is empty or any one of them is null then it returns 0. * - * @param strings String[] - * - * @return int + * @throws NullPointerException If the parameter is null */ public static int lengthOfShortestIn(String[] strings) { - if (CollectionUtil.isEmpty(strings)) { + if (strings.length == 0) { return 0; } @@ -655,28 +346,6 @@ public final class StringUtil { } - /** - * Left pads a string. - * - * @param s The String to pad - * @param length The desired minimum length of the resulting padded String - * - * @return The resulting left padded String - * - * @deprecated {@link StringUtils#leftPad(String, int)} - */ - @Deprecated - public static String lpad(String s, int length) { - String res = s; - if (length - s.length() > 0) { - char[] arr = new char[length - s.length()]; - Arrays.fill(arr, ' '); - res = new StringBuilder(length).append(arr).append(s).toString(); - } - return res; - } - - /** * Are the two String values the same. The Strings can be optionally trimmed * before checking. The Strings can be optionally compared ignoring case. @@ -750,61 +419,6 @@ public final class StringUtil { } - /** - * Converts the given string to Camel case, - * that is, removing all spaces, and capitalising - * the first letter of each word except the first. - * - *

If the first word starts with an uppercase - * letter, it's kept as is. This method can thus - * be used for Pascal case too. - * - * @param name The string to convert - * - * @return The string converted to Camel case - * - * @deprecated Use {@link CaseConvention} - */ - @Deprecated - public static String toCamelCase(String name) { - return toCamelCase(name, false); - } - - - /** - * Converts the given string to Camel case, - * that is, removing all spaces, and capitalising - * the first letter of each word except the first. - * - *

The second parameter can be used to force the - * words to be converted to lowercase before capitalising. - * This can be useful if eg the first word contains - * several uppercase letters. - * - * @param name The string to convert - * @param forceLowerCase Whether to force removal of all upper - * case letters except on word start - * - * @return The string converted to Camel case - * - * @deprecated Use {@link CaseConvention} - */ - @Deprecated - public static String toCamelCase(String name, boolean forceLowerCase) { - StringBuilder sb = new StringBuilder(); - boolean isFirst = true; - for (String word : name.trim().split("\\s++")) { - String pretreated = forceLowerCase ? word.toLowerCase(Locale.ROOT) : word; - if (isFirst) { - sb.append(pretreated); - isFirst = false; - } else { - sb.append(StringUtils.capitalize(pretreated)); - } - } - return sb.toString(); - } - /** * Replaces unprintable characters by their escaped (or unicode escaped) * equivalents in the given string diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/TypeMap.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/TypeMap.java deleted file mode 100644 index c1e598d710..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/TypeMap.java +++ /dev/null @@ -1,170 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import net.sourceforge.pmd.annotation.InternalApi; - -/** - * A specialized map that stores types by both their full and short (without - * package prefixes) names. If an incoming type shares the same name (but - * different package/prefix) with a type already in the map then an - * IllegalArgumentException will be thrown since any subsequent retrievals by - * said short name could be in error. - * - * @author Brian Remedios - * @deprecated Is internal API - */ -@Deprecated -@InternalApi -public class TypeMap { - - private Map> typesByName; - - /** - * Constructor for TypeMap. - * - * @param initialSize - * int - */ - public TypeMap(int initialSize) { - typesByName = new HashMap<>(initialSize); - } - - /** - * Constructor for TypeMap that takes in an initial set of types. - * - * @param types - * Class[] - */ - public TypeMap(Class... types) { - this(types.length); - add(types); - } - - /** - * Adds a type to the receiver and stores it keyed by both its full and - * short names. Throws an exception if the short name of the argument - * matches an existing one already in the map for a different class. - * - * @param type - * Class - * @throws IllegalArgumentException - */ - @SuppressWarnings("PMD.CompareObjectsWithEquals") - public void add(Class type) { - final String shortName = ClassUtil.withoutPackageName(type.getName()); - Class existingType = typesByName.get(shortName); - if (existingType == null) { - typesByName.put(type.getName(), type); - typesByName.put(shortName, type); - return; - } - - if (existingType != type) { - throw new IllegalArgumentException( - "Short name collision between existing " + existingType + " and new " + type); - } - } - - /** - * Returns whether the type is known to the receiver. - * - * @param type - * Class - * @return boolean - */ - public boolean contains(Class type) { - return typesByName.containsValue(type); - } - - /** - * Returns whether the typeName is known to the receiver. - * - * @param typeName - * String - * @return boolean - */ - public boolean contains(String typeName) { - return typesByName.containsKey(typeName); - } - - /** - * Returns the type for the typeName specified. - * - * @param typeName - * String - * @return Class - */ - public Class typeFor(String typeName) { - return typesByName.get(typeName); - } - - /** - * Adds an array of types to the receiver at once. - * - * @param types - * Class[] - */ - public void add(Class... types) { - for (Class element : types) { - add(element); - } - } - - /** - * Creates and returns a map of short type names (without the package - * prefixes) keyed by the classes themselves. - * - * @return Map - */ - public Map, String> asInverseWithShortName() { - Map, String> inverseMap = new HashMap<>(typesByName.size() / 2); - - Iterator>> iter = typesByName.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry> entry = iter.next(); - storeShortest(inverseMap, entry.getValue(), entry.getKey()); - } - - return inverseMap; - } - - /** - * Returns the total number of entries in the receiver. This will be exactly - * twice the number of types added. - * - * @return the total number of entries in the receiver - */ - public int size() { - return typesByName.size(); - } - - /** - * Store the shorter of the incoming value or the existing value in the map - * at the key specified. - * - * @param map - * @param key - * @param value - */ - private void storeShortest(Map, String> map, Class key, String value) { - String existingValue = map.get(key); - - if (existingValue == null) { - map.put(key, value); - return; - } - - if (existingValue.length() < value.length()) { - return; - } - - map.put(key, value); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/designerbindings/DesignerBindings.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/designerbindings/DesignerBindings.java index a01f6f178c..b679b1b965 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/designerbindings/DesignerBindings.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/designerbindings/DesignerBindings.java @@ -9,7 +9,7 @@ import java.util.Collections; import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; import net.sourceforge.pmd.lang.symboltable.ScopedNode; /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeExportCli.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeExportCli.java index 7a878b4ea9..0ae6fad1db 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeExportCli.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeExportCli.java @@ -29,7 +29,7 @@ import net.sourceforge.pmd.lang.LanguageVersionHandler; import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ast.AstAnalysisContext; import net.sourceforge.pmd.lang.ast.RootNode; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertySource; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeRenderers.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeRenderers.java index 8f47c9c9e8..ac173f26c6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeRenderers.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/TreeRenderers.java @@ -15,7 +15,7 @@ import java.util.concurrent.ConcurrentHashMap; import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; import net.sourceforge.pmd.properties.PropertySource; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/XmlTreeRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/XmlTreeRenderer.java index 3c41cf6ea4..615e3c4d1e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/XmlTreeRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/treeexport/XmlTreeRenderer.java @@ -15,7 +15,7 @@ import org.apache.commons.lang3.StringUtils; import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; /** * Renders a tree to XML. The resulting document is as close as possible diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/AbstractRuleTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/AbstractRuleTest.java index bbd5c18dd3..39e27560e2 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/AbstractRuleTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/AbstractRuleTest.java @@ -112,7 +112,7 @@ public class AbstractRuleTest { s.setCoords(5, 1, 6, 1); s.setImage("TestImage"); r.addViolation(ctx, s); - RuleViolation rv = ctx.getReport().getViolationTree().iterator().next(); + RuleViolation rv = ctx.getReport().getViolations().get(0); assertEquals("Message foo 10 ${noSuchProperty}", rv.getDescription()); } @@ -127,7 +127,7 @@ public class AbstractRuleTest { n.setCoords(5, 1, 6, 1); DefaultRuleViolationFactory.defaultInstance().addViolation(ctx, r, n, "specificdescription", new Object[0]); - assertTrue(ctx.getReport().isEmpty()); + assertTrue(ctx.getReport().getViolations().isEmpty()); } @Test diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/ReadableDurationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/ReadableDurationTest.java deleted file mode 100644 index 73de53d6ad..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/ReadableDurationTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd; - -import static org.junit.Assert.assertEquals; - -import java.util.Arrays; -import java.util.Collection; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import junit.framework.JUnit4TestAdapter; - -@RunWith(Parameterized.class) -public class ReadableDurationTest { - - private Integer value; - private String expected; - - public ReadableDurationTest(String expected, Integer value) { - this.value = value; - this.expected = expected; - } - - @Parameters - public static Collection data() { - return Arrays.asList(new Object[][] { { "0s", 35 }, { "25s", (25 * 1000) }, { "5m 0s", (60 * 1000 * 5) }, - { "2h 0m 0s", (60 * 1000 * 120) }, }); - } - - @Test - public void test() { - assertEquals(expected, new Report.ReadableDuration(value).getTime()); - } - - public static junit.framework.Test suite() { - return new JUnit4TestAdapter(ReadableDurationTest.class); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java index 446c98543f..57a845fc8c 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java @@ -14,8 +14,6 @@ import java.io.StringWriter; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Iterator; -import java.util.Map; import org.apache.commons.io.IOUtils; import org.junit.Test; @@ -86,27 +84,7 @@ public class ReportTest implements ThreadSafeReportListener { } @Test - public void testSummary() { - Report r = new Report(); - RuleContext ctx = new RuleContext(); - ctx.setSourceCodeFile(new File("foo1")); - Node s = getNode(5, 5); - Rule rule = new MockRule("name", "desc", "msg", "rulesetname"); - r.addRuleViolation(new ParametricRuleViolation<>(rule, ctx, s, rule.getMessage())); - ctx.setSourceCodeFile(new File("foo2")); - Rule mr = new MockRule("rule1", "rule1", "msg", "rulesetname"); - Node s1 = getNode(20, 5); - Node s2 = getNode(30, 5); - r.addRuleViolation(new ParametricRuleViolation<>(mr, ctx, s1, mr.getMessage())); - r.addRuleViolation(new ParametricRuleViolation<>(mr, ctx, s2, mr.getMessage())); - Map summary = r.getSummary(); - assertEquals(summary.keySet().size(), 2); - assertTrue(summary.containsValue(1)); - assertTrue(summary.containsValue(2)); - } - - @Test - public void testTreeIterator() { + public void testIterator() { Report r = new Report(); RuleContext ctx = new RuleContext(); Rule rule = new MockRule("name", "desc", "msg", "rulesetname"); @@ -115,21 +93,7 @@ public class ReportTest implements ThreadSafeReportListener { Node node2 = getNode(5, 6, true); r.addRuleViolation(new ParametricRuleViolation<>(rule, ctx, node2, rule.getMessage())); - Iterator violations = r.iterator(); - int violationCount = 0; - while (violations.hasNext()) { - violations.next(); - violationCount++; - } - assertEquals(2, violationCount); - - Iterator treeIterator = r.treeIterator(); - int treeCount = 0; - while (treeIterator.hasNext()) { - treeIterator.next(); - treeCount++; - } - assertEquals(2, treeCount); + assertEquals(2, r.getViolations().size()); } private static Node getNode(int line, int column) { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java index 792a365a21..279d60c66b 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java @@ -22,7 +22,7 @@ public class RuleContextTest { @Test public void testReport() { RuleContext ctx = new RuleContext(); - assertEquals(0, ctx.getReport().size()); + assertEquals(0, ctx.getReport().getViolations().size()); Report r = new Report(); ctx.setReport(r); Report r2 = ctx.getReport(); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetTest.java index 8a8fbd079b..c66405e0cf 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetTest.java @@ -29,7 +29,6 @@ import org.junit.Test; import net.sourceforge.pmd.Report.ProcessingError; import net.sourceforge.pmd.RuleSet.RuleSetBuilder; -import net.sourceforge.pmd.internal.util.IteratorUtil; import net.sourceforge.pmd.lang.Dummy2LanguageModule; import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.LanguageRegistry; @@ -423,7 +422,7 @@ public class RuleSetTest { ctx.setSourceCodeFile(file); ctx.setLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getDefaultVersion()); ruleSets.apply(makeCompilationUnits(), ctx); - assertEquals("Violations", 2, r.size()); + assertEquals("Violations", 2, r.getViolations().size()); // One violation ruleSet1 = createRuleSetBuilder("RuleSet1") @@ -436,7 +435,7 @@ public class RuleSetTest { r = new Report(); ctx.setReport(r); ruleSets.apply(makeCompilationUnits(), ctx); - assertEquals("Violations", 1, r.size()); + assertEquals("Violations", 1, r.getViolations().size()); } @Test @@ -463,19 +462,14 @@ public class RuleSetTest { context.setReport(new Report()); new RuleSets(ruleset).apply(makeCompilationUnits(), context); - assertEquals("Invalid number of Violations Reported", size, context.getReport().size()); - - Iterator violations = context.getReport().iterator(); - while (violations.hasNext()) { - RuleViolation violation = violations.next(); + assertEquals("Invalid number of Violations Reported", size, context.getReport().getViolations().size()); + for (RuleViolation violation : context.getReport().getViolations()) { reportedValues.add(violation); assertTrue("Unexpected Violation Returned: " + violation, values.contains(violation)); } - Iterator expected = values.iterator(); - while (expected.hasNext()) { - RuleViolation violation = expected.next(); + for (RuleViolation violation : values) { assertTrue("Expected Violation not Returned: " + violation, reportedValues.contains(violation)); } } @@ -551,13 +545,13 @@ public class RuleSetTest { context.setIgnoreExceptions(true); // the default ruleset.apply(makeCompilationUnits(), context); - assertTrue("Report should have processing errors", context.getReport().hasErrors()); - List errors = IteratorUtil.toList(context.getReport().errors()); + List errors = context.getReport().getProcessingErrors(); + assertFalse("Report should have processing errors", errors.isEmpty()); assertEquals("Errors expected", 1, errors.size()); assertEquals("Wrong error message", "RuntimeException: Test exception while applying rule", errors.get(0).getMsg()); assertTrue("Should be a RuntimeException", errors.get(0).getError() instanceof RuntimeException); - assertEquals("There should be a violation", 1, context.getReport().size()); + assertEquals("There should be a violation", 1, context.getReport().getViolations().size()); } @Test @@ -593,13 +587,12 @@ public class RuleSetTest { RuleSets rulesets = new RuleSets(ruleset); rulesets.apply(makeCompilationUnits(), context); - assertTrue("Report should have processing errors", context.getReport().hasErrors()); - List errors = IteratorUtil.toList(context.getReport().errors()); + List errors = context.getReport().getProcessingErrors(); assertEquals("Errors expected", 1, errors.size()); assertEquals("Wrong error message", "RuntimeException: Test exception while applying rule", errors.get(0).getMsg()); assertTrue("Should be a RuntimeException", errors.get(0).getError() instanceof RuntimeException); - assertEquals("There should be a violation", 1, context.getReport().size()); + assertEquals("There should be a violation", 1, context.getReport().getViolations().size()); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDCommandLineInterfaceTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDCommandLineInterfaceTest.java index 4a554fbffd..acc80b8704 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDCommandLineInterfaceTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDCommandLineInterfaceTest.java @@ -22,6 +22,6 @@ public class CPDCommandLineInterfaceTest { System.setProperty(CPDCommandLineInterface.NO_EXIT_AFTER_RUN, "true"); CPDCommandLineInterface.main(new String[] { "--minimum-tokens", "340", "--language", "java", "--files", "src/test/resources/net/sourceforge/pmd/cpd/files/", "--format", "xml", }); - Assert.assertEquals("" + "\n" + "", log.getLog()); + Assert.assertEquals("" + "\n" + "", log.getLog().trim()); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/jaxen/AttributeAxisIteratorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/jaxen/AttributeAxisIteratorTest.java deleted file mode 100644 index a8b5939a26..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/jaxen/AttributeAxisIteratorTest.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.jaxen; - -import org.junit.Test; - -import net.sourceforge.pmd.lang.ast.DummyNode; -import net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator; - -public class AttributeAxisIteratorTest { - - @Test(expected = UnsupportedOperationException.class) - public void testRemove() { - DummyNode n = new DummyNode(); - AttributeAxisIterator iter = new AttributeAxisIterator(n); - iter.remove(); - } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(AttributeAxisIteratorTest.class); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/jaxen/AttributeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/jaxen/AttributeTest.java deleted file mode 100644 index eec54c965d..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/jaxen/AttributeTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.jaxen; - -import static org.junit.Assert.assertEquals; - -import java.lang.reflect.Method; - -import org.junit.Test; - -import net.sourceforge.pmd.lang.ast.DummyNode; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; - -public class AttributeTest { - - @Test - public void testConstructor() { - DummyNode p = new DummyNode(); - p.setCoords(5, 5, 5, 10); - - Method[] methods = p.getClass().getMethods(); - Method m = null; - for (Method method : methods) { - if (method.getName().equals("getBeginLine")) { - m = method; - break; - } - } - Attribute a = new Attribute(p, "BeginLine", m); - assertEquals("BeginLine", a.getName()); - assertEquals(5, a.getValue()); - assertEquals("5", a.getStringValue()); - assertEquals(p, a.getParent()); - } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(AttributeTest.class); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/jaxen/MatchesFunctionTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/jaxen/MatchesFunctionTest.java deleted file mode 100644 index c5be1ce2c5..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/jaxen/MatchesFunctionTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.jaxen; - -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.List; - -import org.jaxen.Context; -import org.jaxen.FunctionCallException; -import org.junit.Test; - -import net.sourceforge.pmd.lang.ast.impl.AbstractNodeWithTextCoordinates; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; -import net.sourceforge.pmd.lang.xpath.MatchesFunction; - -public class MatchesFunctionTest { - - public static class MyNode extends AbstractNodeWithTextCoordinates { - - private String className; - - public MyNode() { - super(); - } - - @Override - public String toString() { - return "MyNode"; - } - - public void setClassName(String className) { - this.className = className; - } - - public String getClassName() { - return className; - } - - - @Override - public String getXPathNodeName() { - return "MyNode"; - } - } - - @Test - public void testMatch() throws FunctionCallException, NoSuchMethodException { - MyNode myNode = new MyNode(); - myNode.setClassName("Foo"); - assertTrue(tryRegexp(myNode, "Foo") instanceof List); - } - - @Test - public void testNoMatch() throws FunctionCallException, NoSuchMethodException { - MyNode myNode = new MyNode(); - myNode.setClassName("bar"); - assertTrue(tryRegexp(myNode, "Foo") instanceof Boolean); - myNode.setClassName("FobboBar"); - assertTrue(tryRegexp(myNode, "Foo") instanceof Boolean); - } - - private Object tryRegexp(MyNode myNode, String exp) throws FunctionCallException, NoSuchMethodException { - MatchesFunction function = new MatchesFunction(); - List list = new ArrayList<>(); - List attrs = new ArrayList<>(); - attrs.add(new Attribute(myNode, "matches", myNode.getClass().getMethod("getClassName", new Class[0]))); - list.add(attrs); - list.add(exp); - Context c = new Context(null); - c.setNodeSet(new ArrayList<>()); - return function.call(c, list); - } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(MatchesFunctionTest.class); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java index b7c49de123..8985e8a644 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java @@ -13,13 +13,9 @@ import net.sourceforge.pmd.lang.ast.DummyAstStages; import net.sourceforge.pmd.lang.ast.DummyRoot; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.ParseException; -import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler; import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory; -import net.sf.saxon.expr.XPathContext; -import net.sf.saxon.sxpath.IndependentContext; - /** * Dummy language used for testing PMD. */ @@ -46,26 +42,6 @@ public class DummyLanguageModule extends BaseLanguageModule { super(DummyAstStages.class); } - public static class TestFunctions { - public static boolean typeIs(final XPathContext context, final String fullTypeName) { - return false; - } - } - - @Override - public XPathHandler getXPathHandler() { - return new DefaultASTXPathHandler() { - @Override - public void initialize(IndependentContext context) { - super.initialize(context, LanguageRegistry.getLanguage(DummyLanguageModule.NAME), TestFunctions.class); - } - - @Override - public void initialize() { - } - }; - } - @Override public RuleViolationFactory getRuleViolationFactory() { return new RuleViolationFactory(); @@ -97,9 +73,12 @@ public class DummyLanguageModule extends BaseLanguageModule { protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message, int beginLine, int endLine) { ParametricRuleViolation rv = new ParametricRuleViolation(rule, ruleContext, node, message) { + { + this.packageName = "foo"; // just for testing variable expansion + } + @Override public String getPackageName() { - this.packageName = "foo"; // just for testing variable expansion return super.getPackageName(); } }; diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java index 30c7e13873..3594f8822e 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java @@ -11,12 +11,17 @@ import net.sourceforge.pmd.lang.ast.impl.AbstractNodeWithTextCoordinates; import net.sourceforge.pmd.lang.ast.impl.GenericNode; public class DummyNode extends AbstractNodeWithTextCoordinates implements GenericNode { - private final boolean findBoundary; private final String xpathName; private final Map userData = new HashMap<>(); private String image; + public DummyNode(String xpathName) { + super(); + this.findBoundary = false; + this.xpathName = xpathName; + } + public DummyNode() { this(false); } @@ -82,6 +87,9 @@ public class DummyNode extends AbstractNodeWithTextCoordinates root(new DummyNodeWithDeprecatedAttribute(2))) - .findChildNodesWithXPath("//dummyNode[@Size=1]"); - - String log = loggingRule.getLog(); - - assertTrue(log.contains("deprecated")); - assertTrue(log.contains("attribute")); - assertTrue(log.contains("dummyNode/@Size")); - } - - } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/impl/DummyTreeUtil.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/impl/DummyTreeUtil.java index d8ead26590..1623aa7a17 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/impl/DummyTreeUtil.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/impl/DummyTreeUtil.java @@ -4,16 +4,15 @@ package net.sourceforge.pmd.lang.ast.impl; -import java.util.Arrays; import java.util.List; import java.util.function.Supplier; -import java.util.stream.Collectors; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.DummyNode.DummyNodeTypeB; import net.sourceforge.pmd.lang.ast.DummyRoot; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.NodeStream; +import net.sourceforge.pmd.util.CollectionUtil; /** @@ -48,7 +47,7 @@ public final class DummyTreeUtil { public static DummyNode followPath(DummyNode root, String path) { - List pathIndices = Arrays.stream(path.split("")).map(Integer::valueOf).collect(Collectors.toList()); + List pathIndices = CollectionUtil.map(path.split(""), Integer::valueOf); Node current = root; for (int i : pathIndices) { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/DocumentNavigatorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/DocumentNavigatorTest.java deleted file mode 100644 index cf57b85a52..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/DocumentNavigatorTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.ast.xpath; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; - -import org.junit.Test; - -import net.sourceforge.pmd.lang.ast.DummyNode; -import net.sourceforge.pmd.lang.ast.DummyRoot; - -/** - * Unit test for {@link DocumentNavigator} - */ -public class DocumentNavigatorTest { - - @Test - public void getDocumentNode() { - DocumentNavigator nav = new DocumentNavigator(); - - try { - nav.getDocumentNode(null); - fail(); - } catch (RuntimeException e) { - assertNotNull(e); - } - - DummyNode root = new DummyRoot(); - DummyNode n = new DummyNode(); - root.addChild(n, 0); - assertSame(root, nav.getDocumentNode(n)); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/dfa/report/ViolationNodeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/dfa/report/ViolationNodeTest.java deleted file mode 100644 index 4d5ffcdbe0..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/dfa/report/ViolationNodeTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.dfa.report; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import org.junit.Test; - -import net.sourceforge.pmd.RuleViolation; - -/** - * @author Philip Graf - */ -public final class ViolationNodeTest { - - /** - * Verifies that two violations nodes with equal - * {@code filename, beginLine, endLine, beginColumn, endColumn} and - * {@code variableName} are equal. - */ - @Test - public void testEqualsNodeWithTwoEqualViolations() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - assertTrue("Two equal violations should result in equal nodes", node1.equalsNode(node2)); - } - - /** - * Verifies that two violations nodes with different {@code filename} are - * not equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentFilename() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Bar.java", 1, 1, 5, 15, ""); - assertFalse("Two violations with different filename should result in not equal nodes", node1.equalsNode(node2)); - } - - /** - * Verifies that two violations nodes with different {@code beginLine} are - * not equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentBeginLine() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 2, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Foo.java", 2, 2, 5, 15, ""); - assertFalse("Two violations with different beginLine should result in not equal nodes", - node1.equalsNode(node2)); - } - - /** - * Verifies that two violations nodes with different {@code endLine} are not - * equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentEndLine() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Foo.java", 1, 2, 5, 15, ""); - assertFalse("Two violations with different endLine should result in not equal nodes", node1.equalsNode(node2)); - } - - /** - * Verifies that two violations nodes with different {@code beginColumn} are - * not equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentBeginColumn() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 7, 15, ""); - assertFalse("Two violations with different beginColumn should result in not equal nodes", - node1.equalsNode(node2)); - } - - /** - * Verifies that two violations nodes with different {@code endColumn} are - * not equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentEndColumn() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, ""); - final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 5, 17, ""); - assertFalse("Two violations with different end column should result in not equal nodes", - node1.equalsNode(node2)); - } - - /** - * Verifies that two violations with different {@code variableName} are not - * equal. - */ - @Test - public void testEqualsNodeWithTwoDifferentViolationsDifferentVariableName() { - final ViolationNode node1 = createViolationNode("Foo.java", 1, 1, 5, 15, "a"); - final ViolationNode node2 = createViolationNode("Foo.java", 1, 1, 5, 15, "b"); - assertFalse("Two violations with different variableName should result in not equal nodes", - node1.equalsNode(node2)); - } - - private ViolationNode createViolationNode(final String filename, final int beginLine, final int endLine, - final int beginColumn, final int endColumn, final String variableName) { - final RuleViolation violation = mock(RuleViolation.class); - when(violation.getFilename()).thenReturn(filename); - when(violation.getBeginLine()).thenReturn(beginLine); - when(violation.getEndLine()).thenReturn(endLine); - when(violation.getBeginColumn()).thenReturn(beginColumn); - when(violation.getEndColumn()).thenReturn(endColumn); - when(violation.getVariableName()).thenReturn(variableName); - return new ViolationNode(violation); - } - -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/DefaultRuleViolationFactoryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/DefaultRuleViolationFactoryTest.java index e57a709484..baaed1c018 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/DefaultRuleViolationFactoryTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/DefaultRuleViolationFactoryTest.java @@ -33,7 +33,7 @@ public class DefaultRuleViolationFactoryTest { public void testMessage() { factory.addViolation(ruleContext, new TestRule(), null, "message with \"'{'\"", null); - RuleViolation violation = ruleContext.getReport().iterator().next(); + RuleViolation violation = ruleContext.getReport().getViolations().get(0); Assert.assertEquals("message with \"{\"", violation.getDescription()); } @@ -41,7 +41,7 @@ public class DefaultRuleViolationFactoryTest { public void testMessageArgs() { factory.addViolation(ruleContext, new TestRule(), null, "message with 1 argument: \"{0}\"", new Object[] {"testarg1"}); - RuleViolation violation = ruleContext.getReport().iterator().next(); + RuleViolation violation = ruleContext.getReport().getViolations().get(0); Assert.assertEquals("message with 1 argument: \"testarg1\"", violation.getDescription()); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java index 84c5085152..dd4fce8386 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java @@ -17,9 +17,8 @@ import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.DummyNodeWithDeprecatedAttribute; -import net.sourceforge.pmd.lang.ast.DummyNodeWithListAndEnum; import net.sourceforge.pmd.lang.ast.DummyRoot; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; public class XPathRuleTest { @@ -37,55 +36,6 @@ public class XPathRuleTest { testDeprecation(XPathVersion.XPATH_2_0); } - @Test - public void testListAttributeDeprecation20() { - XPathRule xpr = makeRuleWithList("TestRuleWithListAccess"); - loggingRule.clear(); - - RuleContext ctx = new RuleContext(); - ctx.setLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getDefaultVersion()); - DummyNode firstNode = newNodeWithList(); - xpr.apply(firstNode, ctx); - assertEquals(1, ctx.getReport().size()); - - String log = loggingRule.getLog(); - assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@List' by XPath rule 'TestRuleWithListAccess'")); - - loggingRule.clear(); - xpr.apply(newNodeWithList(), ctx); // with another node - assertEquals(2, ctx.getReport().size()); - assertEquals("", loggingRule.getLog()); // no addtional warnings - - // with another rule forked from the same one (in multithreaded processor) - xpr.deepCopy().apply(newNodeWithList(), ctx); - assertEquals(3, ctx.getReport().size()); - assertEquals("", loggingRule.getLog()); // no addtional warnings - - // with another rule on the same node, new warnings - XPathRule otherRule = makeRuleWithList("OtherTestRuleWithListAccess"); - otherRule.setRuleSetName("rset.xml"); - otherRule.apply(firstNode, ctx); - assertEquals(4, ctx.getReport().size()); - log = loggingRule.getLog(); - assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@List' by XPath rule 'OtherTestRuleWithListAccess' (in ruleset 'rset.xml')")); - } - - - private XPathRule makeRuleWithList(String name) { - XPathRule xpr = new XPathRule(XPathVersion.XPATH_2_0, "//dummyNode[@List = 'A']"); - xpr.setName(name); - xpr.setMessage("list is 'a'"); - return xpr; - } - - - private DummyNode newNodeWithList() { - DummyRoot root = new DummyRoot(); - DummyNode firstNode = new DummyNodeWithListAndEnum(0); - firstNode.setCoords(1, 1, 1, 2); - root.addChild(firstNode, 0); - return root; - } public void testDeprecation(XPathVersion version) { XPathRule xpr = makeRule(version, "SomeRule"); @@ -96,7 +46,7 @@ public class XPathRuleTest { ctx.setLanguageVersion(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getDefaultVersion()); DummyNode firstNode = newNode(); xpr.apply(firstNode, ctx); - assertEquals(1, ctx.getReport().size()); + assertEquals(1, ctx.getReport().getViolations().size()); String log = loggingRule.getLog(); assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@Size' by XPath rule 'SomeRule'")); @@ -107,14 +57,14 @@ public class XPathRuleTest { // with another node xpr.apply(newNode(), ctx); - assertEquals(2, ctx.getReport().size()); + assertEquals(2, ctx.getReport().getViolations().size()); assertEquals("", loggingRule.getLog()); // no additional warnings // with another rule forked from the same one (in multithreaded processor) xpr.deepCopy().apply(newNode(), ctx); - assertEquals(3, ctx.getReport().size()); + assertEquals(3, ctx.getReport().getViolations().size()); assertEquals("", loggingRule.getLog()); // no additional warnings @@ -122,7 +72,7 @@ public class XPathRuleTest { XPathRule otherRule = makeRule(version, "OtherRule"); otherRule.setRuleSetName("rset.xml"); otherRule.apply(firstNode, ctx); - assertEquals(4, ctx.getReport().size()); + assertEquals(4, ctx.getReport().getViolations().size()); log = loggingRule.getLog(); assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@Size' by XPath rule 'OtherRule' (in ruleset 'rset.xml')")); @@ -133,6 +83,7 @@ public class XPathRuleTest { public XPathRule makeRule(XPathVersion version, String name) { XPathRule xpr = new XPathRule(version, "//dummyNode[@Size >= 2 and @Name='foo']"); xpr.setName(name); + xpr.setLanguage(LanguageRegistry.getLanguage("Dummy")); xpr.setMessage("gotcha"); return xpr; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQueryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQueryTest.java deleted file mode 100644 index a05b8eee05..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/JaxenXPathRuleQueryTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath; - -import java.util.Collections; -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.ast.DummyNodeWithListAndEnum; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.properties.PropertyDescriptor; - -public class JaxenXPathRuleQueryTest { - - @Test - public void testListAttribute() { - DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1); - - assertQuery(1, "//dummyNode[@SimpleAtt = \"foo\"]", dummy); - assertQuery(1, "//dummyNode[@Enum = \"FOO\"]", dummy); - assertQuery(0, "//dummyNode[@Enum = \"BAR\"]", dummy); - - // queries with lists are not supported with xpath 1.0 - assertQuery(0, "//dummyNode[@List = \"[A, B]\"]", dummy); - assertQuery(0, "//dummyNode[contains(@List, \"B\")]", dummy); - assertQuery(0, "//dummyNode[@List = \"C\"]", dummy); - assertQuery(0, "//dummyNode[@EnumList = \"[FOO, BAR]\"]", dummy); - assertQuery(0, "//dummyNode[contains(@EnumList, \"BAR\")]", dummy); - assertQuery(0, "//dummyNode[@EmptyList = \"A\"]", dummy); - } - - @Test - public void ruleChainVisits() { - final String xpath = "//dummyNode[@Image='baz']/foo | //bar[@Public = 'true'] | //dummyNode[@Public = 'false'] | //dummyNode"; - JaxenXPathRuleQuery query = createQuery(xpath); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(3, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertTrue(ruleChainVisits.contains("bar")); - // Note: Having AST_ROOT in the rule chain visits is probably a mistake. But it doesn't hurt, it shouldn't - // match a real node name. - Assert.assertTrue(ruleChainVisits.contains(JaxenXPathRuleQuery.AST_ROOT)); - - DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1); - RuleContext data = new RuleContext(); - data.setLanguageVersion(LanguageRegistry.findLanguageByTerseName("dummy").getDefaultVersion()); - - query.evaluate(dummy, data); - // note: the actual xpath queries are only available after evaluating - Assert.assertEquals(3, query.nodeNameToXPaths.size()); - Assert.assertEquals("self::node()", query.nodeNameToXPaths.get("dummyNode").get(0).toString()); - Assert.assertEquals("self::node()[(attribute::Public = \"false\")]", query.nodeNameToXPaths.get("dummyNode").get(1).toString()); - Assert.assertEquals("self::node()[(attribute::Image = \"baz\")]/child::foo", query.nodeNameToXPaths.get("dummyNode").get(2).toString()); - Assert.assertEquals("self::node()[(attribute::Public = \"true\")]", query.nodeNameToXPaths.get("bar").get(0).toString()); - Assert.assertEquals(xpath, query.nodeNameToXPaths.get(JaxenXPathRuleQuery.AST_ROOT).get(0).toString()); - } - - @Test - public void ruleChainVisitsMultipleFilters() { - final String xpath = "//dummyNode[@Test1 = 'false'][@Test2 = 'true']"; - JaxenXPathRuleQuery query = createQuery(xpath); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(2, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - // Note: Having AST_ROOT in the rule chain visits is probably a mistake. But it doesn't hurt, it shouldn't - // match a real node name. - Assert.assertTrue(ruleChainVisits.contains(JaxenXPathRuleQuery.AST_ROOT)); - - DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1); - RuleContext data = new RuleContext(); - data.setLanguageVersion(LanguageRegistry.findLanguageByTerseName("dummy").getDefaultVersion()); - - query.evaluate(dummy, data); - // note: the actual xpath queries are only available after evaluating - Assert.assertEquals(2, query.nodeNameToXPaths.size()); - Assert.assertEquals("self::node()[(attribute::Test1 = \"false\")][(attribute::Test2 = \"true\")]", query.nodeNameToXPaths.get("dummyNode").get(0).toString()); - Assert.assertEquals(xpath, query.nodeNameToXPaths.get(JaxenXPathRuleQuery.AST_ROOT).get(0).toString()); - } - - @Test - public void ruleChainVisitsNested() { - final String xpath = "//dummyNode/foo/*/bar[@Test = 'false']"; - JaxenXPathRuleQuery query = createQuery(xpath); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(2, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - // Note: Having AST_ROOT in the rule chain visits is probably a mistake. But it doesn't hurt, it shouldn't - // match a real node name. - Assert.assertTrue(ruleChainVisits.contains(JaxenXPathRuleQuery.AST_ROOT)); - - DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1); - RuleContext data = new RuleContext(); - data.setLanguageVersion(LanguageRegistry.findLanguageByTerseName("dummy").getDefaultVersion()); - - query.evaluate(dummy, data); - // note: the actual xpath queries are only available after evaluating - Assert.assertEquals(2, query.nodeNameToXPaths.size()); - Assert.assertEquals("self::node()/child::foo/child::*/child::bar[(attribute::Test = \"false\")]", query.nodeNameToXPaths.get("dummyNode").get(0).toString()); - Assert.assertEquals(xpath, query.nodeNameToXPaths.get(JaxenXPathRuleQuery.AST_ROOT).get(0).toString()); - } - - @Test - public void ruleChainVisitsNested2() { - final String xpath = "//dummyNode/foo[@Baz = 'a']/*/bar[@Test = 'false']"; - JaxenXPathRuleQuery query = createQuery(xpath); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(2, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - // Note: Having AST_ROOT in the rule chain visits is probably a mistake. But it doesn't hurt, it shouldn't - // match a real node name. - Assert.assertTrue(ruleChainVisits.contains(JaxenXPathRuleQuery.AST_ROOT)); - - DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1); - RuleContext data = new RuleContext(); - data.setLanguageVersion(LanguageRegistry.findLanguageByTerseName("dummy").getDefaultVersion()); - - query.evaluate(dummy, data); - // note: the actual xpath queries are only available after evaluating - Assert.assertEquals(2, query.nodeNameToXPaths.size()); - Assert.assertEquals("self::node()/child::foo[(attribute::Baz = \"a\")]/child::*/child::bar[(attribute::Test = \"false\")]", query.nodeNameToXPaths.get("dummyNode").get(0).toString()); - Assert.assertEquals(xpath, query.nodeNameToXPaths.get(JaxenXPathRuleQuery.AST_ROOT).get(0).toString()); - } - - private static void assertQuery(int resultSize, String xpath, Node node) { - JaxenXPathRuleQuery query = createQuery(xpath); - RuleContext data = new RuleContext(); - data.setLanguageVersion(LanguageRegistry.findLanguageByTerseName("dummy").getDefaultVersion()); - List result = query.evaluate(node, data); - Assert.assertEquals(resultSize, result.size()); - } - - private static JaxenXPathRuleQuery createQuery(String xpath) { - JaxenXPathRuleQuery query = new JaxenXPathRuleQuery(); - query.setVersion("1.0"); - query.setProperties(Collections., Object>emptyMap()); - query.setXPath(xpath); - return query; - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/NoAttributeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/NoAttributeTest.java similarity index 95% rename from pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/NoAttributeTest.java rename to pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/NoAttributeTest.java index 9f9b93e3f6..50476e0979 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/NoAttributeTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/NoAttributeTest.java @@ -2,7 +2,11 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.ast.xpath; +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -15,7 +19,7 @@ import org.junit.Test; import net.sourceforge.pmd.internal.util.IteratorUtil; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.NoAttribute.NoAttrScope; +import net.sourceforge.pmd.lang.rule.xpath.NoAttribute.NoAttrScope; /** * @author Clément Fournier diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQueryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQueryTest.java deleted file mode 100644 index 0920d7c4e4..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/SaxonXPathRuleQueryTest.java +++ /dev/null @@ -1,213 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Assert; -import org.junit.Test; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.DummyNodeWithListAndEnum; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.properties.PropertyDescriptor; -import net.sourceforge.pmd.properties.PropertyFactory; - -import net.sf.saxon.expr.Expression; - -public class SaxonXPathRuleQueryTest { - - @Test - public void testListAttribute() { - DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(1); - - assertQuery(1, "//dummyNode[@List = \"A\"]", dummy); - assertQuery(1, "//dummyNode[@List = \"B\"]", dummy); - assertQuery(0, "//dummyNode[@List = \"C\"]", dummy); - assertQuery(1, "//dummyNode[@Enum = \"FOO\"]", dummy); - assertQuery(0, "//dummyNode[@Enum = \"BAR\"]", dummy); - assertQuery(1, "//dummyNode[@EnumList = \"FOO\"]", dummy); - assertQuery(1, "//dummyNode[@EnumList = \"BAR\"]", dummy); - assertQuery(1, "//dummyNode[@EnumList = (\"FOO\", \"BAR\")]", dummy); - assertQuery(0, "//dummyNode[@EmptyList = (\"A\")]", dummy); - } - - @Test - public void ruleChainVisits() { - SaxonXPathRuleQuery query = createQuery("//dummyNode[@Image='baz']/foo | //bar[@Public = 'true'] | //dummyNode[@Public = false()] | //dummyNode"); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(2, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertTrue(ruleChainVisits.contains("bar")); - - Assert.assertEquals(3, query.nodeNameToXPaths.size()); - assertExpression("((self::node()[QuantifiedExpression(Atomizer(attribute::attribute(Image, xs:anyAtomicType)), ($qq:qq106374177 singleton eq \"baz\"))])/child::element(foo, xs:anyType))", query.nodeNameToXPaths.get("dummyNode").get(0)); - assertExpression("(self::node()[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq609962972 singleton eq false()))])", query.nodeNameToXPaths.get("dummyNode").get(1)); - assertExpression("self::node()", query.nodeNameToXPaths.get("dummyNode").get(2)); - assertExpression("(self::node()[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq232307208 singleton eq \"true\"))])", query.nodeNameToXPaths.get("bar").get(0)); - assertExpression("(((DocumentSorter(((((/)/descendant::element(dummyNode, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Image, xs:anyAtomicType)), ($qq:qq000 singleton eq \"baz\"))])/child::element(foo, xs:anyType))) | (((/)/descendant::element(bar, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq000 singleton eq \"true\"))])) | (((/)/descendant::element(dummyNode, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq000 singleton eq false()))])) | ((/)/descendant::element(dummyNode, xs:anyType)))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - } - - @Test - public void ruleChainVisitsMultipleFilters() { - SaxonXPathRuleQuery query = createQuery("//dummyNode[@Test1 = false()][@Test2 = true()]"); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertEquals(2, query.nodeNameToXPaths.size()); - assertExpression("((self::node()[QuantifiedExpression(Atomizer(attribute::attribute(Test2, xs:anyAtomicType)), ($qq:qq1741979653 singleton eq true()))])[QuantifiedExpression(Atomizer(attribute::attribute(Test1, xs:anyAtomicType)), ($qq:qq1529060733 singleton eq false()))])", query.nodeNameToXPaths.get("dummyNode").get(0)); - assertExpression("((((/)/descendant::element(dummyNode, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Test2, xs:anyAtomicType)), ($qq:qq1741979653 singleton eq true()))])[QuantifiedExpression(Atomizer(attribute::attribute(Test1, xs:anyAtomicType)), ($qq:qq1529060733 singleton eq false()))])", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - } - - @Test - public void ruleChainVisitsCustomFunctions() { - SaxonXPathRuleQuery query = createQuery("//dummyNode[pmd-dummy:typeIs(@Image)]"); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertEquals(2, query.nodeNameToXPaths.size()); - assertExpression("(self::node()[pmd-dummy:typeIs(CardinalityChecker(ItemChecker(UntypedAtomicConverter(Atomizer(attribute::attribute(Image, xs:anyAtomicType))))))])", query.nodeNameToXPaths.get("dummyNode").get(0)); - assertExpression("DocumentSorter((((/)/descendant-or-self::node())/(child::element(dummyNode, xs:anyType)[pmd-dummy:typeIs(CardinalityChecker(ItemChecker(UntypedAtomicConverter(Atomizer(attribute::attribute(Image, xs:anyAtomicType))))))])))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - } - - /** - * If a query contains another unbounded path expression other than the first one, it must be - * excluded from rule chain execution. Saxon itself optimizes this quite good already. - */ - @Test - public void ruleChainVisitsUnboundedPathExpressions() { - SaxonXPathRuleQuery query = createQuery("//dummyNode[//ClassOrInterfaceType]"); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(0, ruleChainVisits.size()); - Assert.assertEquals(1, query.nodeNameToXPaths.size()); - assertExpression("LetExpression(LazyExpression(((/)/descendant::element(ClassOrInterfaceType, xs:anyType))), (((/)/descendant::element(dummyNode, xs:anyType))[$zz:zz771775563]))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - - // second sample, more complex - query = createQuery("//dummyNode[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType]]"); - ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(0, ruleChainVisits.size()); - Assert.assertEquals(1, query.nodeNameToXPaths.size()); - assertExpression("LetExpression(LazyExpression(((/)/descendant::element(ClassOrInterfaceType, xs:anyType))), (((/)/descendant::element(dummyNode, xs:anyType))[(ancestor::element(ClassOrInterfaceDeclaration, xs:anyType)[$zz:zz106374177])]))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - - // third example, with boolean expr - query = createQuery("//dummyNode[//ClassOrInterfaceType or //OtherNode]"); - ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(0, ruleChainVisits.size()); - Assert.assertEquals(1, query.nodeNameToXPaths.size()); - assertExpression("LetExpression(LazyExpression((((/)/descendant::element(ClassOrInterfaceType, xs:anyType)) or ((/)/descendant::element(OtherNode, xs:anyType)))), (((/)/descendant::element(dummyNode, xs:anyType))[$zz:zz1364913072]))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - } - - @Test - public void ruleChainVisitsNested() { - SaxonXPathRuleQuery query = createQuery("//dummyNode/foo/*/bar[@Test = 'false']"); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertEquals(2, query.nodeNameToXPaths.size()); - assertExpression("((((self::node()/child::element(foo, xs:anyType))/child::element())/child::element(bar, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Test, xs:anyAtomicType)), ($qq:qq166794956 singleton eq \"false\"))])", query.nodeNameToXPaths.get("dummyNode").get(0)); - assertExpression("DocumentSorter(((((((/)/descendant::element(dummyNode, xs:anyType))/child::element(foo, xs:anyType))/child::element())/child::element(bar, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Test, xs:anyAtomicType)), ($qq:qq166794956 singleton eq \"false\"))]))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - } - - @Test - public void ruleChainVisitsNested2() { - SaxonXPathRuleQuery query = createQuery("//dummyNode/foo[@Baz = 'a']/*/bar[@Test = 'false']"); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertEquals(2, query.nodeNameToXPaths.size()); - assertExpression("(((((self::node()/child::element(foo, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Baz, xs:anyAtomicType)), ($qq:qq306612792 singleton eq \"a\"))])/child::element())/child::element(bar, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Test, xs:anyAtomicType)), ($qq:qq1803669141 singleton eq \"false\"))])", query.nodeNameToXPaths.get("dummyNode").get(0)); - assertExpression("DocumentSorter((((((((/)/descendant::element(dummyNode, xs:anyType))/child::element(foo, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Baz, xs:anyAtomicType)), ($qq:qq306612792 singleton eq \"a\"))])/child::element())/child::element(bar, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Test, xs:anyAtomicType)), ($qq:qq1803669141 singleton eq \"false\"))]))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - } - - @Test - public void ruleChainVisitWithVariable() { - PropertyDescriptor testClassPattern = PropertyFactory.stringProperty("testClassPattern").desc("test").defaultValue("a").build(); - SaxonXPathRuleQuery query = createQuery("//dummyNode[matches(@SimpleName, $testClassPattern)]", testClassPattern); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertEquals(2, query.nodeNameToXPaths.size()); - assertExpression("LetExpression(LazyExpression(CardinalityChecker(ItemChecker(UntypedAtomicConverter(Atomizer($testClassPattern))))), (self::node()[matches(CardinalityChecker(ItemChecker(UntypedAtomicConverter(Atomizer(attribute::attribute(SimpleName, xs:anyAtomicType))))), $zz:zz952562199)]))", query.nodeNameToXPaths.get("dummyNode").get(0)); - assertExpression("LetExpression(LazyExpression(CardinalityChecker(ItemChecker(UntypedAtomicConverter(Atomizer($testClassPattern))))), (((/)/descendant::element(dummyNode, xs:anyType))[matches(CardinalityChecker(ItemChecker(UntypedAtomicConverter(Atomizer(attribute::attribute(SimpleName, xs:anyAtomicType))))), $zz:zz952562199)]))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - } - - @Test - public void ruleChainVisitWithVariable2() { - PropertyDescriptor testClassPattern = PropertyFactory.stringProperty("testClassPattern").desc("test").defaultValue("a").build(); - SaxonXPathRuleQuery query = createQuery("//dummyNode[matches(@SimpleName, $testClassPattern)]/foo", testClassPattern); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertEquals(2, query.nodeNameToXPaths.size()); - assertExpression("(LetExpression(LazyExpression(CardinalityChecker(ItemChecker(UntypedAtomicConverter(Atomizer($testClassPattern))))), (self::node()[matches(CardinalityChecker(ItemChecker(UntypedAtomicConverter(Atomizer(attribute::attribute(SimpleName, xs:anyAtomicType))))), $zz:zz952562199)]))/child::element(foo, xs:anyType))", query.nodeNameToXPaths.get("dummyNode").get(0)); - assertExpression("DocumentSorter((LetExpression(LazyExpression(CardinalityChecker(ItemChecker(UntypedAtomicConverter(Atomizer($testClassPattern))))), (((/)/descendant::element(dummyNode, xs:anyType))[matches(CardinalityChecker(ItemChecker(UntypedAtomicConverter(Atomizer(attribute::attribute(SimpleName, xs:anyAtomicType))))), $zz:zz952562199)]))/child::element(foo, xs:anyType)))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - } - - private static void assertExpression(String expected, Expression actual) { - Assert.assertEquals(normalizeExprDump(expected), - normalizeExprDump(actual.toString())); - //Assert.assertEquals(expected, actual); - } - - private static String normalizeExprDump(String dump) { - return dump.replaceAll("\\$qq:qq-?\\d+", "\\$qq:qq000") - .replaceAll("\\$zz:zz-?\\d+", "\\$zz:zz000"); - } - - @Test - public void ruleChainVisitsCompatibilityMode() { - SaxonXPathRuleQuery query = createQuery("//dummyNode[@Image='baz']/foo | //bar[@Public = 'true'] | //dummyNode[@Public = 'false']"); - query.setVersion(XPathRuleQuery.XPATH_1_0_COMPATIBILITY); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(2, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertTrue(ruleChainVisits.contains("bar")); - - Assert.assertEquals(3, query.nodeNameToXPaths.size()); - assertExpression("((self::node()[QuantifiedExpression(Atomizer(attribute::attribute(Image, xs:anyAtomicType)), ($qq:qq6519275 singleton eq \"baz\"))])/child::element(foo, xs:anyType))", query.nodeNameToXPaths.get("dummyNode").get(0)); - assertExpression("(self::node()[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq1529060733 singleton eq \"false\"))])", query.nodeNameToXPaths.get("dummyNode").get(1)); - assertExpression("(self::node()[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq1484171695 singleton eq \"true\"))])", query.nodeNameToXPaths.get("bar").get(0)); - assertExpression("((DocumentSorter(((((/)/descendant::element(dummyNode, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Image, xs:anyAtomicType)), ($qq:qq692331943 singleton eq \"baz\"))])/child::element(foo, xs:anyType))) | (((/)/descendant::element(bar, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq2127036371 singleton eq \"true\"))])) | (((/)/descendant::element(dummyNode, xs:anyType))[QuantifiedExpression(Atomizer(attribute::attribute(Public, xs:anyAtomicType)), ($qq:qq1529060733 singleton eq \"false\"))]))", query.nodeNameToXPaths.get(SaxonXPathRuleQuery.AST_ROOT).get(0)); - } - - private static void assertQuery(int resultSize, String xpath, Node node) { - SaxonXPathRuleQuery query = createQuery(xpath); - List result = query.evaluate(node, new RuleContext()); - Assert.assertEquals(resultSize, result.size()); - } - - private static SaxonXPathRuleQuery createQuery(String xpath, PropertyDescriptor ...descriptors) { - SaxonXPathRuleQuery query = new SaxonXPathRuleQuery(); - query.setVersion(XPathRuleQuery.XPATH_2_0); - if (descriptors != null) { - Map, Object> props = new HashMap, Object>(); - for (PropertyDescriptor prop : descriptors) { - props.put(prop, prop.defaultValue()); - } - query.setProperties(props); - } else { - query.setProperties(Collections., Object>emptyMap()); - } - query.setXPath(xpath); - return query; - } - - @Test - public void ruleChainWithUnions() { - SaxonXPathRuleQuery query = createQuery("(//ForStatement | //WhileStatement | //DoStatement)//AssignmentOperator"); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(0, ruleChainVisits.size()); - } - - @Test - public void ruleChainWithUnionsAndFilter() { - SaxonXPathRuleQuery query = createQuery("(//ForStatement | //WhileStatement | //DoStatement)//AssignmentOperator[@Image='foo']"); - List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(0, ruleChainVisits.size()); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java similarity index 88% rename from pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java rename to pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java index 8017a09fd6..dc0ca2f6f6 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIteratorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java @@ -1,8 +1,8 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.ast.xpath; +package net.sourceforge.pmd.lang.rule.xpath.impl; import static org.junit.Assert.assertEquals; @@ -15,11 +15,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.junit.Assert; import org.junit.Test; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; /** @@ -37,7 +37,7 @@ public class AttributeAxisIteratorTest { AttributeAxisIterator it = new AttributeAxisIterator(dummyNode); Map atts = toMap(it); - Assert.assertEquals(6, atts.size()); + assertEquals(6, atts.size()); assertTrue(atts.containsKey("BeginColumn")); assertTrue(atts.containsKey("BeginLine")); assertTrue(atts.containsKey("FindBoundary")); @@ -52,7 +52,7 @@ public class AttributeAxisIteratorTest { AttributeAxisIterator it = new AttributeAxisIterator(dummyNode); Map atts = toMap(it); - Assert.assertEquals(7, atts.size()); + assertEquals(7, atts.size()); assertTrue(atts.containsKey("Enum")); assertEquals(DummyNodeWithEnum.MyEnum.FOO, atts.get("Enum").getValue()); } @@ -63,9 +63,8 @@ public class AttributeAxisIteratorTest { AttributeAxisIterator it = new AttributeAxisIterator(dummyNode); Map atts = toMap(it); - Assert.assertEquals(7, atts.size()); - assertTrue(atts.containsKey("List")); - assertEquals(Arrays.asList("A", "B"), atts.get("List").getValue()); + assertEquals(6, atts.size()); + assertFalse(atts.containsKey("List")); assertFalse(atts.containsKey("NodeList")); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java new file mode 100644 index 0000000000..37d7f2d0dd --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java @@ -0,0 +1,60 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + + +package net.sourceforge.pmd.lang.rule.xpath.internal; + +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.lang.ast.DummyNode; +import net.sourceforge.pmd.lang.ast.DummyRoot; + +import net.sf.saxon.Configuration; +import net.sf.saxon.type.Type; + +public class ElementNodeTest { + + + @Test + public void testCompareOrder() { + DummyRoot root = new DummyRoot(); + + DummyNode c0 = new DummyNode(false, "foo"); + c0.setCoords(1, 1, 2, 2); + root.addChild(c0, 0); + + DummyNode c1 = new DummyNode(false, "foo"); + c1.setCoords(2, 1, 2, 2); + root.addChild(c1, 1); + + + Configuration configuration = Configuration.newConfiguration(); + + AstTreeInfo treeInfo = new AstTreeInfo(root, configuration); + Assert.assertSame(root, treeInfo.getRootNode().getUnderlyingNode()); + Assert.assertEquals(Type.DOCUMENT, treeInfo.getRootNode().getNodeKind()); + + AstElementNode rootElt = treeInfo.getRootNode().getRootElement(); + Assert.assertSame(root, rootElt.getUnderlyingNode()); + Assert.assertEquals(Type.ELEMENT, rootElt.getNodeKind()); + Assert.assertSame(rootElt, treeInfo.findWrapperFor(root)); + + AstElementNode elementFoo0 = rootElt.getChildren().get(0); + Assert.assertSame(c0, elementFoo0.getUnderlyingNode()); + Assert.assertSame(elementFoo0, treeInfo.findWrapperFor(c0)); + + AstElementNode elementFoo1 = rootElt.getChildren().get(1); + Assert.assertSame(c1, elementFoo1.getUnderlyingNode()); + Assert.assertSame(elementFoo1, treeInfo.findWrapperFor(c1)); + + Assert.assertFalse(elementFoo0.isSameNodeInfo(elementFoo1)); + Assert.assertFalse(elementFoo1.isSameNodeInfo(elementFoo0)); + Assert.assertTrue(elementFoo0.compareOrder(elementFoo1) < 0); + Assert.assertTrue(elementFoo1.compareOrder(elementFoo0) > 0); + Assert.assertEquals(0, elementFoo0.compareOrder(elementFoo0)); + Assert.assertEquals(0, elementFoo1.compareOrder(elementFoo1)); + + } +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java new file mode 100644 index 0000000000..dd128e7690 --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java @@ -0,0 +1,339 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.rule.xpath.internal; + +import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.followPath; +import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.node; +import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.nodeB; +import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.root; +import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.tree; +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.lang.ast.DummyNodeWithListAndEnum; +import net.sourceforge.pmd.lang.ast.DummyRoot; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.RootNode; +import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; +import net.sourceforge.pmd.lang.rule.xpath.impl.AbstractXPathFunctionDef; +import net.sourceforge.pmd.lang.rule.xpath.impl.XPathHandler; +import net.sourceforge.pmd.properties.PropertyDescriptor; +import net.sourceforge.pmd.properties.PropertyFactory; + +import net.sf.saxon.expr.Expression; +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.lib.ExtensionFunctionCall; +import net.sf.saxon.om.Sequence; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.value.BooleanValue; +import net.sf.saxon.value.SequenceType; + +public class SaxonXPathRuleQueryTest { + + // Unsupported: https://github.com/pmd/pmd/issues/2451 + // @Test + // public void testListAttribute() { + // RootNode dummy = new DummyNodeWithListAndEnum(); + // + // assertQuery(1, "//dummyNode[@List = \"A\"]", dummy); + // assertQuery(1, "//dummyNode[@List = \"B\"]", dummy); + // assertQuery(0, "//dummyNode[@List = \"C\"]", dummy); + // assertQuery(1, "//dummyNode[@Enum = \"FOO\"]", dummy); + // assertQuery(0, "//dummyNode[@Enum = \"BAR\"]", dummy); + // assertQuery(1, "//dummyNode[@EnumList = \"FOO\"]", dummy); + // assertQuery(1, "//dummyNode[@EnumList = \"BAR\"]", dummy); + // assertQuery(1, "//dummyNode[@EnumList = (\"FOO\", \"BAR\")]", dummy); + // assertQuery(0, "//dummyNode[@EmptyList = (\"A\")]", dummy); + // } + + @Test + public void testHigherOrderFuns() { // XPath 3.1 + DummyRoot tree = tree(() -> root( + node() + )); + + tree.setImage("[oha]"); + + assertQuery(1, "//dummyRootNode[" + + "(@Image => substring-after('[') => substring-before(']')) " + // -------------------- --------------------- + // Those are higher order functions, + // the arrow operator applies it to the left expression + + "! . = 'oha']", tree); + // ^ This is the mapping operator, it applies a function on + // the right to every element of the sequence on the left + + // Together this says, + + // for r in dummyRootNode: + // tmp = atomize(r/@Image) + // tmp = substring-after('[', tmp) + // tmp = substring-before(']', tmp) + // if tmp == 'oha': + // yield r + + } + + @Test + public void testListProperty() { + RootNode dummy = new DummyNodeWithListAndEnum(); + + PropertyDescriptor> prop = PropertyFactory.stringListProperty("prop") + .defaultValues("FOO", "BAR") + .desc("description").build(); + + + assertQuery(1, "//dummyRootNode[@Enum = $prop]", dummy, prop); + } + + @Test + public void ruleChainVisits() { + SaxonXPathRuleQuery query = createQuery("//dummyNode[@Image='baz']/foo | //bar[@Public = 'true'] | //dummyNode[@Public = false()] | //dummyNode"); + List ruleChainVisits = query.getRuleChainVisits(); + assertEquals(2, ruleChainVisits.size()); + Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + Assert.assertTrue(ruleChainVisits.contains("bar")); + + assertEquals(3, query.nodeNameToXPaths.size()); + assertExpression("(self::node()[(string(data(@Image))) eq \"baz\"])/child::element(foo)", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); + assertExpression("self::node()[(boolean(data(@Public))) eq false()]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(1)); + assertExpression("self::node()", query.getExpressionsForLocalNameOrDefault("dummyNode").get(2)); + assertExpression("self::node()[(string(data(@Public))) eq \"true\"]", query.getExpressionsForLocalNameOrDefault("bar").get(0)); + assertExpression("(((docOrder((((/)/descendant::element(dummyNode))[(string(data(@Image))) eq \"baz\"])/child::element(foo))) | (((/)/descendant::element(bar))[(string(data(@Public))) eq \"true\"])) | (((/)/descendant::element(dummyNode))[(boolean(data(@Public))) eq false()])) | ((/)/descendant::element(dummyNode))", query.getFallbackExpr()); + } + + @Test + public void ruleChainVisitsMultipleFilters() { + SaxonXPathRuleQuery query = createQuery("//dummyNode[@Test1 = false()][@Test2 = true()]"); + List ruleChainVisits = query.getRuleChainVisits(); + assertEquals(1, ruleChainVisits.size()); + Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertEquals(2, query.nodeNameToXPaths.size()); + assertExpression("(self::node()[(boolean(data(@Test1))) eq false()])[(boolean(data(@Test2))) eq true()]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); + assertExpression("(((/)/descendant::element(dummyNode))[(boolean(data(@Test1))) eq false()])[(boolean(data(@Test2))) eq true()]", query.getFallbackExpr()); + } + + @Test + public void ruleChainVisitsCustomFunctions() { + SaxonXPathRuleQuery query = createQuery("//dummyNode[pmd-dummy:imageIs(@Image)]"); + List ruleChainVisits = query.getRuleChainVisits(); + assertEquals(1, ruleChainVisits.size()); + Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertEquals(2, query.nodeNameToXPaths.size()); + assertExpression("self::node()[Q{http://pmd.sourceforge.net/pmd-dummy}imageIs(exactly-one(convertUntyped(data(@Image))))]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); + assertExpression("((/)/descendant::element(Q{}dummyNode))[Q{http://pmd.sourceforge.net/pmd-dummy}imageIs(exactly-one(convertUntyped(data(@Image))))]", query.getFallbackExpr()); + } + + /** + * If a query contains another unbounded path expression other than the first one, it must be + * excluded from rule chain execution. Saxon itself optimizes this quite good already. + */ + @Test + public void ruleChainVisitsUnboundedPathExpressions() { + SaxonXPathRuleQuery query = createQuery("//dummyNode[//ClassOrInterfaceType]"); + List ruleChainVisits = query.getRuleChainVisits(); + assertEquals(0, ruleChainVisits.size()); + assertEquals(1, query.nodeNameToXPaths.size()); + assertExpression("let $Q{http://saxon.sf.net/generated-variable}v0 := (/)/descendant::element(Q{}ClassOrInterfaceType) return (((/)/descendant::element(Q{}dummyNode))[exists($Q{http://saxon.sf.net/generated-variable}v0)])", query.getFallbackExpr()); + + // second sample, more complex + query = createQuery("//dummyNode[ancestor::ClassOrInterfaceDeclaration[//ClassOrInterfaceType]]"); + ruleChainVisits = query.getRuleChainVisits(); + assertEquals(0, ruleChainVisits.size()); + assertEquals(1, query.nodeNameToXPaths.size()); + assertExpression("let $Q{http://saxon.sf.net/generated-variable}v0 := (/)/descendant::element(Q{}ClassOrInterfaceType) return (((/)/descendant::element(Q{}dummyNode))[exists(ancestor::element(Q{}ClassOrInterfaceDeclaration)[exists($Q{http://saxon.sf.net/generated-variable}v0)])])", query.getFallbackExpr()); + + // third example, with boolean expr + query = createQuery("//dummyNode[//ClassOrInterfaceType or //OtherNode]"); + ruleChainVisits = query.getRuleChainVisits(); + assertEquals(0, ruleChainVisits.size()); + assertEquals(1, query.nodeNameToXPaths.size()); + assertExpression("let $Q{http://saxon.sf.net/generated-variable}v0 := (exists((/)/descendant::element(Q{}ClassOrInterfaceType))) or (exists((/)/descendant::element(Q{}OtherNode))) return (((/)/descendant::element(Q{}dummyNode))[$Q{http://saxon.sf.net/generated-variable}v0])", query.getFallbackExpr()); + } + + @Test + public void ruleChainVisitsNested() { + SaxonXPathRuleQuery query = createQuery("//dummyNode/foo/*/bar[@Test = 'false']"); + List ruleChainVisits = query.getRuleChainVisits(); + assertEquals(1, ruleChainVisits.size()); + Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertEquals(2, query.nodeNameToXPaths.size()); + assertExpression("(((self::node()/child::element(foo))/child::element())/child::element(bar))[(string(data(@Test))) eq \"false\"]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); + assertExpression("docOrder(((docOrder((((/)/descendant::element(dummyNode))/child::element(foo))/child::element()))/child::element(bar))[(string(data(@Test))) eq \"false\"])", query.getFallbackExpr()); + } + + @Test + public void ruleChainVisitsNested2() { + SaxonXPathRuleQuery query = createQuery("//dummyNode/foo[@Baz = 'a']/*/bar[@Test = 'false']"); + List ruleChainVisits = query.getRuleChainVisits(); + assertEquals(1, ruleChainVisits.size()); + Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertEquals(2, query.nodeNameToXPaths.size()); + assertExpression("((((self::node()/child::element(foo))[(string(data(@Baz))) eq \"a\"])/child::element())/child::element(bar))[(string(data(@Test))) eq \"false\"]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); + assertExpression("docOrder(((docOrder(((((/)/descendant::element(dummyNode))/child::element(foo))[(string(data(@Baz))) eq \"a\"])/child::element()))/child::element(bar))[(string(data(@Test))) eq \"false\"])", query.getFallbackExpr()); + } + + @Test + public void unionBeforeSlash() { + SaxonXPathRuleQuery query = createQuery("(//dummyNode | //dummyNodeB)/dummyNode[@Image = '10']"); + + DummyRoot tree = tree(() -> root( + node( + node() + ), + nodeB( + node() + ) + )); + + tree.descendantsOrSelf().forEach(n -> { + List results = query.evaluate(n); + assertEquals(1, results.size()); + assertEquals(followPath(tree, "10"), results.get(0)); + }); + + assertExpression("docOrder((((/)/descendant::(element(dummyNode) | element(dummyNodeB)))/child::element(dummyNode))[(string(data(@Image))) eq \"10\"])", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); + } + + @Test + public void unionBeforeSlashWithFilter() { + SaxonXPathRuleQuery query = createQuery("(//dummyNode[@Image='0'] | //dummyNodeB[@Image='1'])/dummyNode[@Image = '10']"); + + DummyRoot tree = tree(() -> root( + node( + node() + ), + nodeB( + node() + ) + )); + + assertEquals(0, query.getRuleChainVisits().size()); + assertExpression("docOrder((((((/)/descendant::element(dummyNode))[(string(data(@Image))) eq \"0\"]) | (((/)/descendant::element(dummyNodeB))[(string(data(@Image))) eq \"1\"]))/child::element(dummyNode))[(string(data(@Image))) eq \"10\"])", query.getFallbackExpr()); + + tree.descendantsOrSelf().forEach(n -> { + List results = query.evaluate(n); + assertEquals(1, results.size()); + assertEquals(followPath(tree, "10"), results.get(0)); + }); + } + + @Test + public void unionBeforeSlashDeeper() { + SaxonXPathRuleQuery query = createQuery("(//dummyNode | //dummyNodeB)/dummyNode/dummyNode"); + + DummyRoot tree = tree(() -> root( + node( + node( + node() + ) + ), + nodeB( + node() + ) + )); + + assertEquals(0, query.getRuleChainVisits().size()); + assertExpression("docOrder((((/)/descendant::(element(dummyNode) | element(dummyNodeB)))/child::element(dummyNode))/child::element(dummyNode))", query.getFallbackExpr()); + + tree.descendantsOrSelf().forEach(n -> { + List results = query.evaluate(n); + assertEquals(1, results.size()); + assertEquals(followPath(tree, "000"), results.get(0)); + }); + } + + @Test + public void ruleChainVisitWithVariable() { + PropertyDescriptor testClassPattern = PropertyFactory.stringProperty("testClassPattern").desc("test").defaultValue("a").build(); + SaxonXPathRuleQuery query = createQuery("//dummyNode[matches(@SimpleName, $testClassPattern)]", testClassPattern); + List ruleChainVisits = query.getRuleChainVisits(); + assertEquals(1, ruleChainVisits.size()); + Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertEquals(2, query.nodeNameToXPaths.size()); + assertExpression("self::node()[matches(convertUntyped(data(@SimpleName)), \"a\", \"\")]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); + assertExpression("((/)/descendant::element(Q{}dummyNode))[matches(convertUntyped(data(@SimpleName)), \"a\", \"\")]", query.getFallbackExpr()); + } + + @Test + public void ruleChainVisitWithVariable2() { + PropertyDescriptor testClassPattern = PropertyFactory.stringProperty("testClassPattern").desc("test").defaultValue("a").build(); + SaxonXPathRuleQuery query = createQuery("//dummyNode[matches(@SimpleName, $testClassPattern)]/foo", testClassPattern); + List ruleChainVisits = query.getRuleChainVisits(); + assertEquals(1, ruleChainVisits.size()); + Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertEquals(2, query.nodeNameToXPaths.size()); + assertExpression("(self::node()[matches(convertUntyped(data(@SimpleName)), \"a\", \"\")])/child::element(Q{}foo)", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); + assertExpression("docOrder((((/)/descendant::element(Q{}dummyNode))[matches(convertUntyped(data(@SimpleName)), \"a\", \"\")])/child::element(Q{}foo))", query.getFallbackExpr()); + } + + private static void assertExpression(String expected, Expression actual) { + assertEquals(normalizeExprDump(expected), + normalizeExprDump(actual.toString())); + } + + private static String normalizeExprDump(String dump) { + return dump.replaceAll("Q\\{[^}]*+}", "") // remove namespaces + // generated variable ids + .replaceAll("\\$qq:qq-?\\d+", "\\$qq:qq000") + .replaceAll("\\$zz:zz-?\\d+", "\\$zz:zz000"); + } + + private static void assertQuery(int resultSize, String xpath, Node node, PropertyDescriptor... descriptors) { + SaxonXPathRuleQuery query = createQuery(xpath, descriptors); + List result = query.evaluate(node); + assertEquals("Wrong number of matched nodes", resultSize, result.size()); + } + + private static SaxonXPathRuleQuery createQuery(String xpath, PropertyDescriptor... descriptors) { + Map, Object> props = new HashMap<>(); + if (descriptors != null) { + for (PropertyDescriptor prop : descriptors) { + props.put(prop, prop.defaultValue()); + } + } + + return new SaxonXPathRuleQuery( + xpath, + XPathVersion.DEFAULT, + props, + XPathHandler.getHandlerForFunctionDefs(imageIsFunction()), + DeprecatedAttrLogger.noop() + ); + } + + @NonNull + private static AbstractXPathFunctionDef imageIsFunction() { + return new AbstractXPathFunctionDef("imageIs", "dummy") { + @Override + public SequenceType[] getArgumentTypes() { + return new SequenceType[] {SequenceType.SINGLE_STRING}; + } + + @Override + public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { + return SequenceType.SINGLE_BOOLEAN; + } + + @Override + public ExtensionFunctionCall makeCallExpression() { + return new ExtensionFunctionCall() { + @Override + public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException { + Node contextNode = ((AstElementNode) context.getContextItem()).getUnderlyingNode(); + return BooleanValue.get(arguments[0].head().getStringValue().equals(contextNode.getImage())); + } + }; + } + }; + } +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/saxon/ElementNodeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/saxon/ElementNodeTest.java deleted file mode 100644 index 0a4cf00195..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/saxon/ElementNodeTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.rule.xpath.saxon; - -import org.junit.Assert; -import org.junit.Test; - -import net.sourceforge.pmd.lang.ast.DummyNode; -import net.sourceforge.pmd.lang.ast.xpath.saxon.DocumentNode; -import net.sourceforge.pmd.lang.ast.xpath.saxon.ElementNode; - -public class ElementNodeTest { - - @Test - public void testCompareOrder() { - DummyNode node = new DummyNode(false, "dummy"); - DummyNode foo1 = new DummyNode(false, "foo"); - foo1.setCoords(1, 1, 2, 2); - DummyNode foo2 = new DummyNode(false, "foo"); - foo2.setCoords(2, 1, 2, 2); - node.addChild(foo1, 0); - node.addChild(foo2, 1); - - DocumentNode document = new DocumentNode(node); - ElementNode elementFoo1 = document.nodeToElementNode.get(foo1); - ElementNode elementFoo2 = document.nodeToElementNode.get(foo2); - - Assert.assertFalse(elementFoo1.isSameNodeInfo(elementFoo2)); - Assert.assertFalse(elementFoo2.isSameNodeInfo(elementFoo1)); - Assert.assertTrue(elementFoo1.compareOrder(elementFoo2) < 0); - Assert.assertTrue(elementFoo2.compareOrder(elementFoo1) > 0); - - Assert.assertEquals(0, elementFoo1.compareOrder(elementFoo1)); - } - - @Test - public void testCompareOrderSamePosition() { - DummyNode node = new DummyNode(false, "dummy"); - DummyNode foo1 = new DummyNode(false, "foo"); - foo1.setCoords(1, 1, 5, 5); - DummyNode foo2 = new DummyNode(false, "foo"); - foo2.setCoords(1, 1, 5, 5); - node.addChild(foo1, 0); - node.addChild(foo2, 1); - - DocumentNode document = new DocumentNode(node); - ElementNode elementFoo1 = document.nodeToElementNode.get(foo1); - ElementNode elementFoo2 = document.nodeToElementNode.get(foo2); - - Assert.assertFalse(elementFoo1.isSameNodeInfo(elementFoo2)); - Assert.assertFalse(elementFoo2.isSameNodeInfo(elementFoo1)); - Assert.assertTrue(elementFoo1.compareOrder(elementFoo2) < 0); - Assert.assertTrue(elementFoo2.compareOrder(elementFoo1) > 0); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/symboltable/ApplierTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/symboltable/ApplierTest.java index e3dc8558ad..934ab5edb0 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/symboltable/ApplierTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/symboltable/ApplierTest.java @@ -8,14 +8,13 @@ import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import org.junit.Test; -import net.sourceforge.pmd.util.SearchFunction; - public class ApplierTest { - private static class MyFunction implements SearchFunction { + private static class MyFunction implements Predicate { private int numCallbacks = 0; private final int maxCallbacks; @@ -24,7 +23,7 @@ public class ApplierTest { } @Override - public boolean applyTo(Object o) { + public boolean test(Object o) { this.numCallbacks++; return numCallbacks < maxCallbacks; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java index 67cf33e0ac..9235435a0a 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java @@ -63,7 +63,7 @@ public class MultiThreadProcessorTest { processor.processFiles(ruleSetFactory, files, ctx, Collections.singletonList(renderer)); renderer.end(); - final Iterator configErrors = renderer.getReport().configErrors(); + final Iterator configErrors = renderer.getReport().getConfigurationErrors().iterator(); final ConfigurationError error = configErrors.next(); Assert.assertEquals("Dysfunctional rule message not present", diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/MethodPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/MethodPropertyTest.java deleted file mode 100644 index 8e39e7da90..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/MethodPropertyTest.java +++ /dev/null @@ -1,160 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Assume; -import org.junit.Test; - -import net.sourceforge.pmd.properties.modules.MethodPropertyModule; -import net.sourceforge.pmd.util.ClassUtil; - - -/** - * Evaluates the functionality of the MethodProperty descriptor by testing its - * ability to catch creation errors (illegal args), flag invalid methods per the - * allowable packages, and serialize/deserialize groups of methods onto/from a - * string buffer. - * - * We're using methods from java.lang classes for 'normal' constructors and - * applying ones from java.util types as ones we expect to fail. - * - * @author Brian Remedios - */ -public class MethodPropertyTest extends AbstractPackagedPropertyDescriptorTester { - - private static final Method[] ALL_METHODS; - - private static final String[] METHOD_SIGNATURES = {"String#indexOf(int)", "String#substring(int,int)", - "java.lang.String#substring(int,int)", "Integer#parseInt(String)", "java.util.HashMap#put(Object,Object)", - "HashMap#containsKey(Object)", }; - - static { - List allMethods = new ArrayList<>(); - for (Method m : String.class.getDeclaredMethods()) { - // exclude String.resolveConstantDesc to avoid random test failure with java12 - // there are two methods with the same signature available, but different return types... - if (!m.getName().equals("resolveConstantDesc")) { - allMethods.add(m); - } - } - ALL_METHODS = allMethods.toArray(new Method[0]); - } - - public MethodPropertyTest() { - super("Method"); - } - - - @Override - @Test - public void testMissingPackageNames() { - Map attributes = getPropertyDescriptorValues(); - attributes.remove(PropertyDescriptorField.LEGAL_PACKAGES); - new MethodProperty("p", "d", ALL_METHODS[1], null, 1.0f); // no exception, null is ok - new MethodMultiProperty("p", "d", new Method[]{ALL_METHODS[2], ALL_METHODS[3]}, null, 1.0f); // no exception, null is ok - } - - - @Test - public void testAsStringOn() { - - Method method; - - for (String methodSignature : METHOD_SIGNATURES) { - method = ValueParserConstants.METHOD_PARSER.valueOf(methodSignature); - assertNotNull("Unable to identify method: " + methodSignature, method); - } - } - - - @Test - public void testAsMethodOn() { - - Method[] methods = new Method[METHOD_SIGNATURES.length]; - - for (int i = 0; i < METHOD_SIGNATURES.length; i++) { - methods[i] = ValueParserConstants.METHOD_PARSER.valueOf(METHOD_SIGNATURES[i]); - assertNotNull("Unable to identify method: " + METHOD_SIGNATURES[i], methods[i]); - } - - String translatedMethod; - for (int i = 0; i < methods.length; i++) { - translatedMethod = MethodPropertyModule.asString(methods[i]); - assertTrue("Translated method does not match", ClassUtil.withoutPackageName(METHOD_SIGNATURES[i]) - .equals(ClassUtil.withoutPackageName(translatedMethod))); - } - } - - - @Override - protected Method createValue() { - return randomChoice(ALL_METHODS); - } - - - @Override - protected Method createBadValue() { - return randomChoice(HashMap.class.getDeclaredMethods()); - } - - - @Override - protected PropertyDescriptor createProperty() { - return new MethodProperty("methodProperty", "asdf", ALL_METHODS[1], new String[]{"java.lang", "org.apache"}, - 1.0f); - } - - - @Override - protected PropertyDescriptor> createMultiProperty() { - return new MethodMultiProperty("methodProperty", "asdf", new Method[]{ALL_METHODS[2], ALL_METHODS[3]}, - new String[]{"java.lang"}, 1.0f); - } - - - @Override - protected PropertyDescriptor createBadProperty() { - return new MethodProperty("methodProperty", "asdf", ALL_METHODS[1], new String[]{"java.util"}, 1.0f); - - } - - - @Override - protected PropertyDescriptor> createBadMultiProperty() { - return new MethodMultiProperty("methodProperty", "asdf", new Method[]{ALL_METHODS[2], ALL_METHODS[3]}, - new String[]{"java.util"}, 1.0f); - } - - - @Override - @Test - public void testFactorySingleValue() { - Assume.assumeTrue("MethodProperty cannot be built from XPath (#762)", false); - } - - - @Override - @Test - public void testFactoryMultiValueCustomDelimiter() { - Assume.assumeTrue("MethodProperty cannot be built from XPath (#762)", false); - } - - - @Override - @Test - public void testFactoryMultiValueDefaultDelimiter() { - Assume.assumeTrue("MethodProperty cannot be built from XPath (#762)", false); - } - -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/TypePropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/TypePropertyTest.java deleted file mode 100644 index bb82bbea48..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/TypePropertyTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.properties; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Observer; -import java.util.Set; - -/** - * Evaluates the functionality of the TypeProperty descriptor by testing its - * ability to catch creation errors (illegal args), flag invalid Type values per - * the allowable packages, and serialize/deserialize groups of types onto/from a - * string buffer. - * - * We're using java.lang classes for 'normal' constructors and applying - * java.util types as ones we expect to fail. - * - * @author Brian Remedios - */ -public class TypePropertyTest extends AbstractPackagedPropertyDescriptorTester { - - private static final List JAVA_LANG_CLASSES = Arrays.asList(String.class, Integer.class, Thread.class, - Object.class, Runtime.class); - private static final List JAVA_UTIL_CLASSES = Arrays.asList(HashMap.class, Map.class, - Comparator.class, Set.class, - Observer.class); - - - public TypePropertyTest() { - super("Class"); - } - - - @Override - protected Class createBadValue() { - return JAVA_UTIL_CLASSES.get(randomInt(0, JAVA_UTIL_CLASSES.size())); - } - - - @Override - protected PropertyDescriptor createProperty() { - return new TypeProperty("testType", "Test type property", createValue(), new String[] {"java.lang"}, - 1.0f); - } - - - @Override - protected Class createValue() { - return JAVA_LANG_CLASSES.get(randomInt(0, JAVA_LANG_CLASSES.size())); - } - - - @Override - protected PropertyDescriptor> createMultiProperty() { - return new TypeMultiProperty("testType", "Test type property", JAVA_LANG_CLASSES, new String[] {"java.lang"}, - 1.0f); - } - - - @Override - protected PropertyDescriptor createBadProperty() { - return new TypeProperty("testType", "Test type property", createValue(), new String[] {"java.util"}, - 1.0f); - } - - - @Override - protected PropertyDescriptor> createBadMultiProperty() { - return new TypeMultiProperty("testType", "Test type property", Collections.singletonList(Set.class), - new String[] {"java.lang"}, 1.0f); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java index 9ede80cac5..ddf3c83589 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java @@ -18,6 +18,7 @@ import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; import net.sourceforge.pmd.lang.rule.XPathRule; +import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; public class CodeClimateRendererTest extends AbstractRendererTest { @@ -94,8 +95,7 @@ public class CodeClimateRendererTest extends AbstractRendererTest { RuleContext ctx = new RuleContext(); ctx.setSourceCodeFile(new File(getSourceCodeFilename())); Report report = new Report(); - XPathRule theRule = new XPathRule(); - theRule.setProperty(XPathRule.XPATH_DESCRIPTOR, "//dummyNode"); + XPathRule theRule = new XPathRule(XPathVersion.XPATH_3_1, "//dummyNode"); // Setup as FooRule theRule.setDescription("desc"); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/PapariTextRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/PapariTextRendererTest.java index 43d9651595..7047e79d46 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/PapariTextRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/PapariTextRendererTest.java @@ -30,7 +30,7 @@ public class PapariTextRendererTest extends AbstractRendererTest { public String getExpected() { return "* file: " + getSourceCodeFilename() + PMD.EOL + " src: " + getSourceCodeFilename() + ":1:1" + PMD.EOL + " rule: Foo" + PMD.EOL + " msg: blah" + PMD.EOL + " code: public class Foo {}" + PMD.EOL + PMD.EOL + PMD.EOL + PMD.EOL - + "Summary:" + PMD.EOL + PMD.EOL + " : 1" + PMD.EOL + "* warnings: 1" + PMD.EOL; + + "Summary:" + PMD.EOL + PMD.EOL + "* warnings: 1" + PMD.EOL; } @Override @@ -44,7 +44,7 @@ public class PapariTextRendererTest extends AbstractRendererTest { + " msg: blah" + PMD.EOL + " code: public class Foo {}" + PMD.EOL + PMD.EOL + " src: " + getSourceCodeFilename() + ":1:1" + PMD.EOL + " rule: Foo" + PMD.EOL + " msg: blah" + PMD.EOL + " code: public class Foo {}" + PMD.EOL + PMD.EOL + PMD.EOL + PMD.EOL + "Summary:" + PMD.EOL - + PMD.EOL + " : 2" + PMD.EOL + "* warnings: 2" + PMD.EOL; + + PMD.EOL + "* warnings: 2" + PMD.EOL; } @Override diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/DateTimeUtilTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/DateTimeUtilTest.java deleted file mode 100644 index 61d66292cb..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/DateTimeUtilTest.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -import static org.junit.Assert.assertEquals; - -import java.util.Collection; - -import org.junit.Test; - -import net.sourceforge.pmd.ReadableDurationTest; - -/** - * - * @author Brian Remedios - */ -public class DateTimeUtilTest { - - @Test - public void testConversions() { - - Collection stringNumberPairs = ReadableDurationTest.data(); - - for (Object[] stringAndNumber : stringNumberPairs) { - String result = (String) stringAndNumber[0]; - Integer milliseconds = (Integer) stringAndNumber[1]; - - assertEquals(result, DateTimeUtil.asHoursMinutesSeconds(milliseconds)); - } - - } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(DateTimeUtilTest.class); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java index 9362373baf..f03e7ce6ca 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java @@ -10,11 +10,6 @@ import org.junit.Test; public class StringUtilTest { - @Test - public void testReplaceWithOneChar() { - assertEquals("faa", StringUtil.replaceString("foo", 'o', "a")); - } - @Test public void testColumnNumber() { assertEquals(-1, StringUtil.columnNumberAt("f\rah\nb", -1)); @@ -52,27 +47,6 @@ public class StringUtilTest { assertEquals(-1, StringUtil.columnNumberAt("", 1)); } - @Test - public void testReplaceWithMultipleChars() { - assertEquals("faaaa", StringUtil.replaceString("foo", 'o', "aa")); - } - - @Test - public void testReplaceStringWithString() { - assertEquals("foo]]>bar", StringUtil.replaceString("foo]]>bar", "]]>", "]]>")); - } - - @Test - public void testReplaceStringWithString2() { - assertEquals("replaceString didn't work with a >", "foobar", - StringUtil.replaceString("foobar", "]]>", "]]>")); - } - - @Test - public void testReplaceWithNull() { - assertEquals("replaceString didn't work with a char", "f", StringUtil.replaceString("foo", 'o', null)); - } - @Test public void testUTF8NotSupported() { StringBuilder sb = new StringBuilder(); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/TypeMapTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/TypeMapTest.java deleted file mode 100644 index 08d277ee73..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/TypeMapTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.util; - -import static org.junit.Assert.fail; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Assert; -import org.junit.Test; - -/** - * Evaluates all major functionality of the TypeMap class. - * - * @author Brian Remedios - */ -public class TypeMapTest { - - @Test - public void testAddClassOfQ() { - - TypeMap map = new TypeMap(2); - map.add(List.class); - - try { - map.add(java.awt.List.class); - } catch (IllegalArgumentException ex) { - return; // caught ok - } - - fail("Uncaught error inserting type with same root names"); - } - - @Test - public void testContainsClassOfQ() { - - TypeMap map = new TypeMap(2); - map.add(String.class); - map.add(List.class); - - Assert.assertTrue(map.contains(String.class)); - Assert.assertTrue(map.contains(List.class)); - Assert.assertFalse(map.contains(Map.class)); - } - - @Test - public void testContainsString() { - - TypeMap map = new TypeMap(2); - map.add(String.class); - map.add(List.class); - - Assert.assertTrue(map.contains("String")); - Assert.assertTrue(map.contains("java.lang.String")); - } - - @Test - public void testTypeFor() { - - TypeMap map = new TypeMap(2); - map.add(String.class); - map.add(List.class); - - Assert.assertTrue(map.typeFor("String") == String.class); - Assert.assertTrue(map.typeFor("java.lang.String") == String.class); - Assert.assertTrue(map.typeFor("List") == List.class); - Assert.assertTrue(map.typeFor("java.util.List") == List.class); - } - - @Test - public void testSize() { - - TypeMap map = new TypeMap(4); - map.add(String.class); - map.add(HashMap.class); - map.add(Integer.class); - - Assert.assertTrue(map.size() == 6); - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/treeexport/TreeRenderersTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/treeexport/TreeRenderersTest.java index f2c667d6e3..0d3a3d201a 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/treeexport/TreeRenderersTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/treeexport/TreeRenderersTest.java @@ -19,7 +19,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import net.sourceforge.pmd.lang.ast.DummyNode; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertySource; diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/treeexport/XmlTreeRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/treeexport/XmlTreeRendererTest.java index af6cc024b0..f972c7dcca 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/treeexport/XmlTreeRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/treeexport/XmlTreeRendererTest.java @@ -18,7 +18,7 @@ import org.junit.rules.ExpectedException; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; import net.sourceforge.pmd.util.treeexport.XmlTreeRenderer.XmlRenderingConfig; /** diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 72faaa08dd..847398ce2d 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,4 +1,12 @@ /** + * Remove support for Java 13 preview language features. + * Promote text blocks as a permanent language features with Java 15. + * Support Pattern Matching for instanceof with Java 15 Preview. + * Support Records with Java 15 Preview. + * Support Local Records with Java 15 Preview. + * Support Sealed Classes with Java 15 Preview. + * Andreas Dangel 08/2020 + *==================================================================== * Add support for record types introduced as a preview language * feature with Java 14. See JEP 359. * Andreas Dangel 02/2020 @@ -227,6 +235,7 @@ PARSER_BEGIN(JavaParserImpl) package net.sourceforge.pmd.lang.java.ast; import java.util.ArrayList; import java.util.Collections; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Set; @@ -234,6 +243,7 @@ import java.util.Map; import net.sourceforge.pmd.lang.ast.CharStream; import net.sourceforge.pmd.lang.ast.GenericToken; import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; +import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.TokenMgrError; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.types.JPrimitiveType.PrimitiveTypeKind; @@ -261,6 +271,20 @@ class JavaParserImpl { throw new ParseException("Line " + line + ", Column " + col + ": " + message); } + + private boolean isRecordTypeSupported() { + return (jdkVersion == 14 || jdkVersion == 15) && preview; + } + + private boolean localTypesSupported() { + return isRecordTypeSupported(); + } + + private boolean isSealedClassSupported() { + return jdkVersion == 15 && preview; + } + + /** * Keeps track during tree construction, whether we are currently building a switch label. * A switch label must not contain a LambdaExpression. @@ -275,7 +299,7 @@ class JavaParserImpl { // This is a semantic LOOKAHEAD to determine if we're dealing with an assert // Note that this can't be replaced with a syntactic lookahead // since "assert" isn't a string literal token - private boolean isNextTokenAnAssert() { + private boolean isAssertStart() { if (jdkVersion <= 3) { return false; } @@ -283,12 +307,85 @@ class JavaParserImpl { return getToken(1).getImage().equals("assert"); } + private boolean isRecordStart() { + return isRecordTypeSupported() && isKeyword("record"); + } + + private boolean isEnumStart() { + return jdkVersion >= 5 && isKeyword("enum"); + } + /** * Semantic lookahead to check if the next identifier is a * specific restricted keyword. + * + *

Restricted keywords are: + * var, yield, record, sealed, permits, "non" + "-" + "sealed" + * + *

enum and assert is used like restricted keywords, as they were not keywords + * in the early java versions. */ - private boolean isKeyword(String keyword) { - return getToken(1).kind == IDENTIFIER && getToken(1).getImage().equals(keyword); + private boolean isKeyword(String image) { + return isKeyword(1, image); + } + + private boolean isKeyword(int index, String image) { + Token token = getToken(index); + return token.kind == IDENTIFIER && token.image.equals(image); + } + + private boolean isToken(int index, int kind) { + return getToken(index).kind == kind; + } + + /** + * Semantic lookahead which matches "non-sealed". + * + *

"non-sealed" cannot be a token, for several reasons: + * It is only a keyword with java15 preview+, it consists actually + * of several separate tokens, which are valid on their own. + */ + private boolean isNonSealedModifier() { + if (isKeyword(1, "non") && isToken(2, MINUS) && isKeyword(3, "sealed")) { + JavaccToken nonToken = getToken(1); + JavaccToken minusToken = getToken(2); + JavaccToken sealedToken = getToken(3); + return nonToken.getEndColumn() == minusToken.getBeginColumn() + && minusToken.getEndColumn() == sealedToken.getBeginColumn(); + } + return false; + } + + private boolean classModifierLookahead() { + Token next = getToken(1); + return next.kind == AT + || next.kind == PUBLIC + || next.kind == PROTECTED + || next.kind == PRIVATE + || next.kind == ABSTRACT + || next.kind == STATIC + || next.kind == FINAL + || next.kind == STRICTFP + || isSealedClassSupported() && isKeyword("sealed") + || isSealedClassSupported() && isNonSealedModifier(); + } + + private boolean localTypeDeclAfterModifiers() { + Token next = getToken(1); + return next.kind == CLASS + || localTypesSupported() && ( + next.kind == INTERFACE + || next.kind == AT && isToken(2, INTERFACE) + || next.kind == IDENTIFIER && next.getImage().equals("enum") + || + next.kind == IDENTIFIER && next.image.equals("record") + ); + } + + private boolean localTypeDeclGivenNextIsIdent() { + return localTypesSupported() && ( + isNonSealedModifier() || isRecordStart() || isEnumStart() + ); } /** @@ -361,6 +458,11 @@ class JavaParserImpl { node.setImage(getToken(0).getImage()); } + private void fixLastToken() { + AbstractJavaNode top = (AbstractJavaNode) jjtree.peekNode(); + top.setLastToken(getToken(0)); + } + private void forceExprContext() { AbstractJavaNode top = jjtree.peekNode(); @@ -876,6 +978,8 @@ void ModifierList(): | "volatile" { modifiers.add(JModifier.VOLATILE); } | "strictfp" { modifiers.add(JModifier.STRICTFP); } | "default" { modifiers.add(JModifier.DEFAULT); } + | LOOKAHEAD({isKeyword("sealed")}) { modifiers.add(JModifier.SEALED); } + | LOOKAHEAD({isNonSealedModifier()}) { modifiers.add(JModifier.NON_SEALED); } | Annotation() ) )* @@ -907,6 +1011,7 @@ void ClassOrInterfaceDeclaration(): [ TypeParameters() ] [ ExtendsList() ] [ ImplementsList() ] + [ LOOKAHEAD({isKeyword("permits")}) PermittedSubclasses() ] ClassOrInterfaceBody() } @@ -924,6 +1029,20 @@ void ImplementsList(): ( "," AnnotatedClassOrInterfaceType() )* } +void PermittedSubclasses() #PermitsList: +{ + Token t; +} +{ + t = { + if (!"permits".equals(t.image)) { + throw new ParseException("ERROR: expecting permits"); + } + } + (TypeAnnotation())* ClassOrInterfaceType() + ( "," (TypeAnnotation())* ClassOrInterfaceType() )* +} + void EnumDeclaration(): { JavaccToken t; @@ -1442,10 +1561,11 @@ void PrimitiveType() : } -void ResultType() : +void ResultType() #void: {} { - "void" | AnnotatedType() + "void" #VoidType + | AnnotatedType() } @@ -1733,7 +1853,7 @@ void PrimaryPrefix() #void : | "super" #SuperExpression(true) ("." MemberSelector() | MethodReference()) | UnqualifiedAllocationExpr() -| ("void" "." "class") #ClassLiteral +| ("void" #VoidType "." "class") #ClassLiteral | LOOKAHEAD(1) // suppress the warning here. (PrimitiveType() [ Dims() ] ) #ArrayType(>1) ( @@ -2033,8 +2153,20 @@ void ArrayDimExpr() #void: void Statement() #void: {} { - Block() + StatementNoIdent() +// testing the hard cases last optimises the code gen +// all the previous cases are trivial for the parser +// because they start with a different token | LOOKAHEAD( { isYieldStart() } ) YieldStatement() +| LOOKAHEAD( { isAssertStart() } ) AssertStatement() +| LOOKAHEAD(2) LabeledStatement() +| ( StatementExpression() ";" ) #ExpressionStatement +} + +void StatementNoIdent() #void: +{} +{ + Block() | EmptyStatement() | SwitchStatement() | IfStatement() @@ -2047,12 +2179,6 @@ void Statement() #void: | ThrowStatement() | SynchronizedStatement() | TryStatement() -// testing the hard cases last optimises the code gen -// all the previous cases are trivial for the parser -// because they start with a different token -| LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement() -| LOOKAHEAD(2) LabeledStatement() -| ( StatementExpression() ";" ) #ExpressionStatement } void LabeledStatement() : @@ -2068,40 +2194,60 @@ void Block() : } void BlockStatement() #void: -{} +{} // Note: this has been written this way to minimize lookaheads + // This generates a table switch with very few lookaheads { - LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement() -| LOOKAHEAD( { isYieldStart() } ) YieldStatement() -| - LOOKAHEAD(( "final" | Annotation() )* Type() ) - LocalVariableDeclaration() ";" { - // make it so that the LocalVariableDeclaration's last token is the semicolon - AbstractJavaNode top = (AbstractJavaNode) jjtree.peekNode(); - top.setLastToken(getToken(0)); - } {} -| - // we need to lookahead until the "class" token, - // because a method ref may be annotated - // -> so Expression, and hence Statement, may start with "@" - LOOKAHEAD(ModifierList() "class") LocalClassDecl() -| - Statement() + LOOKAHEAD(1, "@" | "final" ) + // this eagerly parses all modifiers and annotations. After that, either a local type declaration + // or a local variable declaration follows. + // This allows more modifiers for local variables than actually allowed + + // The ModifierList is adopted by the next class to open + ModifierList() ( + LOOKAHEAD({localTypeDeclAfterModifiers()}) LocalTypeDecl() + | LOOKAHEAD({true}) LocalVariableDeclaration() ";" { fixLastToken(); } + ) +| LOOKAHEAD(1, ) + ( + LOOKAHEAD({ localTypeDeclGivenNextIsIdent() }) ModifierList() LocalTypeDecl() + | LOOKAHEAD({ isAssertStart() }) AssertStatement() + | LOOKAHEAD({ isYieldStart() }) YieldStatement() + | LOOKAHEAD({ getToken(2).kind == COLON }) LabeledStatement() + | LOOKAHEAD(ReferenceType() ) LocalVariableDeclaration() ";" { fixLastToken(); } + | LOOKAHEAD({true}) ExpressionStatement() + ) +| LOOKAHEAD(1, LocalTypeStartNoIdent()) ModifierList() LocalTypeDecl() +| LOOKAHEAD(1) StatementNoIdent() +| LOOKAHEAD(Type() ) LocalVariableDeclaration() ";" { fixLastToken(); } +| LOOKAHEAD({true}) ExpressionStatement() } -void LocalClassDecl() #LocalClassStatement: +private void LocalTypeStartNoIdent() #void: // A lookahead {} -{ - // this preserves the modifiers of the local class. - // it allows for modifiers that are forbidden for local classes, - // but anyway we are *not* checking modifiers for incompatibilities - // anywhere else in this grammar (and indeed the production Modifiers - // accepts any modifier explicitly for the purpose of forgiving modifier errors, - // and reporting them later if needed --see its documentation). +{ // notice: not default + "public" | "static" | "protected" | "private" | "final" + | "abstract" | "synchronized" | "native" | "transient" + | "volatile" | "strictfp" - // In particular, it unfortunately allows local class declarations to start - // with a "default" modifier, which introduces an ambiguity with default - // switch labels. This is guarded by a custom lookahead around SwitchLabel - ModifierList() ClassOrInterfaceDeclaration() + | "class" | "interface" +} + +void LocalTypeDecl() #void: +{} // At the point this is called, a ModifierList is on the top of the stack, +{ // waiting for the next node to open. We want that node to be the type declaration, + // not the wrapper statement node. + ( ClassOrInterfaceDeclaration() + | AnnotationTypeDeclaration() + | LOOKAHEAD({isKeyword("record")}) RecordDeclaration() + | LOOKAHEAD({isKeyword("enum")}) EnumDeclaration() + ) { + // Wrap the type decl into a statement + // This can't be done with regular jjtree constructs, as the ModifierList + // is adopted by the first node to be opened. + ASTAnyTypeDeclaration type = (ASTAnyTypeDeclaration) jjtree.popNode(); + ASTLocalClassStatement stmt = new ASTLocalClassStatement(type); + jjtree.pushNode(stmt); + } } /* @@ -2142,6 +2288,12 @@ void EmptyDeclaration() : ";" } +void ExpressionStatement(): +{} +{ + StatementExpression() ";" +} + void StatementExpression() #void: {AssignmentOp op = null;} { @@ -2169,12 +2321,6 @@ void SwitchBlock() #void: "}" } -void SwitchArrowLahead() #void: -{} -{ - SwitchLabel() "->" -} - void SwitchArrowBranch(): {} { @@ -2482,7 +2628,7 @@ void AnnotationTypeMemberDeclaration() #void: void AnnotationMethodDeclaration() #MethodDeclaration: {} { - Type() #ResultType + Type() { setLastTokenImage(jjtThis); } ("(" ")") #FormalParameters [ Dims() ] @@ -2572,3 +2718,4 @@ void VariableAccess(): {} { } // those are created manually void TypeExpression(): {} { } void PatternExpression(): {} { } +void LocalClassStatement(): {} { TypeDeclaration() } diff --git a/pmd-java/pom.xml b/pmd-java/pom.xml index 5959f738af..86d5c7c168 100644 --- a/pmd-java/pom.xml +++ b/pmd-java/pom.xml @@ -133,10 +133,6 @@ net.sourceforge.pmd pmd-core - - net.sourceforge.saxon - saxon - org.ow2.asm asm @@ -149,6 +145,19 @@ org.apache.commons commons-lang3 + + org.checkerframework + checker-qual + + + net.sf.saxon + Saxon-HE + + + org.pcollections + pcollections + + diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java index 1da8afecd5..8bab973c6b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java @@ -28,9 +28,10 @@ public class JavaLanguageModule extends BaseLanguageModule { addVersion("11", new JavaLanguageHandler(11)); addVersion("12", new JavaLanguageHandler(12)); addVersion("13", new JavaLanguageHandler(13)); - addVersion("13-preview", new JavaLanguageHandler(13, true)); - addDefaultVersion("14", new JavaLanguageHandler(14)); // 14 is the default + addVersion("14", new JavaLanguageHandler(14)); addVersion("14-preview", new JavaLanguageHandler(14, true)); + addDefaultVersion("15", new JavaLanguageHandler(15)); // 15 is the default + addVersion("15-preview", new JavaLanguageHandler(15, true)); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java index 2084709fd7..197a63ec92 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.lang.java.ast; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; +import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute; /** * Represents an addition operation on two or more values, or string concatenation. @@ -45,7 +45,7 @@ public final class ASTAdditiveExpression extends AbstractJavaExpr { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } /** diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java index 81edbcd7ce..e7c94470cc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java @@ -17,7 +17,7 @@ public class ASTAllocationExpression extends AbstractJavaTypeNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAndExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAndExpression.java index c5fd1770aa..e97f8aa7a3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAndExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAndExpression.java @@ -31,6 +31,6 @@ public final class ASTAndExpression extends AbstractJavaExpr implements ASTExpre @Override public R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java index 562f4d07c0..c84e9201f8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java @@ -19,7 +19,7 @@ public final class ASTAnnotationMethodDeclaration extends AbstractJavaNode imple @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java index 218d06a216..3b6e21c03f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java @@ -12,9 +12,9 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.ast.NodeStream; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; import net.sourceforge.pmd.lang.java.symbols.JClassSymbol; import net.sourceforge.pmd.lang.java.types.JClassType; +import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute; /** @@ -230,6 +230,16 @@ public interface ASTAnyTypeDeclaration return false; } + /** + * Returns true if this is a regular class declaration (not an enum, + * not a record, not an interface or annotation). Note that eg + * {@link JClassSymbol#isClass()} counts records and enums in, just + * like {@link #isInterface()} counts annotations in. + */ + default boolean isRegularClass() { + return false; + } + /** Returns true if this is an {@linkplain ASTAnnotationTypeDeclaration annotation type declaration}. */ default boolean isAnnotation() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArguments.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArguments.java index ec247e2a9b..b6ec7e2648 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArguments.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArguments.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.lang.java.ast; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; +import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute; /** * @deprecated Replaced by {@link ASTArgumentList} @@ -39,6 +39,6 @@ public class ASTArguments extends AbstractJavaNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } 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 33f97d0d2b..541f793dbe 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 @@ -19,7 +19,7 @@ public class ASTArrayDimsAndInits extends AbstractJavaNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssignmentOperator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssignmentOperator.java index b35250221a..55680278cf 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssignmentOperator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssignmentOperator.java @@ -31,6 +31,6 @@ public class ASTAssignmentOperator extends AbstractJavaNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java index c22c53960a..479d5139e8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java @@ -19,7 +19,7 @@ public final class ASTBlockStatement extends AbstractJavaNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassLiteral.java index f7fa6c21f3..2dfba4cb91 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassLiteral.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.lang.java.ast; -import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.NonNull; /** * A class literal. Class literals are {@linkplain ASTPrimaryExpression primary expressions}, @@ -12,7 +12,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; * *

  *
- * ClassLiteral ::= ({@link ASTType Type} | "void") "." "class"
+ * ClassLiteral ::= {@link ASTType Type} "." "class"
  *
  * 
*/ @@ -26,17 +26,10 @@ public final class ASTClassLiteral extends AbstractJavaExpr implements ASTPrimar return visitor.visit(this, data); } - - public boolean isVoid() { - return getNumChildren() == 0; - } - - /** - * Returns the enclosed type node, or an empty optional if this is void. + * Returns the type node (this may be a {@link ASTVoidType}). */ - @Nullable - public ASTType getTypeNode() { - return isVoid() ? null : (ASTType) getChild(0); + public @NonNull ASTType getTypeNode() { + return (ASTType) getChild(0); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBodyDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBodyDeclaration.java index 8fdfc0c50e..98e4f8ee76 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBodyDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBodyDeclaration.java @@ -12,7 +12,7 @@ public final class ASTClassOrInterfaceBodyDeclaration extends AbstractTypeBodyDe @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java index c69197d8d1..d022f757ef 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java @@ -4,6 +4,9 @@ package net.sourceforge.pmd.lang.java.ast; +import java.util.List; + +import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.lang.ast.Node; @@ -46,6 +49,11 @@ public final class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclara return this.isInterface; } + @Override + public boolean isRegularClass() { + return !isInterface; + } + void setInterface() { this.isInterface = true; } @@ -67,4 +75,10 @@ public final class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclara return extendsList == null ? null : extendsList.iterator().next(); } + + @Experimental + public List getPermittedSubclasses() { + return ASTList.orEmpty(children(ASTPermitsList.class).first()); + } + } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalAndExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalAndExpression.java index a00379c99d..07a5705fd2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalAndExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalAndExpression.java @@ -29,6 +29,6 @@ public final class ASTConditionalAndExpression extends AbstractJavaExpr implemen @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalOrExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalOrExpression.java index 5f900c97c6..abca28f60e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalOrExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalOrExpression.java @@ -29,6 +29,6 @@ public final class ASTConditionalOrExpression extends AbstractJavaExpr implement @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEqualityExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEqualityExpression.java index 3dbd643118..436ce31fc3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEqualityExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEqualityExpression.java @@ -41,7 +41,7 @@ public final class ASTEqualityExpression extends AbstractJavaExpr implements AST @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExclusiveOrExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExclusiveOrExpression.java index d2b0524cdb..f29dffe782 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExclusiveOrExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExclusiveOrExpression.java @@ -30,6 +30,6 @@ public final class ASTExclusiveOrExpression extends AbstractJavaExpr implements @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } 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 b7fb2682ad..4da2b38c2f 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 @@ -5,8 +5,8 @@ package net.sourceforge.pmd.lang.java.ast; import net.sourceforge.pmd.lang.ast.SignedNode; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; import net.sourceforge.pmd.lang.java.multifile.signature.JavaFieldSignature; +import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute; /** diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInclusiveOrExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInclusiveOrExpression.java index 0400b7bfd8..1203ae469e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInclusiveOrExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInclusiveOrExpression.java @@ -31,6 +31,6 @@ public final class ASTInclusiveOrExpression extends AbstractJavaExpr implements @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java index 5856f807b3..17320f5f4e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java @@ -29,7 +29,7 @@ public class ASTInstanceOfExpression extends AbstractJavaExpr implements ASTExpr @Override public R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } 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 71ba58d3a1..ee21bb1167 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 @@ -27,7 +27,6 @@ public interface ASTLiteral extends ASTPrimaryExpression { return this instanceof ASTStringLiteral; } - /** * Returns true if this is a {@linkplain ASTCharLiteral character literal}. */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java index d3e2fe42b8..1aa1f6c7f0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalClassStatement.java @@ -12,7 +12,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; * *
  *
- * LocalClassStatement ::= {@link ASTClassOrInterfaceDeclaration ClassDeclaration}
+ * LocalClassStatement ::= {@link ASTAnyTypeDeclaration TypeDeclaration}
  *
  * 
*/ @@ -22,6 +22,14 @@ public final class ASTLocalClassStatement extends AbstractStatement { super(id); } + ASTLocalClassStatement(ASTAnyTypeDeclaration tdecl) { + super(JavaParserImplTreeConstants.JJTLOCALCLASSSTATEMENT); + assert tdecl != null; + addChild((AbstractJavaNode) tdecl, 0); + setFirstToken(tdecl.getFirstToken()); + setLastToken(tdecl.getLastToken()); + } + @Override protected R acceptVisitor(JavaVisitor visitor, P data) { return visitor.visit(this, data); @@ -31,8 +39,7 @@ public final class ASTLocalClassStatement extends AbstractStatement { /** * Returns the contained declaration. */ - @NonNull - public ASTClassOrInterfaceDeclaration getDeclaration() { - return (ASTClassOrInterfaceDeclaration) getChild(0); + public @NonNull ASTAnyTypeDeclaration getDeclaration() { + return (ASTAnyTypeDeclaration) getChild(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 29f84e2d17..39274f18c7 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 @@ -24,6 +24,7 @@ public final class ASTLocalVariableDeclaration extends AbstractJavaNode implements Iterable, ASTStatement, FinalizableNode, + LeftRecursiveNode, // ModifierList is parsed separately in BlockStatement InternalInterfaces.MultiVariableIdOwner { ASTLocalVariableDeclaration(int id) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberSelector.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberSelector.java index 5157a78488..ef98adcf74 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberSelector.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberSelector.java @@ -15,6 +15,6 @@ public class ASTMemberSelector extends AbstractJavaNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java index 0600294ff0..79f207d9ff 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java @@ -4,10 +4,11 @@ package net.sourceforge.pmd.lang.java.ast; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol; +import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute; /** @@ -27,7 +28,7 @@ import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol; * * MethodDeclaration ::= {@link ASTModifierList ModifierList} * {@link ASTTypeParameters TypeParameters}? - * {@link ASTResultType ResultType} + * {@link ASTType Type} * <IDENTIFIER> * {@link ASTFormalParameters FormalParameters} * {@link ASTArrayDimensions ArrayDimensions}? @@ -87,11 +88,9 @@ public final class ASTMethodDeclaration extends AbstractMethodOrConstructorDecla /** * Returns true if the result type of this method is {@code void}. - * - * TODO remove, just as simple to write getResultType().isVoid() */ public boolean isVoid() { - return getResultType().isVoid(); + return getResultTypeNode().isVoid(); } @@ -106,11 +105,21 @@ public final class ASTMethodDeclaration extends AbstractMethodOrConstructorDecla /** * Returns the result type node of the method. + * + * @deprecated todo When removed from java-grammar, rename the other to this good name */ + @Deprecated public ASTResultType getResultType() { return getFirstChildOfType(ASTResultType.class); } + /** + * Returns the result type node of the method. This may be a {@link ASTVoidType}. + */ + public @NonNull ASTType getResultTypeNode() { + return getFirstChildOfType(ASTType.class); + } + /** * Returns the extra array dimensions that may be after the * formal parameters. diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarator.java index f617bf07fb..649c2699cb 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarator.java @@ -4,7 +4,7 @@ package net.sourceforge.pmd.lang.java.ast; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; +import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute; /** * Child of an {@link ASTMethodDeclaration}. @@ -56,6 +56,6 @@ public final class ASTMethodDeclarator extends AbstractJavaNode { @Override public R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModifierList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModifierList.java index 8645a3108d..4ee7a4cb68 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModifierList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModifierList.java @@ -104,8 +104,8 @@ public final class ASTModifierList extends AbstractJavaNode { } /** Returns the node owning this modifier list. */ - public AccessNode getOwner() { - return (AccessNode) getParent(); // TODO + public Annotatable getOwner() { + return (Annotatable) getParent(); // TODO } /** @@ -167,9 +167,10 @@ public final class ASTModifierList extends AbstractJavaNode { private static final EffectiveModifierVisitor INSTANCE = new EffectiveModifierVisitor(); // TODO strictfp modifier is also implicitly given to descendants + // TODO final modifier is implicitly given to direct subclasses of sealed interface/class @Override - public Void visit(ASTAnyTypeDeclaration node, Set effective) { + public Void visitTypeDecl(ASTAnyTypeDeclaration node, Set effective) { ASTAnyTypeDeclaration enclosing = node.getEnclosingType(); if (enclosing != null && enclosing.isInterface()) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMultiplicativeExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMultiplicativeExpression.java index 4fbccce6a3..8a298afaac 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMultiplicativeExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMultiplicativeExpression.java @@ -42,7 +42,7 @@ public final class ASTMultiplicativeExpression extends AbstractJavaExpr { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNameList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNameList.java index 421a9dcf02..1493114eb5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNameList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNameList.java @@ -17,6 +17,6 @@ public final class ASTNameList extends AbstractJavaNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java index 7df29d5c58..707be4e0cd 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java @@ -8,7 +8,7 @@ import net.sourceforge.pmd.annotation.Experimental; /** * A pattern (for pattern matching constructs like {@link ASTInstanceOfExpression InstanceOfExpression}). - * This is a JDK 14 preview feature and is subject to change. + * This is a JDK 14 and JDK 15 preview feature and is subject to change. * *

This interface will be implemented by all forms of patterns. For * now, only type test patterns are supported. Record deconstruction diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPermitsList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPermitsList.java new file mode 100644 index 0000000000..75a4e18e9e --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPermitsList.java @@ -0,0 +1,35 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +import net.sourceforge.pmd.annotation.Experimental; +import net.sourceforge.pmd.lang.java.ast.ASTList.ASTNonEmptyList; + + +/** + * Represents the {@code permits} clause of a (sealed) class declaration. + * + *

This is a Java 15 Preview feature. + * + *

See https://openjdk.java.net/jeps/360 + * + *

+ *
+ *  PermittedSubclasses ::= "permits" (TypeAnnotation)* ClassOrInterfaceType
+ *                ( "," (TypeAnnotation)* ClassOrInterfaceType )*
+ * 
+ */ +@Experimental +public final class ASTPermitsList extends ASTNonEmptyList { + + ASTPermitsList(int id) { + super(id, ASTClassOrInterfaceType.class); + } + + @Override + protected R acceptVisitor(JavaVisitor visitor, P data) { + return visitor.visit(this, data); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryPrefix.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryPrefix.java index a05e363c6a..29fdba5455 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryPrefix.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryPrefix.java @@ -26,6 +26,6 @@ public class ASTPrimaryPrefix extends AbstractJavaTypeNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimarySuffix.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimarySuffix.java index ca9bf43444..029ac7c30e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimarySuffix.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimarySuffix.java @@ -41,6 +41,6 @@ public class ASTPrimarySuffix extends AbstractJavaTypeNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRSIGNEDSHIFT.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRSIGNEDSHIFT.java index fba7c4b056..391e4cd2dc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRSIGNEDSHIFT.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRSIGNEDSHIFT.java @@ -17,6 +17,6 @@ public final class ASTRSIGNEDSHIFT extends AbstractJavaNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRUNSIGNEDSHIFT.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRUNSIGNEDSHIFT.java index d8525556c0..332f043188 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRUNSIGNEDSHIFT.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRUNSIGNEDSHIFT.java @@ -17,6 +17,6 @@ public final class ASTRUNSIGNEDSHIFT extends AbstractJavaNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java index e34163411f..63b2da1d0f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java @@ -8,7 +8,7 @@ package net.sourceforge.pmd.lang.java.ast; import net.sourceforge.pmd.annotation.Experimental; /** - * Defines the body of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature). + * Defines the body of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature). * This can contain additional methods and or constructors. * *
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java
index a296ecb8ef..59f60996b5 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java
@@ -11,7 +11,7 @@ import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
 import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
 
 /**
- * Defines a single component of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature).
+ * Defines a single component of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature).
  *
  * 

The varargs ellipsis {@code "..."} is parsed as an {@linkplain ASTArrayTypeDim array dimension} * in the type node. diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java index 82cf139908..06b0ed909d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java @@ -11,7 +11,7 @@ import net.sourceforge.pmd.lang.java.ast.InternalInterfaces.AllChildrenAreOfType import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol; /** - * Defines the state description of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature). + * Defines the state description of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 and JDK 15 preview feature). * *

  *
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordConstructorDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordConstructorDeclaration.java
index 3bffa597f2..d8039119ea 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordConstructorDeclaration.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordConstructorDeclaration.java
@@ -10,7 +10,7 @@ import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
 
 /**
  * This defines a compact constructor for a {@link ASTRecordDeclaration RecordDeclaration}
- * (JDK 14 preview feature). Compact constructors implicitly declares formal
+ * (JDK 14 and JDK 15 preview feature). Compact constructors implicitly declares formal
  * parameters corresponding to the record component list. These can be
  * fetched from {@link #getSymbol()}.
  *
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java
index 71c421b23b..66f2eb700d 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java
@@ -12,7 +12,7 @@ import net.sourceforge.pmd.lang.ast.Node;
 import net.sourceforge.pmd.lang.ast.NodeStream;
 
 /**
- * A record declaration is a special data class type (JDK 14 preview feature).
+ * A record declaration is a special data class type (JDK 14 and JDK 15 preview feature).
  * This is a {@linkplain Node#isFindBoundary() find boundary} for tree traversal methods.
  *
  * 
@@ -27,7 +27,7 @@ import net.sourceforge.pmd.lang.ast.NodeStream;
  *
  * 
* - * @see JEP 359: Records (Preview) + * @see JEP 384: Records (Second Preview) */ @Experimental public final class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRelationalExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRelationalExpression.java index c773a4b0a5..42c266eeb4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRelationalExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRelationalExpression.java @@ -30,7 +30,7 @@ public final class ASTRelationalExpression extends AbstractJavaExpr implements A @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResources.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResources.java index 953f8209db..fa05ec4492 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResources.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResources.java @@ -14,6 +14,6 @@ public final class ASTResources extends AbstractJavaNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResultType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResultType.java index d51b431c85..ec66e20841 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResultType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResultType.java @@ -14,7 +14,11 @@ import org.checkerframework.checker.nullness.qual.Nullable; * ResultType ::= "void" | {@link ASTType Type} * *
+ * + * @deprecated This has been replaced by an unwrapped {@link ASTType}, + * "void" being represented by {@link ASTVoidType}. */ +@Deprecated public final class ASTResultType extends AbstractJavaTypeNode { ASTResultType(int id) { @@ -40,6 +44,6 @@ public final class ASTResultType extends AbstractJavaTypeNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTShiftExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTShiftExpression.java index f3cf2f750d..e69f45f203 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTShiftExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTShiftExpression.java @@ -40,7 +40,7 @@ public final class ASTShiftExpression extends AbstractJavaExpr implements ASTExp @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java index 4795d4f380..f2eaf02ad6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java @@ -18,6 +18,6 @@ public final class ASTStatementExpression extends AbstractJavaTypeNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } 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 6ce74cbaf4..ab3731991d 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 @@ -4,9 +4,6 @@ package net.sourceforge.pmd.lang.java.ast; -import org.checkerframework.checker.nullness.qual.Nullable; - -import net.sourceforge.pmd.lang.ast.xpath.NoAttribute; import net.sourceforge.pmd.lang.java.types.TypePrettyPrint; @@ -48,27 +45,21 @@ public interface ASTType extends TypeNode, Annotatable, LeftRecursiveNode { return 0; } - @Nullable - default ASTPrimitiveType asPrimitiveType() { - return isPrimitiveType() ? (ASTPrimitiveType) this : null; - } - - @Nullable - default ASTReferenceType asReferenceType() { - return isReferenceType() ? (ASTReferenceType) this : null; + + /** + * Returns true if this is the "void" pseudo-type, ie an {@link ASTVoidType}. + */ + default boolean isVoid() { + return this instanceof ASTVoidType; } + // TODO remove that, there's enough on JTypeMirror default boolean isPrimitiveType() { return this instanceof ASTPrimitiveType; } - default boolean isReferenceType() { - return !isPrimitiveType(); - } - - default boolean isArrayType() { return this instanceof ASTArrayType; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArgument.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArgument.java index 39ba463ee0..8e415dd892 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArgument.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArgument.java @@ -43,6 +43,6 @@ public final class ASTTypeArgument extends AbstractJavaTypeNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeBound.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeBound.java index 055b4fe71a..bc4315826f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeBound.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeBound.java @@ -37,6 +37,6 @@ public final class ASTTypeBound extends AbstractJavaTypeNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpressionNotPlusMinus.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpressionNotPlusMinus.java index 57938574cc..604d91213a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpressionNotPlusMinus.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpressionNotPlusMinus.java @@ -29,7 +29,7 @@ public final class ASTUnaryExpressionNotPlusMinus extends AbstractJavaTypeNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } 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 378bcd81a2..77c2534126 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 @@ -12,9 +12,9 @@ import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; +import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; // @formatter:off @@ -105,6 +105,8 @@ public final class ASTVariableDeclaratorId extends AbstractTypedSymbolDeclarator JavaNode parent = getParent(); if (parent instanceof ASTVariableDeclarator) { return (AccessNode) parent.getParent(); + } else if (parent instanceof ASTTypeTestPattern) { + return this; // this is pretty weird } return (AccessNode) parent; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVoidType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVoidType.java new file mode 100644 index 0000000000..f7c4f85b78 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVoidType.java @@ -0,0 +1,34 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +/** + * Type node to represent the void pseudo-type. This represents the + * absence of a type, not a type, but it's easier to process that way. + * Can only occur as return type of method declarations, and as the qualifier + * of a {@linkplain ASTClassLiteral class literal}. + * + *
+ *
+ * VoidType ::= "void"
+ *
+ * 
+ */ +public final class ASTVoidType extends AbstractJavaTypeNode implements ASTType { + + ASTVoidType(int id) { + super(id); + } + + @Override + protected R acceptVisitor(JavaVisitor visitor, P data) { + return visitor.visit(this, data); + } + + @Override + public String getTypeImage() { + return "void"; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWildcardBounds.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWildcardBounds.java index a5a01e9626..14f4c3ecc0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWildcardBounds.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWildcardBounds.java @@ -53,6 +53,6 @@ public final class ASTWildcardBounds extends AbstractJavaTypeNode { @Override protected R acceptVisitor(JavaVisitor visitor, P data) { - return visitor.visit(this, data); + throw new UnsupportedOperationException("Node was removed from grammar"); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractAnyTypeDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractAnyTypeDeclaration.java index 947e77ed8a..5e0e0de235 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractAnyTypeDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractAnyTypeDeclaration.java @@ -7,9 +7,9 @@ package net.sourceforge.pmd.lang.java.ast; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; import net.sourceforge.pmd.lang.java.symbols.JClassSymbol; import net.sourceforge.pmd.lang.java.types.JClassType; +import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute; /** diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaNode.java index 6b84c82952..7792e411da 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaNode.java @@ -51,6 +51,11 @@ abstract class AbstractJavaNode extends AbstractJjtreeNode + *
  • {@link #DEFAULT}: this doesn't exist at the class file level. + * A default method is a non-static non-abstract public method declared + * in an interface ({@link JMethodSymbol#isDefault()}). + *
  • {@link #SEALED}: a sealed class has an attribute {@code PermittedSubclasses} + * with a non-zero length (in the compiled class file) + *
  • {@link #NON_SEALED}: this doesn't exist at the class file level at all. + * But a class must have the non-sealed modifier in source if it + * is neither sealed, nor final, and appears in the {@code PermittedSubclasses} + * attribute of some direct supertype. + * */ public int getReflectMod() { return reflect; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitor.java index 4eee257e11..b3c774eece 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitor.java @@ -24,4 +24,169 @@ public interface JavaParserVisitor extends JavaVisitor { return param; } + // REMOVE ME + // deprecated stuff kept for compatibility with existing visitors, not matched by anything + + @Deprecated + default Object visit(ASTExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTLiteral node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTType node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTReferenceType node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTConditionalOrExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTVariableInitializer node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTAssignmentOperator node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTConditionalAndExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTInclusiveOrExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTExclusiveOrExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTAndExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTEqualityExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTRelationalExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTShiftExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTAdditiveExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTMultiplicativeExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTAnnotationMethodDeclaration node, Object data) { + return null; + } + + default Object visit(ASTStatement node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTPrimaryPrefix node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTPrimarySuffix node, Object data) { + return null; + } + + + @Deprecated + default Object visit(ASTPrimaryExpression node, Object data) { + return null; + } + + + @Deprecated + default Object visit(ASTAllocationExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTTypeArgument node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTWildcardBounds node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTUnaryExpressionNotPlusMinus node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTBlockStatement node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTInstanceOfExpression node, Object data) { + return null; + } + + + @Deprecated + default Object visit(ASTStatementExpression node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTMethodDeclarator node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTArguments node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data) { + return null; + } + + @Deprecated + default Object visit(ASTResultType node, Object data) { + return null; + } + } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java index 89d4f7119b..a32204f272 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorAdapter.java @@ -22,457 +22,4 @@ public class JavaParserVisitorAdapter extends JavaVisitorBase im return data; } - - @Override - public Object visit(ASTType node, Object data) { - return visit((JavaNode) node, data); - } - - @Override - public Object visit(ASTPrimitiveType node, Object data) { - return visit((ASTType) node, data); - } - - @Override - public Object visit(ASTReferenceType node, Object data) { - return visit((ASTType) node, data); - } - - - @Override - public Object visit(ASTArrayType node, Object data) { - return visit((ASTReferenceType) node, data); - } - - @Override - public Object visit(ASTUnionType node, Object data) { - return visit((ASTReferenceType) node, data); - } - - @Override - public Object visit(ASTIntersectionType node, Object data) { - return visit((ASTReferenceType) node, data); - } - - - @Override - public Object visit(ASTWildcardType node, Object data) { - return visit((ASTReferenceType) node, data); - } - - @Override - public Object visit(ASTClassOrInterfaceType node, Object data) { - return visit((ASTReferenceType) node, data); - } - - - @Override - public Object visit(ASTExpression node, Object data) { - return visit((JavaNode) node, data); - } - - @Override - public Object visit(ASTLambdaExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Override - public Object visit(ASTAssignmentExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Override - public Object visit(ASTConditionalExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - - @Override - public Object visit(ASTInfixExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - - @Override - public Object visit(ASTUnaryExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Override - public Object visit(ASTCastExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - - @Override - public Object visit(ASTSwitchExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - - @Override - public Object visit(ASTPrimaryExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - - @Override - public Object visit(ASTMethodCall node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - @Override - public Object visit(ASTFieldAccess node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - @Override - public Object visit(ASTConstructorCall node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - - @Override - public Object visit(ASTArrayAllocation node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - - @Override - public Object visit(ASTArrayAccess node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - - @Override - public Object visit(ASTVariableAccess node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - - @Override - public Object visit(ASTMethodReference node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - - @Override - public Object visit(ASTThisExpression node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - @Override - public Object visit(ASTSuperExpression node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - @Override - public Object visit(ASTClassLiteral node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - @Override - public Object visit(ASTLiteral node, Object data) { - return visit((ASTPrimaryExpression) node, data); - } - - @Override - public Object visit(ASTBooleanLiteral node, Object data) { - return visit((ASTLiteral) node, data); - } - - @Override - public Object visit(ASTNullLiteral node, Object data) { - return visit((ASTLiteral) node, data); - } - - @Override - public Object visit(ASTNumericLiteral node, Object data) { - return visit((ASTLiteral) node, data); - } - - @Override - public Object visit(ASTStringLiteral node, Object data) { - return visit((ASTLiteral) node, data); - } - - @Override - public Object visit(ASTCharLiteral node, Object data) { - return visit((ASTLiteral) node, data); - } - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - return visit((ASTAnyTypeDeclaration) node, data); - } - - @Override - public Object visit(ASTAnnotationTypeDeclaration node, Object data) { - return visit((ASTAnyTypeDeclaration) node, data); - } - - @Override - public Object visit(ASTAnonymousClassDeclaration node, Object data) { - return visit((ASTAnyTypeDeclaration) node, data); - } - - @Override - public Object visit(ASTEnumDeclaration node, Object data) { - return visit((ASTAnyTypeDeclaration) node, data); - } - - @Override - public Object visit(ASTRecordDeclaration node, Object data) { - return visit((ASTAnyTypeDeclaration) node, data); - } - - - @Override - public Object visit(ASTAnyTypeDeclaration node, Object data) { - return visit((JavaNode) node, data); - } - - @Override - public Object visit(ASTMethodDeclaration node, Object data) { - return visit((ASTMethodOrConstructorDeclaration) node, data); - } - - - - @Override - public Object visit(ASTConstructorDeclaration node, Object data) { - return visit((ASTMethodOrConstructorDeclaration) node, data); - } - - - @Override - public Object visit(ASTMethodOrConstructorDeclaration node, Object data) { - return visit((MethodLikeNode) node, data); - } - - @Override - public Object visit(ASTAssertStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTBlock node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTBreakStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTContinueStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTDoStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTEmptyStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTExplicitConstructorInvocation node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTExpressionStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTForeachStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTForStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTIfStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTLabeledStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTLocalClassStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTReturnStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTStatementExpressionList node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTSwitchStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTSynchronizedStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTThrowStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTTryStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTWhileStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTYieldStatement node, Object data) { - return visit((ASTStatement) node, data); - } - - @Override - public Object visit(ASTStatement node, Object data) { - return visit((JavaNode) node, data); - } - - // REMOVE ME - // deprecated stuff kept for compatibility with existing visitors, not matched by anything - - @Deprecated - public Object visit(ASTArguments node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTAllocationExpression node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTTypeArgument node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTWildcardBounds node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTUnaryExpressionNotPlusMinus node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTConditionalOrExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTConditionalAndExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTInclusiveOrExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTExclusiveOrExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTAndExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTEqualityExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTRelationalExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTShiftExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTAdditiveExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTMultiplicativeExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTInstanceOfExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTMethodDeclarator node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTAnnotationMethodDeclaration node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTBlockStatement node, Object data) { - return null; - } - - - @Deprecated - public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTStatementExpression node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTResources node, Object data) { - return null; - } - - } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaVisitorBase.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaVisitorBase.java index 1367352974..bde0e3181e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaVisitorBase.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaVisitorBase.java @@ -24,57 +24,55 @@ import net.sourceforge.pmd.lang.ast.AstVisitorBase; */ public class JavaVisitorBase extends AstVisitorBase implements JavaVisitor { - // todo on java-grammar: uncomment - // - public R visit(ASTMethodOrConstructorDeclaration node, P data) { - return visit((JavaNode) node, data); + public R visitMethodOrCtor(ASTMethodOrConstructorDeclaration node, P data) { + return visitJavaNode(node, data); } @Override public R visit(ASTMethodDeclaration node, P data) { - return visit((ASTMethodOrConstructorDeclaration) node, data); + return visitMethodOrCtor(node, data); } @Override public R visit(ASTConstructorDeclaration node, P data) { - return visit((ASTMethodOrConstructorDeclaration) node, data); + return visitMethodOrCtor(node, data); } // // - public R visit(ASTAnyTypeDeclaration node, P data) { - return visit((JavaNode) node, data); + public R visitTypeDecl(ASTAnyTypeDeclaration node, P data) { + return visitJavaNode(node, data); } @Override public R visit(ASTClassOrInterfaceDeclaration node, P data) { - return visit((ASTAnyTypeDeclaration) node, data); + return visitTypeDecl(node, data); } @Override public R visit(ASTAnonymousClassDeclaration node, P data) { - return visit((ASTAnyTypeDeclaration) node, data); + return visitTypeDecl(node, data); } @Override public R visit(ASTRecordDeclaration node, P data) { - return visit((ASTAnyTypeDeclaration) node, data); + return visitTypeDecl(node, data); } @Override public R visit(ASTEnumDeclaration node, P data) { - return visit((ASTAnyTypeDeclaration) node, data); + return visitTypeDecl(node, data); } @Override public R visit(ASTAnnotationTypeDeclaration node, P data) { - return visit((ASTAnyTypeDeclaration) node, data); + return visitTypeDecl(node, data); } // @@ -82,35 +80,35 @@ public class JavaVisitorBase extends AstVisitorBase implements JavaV // - public R visit(ASTType node, P data) { - return visit((JavaNode) node, data); + public R visitType(ASTType node, P data) { + return visitJavaNode(node, data); } @Override public R visit(ASTPrimitiveType node, P data) { - return visit((ASTType) node, data); + return visitType(node, data); } - public R visit(ASTReferenceType node, P data) { - return visit((ASTType) node, data); + public R visitReferenceType(ASTReferenceType node, P data) { + return visitType(node, data); } @Override public R visit(ASTArrayType node, P data) { - return visit((ASTReferenceType) node, data); + return visitReferenceType(node, data); } @Override public R visit(ASTIntersectionType node, P data) { - return visit((ASTReferenceType) node, data); + return visitReferenceType(node, data); } @Override public R visit(ASTWildcardType node, P data) { - return visit((ASTReferenceType) node, data); + return visitReferenceType(node, data); } @Override @@ -120,7 +118,7 @@ public class JavaVisitorBase extends AstVisitorBase implements JavaV @Override public R visit(ASTClassOrInterfaceType node, P data) { - return visit((ASTReferenceType) node, data); + return visitReferenceType(node, data); } // @@ -128,250 +126,261 @@ public class JavaVisitorBase extends AstVisitorBase implements JavaV // - public R visit(ASTExpression node, P data) { - return visit((JavaNode) node, data); + public R visitExpression(ASTExpression node, P data) { + return visitJavaNode(node, data); } @Override public R visit(ASTLambdaExpression node, P data) { - return visit((ASTExpression) node, data); + return visitExpression(node, data); } @Override public R visit(ASTAssignmentExpression node, P data) { - return visit((ASTExpression) node, data); + return visitExpression(node, data); } @Override public R visit(ASTConditionalExpression node, P data) { - return visit((ASTExpression) node, data); + return visitExpression(node, data); } @Override public R visit(ASTInfixExpression node, P data) { - return visit((ASTExpression) node, data); + return visitExpression(node, data); } @Override public R visit(ASTUnaryExpression node, P data) { - return visit((ASTExpression) node, data); + return visitExpression(node, data); } @Override public R visit(ASTCastExpression node, P data) { - return visit((ASTExpression) node, data); + return visitExpression(node, data); } @Override public R visit(ASTSwitchExpression node, P data) { - return visit((ASTExpression) node, data); + return visitExpression(node, data); } - public R visit(ASTPrimaryExpression node, P data) { - return visit((ASTExpression) node, data); + /* + Primaries + */ + + + public R visitPrimaryExpr(ASTPrimaryExpression node, P data) { + return visitExpression(node, data); } @Override public R visit(ASTMethodCall node, P data) { - return visit((ASTPrimaryExpression) node, data); + return visitPrimaryExpr(node, data); } @Override public R visit(ASTFieldAccess node, P data) { - return visit((ASTPrimaryExpression) node, data); + return visitPrimaryExpr(node, data); } @Override public R visit(ASTConstructorCall node, P data) { - return visit((ASTPrimaryExpression) node, data); + return visitPrimaryExpr(node, data); } @Override public R visit(ASTArrayAllocation node, P data) { - return visit((ASTPrimaryExpression) node, data); + return visitPrimaryExpr(node, data); } @Override public R visit(ASTArrayAccess node, P data) { - return visit((ASTPrimaryExpression) node, data); + return visitPrimaryExpr(node, data); } @Override public R visit(ASTVariableAccess node, P data) { - return visit((ASTPrimaryExpression) node, data); + return visitPrimaryExpr(node, data); } @Override public R visit(ASTMethodReference node, P data) { - return visit((ASTPrimaryExpression) node, data); + return visitPrimaryExpr(node, data); } @Override public R visit(ASTThisExpression node, P data) { - return visit((ASTPrimaryExpression) node, data); + return visitPrimaryExpr(node, data); } @Override public R visit(ASTSuperExpression node, P data) { - return visit((ASTPrimaryExpression) node, data); + return visitPrimaryExpr(node, data); } @Override public R visit(ASTClassLiteral node, P data) { - return visit((ASTPrimaryExpression) node, data); + return visitPrimaryExpr(node, data); } - public R visit(ASTLiteral node, P data) { - return visit((ASTPrimaryExpression) node, data); + /* + Literals + */ + + public R visitLiteral(ASTLiteral node, P data) { + return visitPrimaryExpr(node, data); } @Override public R visit(ASTBooleanLiteral node, P data) { - return visit((ASTLiteral) node, data); + return visitLiteral(node, data); } @Override public R visit(ASTNullLiteral node, P data) { - return visit((ASTLiteral) node, data); + return visitLiteral(node, data); } @Override public R visit(ASTNumericLiteral node, P data) { - return visit((ASTLiteral) node, data); + return visitLiteral(node, data); } @Override public R visit(ASTStringLiteral node, P data) { - return visit((ASTLiteral) node, data); + return visitLiteral(node, data); } @Override public R visit(ASTCharLiteral node, P data) { - return visit((ASTLiteral) node, data); + return visitLiteral(node, data); } // // + + public R visitStatement(ASTStatement node, P data) { + return visitJavaNode(node, data); + } + @Override public R visit(ASTAssertStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTBlock node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTBreakStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTContinueStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTDoStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTEmptyStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTExplicitConstructorInvocation node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTExpressionStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTForeachStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTForStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTIfStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTLabeledStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTLocalClassStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTReturnStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTStatementExpressionList node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTSwitchStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTSynchronizedStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTThrowStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTTryStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTWhileStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } @Override public R visit(ASTYieldStatement node, P data) { - return visit((ASTStatement) node, data); + return visitStatement(node, data); } - public R visit(ASTStatement node, P data) { - return visit((JavaNode) node, data); - } // diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java index a1c417675b..8959b9c9b4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/LanguageLevelChecker.java @@ -116,13 +116,17 @@ public class LanguageLevelChecker { SWITCH_EXPRESSIONS(12, 13, true), SWITCH_RULES(12, 13, true), - TEXT_BLOCK_LITERALS(13, 14, false), + TEXT_BLOCK_LITERALS(13, 14, true), YIELD_STATEMENTS(13, 13, true), /** \s */ - SPACE_STRING_ESCAPES(14, 14, false), - RECORD_DECLARATIONS(14, 14, false), - TYPE_TEST_PATTERNS_IN_INSTANCEOF(14, 14, false); + SPACE_STRING_ESCAPES(14, 14, true), + RECORD_DECLARATIONS(14, 15, false), + TYPE_TEST_PATTERNS_IN_INSTANCEOF(14, 15, false), + SEALED_CLASSES(15, 15, false), + STATIC_LOCAL_TYPE_DECLARATIONS(15, 15, false), // part of the sealed classes JEP + + ; // SUPPRESS CHECKSTYLE enum trailing semi is awesome private final int minPreviewVersion; @@ -357,7 +361,7 @@ public class LanguageLevelChecker { @Override public Void visit(ASTEnumDeclaration node, T data) { check(node, RegularLanguageFeature.ENUMS, data); - visit((ASTAnyTypeDeclaration) node, data); + visitTypeDecl((ASTAnyTypeDeclaration) node, data); return null; } @@ -472,7 +476,12 @@ public class LanguageLevelChecker { } @Override - public Void visit(ASTAnyTypeDeclaration node, T data) { + public Void visitTypeDecl(ASTAnyTypeDeclaration node, T data) { + if (node.getModifiers().hasAnyExplicitly(JModifier.SEALED, JModifier.NON_SEALED)) { + check(node, PreviewFeature.SEALED_CLASSES, data); + } else if (node.isLocal() && !node.isRegularClass()) { + check(node, PreviewFeature.STATIC_LOCAL_TYPE_DECLARATIONS, data); + } String simpleName = node.getSimpleName(); if ("var".equals(simpleName)) { check(node, ReservedIdentifiers.VAR_AS_A_TYPE_NAME, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaDesignerBindings.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaDesignerBindings.java index d710ddbc57..956646196e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaDesignerBindings.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaDesignerBindings.java @@ -10,7 +10,6 @@ import java.util.Collection; import java.util.Collections; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; @@ -32,6 +31,7 @@ import net.sourceforge.pmd.lang.java.ast.JavaVisitorBase; import net.sourceforge.pmd.lang.java.ast.TypeNode; import net.sourceforge.pmd.lang.java.types.JTypeMirror; import net.sourceforge.pmd.lang.java.types.JVariableSig; +import net.sourceforge.pmd.lang.rule.xpath.Attribute; import net.sourceforge.pmd.util.designerbindings.DesignerBindings.DefaultDesignerBindings; import net.sourceforge.pmd.util.designerbindings.RelatedNodesSelector; @@ -52,7 +52,6 @@ public final class JavaDesignerBindings extends DefaultDesignerBindings { } } - return super.getMainAttribute(node); } @@ -129,7 +128,7 @@ public final class JavaDesignerBindings extends DefaultDesignerBindings { private static final MainAttrVisitor INSTANCE = new MainAttrVisitor(); @Override - public Attribute visit(JavaNode node, Void data) { + public Attribute visitJavaNode(JavaNode node, Void data) { return null; // don't recurse } @@ -139,7 +138,7 @@ public final class JavaDesignerBindings extends DefaultDesignerBindings { } @Override - public Attribute visit(ASTAnyTypeDeclaration node, Void data) { + public Attribute visitTypeDecl(ASTAnyTypeDeclaration node, Void data) { return new Attribute(node, "SimpleName", node.getSimpleName()); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageHandler.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageHandler.java index 8a5199f426..ef94005886 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageHandler.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageHandler.java @@ -8,12 +8,8 @@ import java.util.Arrays; import java.util.List; import net.sourceforge.pmd.lang.AbstractPmdLanguageVersionHandler; -import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ParserOptions; -import net.sourceforge.pmd.lang.XPathHandler; -import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler; -import net.sourceforge.pmd.lang.java.JavaLanguageModule; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.JavaParser; import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; @@ -22,22 +18,26 @@ import net.sourceforge.pmd.lang.java.ast.internal.ReportingStrategy; import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey; import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey; import net.sourceforge.pmd.lang.java.rule.internal.JavaRuleViolationFactory; -import net.sourceforge.pmd.lang.java.xpath.GetCommentOnFunction; -import net.sourceforge.pmd.lang.java.xpath.JavaFunctions; -import net.sourceforge.pmd.lang.java.xpath.MetricFunction; -import net.sourceforge.pmd.lang.java.xpath.TypeIsExactlyFunction; -import net.sourceforge.pmd.lang.java.xpath.TypeIsFunction; -import net.sourceforge.pmd.lang.java.xpath.TypeOfFunction; +import net.sourceforge.pmd.lang.java.rule.xpath.internal.GetCommentOnFunction; +import net.sourceforge.pmd.lang.java.rule.xpath.internal.MetricFunction; +import net.sourceforge.pmd.lang.java.rule.xpath.internal.TypeIsFunction; import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider; import net.sourceforge.pmd.lang.metrics.MetricKey; import net.sourceforge.pmd.lang.metrics.internal.AbstractLanguageMetricsProvider; import net.sourceforge.pmd.lang.rule.RuleViolationFactory; +import net.sourceforge.pmd.lang.rule.xpath.impl.XPathHandler; import net.sourceforge.pmd.util.designerbindings.DesignerBindings; -import net.sf.saxon.sxpath.IndependentContext; - public class JavaLanguageHandler extends AbstractPmdLanguageVersionHandler { + private static final XPathHandler XPATH_HANDLER = + XPathHandler.getHandlerForFunctionDefs( + TypeIsFunction.TYPE_IS_EXACTLY, + TypeIsFunction.TYPE_IS, + MetricFunction.INSTANCE, + GetCommentOnFunction.INSTANCE + ); + private final LanguageLevelChecker levelChecker; private final LanguageMetricsProvider myMetricsProvider = new JavaMetricsProvider(); @@ -66,21 +66,7 @@ public class JavaLanguageHandler extends AbstractPmdLanguageVersionHandler { @Override public XPathHandler getXPathHandler() { - return new DefaultASTXPathHandler() { - @Override - public void initialize() { - TypeOfFunction.registerSelfInSimpleContext(); - GetCommentOnFunction.registerSelfInSimpleContext(); - MetricFunction.registerSelfInSimpleContext(); - TypeIsFunction.registerSelfInSimpleContext(); - TypeIsExactlyFunction.registerSelfInSimpleContext(); - } - - @Override - public void initialize(IndependentContext context) { - super.initialize(context, LanguageRegistry.getLanguage(JavaLanguageModule.NAME), JavaFunctions.class); - } - }; + return XPATH_HANDLER; } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/CycloVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/CycloVisitor.java index 00dc26ef76..01be0d4b10 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/CycloVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/CycloVisitor.java @@ -50,8 +50,8 @@ public class CycloVisitor extends JavaVisitorBase { @Override - public final Void visit(JavaNode localNode, MutableInt data) { - return localNode.isFindBoundary() && !localNode.equals(topNode) ? null : super.visit(localNode, data); + public final Void visitJavaNode(JavaNode localNode, MutableInt data) { + return localNode.isFindBoundary() && !localNode.equals(topNode) ? null : super.visitJavaNode(localNode, data); } @Override @@ -84,7 +84,7 @@ public class CycloVisitor extends JavaVisitorBase { } } - return visit(node, data); + return visitJavaNode(node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NcssVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NcssVisitor.java index 3a719da62e..8ed41865fc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NcssVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NcssVisitor.java @@ -64,9 +64,9 @@ public class NcssVisitor extends JavaParserVisitorAdapter { @Override - public final Object visit(JavaNode node, Object data) { + public final Object visitJavaNode(JavaNode node, Object data) { // same here - return super.visit(node, data); + return super.visitJavaNode(node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NpathBaseVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NpathBaseVisitor.java index 63db33d656..54778ba4fc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NpathBaseVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/NpathBaseVisitor.java @@ -85,13 +85,13 @@ public class NpathBaseVisitor extends JavaParserVisitorAdapter { @Override - public Object visit(ASTMethodOrConstructorDeclaration node, Object data) { + public Object visitMethodOrCtor(ASTMethodOrConstructorDeclaration node, Object data) { return multiplyChildrenComplexities(node, data); } @Override - public Object visit(JavaNode node, Object data) { + public Object visitJavaNode(JavaNode node, Object data) { return multiplyChildrenComplexities(node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/TccAttributeAccessCollector.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/TccAttributeAccessCollector.java index 1a72305be0..11dac75119 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/TccAttributeAccessCollector.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/TccAttributeAccessCollector.java @@ -52,17 +52,17 @@ public class TccAttributeAccessCollector extends JavaParserVisitorAdapter { */ @SuppressWarnings("unchecked") public Map> start() { - return (Map>) this.visit(exploredClass, new HashMap>()); + return (Map>) this.visitTypeDecl(exploredClass, new HashMap>()); } @Override - public Object visit(ASTAnyTypeDeclaration node, Object data) { + public Object visitTypeDecl(ASTAnyTypeDeclaration node, Object data) { if (Objects.equals(node, exploredClass)) { methodAttributeAccess = new HashMap<>(); - super.visit(node, data); + super.visitTypeDecl(node, data); } else if (node.isLocal()) { - super.visit(node, data); + super.visitTypeDecl(node, data); } return methodAttributeAccess; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/multifile/signature/JavaOperationSignature.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/multifile/signature/JavaOperationSignature.java index 239366b5a5..82ea70a122 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/multifile/signature/JavaOperationSignature.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/multifile/signature/JavaOperationSignature.java @@ -15,7 +15,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTResultType; /** * Signature for an operation. @@ -128,7 +127,7 @@ public final class JavaOperationSignature extends JavaSignature fieldNames) { - if (node.getArity() != 0 || node.getFirstDescendantOfType(ASTResultType.class).isVoid()) { + if (node.getArity() != 0 || node.isVoid()) { return false; } @@ -146,7 +145,7 @@ public final class JavaOperationSignature extends JavaSignature fieldNames) { - if (node.getArity() != 1 || !node.getFirstDescendantOfType(ASTResultType.class).isVoid()) { + if (node.getArity() != 1 || !node.isVoid()) { return false; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJUnitRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJUnitRule.java index a67d7e9071..874331fbf2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJUnitRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJUnitRule.java @@ -10,14 +10,12 @@ import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTExtendsList; import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.TypeNode; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; /** * @deprecated Internal API @@ -97,26 +95,7 @@ public abstract class AbstractJUnitRule extends AbstractJavaRule { private boolean isJUnit3Class(ASTCompilationUnit node) { ASTClassOrInterfaceDeclaration cid = node.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class); - if (cid == null) { - return false; - } - - if (node.getType() != null && TypeHelper.isA(node, JUNIT3_CLASS_NAME)) { - return true; - } else if (node.getType() == null) { - ASTExtendsList extendsList = cid.getFirstChildOfType(ASTExtendsList.class); - if (extendsList == null) { - return false; - } - if (((ASTClassOrInterfaceType) extendsList.getChild(0)).getImage().endsWith("TestCase")) { - return true; - } - String className = cid.getSimpleName(); - return className.endsWith("Test"); - } else if (hasImports(node, JUNIT3_CLASS_NAME)) { - return cid.getSimpleName().endsWith("Test"); - } - return false; + return TypeTestUtil.isA(JUNIT3_CLASS_NAME, cid); } private boolean isJUnit4Class(ASTCompilationUnit node) { @@ -137,7 +116,7 @@ public abstract class AbstractJUnitRule extends AbstractJavaRule { if (name != null && (name.hasImageEqualTo("Test") || name.hasImageEqualTo(annotationTypeClassName))) { return true; } - } else if (TypeHelper.isA(annotationType, annotationTypeClassName)) { + } else if (TypeTestUtil.isA(annotationTypeClassName, annotationType)) { return true; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaMetricsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaMetricsRule.java index 95e089c3b3..9fff87435c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaMetricsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaMetricsRule.java @@ -12,7 +12,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; @@ -45,7 +44,7 @@ public abstract class AbstractJavaMetricsRule extends AbstractJavaRule { public Object visit(ASTAnyTypeDeclaration node, Object data) { - return visit((JavaNode) node, data); + return visitJavaNode(node, data); } @@ -67,7 +66,7 @@ public abstract class AbstractJavaMetricsRule extends AbstractJavaRule { public Object visit(MethodLikeNode node, Object data) { - return visit((JavaNode) node, data); + return visitJavaNode(node, data); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java index 100cfcfa64..4dd0570d1c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRule.java @@ -35,6 +35,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.ast.ASTRelationalExpression; +import net.sourceforge.pmd.lang.java.ast.ASTResultType; import net.sourceforge.pmd.lang.java.ast.ASTShiftExpression; import net.sourceforge.pmd.lang.java.ast.ASTStatement; import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; @@ -64,7 +65,7 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse @Override public void apply(Node target, RuleContext ctx) { - ((JavaNode) target).jjtAccept(this, ctx); + target.acceptVisitor(this, ctx); } public static boolean isQualifiedName(@Nullable String node) { @@ -91,146 +92,4 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse return true; } - // FIXME those are not in sync with JavaParserVisitorAdapter - // See #1786 - - - public Object visit(ASTExpression node, Object data) { - return JavaParserVisitor.super.visit(node, data); - } - - public Object visit(ASTLiteral node, Object data) { - return JavaParserVisitor.super.visit(node, data); - } - - - // REMOVE ME - // deprecated stuff kept for compatibility with existing visitors, not matched by anything - - @Deprecated - public Object visit(ASTConditionalOrExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTVariableInitializer node, Object data) { - return visit((JavaNode) node, data); - } - - @Deprecated - public Object visit(ASTAssignmentOperator node, Object data) { - return visit((JavaNode) node, data); - } - - @Deprecated - public Object visit(ASTConditionalAndExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTInclusiveOrExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTExclusiveOrExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTAndExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTEqualityExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTRelationalExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTShiftExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTAdditiveExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - @Deprecated - public Object visit(ASTMultiplicativeExpression node, Object data) { - return visit((ASTExpression) node, data); - } - - public Object visit(ASTStatement node, Object data) { - return visit((JavaNode) node, data); - } - - @Deprecated - public Object visit(ASTPrimaryPrefix node, Object data) { - return JavaParserVisitor.super.visit(node, data); - } - - @Deprecated - public Object visit(ASTPrimarySuffix node, Object data) { - return JavaParserVisitor.super.visit(node, data); - } - - - @Deprecated - public Object visit(ASTPrimaryExpression node, Object data) { - return JavaParserVisitor.super.visit(node, data); - } - - - @Deprecated - public Object visit(ASTAllocationExpression node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTTypeArgument node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTWildcardBounds node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTUnaryExpressionNotPlusMinus node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTBlockStatement node, Object data) { - return null; - } - - - @Deprecated - public Object visit(ASTStatementExpression node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTMethodDeclarator node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTArguments node, Object data) { - return null; - } - - @Deprecated - public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data) { - return null; - } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRulechainRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRulechainRule.java index a8a6d05b4c..68b4861393 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRulechainRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractJavaRulechainRule.java @@ -39,7 +39,7 @@ public abstract class AbstractJavaRulechainRule extends AbstractJavaRule { } @Override - public Object visit(JavaNode node, Object data) { + public Object visitJavaNode(JavaNode node, Object data) { return data; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ForLoopCanBeForeachRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ForLoopCanBeForeachRule.java index 94dcc6a133..81fe23a7e3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ForLoopCanBeForeachRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/ForLoopCanBeForeachRule.java @@ -35,7 +35,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; import net.sourceforge.pmd.lang.symboltable.Scope; @@ -69,7 +69,7 @@ public class ForLoopCanBeForeachRule extends AbstractJavaRule { final List occurrences = indexDecl.get().getValue(); final VariableNameDeclaration index = indexDecl.get().getKey(); - if (TypeHelper.isExactlyAny(index, Iterator.class)) { + if (TypeTestUtil.isA(Iterator.class, index.getDeclaratorId())) { getIterableDeclOfIteratorLoop(index, node.getScope()) .filter(iterableInfo -> isReplaceableIteratorLoop(indexDecl.get(), guardCondition, iterableInfo, node)) .ifPresent(ignored -> addViolation(data, node)); 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 315fe6c7df..73e3926c3e 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 @@ -21,7 +21,7 @@ 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.java.types.TypeTestUtil; import net.sourceforge.pmd.lang.symboltable.NameDeclaration; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; import net.sourceforge.pmd.lang.symboltable.Scope; @@ -99,7 +99,7 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule { Node parent = entry.getKey().getNode().getParent().getParent().getParent(); if (parent.getFirstChildOfType(ASTFieldDeclaration.class) != null) { ASTAnnotation annot = parent.getFirstDescendantOfType(ASTAnnotation.class); - if (annot == null || !TypeHelper.isA(annot, "org.junit.Rule")) { + if (annot == null || !TypeTestUtil.isA("org.junit.Rule", annot)) { continue; } @@ -118,7 +118,7 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule { */ private boolean isExpectAnnotated(ASTMethodDeclaration method) { return method.getDeclaredAnnotations() - .filter(it -> TypeHelper.isA(it, JUNIT4_CLASS_NAME)) + .filter(it -> TypeTestUtil.isA(JUNIT4_CLASS_NAME, it)) .flatMap(ASTAnnotation::getMembers) .any(it -> "expected".equals(it.getName())); @@ -208,7 +208,7 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule { String varName = tokens[0]; boolean variableTypeIsSoftAssertion = variables.containsKey(varName) - && TypeHelper.isA(variables.get(varName), "org.assertj.core.api.AbstractSoftAssertions"); + && TypeTestUtil.isA("org.assertj.core.api.AbstractSoftAssertions", variables.get(varName).getDeclaratorId()); return methodIsAssertAll && variableTypeIsSoftAssertion; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java index f85eecc207..b56cf0ddc6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LooseCouplingRule.java @@ -4,6 +4,9 @@ package net.sourceforge.pmd.lang.java.rule.bestpractices; +import java.util.Collection; +import java.util.Map; + import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; @@ -12,29 +15,19 @@ import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTResultType; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.util.CollectionUtil; +import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; public class LooseCouplingRule extends AbstractJavaRule { - // TODO - these should be brought in via external properties - // private static final Set implClassNames = CollectionUtil.asSet( new - // Object[] { - // "ArrayList", "HashSet", "HashMap", "LinkedHashMap", "LinkedHashSet", - // "TreeSet", "TreeMap", "Vector", - // "java.util.ArrayList", "java.util.HashSet", "java.util.HashMap", - // "java.util.LinkedHashMap", "java.util.LinkedHashSet", - // "java.util.TreeSet", - // "java.util.TreeMap", "java.util.Vector" - // }); - @Override public Object visit(ASTClassOrInterfaceType node, Object data) { if (methodHasOverride(node)) { return data; } Node parent = node.getNthParent(3); - Class clazzType = node.getType(); - boolean isType = CollectionUtil.isCollectionType(clazzType, false); + boolean isType = (TypeHelper.isA(node, Collection.class) || TypeHelper.isA(node, Map.class)) + && !(node.getType() != null && node.getType().isInterface()); + if (isType && (parent instanceof ASTFieldDeclaration || parent instanceof ASTFormalParameter || parent instanceof ASTResultType)) { addViolation(data, node, node.getImage()); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MethodReturnsInternalArrayRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MethodReturnsInternalArrayRule.java index 8cf1cc5f61..8d31c762b5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MethodReturnsInternalArrayRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MethodReturnsInternalArrayRule.java @@ -6,8 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.bestpractices; import java.util.List; -import org.jaxen.JaxenException; - import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; @@ -123,14 +121,9 @@ public class MethodReturnsInternalArrayRule extends AbstractSunSecureRule { if (child instanceof ASTArrayInitializer && child.getNumChildren() == 0) { return true; } else if (child instanceof ASTExpression) { - try { - List arrayAllocation = child.findChildNodesWithXPath( - "./PrimaryExpression/PrimaryPrefix/AllocationExpression/ArrayDimsAndInits/Expression/PrimaryExpression/PrimaryPrefix/Literal[@IntLiteral=\"true\"][@Image=\"0\"]"); - if (arrayAllocation != null && arrayAllocation.size() == 1) { - return true; - } - } catch (JaxenException e) { - return false; + List arrayAllocation = child.findChildNodesWithXPath("./PrimaryExpression/PrimaryPrefix/AllocationExpression/ArrayDimsAndInits/Expression/PrimaryExpression/PrimaryPrefix/Literal[@IntLiteral=\"true\"][@Image=\"0\"]"); + if (arrayAllocation != null && arrayAllocation.size() == 1) { + return true; } } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedAssignmentRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedAssignmentRule.java index fa3238430a..ad1dd1fdda 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedAssignmentRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedAssignmentRule.java @@ -25,7 +25,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator; +import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr; +import net.sourceforge.pmd.lang.java.ast.ASTAssignmentExpression; import net.sourceforge.pmd.lang.java.ast.ASTBlock; import net.sourceforge.pmd.lang.java.ast.ASTBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement; @@ -61,7 +62,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.ast.ASTResourceList; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; import net.sourceforge.pmd.lang.java.ast.ASTStatement; -import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; import net.sourceforge.pmd.lang.java.ast.ASTSwitchArrowBranch; import net.sourceforge.pmd.lang.java.ast.ASTSwitchExpression; import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel; @@ -76,7 +76,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; import net.sourceforge.pmd.lang.java.ast.ASTYieldStatement; import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter; +import net.sourceforge.pmd.lang.java.ast.JavaVisitorBase; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.ClassScope; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; @@ -151,7 +151,7 @@ public class UnusedAssignmentRule extends AbstractJavaRule { public Object visit(ASTCompilationUnit node, Object data) { for (ASTAnyTypeDeclaration typeDecl : node.getTypeDeclarations()) { GlobalAlgoState result = new GlobalAlgoState(); - typeDecl.jjtAccept(ReachingDefsVisitor.ONLY_LOCALS, new SpanInfo(result)); + typeDecl.acceptVisitor(ReachingDefsVisitor.ONLY_LOCALS, new SpanInfo(result)); reportFinished(result, (RuleContext) data); } @@ -298,7 +298,7 @@ public class UnusedAssignmentRule extends AbstractJavaRule { return sb.toString(); } - private static class ReachingDefsVisitor extends JavaParserVisitorAdapter { + private static class ReachingDefsVisitor extends JavaVisitorBase { static final ReachingDefsVisitor ONLY_LOCALS = new ReachingDefsVisitor(null); @@ -318,22 +318,20 @@ public class UnusedAssignmentRule extends AbstractJavaRule { // following deals with control flow structures @Override - public Object visit(JavaNode node, Object data) { - - for (JavaNode child : node.children()) { + protected SpanInfo visitChildren(Node node, SpanInfo data) { + for (Node child : node.children()) { // each output is passed as input to the next (most relevant for blocks) - data = child.jjtAccept(this, data); + data = child.acceptVisitor(this, data); } - return data; } @Override - public Object visit(ASTBlock node, final Object data) { + public SpanInfo visit(ASTBlock node, final SpanInfo data) { // variables local to a loop iteration must be killed before the // next iteration - SpanInfo state = (SpanInfo) data; + SpanInfo state = data; Set localsToKill = new HashSet<>(); for (JavaNode child : node.children()) { @@ -356,13 +354,13 @@ public class UnusedAssignmentRule extends AbstractJavaRule { } @Override - public Object visit(ASTSwitchStatement node, Object data) { - return processSwitch(node, (SpanInfo) data, node.getTestedExpression()); + public SpanInfo visit(ASTSwitchStatement node, SpanInfo data) { + return processSwitch(node, data, node.getTestedExpression()); } @Override - public Object visit(ASTSwitchExpression node, Object data) { - return processSwitch(node, (SpanInfo) data, node.getChild(0)); + public SpanInfo visit(ASTSwitchExpression node, SpanInfo data) { + return processSwitch(node, data, node.getChild(0)); } private SpanInfo processSwitch(JavaNode switchLike, SpanInfo data, JavaNode testedExpr) { @@ -393,14 +391,14 @@ public class UnusedAssignmentRule extends AbstractJavaRule { } @Override - public Object visit(ASTIfStatement node, Object data) { - SpanInfo before = (SpanInfo) data; + public SpanInfo visit(ASTIfStatement node, SpanInfo data) { + SpanInfo before = data; return makeConditional(before, node.getCondition(), node.getThenBranch(), node.getElseBranch()); } @Override - public Object visit(ASTConditionalExpression node, Object data) { - SpanInfo before = (SpanInfo) data; + public SpanInfo visit(ASTConditionalExpression node, SpanInfo data) { + SpanInfo before = data; return makeConditional(before, node.getCondition(), node.getChild(1), node.getChild(2)); } @@ -504,8 +502,8 @@ public class UnusedAssignmentRule extends AbstractJavaRule { @Override - public Object visit(ASTTryStatement node, Object data) { - final SpanInfo before = (SpanInfo) data; + public SpanInfo visit(ASTTryStatement node, SpanInfo data) { + final SpanInfo before = data; ASTFinallyClause finallyClause = node.getFinallyClause(); /* @@ -579,14 +577,14 @@ public class UnusedAssignmentRule extends AbstractJavaRule { } @Override - public Object visit(ASTCatchClause node, Object data) { - SpanInfo result = (SpanInfo) visit((JavaNode) node, data); + public SpanInfo visit(ASTCatchClause node, SpanInfo data) { + SpanInfo result = visitJavaNode(node, data); result.deleteVar(node.getParameter().getVarId()); return result; } @Override - public Object visit(ASTLambdaExpression node, Object data) { + public SpanInfo visit(ASTLambdaExpression node, SpanInfo data) { // Lambda expression have control flow that is separate from the method // So we fork the context, but don't join it @@ -594,7 +592,7 @@ public class UnusedAssignmentRule extends AbstractJavaRule { // Since those definitions are [effectively] final, they actually can't be // killed, but they can be used in the lambda - SpanInfo before = (SpanInfo) data; + SpanInfo before = data; JavaNode lambdaBody = node.getChild(node.getNumChildren() - 1); // if it's an expression, then no assignments may occur in it, @@ -604,31 +602,31 @@ public class UnusedAssignmentRule extends AbstractJavaRule { } @Override - public Object visit(ASTWhileStatement node, Object data) { - return handleLoop(node, (SpanInfo) data, null, node.getCondition(), null, node.getBody(), true, null); + public SpanInfo visit(ASTWhileStatement node, SpanInfo data) { + return handleLoop(node, data, null, node.getCondition(), null, node.getBody(), true, null); } @Override - public Object visit(ASTDoStatement node, Object data) { - return handleLoop(node, (SpanInfo) data, null, node.getCondition(), null, node.getBody(), false, null); + public SpanInfo visit(ASTDoStatement node, SpanInfo data) { + return handleLoop(node, data, null, node.getCondition(), null, node.getBody(), false, null); } @Override - public Object visit(ASTForeachStatement node, Object data) { + public SpanInfo visit(ASTForeachStatement node, SpanInfo data) { ASTStatement body = node.getBody(); // the iterable expression JavaNode init = node.getChild(1); ASTVariableDeclaratorId foreachVar = ((ASTLocalVariableDeclaration) node.getChild(0)).iterator().next(); - return handleLoop(node, (SpanInfo) data, init, null, null, body, true, foreachVar); + return handleLoop(node, data, init, null, null, body, true, foreachVar); } @Override - public Object visit(ASTForStatement node, Object data) { + public SpanInfo visit(ASTForStatement node, SpanInfo data) { ASTStatement body = node.getBody(); ASTForInit init = node.getFirstChildOfType(ASTForInit.class); ASTExpression cond = node.getCondition(); ASTForUpdate update = node.getFirstChildOfType(ASTForUpdate.class); - return handleLoop(node, (SpanInfo) data, init, cond, update, body, true, null); + return handleLoop(node, data, init, cond, update, body, true, null); } @@ -737,114 +735,96 @@ public class UnusedAssignmentRule extends AbstractJavaRule { } private SpanInfo acceptOpt(JavaNode node, SpanInfo before) { - return node == null ? before : (SpanInfo) node.jjtAccept(this, before); + return node == null ? before : node.acceptVisitor(this, before); } @Override - public Object visit(ASTContinueStatement node, Object data) { - SpanInfo state = (SpanInfo) data; - return state.global.continueTargets.doBreak(state, node.getImage()); + public SpanInfo visit(ASTContinueStatement node, SpanInfo data) { + return data.global.continueTargets.doBreak(data, node.getImage()); } @Override - public Object visit(ASTBreakStatement node, Object data) { - SpanInfo state = (SpanInfo) data; - return state.global.breakTargets.doBreak(state, node.getImage()); + public SpanInfo visit(ASTBreakStatement node, SpanInfo data) { + return data.global.breakTargets.doBreak(data, node.getImage()); } @Override - public Object visit(ASTYieldStatement node, Object data) { + public SpanInfo visit(ASTYieldStatement node, SpanInfo data) { super.visit(node, data); // visit expression - SpanInfo state = (SpanInfo) data; // treat as break, ie abrupt completion + link reaching defs to outer context - return state.global.breakTargets.doBreak(state, null); + return data.global.breakTargets.doBreak(data, null); } // both of those exit the scope of the method/ctor, so their assignments go dead @Override - public Object visit(ASTThrowStatement node, Object data) { + public SpanInfo visit(ASTThrowStatement node, SpanInfo data) { super.visit(node, data); - return ((SpanInfo) data).abruptCompletionByThrow(false); + return data.abruptCompletionByThrow(false); } @Override - public Object visit(ASTReturnStatement node, Object data) { + public SpanInfo visit(ASTReturnStatement node, SpanInfo data) { super.visit(node, data); - return ((SpanInfo) data).abruptCompletion(null); + return data.abruptCompletion(null); } // following deals with assignment @Override - public Object visit(ASTFormalParameter node, Object data) { + public SpanInfo visit(ASTFormalParameter node, SpanInfo data) { ASTVariableDeclaratorId id = node.getVarId(); - ((SpanInfo) data).assign(id, id); + data.assign(id, id); return data; } @Override - public Object visit(ASTVariableDeclarator node, Object data) { + public SpanInfo visit(ASTVariableDeclarator node, SpanInfo data) { ASTVariableDeclaratorId var = node.getVarId(); ASTExpression rhs = node.getInitializer(); if (rhs != null) { - rhs.jjtAccept(this, data); - ((SpanInfo) data).assign(var, rhs); + rhs.acceptVisitor(this, data); + data.assign(var, rhs); } else { - ((SpanInfo) data).assign(var, node.getVarId()); + data.assign(var, node.getVarId()); } return data; } @Override - public Object visit(ASTExpression node, Object data) { - return checkAssignment(node, data); - } + public SpanInfo visit(ASTAssignmentExpression node, SpanInfo data) { + SpanInfo result = data; + ASTAssignableExpr lhs = node.getLeftOperand(); + ASTExpression rhs = node.getRightOperand(); - @Override - public Object visit(ASTStatementExpression node, Object data) { - return checkAssignment(node, data); - } + // visit the rhs as it is evaluated before + result = acceptOpt(rhs, result); - public Object checkAssignment(JavaNode node, Object data) { - SpanInfo result = (SpanInfo) data; - if (node.getNumChildren() == 3) { - // assignment - assert node.getChild(1) instanceof ASTAssignmentOperator; + ASTVariableDeclaratorId lhsVar = getVarFromExpression(lhs, true, result); + if (lhsVar != null) { + // in that case lhs is a normal variable (array access not supported) - // visit the rhs as it is evaluated before - JavaNode rhs = node.getChild(2); - result = acceptOpt(rhs, result); - - ASTVariableDeclaratorId lhsVar = getVarFromExpression(node.getChild(0), true, result); - if (lhsVar != null) { - // in that case lhs is a normal variable (array access not supported) - - if (node.getChild(1).getImage().length() >= 2) { - // compound assignment, to use BEFORE assigning - result.use(lhsVar); - } - - result.assign(lhsVar, rhs); - } else { - result = acceptOpt(node.getChild(0), result); + if (node.getOperator().isCompound()) { + // compound assignment, to use BEFORE assigning + result.use(lhsVar); } - return result; + + result.assign(lhsVar, rhs); } else { - return visit(node, data); + result = acceptOpt(lhs, result); } + return result; } @Override - public Object visit(ASTUnaryExpression node, Object data) { - SpanInfo state = (SpanInfo) data; - ASTVariableDeclaratorId var = getVarFromExpression(node.getChild(0), true, state); + public SpanInfo visit(ASTUnaryExpression node, SpanInfo data) { + ASTVariableDeclaratorId var = getVarFromExpression(node.getChild(0), true, data); if (var != null) { - state.use(var); - state.assign(var, node); + data.use(var); + data.assign(var, node); } return data; } @@ -852,8 +832,8 @@ public class UnusedAssignmentRule extends AbstractJavaRule { // variable usage @Override - public Object visit(ASTPrimaryExpression node, Object data) { - SpanInfo state = (SpanInfo) visit((JavaNode) node, data); // visit subexpressions + public SpanInfo visitPrimaryExpr(ASTPrimaryExpression node, SpanInfo data) { + SpanInfo state = visitJavaNode(node, data); // visit subexpressions ASTVariableDeclaratorId var = getVarFromExpression(node, false, state); if (var != null) { @@ -1008,14 +988,14 @@ public class UnusedAssignmentRule extends AbstractJavaRule { // this is the common denominator between anonymous class & astAnyTypeDeclaration on master @Override - public Object visit(ASTClassOrInterfaceBody node, Object data) { - visitTypeBody(node, (SpanInfo) data); + public SpanInfo visit(ASTClassOrInterfaceBody node, SpanInfo data) { + visitTypeBody(node, data); return data; // type doesn't contribute anything to the enclosing control flow } @Override - public Object visit(ASTEnumBody node, Object data) { - visitTypeBody(node, (SpanInfo) data); + public SpanInfo visit(ASTEnumBody node, SpanInfo data) { + visitTypeBody(node, data); return data; // type doesn't contribute anything to the enclosing control flow } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseCollectionIsEmptyRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseCollectionIsEmptyRule.java index 552d1116a7..190e51c20a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseCollectionIsEmptyRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseCollectionIsEmptyRule.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.rule.bestpractices; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -25,6 +26,7 @@ import net.sourceforge.pmd.lang.java.rule.AbstractInefficientZeroCheck; import net.sourceforge.pmd.lang.java.symboltable.ClassScope; import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration; +import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; import net.sourceforge.pmd.util.CollectionUtil; @@ -87,8 +89,7 @@ public class UseCollectionIsEmptyRule extends AbstractInefficientZeroCheck { if (calledOnType == null) { calledOnType = getTypeOfMethodCall(primarySuffix); } - return calledOnType != null - && CollectionUtil.isCollectionType(calledOnType.getType(), true); + return calledOnType != null && TypeHelper.isA(calledOnType, Collection.class); } private ASTClassOrInterfaceType getTypeOfVariable(ASTPrimarySuffix primarySuffix) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/LinguisticNamingRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/LinguisticNamingRule.java index 680e632522..ada158763e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/LinguisticNamingRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/LinguisticNamingRule.java @@ -18,11 +18,10 @@ import org.apache.commons.lang3.StringUtils; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTResultType; import net.sourceforge.pmd.lang.java.ast.ASTType; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; import net.sourceforge.pmd.lang.java.rule.AbstractIgnoredAnnotationRule; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.properties.PropertyDescriptor; public class LinguisticNamingRule extends AbstractIgnoredAnnotationRule { @@ -107,10 +106,9 @@ public class LinguisticNamingRule extends AbstractIgnoredAnnotationRule { } private void checkPrefixedTransformMethods(ASTMethodDeclaration node, Object data, String nameOfMethod) { - ASTResultType resultType = node.getResultType(); List prefixes = getProperty(TRANSFORM_METHOD_NAMES_PROPERTY); String[] splitMethodName = StringUtils.splitByCharacterTypeCamelCase(nameOfMethod); - if (resultType.isVoid() && splitMethodName.length > 0 + if (node.isVoid() && splitMethodName.length > 0 && prefixes.contains(splitMethodName[0].toLowerCase(Locale.ROOT))) { // "To" or any other configured prefix found addViolationWithMessage(data, node, "Linguistics Antipattern - The transform method ''{0}'' should not return void linguistically", @@ -119,10 +117,9 @@ public class LinguisticNamingRule extends AbstractIgnoredAnnotationRule { } private void checkTransformMethods(ASTMethodDeclaration node, Object data, String nameOfMethod) { - ASTResultType resultType = node.getResultType(); List infixes = getProperty(TRANSFORM_METHOD_NAMES_PROPERTY); for (String infix : infixes) { - if (resultType.isVoid() && containsWord(nameOfMethod, StringUtils.capitalize(infix))) { + if (node.isVoid() && containsWord(nameOfMethod, StringUtils.capitalize(infix))) { // "To" or any other configured infix in the middle somewhere addViolationWithMessage(data, node, "Linguistics Antipattern - The transform method ''{0}'' should not return void linguistically", new Object[] { nameOfMethod }); @@ -133,16 +130,14 @@ public class LinguisticNamingRule extends AbstractIgnoredAnnotationRule { } private void checkGetters(ASTMethodDeclaration node, Object data, String nameOfMethod) { - ASTResultType resultType = node.getResultType(); - if (hasPrefix(nameOfMethod, "get") && resultType.isVoid()) { + if (hasPrefix(nameOfMethod, "get") && node.isVoid()) { addViolationWithMessage(data, node, "Linguistics Antipattern - The getter ''{0}'' should not return void linguistically", new Object[] { nameOfMethod }); } } private void checkSetters(ASTMethodDeclaration node, Object data, String nameOfMethod) { - ASTResultType resultType = node.getResultType(); - if (hasPrefix(nameOfMethod, "set") && !resultType.isVoid()) { + if (hasPrefix(nameOfMethod, "set") && !node.isVoid()) { addViolationWithMessage(data, node, "Linguistics Antipattern - The setter ''{0}'' should not return any type except void linguistically", new Object[] { nameOfMethod }); } @@ -150,14 +145,13 @@ public class LinguisticNamingRule extends AbstractIgnoredAnnotationRule { private boolean isBooleanType(ASTType node) { return "boolean".equalsIgnoreCase(node.getTypeImage()) - || TypeHelper.isA(node, "java.util.concurrent.atomic.AtomicBoolean") - || TypeHelper.isA(node, "java.util.function.Predicate"); + || TypeTestUtil.isA("java.util.concurrent.atomic.AtomicBoolean", node) + || TypeTestUtil.isA("java.util.function.Predicate", node); } private void checkBooleanMethods(ASTMethodDeclaration node, Object data, String nameOfMethod) { - ASTResultType resultType = node.getResultType(); - ASTType t = node.getResultType().getFirstChildOfType(ASTType.class); - if (!resultType.isVoid() && t != null) { + ASTType t = node.getResultTypeNode(); + if (!t.isVoid()) { for (String prefix : getProperty(BOOLEAN_METHOD_PREFIXES_PROPERTY)) { if (hasPrefix(nameOfMethod, prefix) && !isBooleanType(t)) { addViolationWithMessage(data, node, "Linguistics Antipattern - The method ''{0}'' indicates linguistically it returns a boolean, but it returns ''{1}''", @@ -187,7 +181,7 @@ public class LinguisticNamingRule extends AbstractIgnoredAnnotationRule { @Override public Object visit(ASTFieldDeclaration node, Object data) { - ASTType type = node.getFirstChildOfType(ASTType.class); + ASTType type = node.getTypeNode(); if (type != null && getProperty(CHECK_FIELDS)) { List fields = node.findChildrenOfType(ASTVariableDeclarator.class); for (ASTVariableDeclarator field : fields) { @@ -199,7 +193,7 @@ public class LinguisticNamingRule extends AbstractIgnoredAnnotationRule { @Override public Object visit(ASTLocalVariableDeclaration node, Object data) { - ASTType type = node.getFirstChildOfType(ASTType.class); + ASTType type = node.getTypeNode(); if (type != null && getProperty(CHECK_VARIABLES)) { List variables = node.findChildrenOfType(ASTVariableDeclarator.class); for (ASTVariableDeclarator variable : variables) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java index 03aaf0cd37..f921900586 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java @@ -13,11 +13,10 @@ import java.util.regex.Pattern; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.JavaNode; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.properties.PropertyBuilder.RegexPropertyBuilder; import net.sourceforge.pmd.properties.PropertyDescriptor; @@ -64,9 +63,7 @@ public class MethodNamingConventionsRule extends AbstractNamingConventionRule types = collectionType.findDescendantsOfType(ASTClassOrInterfaceType.class); if (types.size() >= 2) { return types.get(1); // the value type of the map diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryReturnRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryReturnRule.java index 61d4a17df7..7842ba466e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryReturnRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryReturnRule.java @@ -16,7 +16,7 @@ public class UnnecessaryReturnRule extends AbstractJavaRule { @Override public Object visit(ASTMethodDeclaration node, Object data) { - if (node.getResultType().isVoid()) { + if (node.isVoid()) { super.visit(node, data); } return data; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityRule.java index 98c5d78a4e..97c3db3541 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityRule.java @@ -64,9 +64,9 @@ public class SwitchDensityRule extends AbstractJavaRulechainRule { @Override - public Object visit(ASTStatement statement, Object data) { + public Object visitStatement(ASTStatement statement, Object data) { stmts++; - return super.visit(statement, data); + return super.visitStatement(statement, data); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentSizeRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentSizeRule.java index 4f27e3ee66..eeb80497cd 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentSizeRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentSizeRule.java @@ -5,9 +5,11 @@ package net.sourceforge.pmd.lang.java.rule.documentation; import static net.sourceforge.pmd.properties.constraints.NumericConstraints.positive; +import static net.sourceforge.pmd.util.CollectionUtil.setOf; import java.util.ArrayList; import java.util.List; +import java.util.Set; import org.apache.commons.lang3.StringUtils; @@ -36,6 +38,8 @@ public class CommentSizeRule extends AbstractCommentRule { private static final String CR = "\n"; + static final Set IGNORED_LINES = setOf("//", "/*", "/**", "*", "*/"); + public CommentSizeRule() { definePropertyDescriptor(MAX_LINES); definePropertyDescriptor(MAX_LINE_LENGTH); @@ -47,7 +51,7 @@ public class CommentSizeRule extends AbstractCommentRule { return false; } - return !StringUtil.isAnyOf(line.trim(), "//", "/*", "/**", "*", "*/"); + return !IGNORED_LINES.contains(line.trim()); } private boolean hasTooManyLines(Comment comment) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CheckSkipResultRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CheckSkipResultRule.java index d71365d0c4..112abecbf4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CheckSkipResultRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CheckSkipResultRule.java @@ -11,19 +11,17 @@ import net.sourceforge.pmd.lang.java.ast.ASTExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; -import net.sourceforge.pmd.lang.java.ast.ASTType; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; public class CheckSkipResultRule extends AbstractJavaRule { @Override public Object visit(ASTVariableDeclaratorId node, Object data) { - ASTType typeNode = node.getTypeNode(); - if (typeNode == null || !TypeHelper.isA(typeNode, InputStream.class)) { + if (!TypeTestUtil.isA(InputStream.class, node.getTypeNode())) { return data; } for (NameOccurrence occ : node.getUsages()) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java index 6cc9cd5840..f8d486ea9e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java @@ -14,8 +14,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.jaxen.JaxenException; - import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; @@ -45,7 +43,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.TypeNode; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.properties.PropertyDescriptor; /** @@ -288,7 +286,7 @@ public class CloseResourceRule extends AbstractJavaRule { for (String type : allowedResourceTypes) { // the check here must be a exact type match, since subclasses may override close() // and actually require closing - if (TypeHelper.isExactlyA(refType, type)) { + if (TypeTestUtil.isExactlyA(type, refType)) { return true; } } @@ -340,7 +338,7 @@ public class CloseResourceRule extends AbstractJavaRule { private boolean isNodeInstanceOfResourceType(TypeNode refType) { for (String resType : types) { - if (TypeHelper.isA(refType, resType)) { + if (TypeTestUtil.isA(resType, refType)) { return true; } } @@ -517,15 +515,11 @@ public class CloseResourceRule extends AbstractJavaRule { private boolean isNotConditional(ASTBlock enclosingBlock, Node node, String varName) { ASTIfStatement ifStatement = findIfStatement(enclosingBlock, node); if (ifStatement != null) { - try { - // find expressions like: varName != null or null != varName - List nodes = ifStatement.findChildNodesWithXPath("Expression/EqualityExpression[@Image='!=']" - + " [PrimaryExpression/PrimaryPrefix/Name[@Image='" + varName + "']]" - + " [PrimaryExpression/PrimaryPrefix/Literal/NullLiteral]"); - return !nodes.isEmpty(); - } catch (JaxenException e) { - throw new RuntimeException(e); - } + // find expressions like: varName != null or null != varName + List nodes = ifStatement.findChildNodesWithXPath("Expression/EqualityExpression[@Image='!=']" + + " [PrimaryExpression/PrimaryPrefix/Name[@Image='" + varName + "']]" + + " [PrimaryExpression/PrimaryPrefix/Literal/NullLiteral]"); + return !nodes.isEmpty(); } return true; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidLogMessageFormatRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidLogMessageFormatRule.java index 213feaa27c..8aaf815617 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidLogMessageFormatRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/InvalidLogMessageFormatRule.java @@ -38,7 +38,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.lang.symboltable.NameDeclaration; public class InvalidLogMessageFormatRule extends AbstractJavaRule { @@ -130,14 +130,12 @@ public class InvalidLogMessageFormatRule extends AbstractJavaRule { private boolean isNewThrowable(ASTPrimaryExpression last) { // in case a new exception is created or the exception class is // mentioned. - ASTClassOrInterfaceType classOrInterface = last.getFirstDescendantOfType(ASTClassOrInterfaceType.class); - return classOrInterface != null && classOrInterface.getType() != null - && TypeHelper.isA(classOrInterface, Throwable.class); + return TypeTestUtil.isA(Throwable.class, last.getFirstDescendantOfType(ASTClassOrInterfaceType.class)); } private boolean hasTypeThrowable(ASTPrimaryExpression last) { // if the type could be determined already - return last.getType() != null && TypeHelper.isA(last, Throwable.class); + return last.getType() != null && TypeTestUtil.isA(Throwable.class, last); } private boolean isReferencingThrowable(ASTPrimaryExpression last) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/MoreThanOneLoggerRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/MoreThanOneLoggerRule.java index 4a12afe969..957e19f70c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/MoreThanOneLoggerRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/MoreThanOneLoggerRule.java @@ -16,8 +16,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTType; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; -import net.sourceforge.pmd.util.NumericConstants; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; public class MoreThanOneLoggerRule extends AbstractJavaRule { @@ -47,7 +46,7 @@ public class MoreThanOneLoggerRule extends AbstractJavaRule { private Object init(JavaNode node, Object data) { stack.push(count); - count = NumericConstants.ZERO; + count = 0; node.children().forEach(it -> it.acceptVisitor(this, data)); @@ -70,13 +69,12 @@ public class MoreThanOneLoggerRule extends AbstractJavaRule { if (reftypeNode instanceof ASTReferenceType) { Node classOrIntType = reftypeNode.getChild(0); if (classOrIntType instanceof ASTClassOrInterfaceType) { - Class clazzType = ((ASTClassOrInterfaceType) classOrIntType).getType(); - if (clazzType != null - && (TypeHelper.isA((ASTClassOrInterfaceType) classOrIntType, LOG4J_LOGGER_NAME) - || TypeHelper.isA((ASTClassOrInterfaceType) classOrIntType, LOG4J2_LOGGER_NAME) - || TypeHelper.isA((ASTClassOrInterfaceType) classOrIntType, JAVA_LOGGER_NAME) - || TypeHelper.isA((ASTClassOrInterfaceType) classOrIntType, SLF4J_LOGGER_NAME)) - || clazzType == null && "Logger".equals(classOrIntType.getImage())) { + ASTClassOrInterfaceType classType = (ASTClassOrInterfaceType) classOrIntType; + if (TypeTestUtil.isA(LOG4J_LOGGER_NAME, classType) + || TypeTestUtil.isA(LOG4J2_LOGGER_NAME, classType) + || TypeTestUtil.isA(JAVA_LOGGER_NAME, classType) + || TypeTestUtil.isA(SLF4J_LOGGER_NAME, classType) + || "Logger".equals(classOrIntType.getImage())) { ++count; } } 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 d1e059c61d..c6f354e92d 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 @@ -27,7 +27,7 @@ public class SingletonClassReturningNewInstanceRule extends AbstractJavaRule { String localVarName = null; String returnVariableName = null; - if (node.getResultType().isVoid()) { + if (node.isVoid()) { return super.visit(node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AbstractJavaCounterCheckRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AbstractJavaCounterCheckRule.java index bb53d162a5..d9a741004f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AbstractJavaCounterCheckRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/AbstractJavaCounterCheckRule.java @@ -46,7 +46,7 @@ public abstract class AbstractJavaCounterCheckRule extends A @Override - public Object visit(JavaNode node, Object data) { + public Object visitJavaNode(JavaNode node, Object data) { @SuppressWarnings("unchecked") T t = (T) node; // since we only visit this node, it's ok diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticFormatterRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticFormatterRule.java index 09d643f167..414d547b90 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticFormatterRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticFormatterRule.java @@ -17,7 +17,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; @@ -60,13 +60,13 @@ public class UnsynchronizedStaticFormatterRule extends AbstractJavaRule { return data; } ASTClassOrInterfaceType cit = node.getFirstDescendantOfType(ASTClassOrInterfaceType.class); - if (cit == null || !TypeHelper.isA(cit, formatterClassToCheck)) { + if (cit == null || !TypeTestUtil.isA(formatterClassToCheck, cit)) { return data; } ASTVariableDeclaratorId var = node.getFirstDescendantOfType(ASTVariableDeclaratorId.class); for (String formatter: THREAD_SAFE_FORMATTER) { - if (TypeHelper.isA(var, formatter)) { + if (TypeTestUtil.isA(formatter, var)) { return data; } } @@ -83,7 +83,7 @@ public class UnsynchronizedStaticFormatterRule extends AbstractJavaRule { ASTExpression expression = syncStatement.getFirstChildOfType(ASTExpression.class); if (expression != null) { ASTName name = expression.getFirstDescendantOfType(ASTName.class); - if (name != null && name.hasImageEqualTo(var.getVariableName())) { + if (name != null && name.hasImageEqualTo(var.getName())) { continue; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidInstantiatingObjectsInLoopsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidInstantiatingObjectsInLoopsRule.java index 1ffe5fa6e9..d4200d3831 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidInstantiatingObjectsInLoopsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidInstantiatingObjectsInLoopsRule.java @@ -22,7 +22,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement; import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; public class AvoidInstantiatingObjectsInLoopsRule extends AbstractJavaRule { @@ -65,7 +65,7 @@ public class AvoidInstantiatingObjectsInLoopsRule extends AbstractJavaRule { private boolean notCollectionAccess(ASTAllocationExpression node) { if (node.getNthParent(4) instanceof ASTArgumentList && node.getNthParent(8) instanceof ASTStatementExpression) { ASTStatementExpression statement = (ASTStatementExpression) node.getNthParent(8); - return !TypeHelper.isA(statement, Collection.class); + return !TypeTestUtil.isA(Collection.class, statement); } return true; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BigIntegerInstantiationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BigIntegerInstantiationRule.java index f0a4d7ddda..b2627c00b8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BigIntegerInstantiationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BigIntegerInstantiationRule.java @@ -17,7 +17,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTLiteral; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; /** * Rule that marks instantiations of new {@link BigInteger} or @@ -36,8 +36,8 @@ public class BigIntegerInstantiationRule extends AbstractJavaRule { boolean jdk15 = ((RuleContext) data).getLanguageVersion() .compareTo(LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5")) >= 0; - if ((TypeHelper.isA((ASTClassOrInterfaceType) type, BigInteger.class) - || jdk15 && TypeHelper.isA((ASTClassOrInterfaceType) type, BigDecimal.class)) + if ((TypeTestUtil.isA(BigInteger.class, (ASTClassOrInterfaceType) type) + || jdk15 && TypeTestUtil.isA(BigDecimal.class, (ASTClassOrInterfaceType) type)) && !node.hasDescendantOfType(ASTArrayDimsAndInits.class)) { ASTArguments args = node.getFirstChildOfType(ASTArguments.class); if (args.size() == 1) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BooleanInstantiationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BooleanInstantiationRule.java index b7aea0411d..b8b345c071 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BooleanInstantiationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BooleanInstantiationRule.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.java.rule.performance; -import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits; import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; @@ -17,7 +16,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; /** * Avoid instantiating Boolean objects; you can reference Boolean.TRUE, @@ -67,8 +66,8 @@ public class BooleanInstantiationRule extends AbstractJavaRule { return super.visit(node, data); } - Node n1 = node.getFirstChildOfType(ASTClassOrInterfaceType.class); - if (TypeHelper.isA((ASTClassOrInterfaceType) n1, Boolean.class)) { + ASTClassOrInterfaceType n1 = node.getFirstChildOfType(ASTClassOrInterfaceType.class); + if (TypeTestUtil.isA(Boolean.class, n1)) { super.addViolation(data, node); return data; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveAppendsShouldReuseRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveAppendsShouldReuseRule.java index 8833215f67..26172c63a8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveAppendsShouldReuseRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveAppendsShouldReuseRule.java @@ -21,7 +21,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; public class ConsecutiveAppendsShouldReuseRule extends AbstractJavaRule { @@ -129,7 +128,7 @@ public class ConsecutiveAppendsShouldReuseRule extends AbstractJavaRule { Map> declarations = node.getScope() .getDeclarations(VariableNameDeclaration.class); for (VariableNameDeclaration decl : declarations.keySet()) { - if (decl.getName().equals(name) && TypeHelper.isExactlyAny(decl, StringBuilder.class, StringBuffer.class)) { + if (decl.getName().equals(name) && ConsecutiveLiteralAppendsRule.isStringBuilderOrBuffer(decl.getDeclaratorId())) { return true; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveLiteralAppendsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveLiteralAppendsRule.java index a84c498d76..258d524068 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveLiteralAppendsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/ConsecutiveLiteralAppendsRule.java @@ -36,7 +36,7 @@ import net.sourceforge.pmd.lang.java.ast.TypeNode; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; @@ -259,7 +259,7 @@ public class ConsecutiveLiteralAppendsRule extends AbstractJavaRule { private int processAdditive(Object data, int concurrentCount, Node sn, Node rootNode) { ASTAdditiveExpression additive = sn.getFirstDescendantOfType(ASTAdditiveExpression.class); // The additive expression must of be type String to count - if (additive == null || additive.getType() != null && !TypeHelper.isA(additive, String.class)) { + if (additive == null || additive.getType() != null && !TypeTestUtil.isA(String.class, additive)) { return 0; } // check for at least one string literal @@ -396,14 +396,8 @@ public class ConsecutiveLiteralAppendsRule extends AbstractJavaRule { return n instanceof ASTLiteral; } - private static boolean isStringBuilderOrBuffer(ASTVariableDeclaratorId node) { - if (node.getType() != null) { - return TypeHelper.isEither(node, StringBuffer.class, StringBuilder.class); - } - Node nn = node.getTypeNameNode(); - if (nn == null || nn.getNumChildren() == 0) { - return false; - } - return TypeHelper.isEither((TypeNode) nn.getChild(0), StringBuffer.class, StringBuilder.class); + static boolean isStringBuilderOrBuffer(TypeNode node) { + return TypeTestUtil.isA(StringBuffer.class, node) + || TypeTestUtil.isA(StringBuilder.class, node); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InefficientStringBufferingRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InefficientStringBufferingRule.java index 3850e21101..cf832d2882 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InefficientStringBufferingRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InefficientStringBufferingRule.java @@ -27,9 +27,8 @@ import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; import net.sourceforge.pmd.lang.java.ast.ASTType; import net.sourceforge.pmd.lang.java.ast.AccessNode; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.TypedNameDeclaration; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; /** * How this rule works: find additive expressions: + check that the addition is @@ -128,10 +127,7 @@ public class InefficientStringBufferingRule extends AbstractJavaRule { if (type != null) { List types = type.findDescendantsOfType(ASTClassOrInterfaceType.class); if (!types.isEmpty()) { - ASTClassOrInterfaceType typeDeclaration = types.get(0); - if (TypeHelper.isA(typeDeclaration, String.class)) { - return true; - } + return TypeTestUtil.isA(String.class, types.get(0)); } } return false; @@ -186,7 +182,7 @@ public class InefficientStringBufferingRule extends AbstractJavaRule { } ASTName n = s.getFirstDescendantOfType(ASTName.class); if (n == null || n.getImage().indexOf(methodName) == -1 - || !(n.getNameDeclaration() instanceof TypedNameDeclaration)) { + || !(n.getNameDeclaration() instanceof VariableNameDeclaration)) { return false; } @@ -198,8 +194,7 @@ public class InefficientStringBufferingRule extends AbstractJavaRule { if (argList == null || argList.getNumChildren() > 1) { return false; } - return TypeHelper.isExactlyAny((TypedNameDeclaration) n.getNameDeclaration(), StringBuffer.class, - StringBuilder.class); + return ConsecutiveLiteralAppendsRule.isStringBuilderOrBuffer(((VariableNameDeclaration) n.getNameDeclaration()).getDeclaratorId()); } private boolean isAllocatedStringBuffer(ASTAdditiveExpression node) { @@ -210,7 +205,7 @@ public class InefficientStringBufferingRule extends AbstractJavaRule { // note that the child can be an ArrayDimsAndInits, for example, from // java.lang.FloatingDecimal: t = new int[ nWords+wordcount+1 ]; ASTClassOrInterfaceType an = ao.getFirstChildOfType(ASTClassOrInterfaceType.class); - return an != null && TypeHelper.isEither(an, StringBuffer.class, StringBuilder.class); + return ConsecutiveLiteralAppendsRule.isStringBuilderOrBuffer(an); } private static class MethodCallChain { @@ -226,12 +221,12 @@ public class InefficientStringBufferingRule extends AbstractJavaRule { boolean isExactlyOfAnyType(Class clazz, Class ... clazzes) { ASTPrimaryPrefix typeNode = getTypeNode(); - if (TypeHelper.isExactlyA(typeNode, clazz.getName())) { + if (TypeTestUtil.isExactlyA(clazz, typeNode)) { return true; } if (clazzes != null) { for (Class c : clazzes) { - if (TypeHelper.isExactlyA(typeNode, c.getName())) { + if (TypeTestUtil.isExactlyA(c, typeNode)) { return true; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InsufficientStringBufferDeclarationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InsufficientStringBufferDeclarationRule.java index c0f9c8d4af..3aeeffa35a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InsufficientStringBufferDeclarationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InsufficientStringBufferDeclarationRule.java @@ -31,7 +31,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; /** @@ -56,7 +55,7 @@ public class InsufficientStringBufferDeclarationRule extends AbstractJavaRule { @Override public Object visit(ASTVariableDeclaratorId node, Object data) { if (node.getNameDeclaration() == null - || !TypeHelper.isExactlyAny(node.getNameDeclaration(), StringBuffer.class, StringBuilder.class)) { + || !ConsecutiveLiteralAppendsRule.isStringBuilderOrBuffer(node)) { return data; } Node rootNode = node; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringInstantiationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringInstantiationRule.java index 5e4092faad..57a3b8569c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringInstantiationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringInstantiationRule.java @@ -21,7 +21,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.TypedNameDeclaration; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.lang.symboltable.NameDeclaration; public class StringInstantiationRule extends AbstractJavaRule { @@ -36,7 +36,7 @@ public class StringInstantiationRule extends AbstractJavaRule { return data; } - if (!TypeHelper.isA((ASTClassOrInterfaceType) node.getChild(0), String.class)) { + if (!TypeTestUtil.isA(String.class, (ASTClassOrInterfaceType) node.getChild(0))) { return data; } @@ -62,11 +62,11 @@ public class StringInstantiationRule extends AbstractJavaRule { } NameDeclaration nd = name.getNameDeclaration(); - if (nd == null) { + if (!(nd instanceof TypedNameDeclaration)) { return data; } - if (nd instanceof TypedNameDeclaration && TypeHelper.isExactlyAny((TypedNameDeclaration) nd, String.class)) { + if (TypeTestUtil.isA(String.class, ((TypedNameDeclaration) nd).getTypeNode())) { addViolation(data, node); } return data; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringToStringRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringToStringRule.java index c716a2f42f..5696823728 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringToStringRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/StringToStringRule.java @@ -8,7 +8,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import net.sourceforge.pmd.lang.java.ast.ASTMethodCall; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.lang.rule.RuleTargetSelector; /** @@ -56,10 +56,9 @@ public class StringToStringRule extends AbstractJavaRule { @Override public Object visit(ASTMethodCall node, Object data) { if ("toString".equals(node.getMethodName()) - && node.getArguments().size() == 0) { - if (TypeHelper.symbolEquals(String.class, node.getQualifier())) { - addViolation(data, node); - } + && node.getArguments().size() == 0 + && TypeTestUtil.symbolEquals(String.class, node.getQualifier())) { + addViolation(data, node); } return data; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferForStringAppendsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferForStringAppendsRule.java index d06b4ad1c6..ac91f98e46 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferForStringAppendsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferForStringAppendsRule.java @@ -21,7 +21,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; public class UseStringBufferForStringAppendsRule extends AbstractJavaRule { @@ -38,7 +38,7 @@ public class UseStringBufferForStringAppendsRule extends AbstractJavaRule { */ @Override public Object visit(ASTVariableDeclaratorId node, Object data) { - if (!TypeHelper.isA(node, String.class) || node.hasArrayType() + if (!TypeTestUtil.isA(String.class, node) || node.hasArrayType() || node.getNthParent(3) instanceof ASTForStatement) { return data; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferLengthRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferLengthRule.java index 54bfa716eb..7b449d59d7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferLengthRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UseStringBufferLengthRule.java @@ -14,8 +14,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTLiteral; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.symboltable.TypedNameDeclaration; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; import net.sourceforge.pmd.lang.symboltable.NameDeclaration; /** @@ -63,8 +62,8 @@ public class UseStringBufferLengthRule extends AbstractJavaRule { if (nd == null) { return data; } - if (alreadySeen.contains(nd) || !(nd instanceof TypedNameDeclaration) || nd instanceof TypedNameDeclaration - && TypeHelper.isExactlyNone((TypedNameDeclaration) nd, StringBuffer.class, StringBuilder.class)) { + if (alreadySeen.contains(nd) || !(nd instanceof VariableNameDeclaration) + || !ConsecutiveLiteralAppendsRule.isStringBuilderOrBuffer(((VariableNameDeclaration) nd).getDeclaratorId())) { return data; } alreadySeen.add(nd); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/security/HardCodedCryptoKeyRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/security/HardCodedCryptoKeyRule.java index d1b001af89..246478f989 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/security/HardCodedCryptoKeyRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/security/HardCodedCryptoKeyRule.java @@ -16,7 +16,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; /** * Finds hard coded encryption keys that are passed to @@ -35,8 +35,7 @@ public class HardCodedCryptoKeyRule extends AbstractJavaRule { @Override public Object visit(ASTAllocationExpression node, Object data) { - ASTClassOrInterfaceType declClassName = node.getFirstChildOfType(ASTClassOrInterfaceType.class); - if (declClassName != null && TypeHelper.isA(declClassName, SECRET_KEY_SPEC)) { + if (TypeTestUtil.isA(SECRET_KEY_SPEC, node.getFirstChildOfType(ASTClassOrInterfaceType.class))) { Node firstArgument = null; ASTArguments arguments = node.getFirstChildOfType(ASTArguments.class); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/security/InsecureCryptoIvRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/security/InsecureCryptoIvRule.java index 0bffb60dec..7dbb8bde5c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/security/InsecureCryptoIvRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/security/InsecureCryptoIvRule.java @@ -16,7 +16,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; -import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; /** * Finds hardcoded static Initialization Vectors vectors used with cryptographic @@ -42,8 +42,7 @@ public class InsecureCryptoIvRule extends AbstractJavaRule { @Override public Object visit(ASTAllocationExpression node, Object data) { - ASTClassOrInterfaceType declClassName = node.getFirstChildOfType(ASTClassOrInterfaceType.class); - if (declClassName != null && TypeHelper.isA(declClassName, javax.crypto.spec.IvParameterSpec.class)) { + if (TypeTestUtil.isA(javax.crypto.spec.IvParameterSpec.class, node.getFirstChildOfType(ASTClassOrInterfaceType.class))) { Node firstArgument = null; ASTArguments arguments = node.getFirstChildOfType(ASTArguments.class); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/BaseJavaXPathFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/BaseJavaXPathFunction.java new file mode 100644 index 0000000000..be3096f6dd --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/BaseJavaXPathFunction.java @@ -0,0 +1,15 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.xpath.internal; + +import net.sourceforge.pmd.lang.java.JavaLanguageModule; +import net.sourceforge.pmd.lang.rule.xpath.impl.AbstractXPathFunctionDef; + +abstract class BaseJavaXPathFunction extends AbstractXPathFunctionDef { + + protected BaseJavaXPathFunction(String localName) { + super(localName, JavaLanguageModule.TERSE_NAME); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/GetCommentOnFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/GetCommentOnFunction.java new file mode 100644 index 0000000000..25eb1a7ec5 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/GetCommentOnFunction.java @@ -0,0 +1,80 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.xpath.internal; + +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.Comment; +import net.sourceforge.pmd.lang.rule.xpath.internal.AstElementNode; + +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.lib.ExtensionFunctionCall; +import net.sf.saxon.om.EmptyAtomicSequence; +import net.sf.saxon.om.Sequence; +import net.sf.saxon.value.SequenceType; +import net.sf.saxon.value.StringValue; + + +/** + * The XPath query "//VariableDeclarator[contains(getCommentOn(), + * '//password')]" will find all variables declared that are annotated with the + * password comment. + * + * @author Andy Throgmorton + */ +public class GetCommentOnFunction extends BaseJavaXPathFunction { + + + public static final GetCommentOnFunction INSTANCE = new GetCommentOnFunction(); + + protected GetCommentOnFunction() { + super("getCommentOn"); + } + + @Override + public SequenceType[] getArgumentTypes() { + return new SequenceType[0]; + } + + + @Override + public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { + return SequenceType.OPTIONAL_STRING; + } + + + @Override + public boolean dependsOnFocus() { + return true; + } + + + @Override + public ExtensionFunctionCall makeCallExpression() { + return new ExtensionFunctionCall() { + @Override + public Sequence call(XPathContext context, Sequence[] arguments) { + Node contextNode = ((AstElementNode) context.getContextItem()).getUnderlyingNode(); + + int codeBeginLine = contextNode.getBeginLine(); + int codeEndLine = contextNode.getEndLine(); + + List commentList = contextNode.getFirstParentOfType(ASTCompilationUnit.class).getComments(); + for (Comment comment : commentList) { + if (comment.getBeginLine() == codeBeginLine || comment.getEndLine() == codeEndLine) { + return new StringValue(comment.getImage()); + } + } + return EmptyAtomicSequence.INSTANCE; + } + + }; + } +} + + + 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/rule/xpath/internal/MetricFunction.java similarity index 58% rename from pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java rename to pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/MetricFunction.java index 03de85754d..6337d147ea 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/rule/xpath/internal/MetricFunction.java @@ -1,21 +1,14 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.java.xpath; +package net.sourceforge.pmd.lang.java.rule.xpath.internal; -import java.util.List; import java.util.Locale; import java.util.Map; import org.apache.commons.lang3.EnumUtils; -import org.jaxen.Context; -import org.jaxen.Function; -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; @@ -23,6 +16,16 @@ import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey; import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey; import net.sourceforge.pmd.lang.metrics.MetricKey; import net.sourceforge.pmd.lang.metrics.MetricsUtil; +import net.sourceforge.pmd.lang.rule.xpath.internal.AstElementNode; + +import net.sf.saxon.expr.Expression; +import net.sf.saxon.expr.StaticContext; +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.lib.ExtensionFunctionCall; +import net.sf.saxon.om.Sequence; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.value.BigDecimalValue; +import net.sf.saxon.value.SequenceType; /** @@ -34,54 +37,69 @@ import net.sourceforge.pmd.lang.metrics.MetricsUtil; * @author Clément Fournier * @since 6.0.0 */ -@InternalApi -@Deprecated -public class MetricFunction implements Function { +public final class MetricFunction extends BaseJavaXPathFunction { + public static final MetricFunction INSTANCE = new MetricFunction(); private static final Map CLASS_METRIC_KEY_MAP = EnumUtils.getEnumMap(JavaClassMetricKey.class); private static final Map OPERATION_METRIC_KEY_MAP = EnumUtils.getEnumMap(JavaOperationMetricKey.class); + private MetricFunction() { + super("metric"); + } @Override - public Object call(Context context, List args) throws FunctionCallException { - - if (args.isEmpty()) { - throw new IllegalArgumentException(badMetricKeyArgMessage()); - } - - if (!(args.get(0) instanceof String)) { - throw new IllegalArgumentException(badMetricKeyArgMessage()); - } - - String metricKeyName = (String) args.get(0); - Node n = (Node) context.getNodeSet().get(0); - - return getMetric(n, metricKeyName); + public SequenceType[] getArgumentTypes() { + return new SequenceType[]{SequenceType.SINGLE_STRING}; } - public static String badOperationMetricKeyMessage() { + @Override + public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { + return SequenceType.SINGLE_DECIMAL; + } + + + @Override + public boolean dependsOnFocus() { + return true; + } + + + @Override + public ExtensionFunctionCall makeCallExpression() { + return new ExtensionFunctionCall() { + @Override + public Expression rewrite(StaticContext context, Expression[] arguments) throws XPathException { + return super.rewrite(context, arguments); + } + + @Override + public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException { + Node contextNode = ((AstElementNode) context.getContextItem()).getUnderlyingNode(); + String metricKey = arguments[0].head().getStringValue(); + + return new BigDecimalValue(getMetric(contextNode, metricKey)); + } + }; + } + + + static String badOperationMetricKeyMessage() { return "This is not the name of an operation metric"; } - public static String badClassMetricKeyMessage() { + static String badClassMetricKeyMessage() { return "This is not the name of a class metric"; } - public static String genericBadNodeMessage() { + static String genericBadNodeMessage() { return "Incorrect node type: the 'metric' function cannot be applied"; } - - public static String badMetricKeyArgMessage() { - return "The 'metric' function expects the name of a metric key"; - } - - - public static double getMetric(Node n, String metricKeyName) { + private static double getMetric(Node n, String metricKeyName) { if (n instanceof ASTAnyTypeDeclaration) { return computeMetric(getClassMetricKey(metricKeyName), (ASTAnyTypeDeclaration) n); } else if (n instanceof MethodLikeNode) { @@ -113,10 +131,4 @@ public class MetricFunction implements Function { return OPERATION_METRIC_KEY_MAP.get(constantName); } - - public static void registerSelfInSimpleContext() { - ((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, - "metric", - new MetricFunction()); - } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/TypeIsFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/TypeIsFunction.java new file mode 100644 index 0000000000..a339bd4b43 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/xpath/internal/TypeIsFunction.java @@ -0,0 +1,75 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.xpath.internal; + +import java.util.function.BiPredicate; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.TypeNode; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; +import net.sourceforge.pmd.lang.rule.xpath.internal.AstElementNode; + +import net.sf.saxon.expr.XPathContext; +import net.sf.saxon.lib.ExtensionFunctionCall; +import net.sf.saxon.om.Sequence; +import net.sf.saxon.trans.XPathException; +import net.sf.saxon.value.BooleanValue; +import net.sf.saxon.value.SequenceType; + + +/** + * XPath function {@code pmd-java:typeIs(typeName as xs:string) as xs:boolean} + * and {@code typeIsExactly}. + * + *

    Example XPath 2.0: {@code //ClassOrInterfaceType[pmd-java:typeIs('java.lang.String')]} + * + *

    Returns true if the type of the node matches, false otherwise. + */ +public final class TypeIsFunction extends BaseJavaXPathFunction { + + public static final TypeIsFunction TYPE_IS_EXACTLY = new TypeIsFunction("typeIsExactly", TypeTestUtil::isExactlyA); + public static final TypeIsFunction TYPE_IS = new TypeIsFunction("typeIs", TypeTestUtil::isA); + + private final BiPredicate checker; + + private TypeIsFunction(String localName, BiPredicate checker) { + super(localName); + this.checker = checker; + } + + @Override + public SequenceType[] getArgumentTypes() { + return new SequenceType[] {SequenceType.SINGLE_STRING}; + } + + + @Override + public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { + return SequenceType.SINGLE_BOOLEAN; + } + + + @Override + public boolean dependsOnFocus() { + return true; + } + + @Override + public ExtensionFunctionCall makeCallExpression() { + return new ExtensionFunctionCall() { + @Override + public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException { + Node contextNode = ((AstElementNode) context.getContextItem()).getUnderlyingNode(); + String fullTypeName = arguments[0].head().getStringValue(); + + if (contextNode instanceof TypeNode) { + return BooleanValue.get(checker.test(fullTypeName, (TypeNode) contextNode)); + } else { + throw new IllegalArgumentException("typeIs function may only be called on a TypeNode."); + } + } + }; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java index fde1a1ab36..0cd9b3ba31 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java @@ -190,6 +190,11 @@ public interface JClassSymbol extends JTypeDeclSymbol, boolean isAnonymousClass(); + // todo isSealed + getPermittedSubclasses + // (isNonSealed is not so useful I think) + + // todo getEnumConstants + /** * This returns true if this is not an interface, primitive or array. */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/ast/AstSymbolMakerVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/ast/AstSymbolMakerVisitor.java index d141e537dd..96355c2a72 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/ast/AstSymbolMakerVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/ast/AstSymbolMakerVisitor.java @@ -19,7 +19,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.InternalApiBridge; -import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter; +import net.sourceforge.pmd.lang.java.ast.JavaVisitorBase; import net.sourceforge.pmd.lang.java.symbols.JClassSymbol; import net.sourceforge.pmd.lang.java.symbols.JTypeParameterOwnerSymbol; import net.sourceforge.pmd.lang.java.symbols.SymbolResolver; @@ -28,7 +28,7 @@ import net.sourceforge.pmd.lang.java.symbols.SymbolResolver; /** * Populates symbols on declaration nodes. Cannot be reused. */ -final class AstSymbolMakerVisitor extends JavaParserVisitorAdapter { +final class AstSymbolMakerVisitor extends JavaVisitorBase { private static final String NO_CANONICAL_NAME = ""; @@ -59,10 +59,10 @@ final class AstSymbolMakerVisitor extends JavaParserVisitorAdapter { } @Override - public Object visit(ASTVariableDeclaratorId node, Object data) { + public Void visit(ASTVariableDeclaratorId node, AstSymFactory data) { if (isTrueLocalVar(node)) { - ((AstSymFactory) data).setLocalVarSymbol(node); + data.setLocalVarSymbol(node); } else { // in the other cases, building the method/ctor/class symbols already set the symbols assert node.getSymbol() != null : "Symbol was null for " + node; @@ -80,11 +80,11 @@ final class AstSymbolMakerVisitor extends JavaParserVisitorAdapter { @Override - public Object visit(ASTAnyTypeDeclaration node, Object data) { + public Void visitTypeDecl(ASTAnyTypeDeclaration node, AstSymFactory data) { String binaryName = makeBinaryName(node); @Nullable String canonicalName = makeCanonicalName(node, binaryName); InternalApiBridge.setQname(node, binaryName, canonicalName); - JClassSymbol sym = ((AstSymFactory) data).setClassSymbol(enclosingSymbols.peek(), node); + JClassSymbol sym = data.setClassSymbol(enclosingSymbols.peek(), node); byBinaryName.put(binaryName, sym); if (canonicalName != null) { @@ -97,7 +97,7 @@ final class AstSymbolMakerVisitor extends JavaParserVisitorAdapter { anonymousCounters.push(new MutableInt(0)); currentLocalIndices.push(new HashMap<>()); - super.visit(node, data); + visitChildren(node, data); currentLocalIndices.pop(); anonymousCounters.pop(); @@ -143,9 +143,9 @@ final class AstSymbolMakerVisitor extends JavaParserVisitorAdapter { } @Override - public Object visit(ASTMethodOrConstructorDeclaration node, Object data) { + public Void visitMethodOrCtor(ASTMethodOrConstructorDeclaration node, AstSymFactory data) { enclosingSymbols.push(node.getSymbol()); - super.visit(node, data); + visitChildren(node, data); enclosingSymbols.pop(); return null; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/ast/SymbolResolutionPass.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/ast/SymbolResolutionPass.java index 78e374399a..0ec32aa675 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/ast/SymbolResolutionPass.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/ast/SymbolResolutionPass.java @@ -31,7 +31,7 @@ public final class SymbolResolutionPass { */ public static SymbolResolver traverse(JavaAstProcessor processor, ASTCompilationUnit root) { AstSymbolMakerVisitor visitor = new AstSymbolMakerVisitor(root); - root.jjtAccept(visitor, new AstSymFactory(processor.getTypeSystem())); + root.acceptVisitor(visitor, new AstSymFactory(processor.getTypeSystem())); return visitor.makeKnownSymbolResolver(); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SymbolTableResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SymbolTableResolver.java index afc19a39d3..c8af9b3080 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SymbolTableResolver.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SymbolTableResolver.java @@ -17,7 +17,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTAnonymousClassDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTBlock; import net.sourceforge.pmd.lang.java.ast.ASTCatchClause; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; @@ -161,7 +160,7 @@ public final class SymbolTableResolver { } @Override - public Void visit(ASTAnyTypeDeclaration node, Void data) { + public Void visitTypeDecl(ASTAnyTypeDeclaration node, Void data) { int pushed = 0; enclosingType.push(node); @@ -215,7 +214,7 @@ public final class SymbolTableResolver { @Override - public Void visit(ASTMethodOrConstructorDeclaration node, Void data) { + public Void visitMethodOrCtor(ASTMethodOrConstructorDeclaration node, Void data) { setTopSymbolTable(node.getModifiers()); int pushed = pushOnStack(f.bodyDeclaration(top(), enclosing(), node.getFormalParameters(), node.getTypeParameters())); setTopSymbolTableAndRecurse(node); @@ -284,7 +283,7 @@ public final class SymbolTableResolver { if (st instanceof ASTLocalVariableDeclaration) { pushed += pushOnStack(f.localVarSymTable(top(), enclosing(), ((ASTLocalVariableDeclaration) st).getVarIds())); } else if (st instanceof ASTLocalClassStatement) { - ASTClassOrInterfaceDeclaration local = ((ASTLocalClassStatement) st).getDeclaration(); + ASTAnyTypeDeclaration local = ((ASTLocalClassStatement) st).getDeclaration(); pushed += pushOnStack(f.localTypeSymTable(top(), local.getTypeMirror())); processTypeHeader(local); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/AbstractJavaScope.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/AbstractJavaScope.java index d93cf75f01..fafd311a95 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/AbstractJavaScope.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/AbstractJavaScope.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.symboltable; import java.util.Set; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.symboltable.AbstractScope; import net.sourceforge.pmd.lang.symboltable.NameDeclaration; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; @@ -15,6 +16,8 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence; * * @see JLS 6.3 */ +@Deprecated +@InternalApi public abstract class AbstractJavaScope extends AbstractScope { @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassNameDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassNameDeclaration.java index 28bf128809..4b54468e34 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassNameDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassNameDeclaration.java @@ -5,8 +5,10 @@ package net.sourceforge.pmd.lang.java.symboltable; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.ast.TypeNode; +import net.sourceforge.pmd.lang.java.ast.internal.PrettyPrintingUtil; import net.sourceforge.pmd.lang.symboltable.AbstractNameDeclaration; public class ClassNameDeclaration extends AbstractNameDeclaration implements TypedNameDeclaration { @@ -17,15 +19,10 @@ public class ClassNameDeclaration extends AbstractNameDeclaration implements Typ @Override public String toString() { - if (node instanceof ASTClassOrInterfaceDeclaration) { - if (((ASTClassOrInterfaceDeclaration) node).isInterface()) { - return "Interface " + node.getImage(); - } else { - return "Class " + node.getImage(); - } - } else { - return "Enum " + node.getImage(); + if (node instanceof ASTAnyTypeDeclaration) { + return PrettyPrintingUtil.kindName((ASTAnyTypeDeclaration) node) + node.getImage(); } + return "anonymous"; } public Node getAccessNodeParent() { @@ -34,11 +31,22 @@ public class ClassNameDeclaration extends AbstractNameDeclaration implements Typ @Override public String getTypeImage() { - return ((ASTClassOrInterfaceDeclaration) node).getImage(); + return getTypeNode().getImage(); } @Override public Class getType() { - return ((ASTClassOrInterfaceDeclaration) node).getType(); + if (node instanceof ASTAnyTypeDeclaration) { + return ((ASTAnyTypeDeclaration) node).getType(); + } + return null; + } + + /** + * Null for anonymous classes. + */ + @Override + public TypeNode getTypeNode() { + return node instanceof TypeNode ? (TypeNode) node : null; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/DeclarationFinderFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/DeclarationFinderFunction.java index b513294028..9dd5336959 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/DeclarationFinderFunction.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/DeclarationFinderFunction.java @@ -4,12 +4,16 @@ package net.sourceforge.pmd.lang.java.symboltable; +import java.util.function.Predicate; + +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.ast.ASTMethodReference; import net.sourceforge.pmd.lang.symboltable.NameDeclaration; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; -import net.sourceforge.pmd.util.SearchFunction; -public class DeclarationFinderFunction implements SearchFunction { +@Deprecated +@InternalApi +public class DeclarationFinderFunction implements Predicate { private NameOccurrence occurrence; private NameDeclaration decl; @@ -19,7 +23,7 @@ public class DeclarationFinderFunction implements SearchFunction getType(); + /** + * Nullable + */ + TypeNode getTypeNode(); + } 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 44711adab5..92dab519e6 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 @@ -32,8 +32,9 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements return getDeclaratorId().hasArrayType(); } + @Deprecated public int getArrayDepth() { - return getTypeNode().getArrayDepth(); + return getExplicitTypeNode().getArrayDepth(); } public boolean isVarargs() { @@ -58,12 +59,12 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements } public boolean isPrimitiveType() { - return getTypeNode().isPrimitiveType(); + return getExplicitTypeNode().isPrimitiveType(); } @Override public String getTypeImage() { - ASTType typeNode = getTypeNode(); + ASTType typeNode = getExplicitTypeNode(); if (typeNode != null) { return typeNode.getTypeImage(); } @@ -97,13 +98,18 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements return (ASTVariableDeclaratorId) node; } - private ASTType getTypeNode() { + @Override + public TypeNode getTypeNode() { + return getDeclaratorId(); + } + + private ASTType getExplicitTypeNode() { return getDeclaratorId().getTypeNode(); } @Override public Class getType() { - TypeNode typeNode = getTypeNode(); + TypeNode typeNode = getExplicitTypeNode(); if (typeNode != null) { return typeNode.getType(); } 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 2dc40cb472..85df38bc93 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 @@ -4,76 +4,24 @@ package net.sourceforge.pmd.lang.java.typeresolution; -import static net.sourceforge.pmd.util.CollectionUtil.any; - -import java.lang.reflect.Array; -import java.util.HashMap; -import java.util.Map; import java.util.Objects; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; - -import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; -import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; import net.sourceforge.pmd.lang.java.ast.TypeNode; +import net.sourceforge.pmd.lang.java.symbols.JClassSymbol; import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol; import net.sourceforge.pmd.lang.java.symboltable.TypedNameDeclaration; -import net.sourceforge.pmd.lang.java.typeresolution.internal.NullableClassLoader; -import net.sourceforge.pmd.lang.java.typeresolution.internal.NullableClassLoader.ClassLoaderWrapper; -import net.sourceforge.pmd.lang.java.types.JClassType; -import net.sourceforge.pmd.lang.java.types.JTypeMirror; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; +/** + * @deprecated Use the similar {@link TypeTestUtil} + */ +@Deprecated public final class TypeHelper { - /** Maps names of primitives to their corresponding primitive {@code Class}es. */ - private static final Map> PRIMITIVES_BY_NAME = new HashMap<>(); - - - static { - PRIMITIVES_BY_NAME.put("boolean", Boolean.TYPE); - PRIMITIVES_BY_NAME.put("byte", Byte.TYPE); - PRIMITIVES_BY_NAME.put("char", Character.TYPE); - PRIMITIVES_BY_NAME.put("short", Short.TYPE); - PRIMITIVES_BY_NAME.put("int", Integer.TYPE); - PRIMITIVES_BY_NAME.put("long", Long.TYPE); - PRIMITIVES_BY_NAME.put("double", Double.TYPE); - PRIMITIVES_BY_NAME.put("float", Float.TYPE); - PRIMITIVES_BY_NAME.put("void", Void.TYPE); - } - - private TypeHelper() { // utility class } - /** - * Returns true if the type of the given type node has the same symbol - * as the given class. This ignores type parameters and such. It is not - * equivalent to a subtyping check, unless {@code someClass} is final. - * Returns false if the node is null. - * - * @param someClass A class - * @param node A node - * - * @throws NullPointerException If the class is null - */ - public static boolean symbolEquals(@NonNull Class someClass, @Nullable TypeNode node) { - Objects.requireNonNull(someClass); - if (node == null) { - return false; - } - - JTypeDeclSymbol symbol = node.getTypeMirror().getSymbol(); - return symbol != null && symbol.equals(node.getTypeSystem().getClassSymbol(someClass)); - } - /** * Checks whether the resolved type of the given {@link TypeNode} n is of the type * given by the clazzName. If the clazzName is on the auxclasspath, then also subclasses @@ -86,81 +34,12 @@ public final class TypeHelper { * @param n the type node to check * @param clazzName the class name to compare to * @return true if type node n is of type clazzName or a subtype of clazzName + * @deprecated Use {@link TypeTestUtil#isA(Class, TypeNode)} */ + @Deprecated public static boolean isA(final TypeNode n, final String clazzName) { - if (n.getType() != null && n.getType().isAnnotation()) { - return isAnnotationSubtype(n.getType(), clazzName); - } - - final Class clazz = loadClassWithNodeClassloader(n, clazzName); - - if (clazz != null || n.getType() != null) { - return isA(n, clazz); - } - - // FIXME checking against the image is for the most part meaningless. - // Many type nodes don't have an image or have one that has no relation - // to their type. The TypeNode interface should have a method getTypeImage, - // or better, we could use symbols instead. - return fallbackIsA(n, clazzName); - } - - /** - * Returns true if the class n is a subtype of clazzName, given n - * is an annotationt type. - */ - private static boolean isAnnotationSubtype(Class n, String clazzName) { - assert n != null && n.isAnnotation() : "Not an annotation type"; - // then, the supertype may only be Object, j.l.Annotation, or the class name - // this avoids classloading altogether - // this is used e.g. by the typeIs function in XPath - return "java.lang.annotation.Annotation".equals(clazzName) - || "java.lang.Object".equals(clazzName) - || clazzName.equals(n.getName()); - } - - private static boolean fallbackIsA(final TypeNode n, String clazzName) { - // Later we won't need a fallback. Symbols already contain subclass information. - - if (n instanceof ASTAnyTypeDeclaration && ((ASTAnyTypeDeclaration) n).getBinaryName().equals(clazzName)) { - return true; - } else if (n instanceof ASTClassOrInterfaceType || n instanceof ASTAnnotation) { - ASTClassOrInterfaceType classType; - if (n instanceof ASTAnnotation) { - classType = ((ASTAnnotation) n).getTypeNode(); - } else { - classType = (ASTClassOrInterfaceType) n; - } - - JTypeMirror sym = classType.getTypeMirror(); - return sym instanceof JClassType && ((JClassType) sym).getSymbol().getBinaryName().equals(clazzName); - } - - if (n instanceof ASTClassOrInterfaceDeclaration) { - ASTClassOrInterfaceType superClass = ((ASTClassOrInterfaceDeclaration) n).getSuperClassTypeNode(); - if (superClass != null) { - return isA(superClass, clazzName); - } - - return any(((ASTClassOrInterfaceDeclaration) n).getSuperInterfaceTypeNodes(), itf -> isA(itf, clazzName)); - - } else if (n instanceof ASTEnumDeclaration) { - - if (any(((ASTEnumDeclaration) n).getSuperInterfaceTypeNodes(), itf -> isA(itf, clazzName))) { - return true; - } - - return "java.lang.Enum".equals(clazzName) - // supertypes of Enum - || "java.lang.Comparable".equals(clazzName) - || "java.io.Serializable".equals(clazzName) - || "java.lang.Object".equals(clazzName); - } else if (n instanceof ASTAnnotationTypeDeclaration) { - return "java.lang.annotation.Annotation".equals(clazzName) - || "java.lang.Object".equals(clazzName); - } - - return false; + Objects.requireNonNull(n); + return clazzName != null && TypeTestUtil.isA(clazzName, n); } /** @@ -170,116 +49,36 @@ public final class TypeHelper { * @param n the type node to check * @param clazzName the class name to compare to * @return true if type node n is exactly of type clazzName. - * - * @throws NullPointerException if n is null + * @deprecated Use {@link TypeTestUtil#isExactlyA(Class, TypeNode)} */ + @Deprecated public static boolean isExactlyA(final TypeNode n, final String clazzName) { - if (n.getType() != null && n.getType().getName().equals(clazzName)) { - // fast path avoiding classloading - return true; - } - - final Class clazz = loadClassWithNodeClassloader(n, clazzName); - - if (clazz != null) { - return n.getType() == clazz; - } - - return clazzName.equals(n.getImage()) || clazzName.endsWith("." + n.getImage()); - } - - private static Class loadClassWithNodeClassloader(final TypeNode n, final String clazzName) { - if (n.getType() != null) { - return loadClass(n.getRoot().getClassTypeResolver(), clazzName); - } - - return null; + Objects.requireNonNull(n); + return clazzName != null && TypeTestUtil.isExactlyA(clazzName, n); } /** - * Load a class. Supports loading array types like 'java.lang.String[]' and - * converting a canonical name to a binary name (eg 'java.util.Map.Entry' -> - * 'java.util.Map$Entry'). + * @deprecated Use {@link TypeTestUtil#isA(Class, TypeNode)} */ - // test only - static Class loadClass(NullableClassLoader ctr, String className) { - return loadClassMaybeArray(ctr, StringUtils.deleteWhitespace(className)); - } - - private static Class loadClassFromCanonicalName(NullableClassLoader ctr, String className) { - Class clazz = PRIMITIVES_BY_NAME.get(className); - if (clazz == null) { - clazz = ctr.loadClassOrNull(className); - } - if (clazz != null) { - return clazz; - } - // allow path separators (.) as inner class name separators - final int lastDotIndex = className.lastIndexOf('.'); - - if (lastDotIndex >= 0) { - String asInner = className.substring(0, lastDotIndex) - + '$' + className.substring(lastDotIndex + 1); - return loadClassFromCanonicalName(ctr, asInner); - } - return null; - } - - - private static Class loadClassMaybeArray(NullableClassLoader classLoader, - String className) { - Validate.notNull(className, "className must not be null."); - if (className.endsWith("[]")) { - int dimension = 0; - int i = className.length(); - while (i >= 2 && className.startsWith("[]", i - 2)) { - dimension++; - i -= 2; - } - - checkJavaIdent(className, i); - String elementName = className.substring(0, i); - - Class elementType = loadClassFromCanonicalName(classLoader, elementName); - if (elementType == null) { - return null; - } - - return Array.newInstance(elementType, (int[]) Array.newInstance(int.class, dimension)).getClass(); - } else { - checkJavaIdent(className, className.length()); - return loadClassFromCanonicalName(classLoader, className); - } - } - - private static IllegalArgumentException invalidClassName(String className) { - return new IllegalArgumentException("Not a valid class name \"" + className + "\""); - } - - private static void checkJavaIdent(String className, int endOffsetExclusive) { - if (endOffsetExclusive <= 0 || !Character.isJavaIdentifierStart(className.charAt(0))) { - throw invalidClassName(className); - } - - for (int i = 1; i < endOffsetExclusive; i++) { - char c = className.charAt(i); - if (!(Character.isJavaIdentifierPart(c) || c == '.')) { - throw invalidClassName(className); - } - } - } - - - /** @see #isA(TypeNode, String) */ + @Deprecated public static boolean isA(TypeNode n, Class clazz) { - return subclasses(n, clazz); + Objects.requireNonNull(n); + return clazz != null && TypeTestUtil.isA(clazz, n); } + /** + * @deprecated Not useful, use {@link TypeTestUtil#isA(Class, TypeNode)} + */ + @Deprecated public static boolean isEither(TypeNode n, Class class1, Class class2) { return subclasses(n, class1) || subclasses(n, class2); } + /** + * @deprecated Not useful, use {@link TypedNameDeclaration#getTypeNode()} and {@link TypeTestUtil#isExactlyA(Class, TypeNode)} + */ + @Deprecated public static boolean isExactlyAny(TypedNameDeclaration vnd, Class... clazzes) { Class type = vnd.getType(); for (final Class clazz : clazzes) { @@ -292,20 +91,25 @@ public final class TypeHelper { return false; } + /** + * @deprecated Not useful, use a negated {@link TypeTestUtil#isExactlyA(Class, TypeNode)} + */ + @Deprecated public static boolean isExactlyNone(TypedNameDeclaration vnd, Class... clazzes) { return !isExactlyAny(vnd, clazzes); } /** - * @deprecated use {@link #isExactlyAny(TypedNameDeclaration, Class...)} + * @deprecated use {@link TypeTestUtil#isA(Class, TypeNode) TypeTestUtil.isA(vnd.getTypeNode(), clazz)} */ @Deprecated public static boolean isA(TypedNameDeclaration vnd, Class clazz) { return isExactlyAny(vnd, clazz); } + /** - * @deprecated use {@link #isExactlyAny(TypedNameDeclaration, Class...)} + * @deprecated Not useful, use {@link TypeTestUtil#isA(Class, TypeNode)} */ @Deprecated public static boolean isEither(TypedNameDeclaration vnd, Class class1, Class class2) { @@ -313,32 +117,27 @@ public final class TypeHelper { } /** - * @deprecated use {@link #isExactlyNone(TypedNameDeclaration, Class...)} + * @deprecated Not useful, use a negated {@link TypeTestUtil#isA(Class, TypeNode)} */ @Deprecated public static boolean isNeither(TypedNameDeclaration vnd, Class class1, Class class2) { return !isA(vnd, class1) && !isA(vnd, class2); } + /** + * @deprecated Use {@link TypeTestUtil#isA(Class, TypeNode)} + */ + @Deprecated public static boolean subclasses(TypeNode n, Class clazz) { - Class type = n.getType(); - if (clazz == null) { - return false; // If in auxclasspath, both should be resolvable, or are not the same - } else if (type == null) { - return fallbackIsA(n, clazz.getName()); - } - - return clazz.isAssignableFrom(type); + Objects.requireNonNull(n); + return clazz != null && TypeTestUtil.isA(clazz, n); } + + /** + * @deprecated use {@link TypeTestUtil#isA(Class, TypeNode) TypeTestUtil.isA(vnd.getTypeNode(), className)} + */ public static boolean isA(TypedNameDeclaration vnd, String className) { - Class type = vnd.getType(); - if (type != null) { - Class clazz = loadClass(ClassLoaderWrapper.wrapNullable(type.getClassLoader()), className); - if (clazz != null) { - return clazz.isAssignableFrom(type); - } - } - return false; + return isA(vnd.getTypeNode(), className); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java index 3597ab88ca..e3fe30b2ac 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/visitors/PMDASMVisitor.java @@ -40,7 +40,7 @@ public class PMDASMVisitor extends ClassVisitor { public List innerClasses; public PMDASMVisitor(String outerName) { - super(Opcodes.ASM7); + super(Opcodes.ASM9); this.outerName = outerName; } @@ -181,7 +181,7 @@ public class PMDASMVisitor extends ClassVisitor { private PMDASMVisitor parent; PMDFieldVisitor(PMDASMVisitor visitor) { - super(Opcodes.ASM5); + super(Opcodes.ASM9); parent = visitor; } @@ -196,7 +196,7 @@ public class PMDASMVisitor extends ClassVisitor { private PMDASMVisitor parent; PMDAnnotationVisitor(PMDASMVisitor visitor) { - super(Opcodes.ASM5); + super(Opcodes.ASM9); parent = visitor; } @@ -228,7 +228,7 @@ public class PMDASMVisitor extends ClassVisitor { private PMDASMVisitor parent; PMDSignatureVisitor(PMDASMVisitor visitor) { - super(Opcodes.ASM5); + super(Opcodes.ASM9); this.parent = visitor; } @@ -292,7 +292,7 @@ public class PMDASMVisitor extends ClassVisitor { private PMDASMVisitor parent; PMDMethodVisitor(PMDASMVisitor visitor) { - super(Opcodes.ASM5); + super(Opcodes.ASM9); parent = visitor; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java new file mode 100644 index 0000000000..c7236db1e5 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java @@ -0,0 +1,308 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.types; + +import java.util.List; +import java.util.Objects; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.objectweb.asm.Opcodes; + +import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTImplementsList; +import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; +import net.sourceforge.pmd.lang.java.ast.TypeNode; +import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol; +import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; + +/** + * Public utilities to test the type of nodes. + * + *

    This replaces {@link TypeHelper}. Note that in constrast to methods + * in {@link TypeHelper}, these methods: + *

      + *
    • Take the node as the second parameter + *
    • Systematically return false if the node argument is null + *
    • Systematically throw if the other argument is null + *
    + */ +public final class TypeTestUtil { + + private TypeTestUtil() { + // utility class + } + + /** + * Returns true if the type of the given type node has the same symbol + * as the given class. This ignores type parameters and such. It is not + * equivalent to a subtyping check, unless {@code someClass} is final. + * Returns false if the node is null. + * + * @param someClass A class + * @param node A node + * + * @throws NullPointerException If the class is null + */ + @Deprecated + public static boolean symbolEquals(@NonNull Class someClass, @Nullable TypeNode node) { + Objects.requireNonNull(someClass); + if (node == null) { + return false; + } + + JTypeDeclSymbol symbol = node.getTypeMirror().getSymbol(); + return symbol != null && symbol.equals(node.getTypeSystem().getClassSymbol(someClass)); + } + + + /** + * Checks whether the static type of the node is a subtype of the + * class identified by the given name. This ignores type arguments, + * if the type of the node is parameterized. Examples: + * + *
    {@code
    +     * isA(()>, List.class)      = true
    +     * isA(()>, ArrayList.class) = true
    +     * isA(, int[].class)                  = true
    +     * isA(, Object[].class)            = true
    +     * isA(_, null) = false
    +     * isA(null, _) = NullPointerException
    +     * }
    + * + * @param clazz a class (non-null) + * @param node the type node to check + * + * @return true if the type test matches + * + * @throws NullPointerException if the class parameter is null + */ + public static boolean isA(/*@NonNull*/ Class clazz, /*@Nullable*/ TypeNode node) { + requireParamNotNull("class", clazz); + if (node == null) { + return false; + } else if (node.getType() == clazz) { + return true; + } + + return canBeExtended(clazz) ? isA(clazz.getName(), node) + : isExactlyA(clazz, node); + } + + + /** + * Checks whether the static type of the node is a subtype of the + * class identified by the given name. This ignores type arguments, + * if the type of the node is parameterized. Examples: + * + *
    {@code
    +     * isA(()>, "java.util.List")      = true
    +     * isA(()>, "java.util.ArrayList") = true
    +     * isA(, "int[]")                            = true
    +     * isA(, "java.lang.Object[]")            = true
    +     * isA(_, null) = false
    +     * isA(null, _) = NullPointerException
    +     * }
    + * + * @param canonicalName the canonical name of a class or array type (without whitespace) + * @param node the type node to check + * + * @return true if the type test matches + * + * @throws NullPointerException if the class name parameter is null + */ + public static boolean isA(/*@NonNull*/ String canonicalName, /*@Nullable*/ TypeNode node) { + requireParamNotNull("canonicalName", canonicalName); + if (node == null) { + return false; + } + + Class nodeType = node.getType(); + if (nodeType == null) { + return fallbackIsA(node, canonicalName, true); + } else if (nodeType.isAnnotation()) { + return isAnnotationSubtype(nodeType, canonicalName); + } + + final Class clazz = loadClassWithNodeClassloader(node, canonicalName); + + if (clazz != null) { + return clazz.isAssignableFrom(nodeType); + } else { + return fallbackIsA(node, canonicalName, true); + } + } + + + /** + * Checks whether the static type of the node is exactly the type + * of the class. This ignores strict supertypes, and type arguments, + * if the type of the node is parameterized. + * + *
    {@code
    +     * isExactlyA(List.class, ()>)      = false
    +     * isExactlyA(ArrayList.class, ()>) = true
    +     * isExactlyA(int[].class, )                  = true
    +     * isExactlyA(Object[].class, )            = false
    +     * isExactlyA(_, null) = false
    +     * isExactlyA(null, _) = NullPointerException
    +     * }
    + * + * @param clazz a class (non-null) + * @param node the type node to check + * + * @return true if the node is non-null and has the given type + * + * @throws NullPointerException if the class parameter is null + */ + public static boolean isExactlyA(/*@NonNull*/ Class clazz, /*@Nullable*/ TypeNode node) { + requireParamNotNull("class", clazz); + if (node == null) { + return false; + } + + return node.getType() == null ? fallbackIsA(node, clazz.getName(), false) + : node.getType() == clazz; + } + + + /** + * Checks whether the static type of the node is exactly the type + * given by the name. This ignores strict supertypes, and type arguments + * if the type of the node is parameterized. + * + *
    {@code
    +     * isExactlyA(()>, List.class)      = false
    +     * isExactlyA(()>, ArrayList.class) = true
    +     * isExactlyA(, int[].class)                  = true
    +     * isExactlyA(, Object[].class)            = false
    +     * isExactlyA(_, null) = false
    +     * isExactlyA(null, _) = NullPointerException
    +     * }
    + * + * @param canonicalName a canonical name of a class or array type + * @param node the type node to check + * + * @return true if the node is non-null and has the given type + * + * @throws NullPointerException if the class name parameter is null + */ + public static boolean isExactlyA(/*@Nullable*/ String canonicalName, TypeNode node /*@NonNull*/) { + requireParamNotNull("canonicalName", canonicalName); + if (node == null) { + return false; + } + + + return node.getType() == null ? fallbackIsA(node, canonicalName, false) + : node.getType().getCanonicalName().equals(canonicalName); + } + + + // this is in AssertionUtil in 7.0 + private static void requireParamNotNull(String name, Object o) { + if (o == null) { + throw new NullPointerException("Parameter '" + name + "' was null"); + } + } + + private static boolean canBeExtended(Class clazz) { + // Neither final nor an annotation. Enums & records have ACC_FINAL + return (clazz.getModifiers() & (Opcodes.ACC_ANNOTATION | Opcodes.ACC_FINAL)) == 0; + } + + // those fallbacks can be removed with the newer symbol resolution, + // symbols reflect enough information to do this fallback transparently. + + /** + * Returns true if the class n is a subtype of clazzName, given n + * is an annotationt type. + */ + private static boolean isAnnotationSubtype(Class n, String clazzName) { + assert n != null && n.isAnnotation() : "Not an annotation type"; + // then, the supertype may only be Object, j.l.Annotation, or the class name + // this avoids classloading altogether + // this is used e.g. by the typeIs function in XPath + return "java.lang.annotation.Annotation".equals(clazzName) + || "java.lang.Object".equals(clazzName) + || clazzName.equals(n.getName()); + } + + private static boolean fallbackIsA(TypeNode n, String canonicalName, boolean considerSubtype) { + if (n.getImage() != null && !n.getImage().contains(".") && canonicalName.contains(".")) { + // simple name detected, check the imports to get the full name and use that for fallback + List imports = n.getRoot().findChildrenOfType(ASTImportDeclaration.class); + for (ASTImportDeclaration importDecl : imports) { + if (n.hasImageEqualTo(importDecl.getImportedSimpleName())) { + // found the import, compare the full names + return canonicalName.equals(importDecl.getImportedName()); + } + } + } + + if (n instanceof ASTAnyTypeDeclaration) { + ASTAnyTypeDeclaration decl = (ASTAnyTypeDeclaration) n; + if (decl.getBinaryName().equals(canonicalName)) { + return true; + } else if (!considerSubtype) { // otherwise fallthrough + return false; + } else { + return isStrictSuperType(decl, canonicalName); + } + } + + // fall back on using the simple name of the class only + return canonicalName.equals(n.getImage()) || canonicalName.endsWith("." + n.getImage()); + } + + private static boolean isStrictSuperType(ASTAnyTypeDeclaration n, String binaryName) { + if (n instanceof ASTClassOrInterfaceDeclaration) { + + ASTClassOrInterfaceType superClass = ((ASTClassOrInterfaceDeclaration) n).getSuperClassTypeNode(); + if (superClass != null) { + return isA(binaryName, superClass); + } + + for (ASTClassOrInterfaceType itf : n.getSuperInterfaceTypeNodes()) { + if (isA(binaryName, itf)) { + return true; + } + } + } else if (n instanceof ASTEnumDeclaration) { + + ASTImplementsList implemented = n.getFirstChildOfType(ASTImplementsList.class); + if (implemented != null) { + for (ASTClassOrInterfaceType itf : implemented) { + if (isA(binaryName, itf)) { + return true; + } + } + } + + return "java.lang.Enum".equals(binaryName) + // supertypes of Enum + || "java.lang.Comparable".equals(binaryName) + || "java.io.Serializable".equals(binaryName) + || "java.lang.Object".equals(binaryName); + } else if (n instanceof ASTAnnotationTypeDeclaration) { + return "java.lang.annotation.Annotation".equals(binaryName) + || "java.lang.Object".equals(binaryName); + } + + return false; + } + + static Class loadClassWithNodeClassloader(final TypeNode n, final String clazzName) { + if (n.getType() != null) { + return TypesFromReflection.loadClass(n.getRoot().getClassTypeResolver(), clazzName); + } + + return null; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypesFromReflection.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypesFromReflection.java index 54ae89b20f..abb3492b02 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypesFromReflection.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypesFromReflection.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.types; +import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; @@ -11,15 +12,20 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.reflect.TypeLiteral; import org.apache.commons.lang3.reflect.Typed; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.java.symbols.JClassSymbol; +import net.sourceforge.pmd.lang.java.typeresolution.internal.NullableClassLoader; import net.sourceforge.pmd.util.CollectionUtil; /** @@ -182,4 +188,95 @@ public final class TypesFromReflection { return ts.wildcard(isUpper, ts.glb(boundsMapped)); } + + + /** Maps names of primitives to their corresponding primitive {@code Class}es. */ + private static final Map> PRIMITIVES_BY_NAME = new HashMap<>(); + + + static { + PRIMITIVES_BY_NAME.put("boolean", Boolean.TYPE); + PRIMITIVES_BY_NAME.put("byte", Byte.TYPE); + PRIMITIVES_BY_NAME.put("char", Character.TYPE); + PRIMITIVES_BY_NAME.put("short", Short.TYPE); + PRIMITIVES_BY_NAME.put("int", Integer.TYPE); + PRIMITIVES_BY_NAME.put("long", Long.TYPE); + PRIMITIVES_BY_NAME.put("double", Double.TYPE); + PRIMITIVES_BY_NAME.put("float", Float.TYPE); + PRIMITIVES_BY_NAME.put("void", Void.TYPE); + } + + + /** + * Load a class. Supports loading array types like 'java.lang.String[]' and + * converting a canonical name to a binary name (eg 'java.util.Map.Entry' -> + * 'java.util.Map$Entry'). + */ + public static Class loadClass(NullableClassLoader ctr, String className) { + return loadClassMaybeArray(ctr, StringUtils.deleteWhitespace(className)); + } + + private static Class loadClassFromCanonicalName(NullableClassLoader ctr, String className) { + Class clazz = PRIMITIVES_BY_NAME.get(className); + if (clazz == null) { + clazz = ctr.loadClassOrNull(className); + } + if (clazz != null) { + return clazz; + } + // allow path separators (.) as inner class name separators + final int lastDotIndex = className.lastIndexOf('.'); + + if (lastDotIndex >= 0) { + String asInner = className.substring(0, lastDotIndex) + + '$' + className.substring(lastDotIndex + 1); + return loadClassFromCanonicalName(ctr, asInner); + } + return null; + } + + + private static Class loadClassMaybeArray(NullableClassLoader classLoader, + String className) { + Validate.notNull(className, "className must not be null."); + if (className.endsWith("[]")) { + int dimension = 0; + int i = className.length(); + while (i >= 2 && className.startsWith("[]", i - 2)) { + dimension++; + i -= 2; + } + + checkJavaIdent(className, i); + String elementName = className.substring(0, i); + + Class elementType = loadClassFromCanonicalName(classLoader, elementName); + if (elementType == null) { + return null; + } + + return Array.newInstance(elementType, (int[]) Array.newInstance(int.class, dimension)).getClass(); + } else { + checkJavaIdent(className, className.length()); + return loadClassFromCanonicalName(classLoader, className); + } + } + + private static IllegalArgumentException invalidClassName(String className) { + return new IllegalArgumentException("Not a valid class name \"" + className + "\""); + } + + private static void checkJavaIdent(String className, int endOffsetExclusive) { + if (endOffsetExclusive <= 0 || !Character.isJavaIdentifierStart(className.charAt(0))) { + throw invalidClassName(className); + } + + for (int i = 1; i < endOffsetExclusive; i++) { + char c = className.charAt(i); + if (!(Character.isJavaIdentifierPart(c) || c == '.')) { + throw invalidClassName(className); + } + } + } + } 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 deleted file mode 100644 index 2f1dae6f88..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/GetCommentOnFunction.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.xpath; - -import java.util.List; - -import org.jaxen.Context; -import org.jaxen.Function; -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.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.Comment; - -/** - * The XPath query "//VariableDeclarator[contains(getCommentOn(), - * '//password')]" will find all variables declared that are annotated with the - * password comment. - * - * @author Andy Throgmorton - */ -@InternalApi -@Deprecated -public class GetCommentOnFunction implements Function { - - public static void registerSelfInSimpleContext() { - // see http://jaxen.org/extensions.html - ((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "getCommentOn", - new GetCommentOnFunction()); - } - - @Override - public Object call(Context context, List args) throws FunctionCallException { - if (!args.isEmpty()) { - return Boolean.FALSE; - } - Node n = (Node) context.getNodeSet().get(0); - int codeBeginLine = n.getBeginLine(); - int codeEndLine = n.getEndLine(); - - List commentList = n.getFirstParentOfType(ASTCompilationUnit.class).getComments(); - for (Comment comment : commentList) { - if (comment.getBeginLine() == codeBeginLine || comment.getEndLine() == codeEndLine) { - return comment.getImage(); - } - } - return Boolean.FALSE; - } -} 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 deleted file mode 100644 index d4242f26e6..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/JavaFunctions.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -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; - -import net.sf.saxon.expr.XPathContext; - -/** - * Exposes all Java Language specific functions for Saxon use. - */ -@InternalApi -@Deprecated -public final class JavaFunctions { - - private JavaFunctions() { - // utility class - } - - @Deprecated - public static boolean typeof(final XPathContext context, final String nodeTypeName, final String fullTypeName) { - return typeof(context, nodeTypeName, fullTypeName, null); - } - - @Deprecated - public static boolean typeof(final XPathContext context, final String nodeTypeName, - final String fullTypeName, final String shortTypeName) { - return TypeOfFunction.typeof((Node) ((ElementNode) context.getContextItem()).getUnderlyingNode(), nodeTypeName, - fullTypeName, shortTypeName); - } - - public static double metric(final XPathContext context, final String metricKeyName) { - return MetricFunction.getMetric((Node) ((ElementNode) context.getContextItem()).getUnderlyingNode(), metricKeyName); - } - - public static boolean typeIs(final XPathContext context, final String fullTypeName) { - return TypeIsFunction.typeIs((Node) ((ElementNode) context.getContextItem()).getUnderlyingNode(), fullTypeName); - } - - public static boolean typeIsExactly(final XPathContext context, final String fullTypeName) { - return TypeIsExactlyFunction.typeIsExactly((Node) ((ElementNode) context.getContextItem()).getUnderlyingNode(), fullTypeName); - } -} 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 deleted file mode 100644 index ad2cd4a6e5..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeIsExactlyFunction.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.xpath; - -import java.util.List; - -import org.jaxen.Context; -import org.jaxen.Function; -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() { - ((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "typeIsExactly", - new TypeIsExactlyFunction()); - } - - @Override - public Object call(final Context context, final List args) throws FunctionCallException { - if (args.size() != 1) { - throw new IllegalArgumentException( - "typeIsExactly function takes a single String argument with the fully qualified type name to check against."); - } - final String fullTypeName = (String) args.get(0); - final Node n = (Node) context.getNodeSet().get(0); - - return typeIsExactly(n, fullTypeName); - } - - /** - * Example XPath 1.0: {@code //ClassOrInterfaceType[typeIsExactly('java.lang.String')]} - *

    - * Example XPath 2.0: {@code //ClassOrInterfaceType[pmd-java:typeIsExactly('java.lang.String')]} - * - * @param n The node on which to check for types - * @param fullTypeName The fully qualified name of the class or any supertype - * @return True if the type of the node matches, false otherwise. - */ - public static boolean typeIsExactly(final Node n, final String fullTypeName) { - if (n instanceof TypeNode) { - return TypeHelper.isExactlyA((TypeNode) n, fullTypeName); - } else { - throw new IllegalArgumentException("typeIsExactly function may only be called on a TypeNode."); - } - } -} 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 deleted file mode 100644 index 1bf3853df9..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeIsFunction.java +++ /dev/null @@ -1,58 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.xpath; - -import java.util.List; - -import org.jaxen.Context; -import org.jaxen.Function; -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() { - ((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "typeIs", - new TypeIsFunction()); - } - - @Override - public Object call(final Context context, final List args) throws FunctionCallException { - if (args.size() != 1) { - throw new IllegalArgumentException( - "typeIs function takes a single String argument with the fully qualified type name to check against."); - } - final String fullTypeName = (String) args.get(0); - final Node n = (Node) context.getNodeSet().get(0); - - return typeIs(n, fullTypeName); - } - - /** - * Example XPath 1.0: {@code //ClassOrInterfaceType[typeIs('java.lang.String')]} - *

    - * Example XPath 2.0: {@code //ClassOrInterfaceType[pmd-java:typeIs('java.lang.String')]} - * - * @param n The node on which to check for types - * @param fullTypeName The fully qualified name of the class or any supertype - * @return True if the type of the node matches, false otherwise. - */ - public static boolean typeIs(final Node n, final String fullTypeName) { - if (n instanceof TypeNode) { - return TypeHelper.isA((TypeNode) n, fullTypeName); - } else { - throw new IllegalArgumentException("typeIs function may only be called on a TypeNode."); - } - } -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeOfFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeOfFunction.java deleted file mode 100644 index 2fe6167146..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/TypeOfFunction.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.xpath; - -import java.util.Arrays; -import java.util.List; -import java.util.logging.Logger; - -import org.jaxen.Context; -import org.jaxen.Function; -import org.jaxen.FunctionCallException; -import org.jaxen.SimpleFunctionContext; -import org.jaxen.XPathFunctionContext; - -import net.sourceforge.pmd.PMDVersion; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.ast.xpath.Attribute; -import net.sourceforge.pmd.lang.java.ast.TypeNode; - -@Deprecated -public class TypeOfFunction implements Function { - - private static final Logger LOG = Logger.getLogger(TypeOfFunction.class.getName()); - private static boolean deprecationWarned = false; - - public static void registerSelfInSimpleContext() { - ((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "typeof", - new TypeOfFunction()); - } - - @Override - public Object call(Context context, List args) throws FunctionCallException { - nagDeprecatedFunction(); - - String nodeTypeName = null; - String fullTypeName = null; - String shortTypeName = null; - Attribute attr = null; - for (int i = 0; i < args.size(); i++) { - if (args.get(i) instanceof List) { - if (attr == null) { - attr = ((List) args.get(i)).get(0); - nodeTypeName = attr.getStringValue(); - } else { - throw new IllegalArgumentException( - "typeof function can take only a single argument which is an Attribute."); - } - } else { - if (fullTypeName == null) { - fullTypeName = (String) args.get(i); - } else if (shortTypeName == null) { - shortTypeName = (String) args.get(i); - } else { - break; - } - } - } - if (fullTypeName == null) { - throw new IllegalArgumentException( - "typeof function must be given at least one String argument for the fully qualified type name."); - } - Node n = (Node) context.getNodeSet().get(0); - return typeof(n, nodeTypeName, fullTypeName, shortTypeName); - } - - private static void nagDeprecatedFunction() { - if (!deprecationWarned) { - deprecationWarned = true; - LOG.warning("The XPath function typeof() is deprecated and will be removed in " - + PMDVersion.getNextMajorRelease() + ". Use typeIs() instead."); - } - } - - /** - * Example XPath 1.0: {@code //ClassOrInterfaceType[typeof(@Image, 'java.lang.String', 'String')]} - *

    - * Example XPath 2.0: {@code //ClassOrInterfaceType[pmd-java:typeof(@Image, 'java.lang.String', 'String')]} - * - * @param n - * @param nodeTypeName Usually the {@code @Image} attribute of the node - * @param fullTypeName The fully qualified name of the class or any supertype - * @param shortTypeName The simple class name, might be null - * @return - */ - public static boolean typeof(Node n, String nodeTypeName, String fullTypeName, String shortTypeName) { - nagDeprecatedFunction(); - - if (n instanceof TypeNode) { - Class type = ((TypeNode) n).getType(); - if (type == null) { - return nodeTypeName != null - && (nodeTypeName.equals(fullTypeName) || nodeTypeName.equals(shortTypeName)); - } - if (type.getName().equals(fullTypeName)) { - return true; - } - List> implementors = Arrays.asList(type.getInterfaces()); - if (implementors.contains(type)) { - return true; - } - Class superC = type.getSuperclass(); - while (superC != null && !superC.equals(Object.class)) { - if (superC.getName().equals(fullTypeName)) { - return true; - } - superC = superC.getSuperclass(); - } - } else { - throw new IllegalArgumentException("typeof function may only be called on a TypeNode."); - } - return false; - } -} diff --git a/pmd-java/src/main/resources/category/java/bestpractices.xml b/pmd-java/src/main/resources/category/java/bestpractices.xml index fcf93be49c..650b24d428 100644 --- a/pmd-java/src/main/resources/category/java/bestpractices.xml +++ b/pmd-java/src/main/resources/category/java/bestpractices.xml @@ -135,7 +135,6 @@ public class Foo { 3 - 3 - 3 - 3 - 3 - 3 - - //ForInit/LocalVariableDeclaration[count(VariableDeclarator) > $maximumVariables] @@ -617,7 +610,6 @@ through the @RunWith(Suite.class) annotation. 3 - 3 - 3 - 3 - - 3 - - 4 - - @@ -1184,7 +1168,6 @@ Consider replacing Enumeration usages with the newer java.util.Iterator 3 - 3 - //Type/ReferenceType/ClassOrInterfaceType[@Image='Hashtable'] @@ -1246,7 +1228,6 @@ Consider replacing Vector usages with the newer java.util.ArrayList if expensive 3 - //Type/ReferenceType/ClassOrInterfaceType[@Image='Vector'] @@ -1273,7 +1254,6 @@ All switch statements should include a default option to catch any unspecified v 3 - 2 - 3 - 3 - 3 - 3 - 3 - 3 - 2 - //Name[starts-with(@Image,'System.loadLibrary')] @@ -169,7 +166,6 @@ prefix for these methods. 4 - 3 - - - 3 - 1 - No need to explicitly extend Object. 4 - 3 - 4 - 4 - 4 - 3 - 4 - /CompilationUnit[not(./PackageDeclaration)]/TypeDeclaration[1] - 3 - @@ -1219,7 +1201,6 @@ Detects when a package definition contains uppercase characters. 3 - //PackageDeclaration/Name[lower-case(@Image)!=@Image] @@ -1273,7 +1254,6 @@ Remote Interface of a Session EJB should not have a suffix. 4 - 4 - 4 - 3 - 3 - - stringsWithDiamond = new ArrayList<>(); // using the diamond operat Useless parentheses should be removed. 4 - 3 - 3 - - 1 - 3 - 3 - 3 - 1 - 3 - 1 - 3 - 3 - @@ -730,7 +718,6 @@ in each object at runtime. 3 - Identifies private fields whose values never change once object initialization ends either in the declaration -of the field or by a constructor. This helps in converting existing classes to becoming immutable ones. +of the field or by a constructor. This helps in converting existing classes to becoming immutable ones. +Note that this rule does not enforce referenced object to be immutable itself. A class can still be mutable, even +if all its member fields are declared final. This is referred to as shallow immutability. For more information on +mutability, see Effective Java, 3rd Edition, Item 17: Minimize mutability. 3 @@ -854,7 +844,6 @@ Use opposite operator instead of negating the whole expression with a logic comp 3 - 3 - 3 - 3 - 3 - 3 - - 3 - 3 - 3 -