From f725f1ebfa780343208b59716da9b17151a80c94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Sat, 3 Mar 2018 20:01:40 -0300 Subject: [PATCH 01/21] [java] Honor find boundaries - This fixes #904 - `hasDescendantOfType`, `getFirstDescendantOfType` and `findDescendantsOfType` are now consistent --- .../net/sourceforge/pmd/lang/ast/AbstractNode.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java index aef48f0d30..3c6b6d1c0c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java @@ -340,14 +340,18 @@ public abstract class AbstractNode implements Node { } - private static T getFirstDescendantOfType(Class descendantType, Node node) { - int n = node.jjtGetNumChildren(); + private static T getFirstDescendantOfType(final Class descendantType, final Node node) { + if (node.isFindBoundary()) { + return null; + } + + final int n = node.jjtGetNumChildren(); for (int i = 0; i < n; i++) { Node n1 = node.jjtGetChild(i); if (descendantType.isAssignableFrom(n1.getClass())) { return descendantType.cast(n1); } - T n2 = getFirstDescendantOfType(descendantType, n1); + final T n2 = getFirstDescendantOfType(descendantType, n1); if (n2 != null) { return n2; } From ba54b1c91a08cb3ec49c40d2fb17950cd09af51b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Sat, 3 Mar 2018 20:02:28 -0300 Subject: [PATCH 02/21] Fix failing tests --- .../pmd/typeresolution/ClassTypeResolverTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java index c876f60183..ed3203d271 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java @@ -38,6 +38,7 @@ import net.sourceforge.pmd.lang.java.ParserTstUtil; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; @@ -238,7 +239,9 @@ public class ClassTypeResolverTest { Node acu = parseAndTypeResolveForClass(NestedAnonymousClass.class, "1.8"); ASTAllocationExpression allocationExpression = acu.getFirstDescendantOfType(ASTAllocationExpression.class); ASTAllocationExpression nestedAllocation - = allocationExpression.getFirstDescendantOfType(ASTAllocationExpression.class); + = allocationExpression.getFirstChildOfType(ASTClassOrInterfaceBody.class) // get the declaration + .jjtGetChild(0).jjtGetChild(1) // into the declaration, through the boundary + .getFirstDescendantOfType(ASTAllocationExpression.class); TypeNode child = (TypeNode) nestedAllocation.jjtGetChild(0); Assert.assertTrue(Converter.class.isAssignableFrom(child.getType())); Assert.assertSame(String.class, child.getTypeDefinition().getGenericType(0).getType()); From 19c3487f9e9e66a12c32c6b5ebbade2986211f1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Sat, 3 Mar 2018 20:02:43 -0300 Subject: [PATCH 03/21] Add test case for #370 - Fixes #370 --- .../bestpractices/xml/GuardLogStatement.xml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/GuardLogStatement.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/GuardLogStatement.xml index edfa19ba70..896ee9e2a1 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/GuardLogStatement.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/GuardLogStatement.xml @@ -311,6 +311,26 @@ public class Foo { LOGGER.log(Level.FINE, "This is a severe message" + " and concat"); } } +} + ]]> + + + #370 rule not considering lambdas + 0 + "Bla " + " bla"); // The lambda is free to do whatever it likes + } + + @Override + public void info(Supplier message) { + if (logger.isInfoEnabled()) { + logger.info(message.get()); + } + } } ]]> From 180cfc1dcc175ce6bde3a058aa67a201cbedfe1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Sat, 3 Mar 2018 20:34:33 -0300 Subject: [PATCH 04/21] Update changelog, refs #370 & #904 --- docs/pages/release_notes.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 7f5b9dc6e7..15ee968466 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -15,6 +15,7 @@ This is a bug fixing release. * [New and noteworthy](#new-and-noteworthy) * [Fixed Issues](#fixed-issues) * [Ecmascript (JavaScript)](#ecmascript-javascript) + * [Tree transversal revision](#tree-transversal-revision) * [Disable Incremental Analysis](#disable-incremental-analysis) * [New Rules](#new-rules) * [Modified Rules](#modified-rules) @@ -23,7 +24,7 @@ This is a bug fixing release. ### New and noteworthy -#### Ecmascript (JavaScript) +#### Rhino library updated The [Rhino Library](https://github.com/mozilla/rhino) has been upgraded from version 1.7.7 to version 1.7.7.2. @@ -33,6 +34,18 @@ Detailed changes for changed in Rhino can be found: Both are bugfixing releases. +#### Tree transversal revision + +As described in [#904](https://github.com/pmd/pmd/issues/904), when searching for child nodes of the AST methods +such as `hasDescendantOfType`, `getFirstDescendantOfType` and `findDescendantsOfType` were found to behave inconsistently, +not all of them honoring find boundaries; that is, nodes that define a self-contained entity which should be considered separately +(think of lambdas, nested classes, anonymous classes, etc.). We have modified these methods to ensure all of them honor +find boundaries. + +This change implies several false positives / unexpected results (ie: `ASTBlockStatement` falsely returning `true` to `isAllocation()`) +have been fixed; and lots of searches are now restricted to smaller search areas, which improves performance (depending on the project, +we have measured up to 10% improvements during Type Resolution, Symbol Table analysis, and some rule's application). + ### Disable Incremental Analysis Some time ago, we added support for [Incremental Analhysis](pmd_userdocs_getting_started.html). On PMD 6.0.0, we @@ -64,12 +77,13 @@ On both scenarios, disabling the cache takes precedence over setting a cache loc that allows to configure annotations that imply the method should be ignored. By default `@java.lang.Deprecated` is ignored. - ### Fixed Issues * all + * [#904](https://github.com/pmd/pmd/issues/904): \[core] Tree traversal revision * [#928](https://github.com/pmd/pmd/issues/928): \[core] PMD build failure on Windows * java-bestpracrtices + * [#370](https://github.com/pmd/pmd/issues/370): \[java] GuardLogStatementJavaUtil not considering lambdas * [#907](https://github.com/pmd/pmd/issues/907): \[java] UnusedPrivateField false-positive with @FXML * [#963](https://github.com/pmd/pmd/issues/965): \[java] ArrayIsStoredDirectly not triggered from variadic functions * java-design From cdc50f7667bedebce99b4fd3a1a838ca69ebde76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Sat, 3 Mar 2018 20:37:08 -0300 Subject: [PATCH 05/21] Remove no longer needed parent check - Also break once we have a result --- .../rule/errorprone/TestClassWithoutTestCasesRule.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/TestClassWithoutTestCasesRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/TestClassWithoutTestCasesRule.java index abc5fa4463..6900c018fc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/TestClassWithoutTestCasesRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/TestClassWithoutTestCasesRule.java @@ -23,8 +23,9 @@ public class TestClassWithoutTestCasesRule extends AbstractJUnitRule { if (m != null) { for (ASTMethodDeclaration md : m) { - if (!isInInnerClassOrInterface(md) && isJUnitMethod(md, data)) { + if (isJUnitMethod(md, data)) { testsFound = true; + break; } } } @@ -35,9 +36,4 @@ public class TestClassWithoutTestCasesRule extends AbstractJUnitRule { return data; } - - private boolean isInInnerClassOrInterface(ASTMethodDeclaration md) { - ASTClassOrInterfaceDeclaration p = md.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class); - return p != null && p.isNested(); - } } From 8deaf20f4d6734dbf1672dbf659ddff99a963e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 5 Mar 2018 02:13:14 -0300 Subject: [PATCH 06/21] findDescendantsOfType defaults to not crossing boundaries - A few places actually need to do so, and some other were simply wrong - We can now cross the boundary if searching dowm from it - Anonymous inner classes are still somewhat inconsistent --- .../pmd/lang/ast/AbstractNode.java | 24 +++++-------- .../java/ast/ASTClassOrInterfaceType.java | 7 ++-- .../impl/visitors/AtfdBaseVisitor.java | 2 +- .../bestpractices/PreserveStackTraceRule.java | 4 ++- .../bestpractices/UnusedPrivateFieldRule.java | 6 ++-- .../CommentDefaultAccessModifierRule.java | 11 ++---- .../java/rule/design/TooManyFieldsRule.java | 36 ++++--------------- .../documentation/AbstractCommentRule.java | 18 ++++++---- .../rule/errorprone/CloseResourceRule.java | 4 +-- .../java/ast/ASTVariableDeclaratorIdTest.java | 6 ++-- .../pmd/lang/java/ast/JDKVersionTest.java | 4 ++- .../lang/java/symboltable/AcceptanceTest.java | 4 ++- .../ScopeAndDeclarationFinderTest.java | 8 ++++- 13 files changed, 62 insertions(+), 72 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java index 3c6b6d1c0c..8f9d12fa98 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java @@ -237,15 +237,13 @@ public abstract class AbstractNode implements Node { return parents; } - @Override public List findDescendantsOfType(Class targetType) { List list = new ArrayList<>(); - findDescendantsOfType(this, targetType, list, true); + findDescendantsOfType(this, targetType, list, false); return list; } - @Override public void findDescendantsOfType(Class targetType, List results, boolean crossBoundaries) { findDescendantsOfType(this, targetType, results, crossBoundaries); @@ -254,17 +252,15 @@ public abstract class AbstractNode implements Node { private static void findDescendantsOfType(Node node, Class targetType, List results, boolean crossFindBoundaries) { - if (!crossFindBoundaries && node.isFindBoundary()) { - return; - } - for (int i = 0; i < node.jjtGetNumChildren(); i++) { Node child = node.jjtGetChild(i); if (child.getClass() == targetType) { results.add(targetType.cast(child)); } - findDescendantsOfType(child, targetType, results, crossFindBoundaries); + if (crossFindBoundaries || !child.isFindBoundary()) { + findDescendantsOfType(child, targetType, results, crossFindBoundaries); + } } } @@ -341,19 +337,17 @@ public abstract class AbstractNode implements Node { private static T getFirstDescendantOfType(final Class descendantType, final Node node) { - if (node.isFindBoundary()) { - return null; - } - final int n = node.jjtGetNumChildren(); for (int i = 0; i < n; i++) { Node n1 = node.jjtGetChild(i); if (descendantType.isAssignableFrom(n1.getClass())) { return descendantType.cast(n1); } - final T n2 = getFirstDescendantOfType(descendantType, n1); - if (n2 != null) { - return n2; + if (!n1.isFindBoundary()) { + final T n2 = getFirstDescendantOfType(descendantType, n1); + if (n2 != null) { + return n2; + } } } return null; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java index 7b86601c23..4a3bb535c4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.java.ast; +import java.util.ArrayList; import java.util.List; import net.sourceforge.pmd.lang.ast.Node; @@ -35,13 +36,15 @@ public class ASTClassOrInterfaceType extends AbstractJavaTypeNode { */ public boolean isReferenceToClassSameCompilationUnit() { ASTCompilationUnit root = getFirstParentOfType(ASTCompilationUnit.class); - List classes = root.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class); + List classes = new ArrayList<>(); + root.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class, classes, true); for (ASTClassOrInterfaceDeclaration c : classes) { if (c.hasImageEqualTo(getImage())) { return true; } } - List enums = root.findDescendantsOfType(ASTEnumDeclaration.class); + List enums = new ArrayList<>(); + root.findDescendantsOfType(ASTEnumDeclaration.class, enums, true); for (ASTEnumDeclaration e : enums) { if (e.hasImageEqualTo(getImage())) { return true; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/visitors/AtfdBaseVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/visitors/AtfdBaseVisitor.java index 6c95fa3821..34873640c1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/visitors/AtfdBaseVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/visitors/AtfdBaseVisitor.java @@ -103,7 +103,7 @@ public class AtfdBaseVisitor extends JavaParserVisitorAdapter { private boolean isAttributeAccess(ASTPrimaryExpression node) { - return node.findDescendantsOfType(ASTPrimarySuffix.class).isEmpty(); + return !node.hasDescendantOfType(ASTPrimarySuffix.class); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java index dbff360e20..9fb38e8fee 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.rule.bestpractices; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -139,7 +140,8 @@ public class PreserveStackTraceRule extends AbstractJavaRule { private boolean checkForTargetUsage(String target, Node baseNode) { boolean match = false; if (target != null && baseNode != null) { - List nameNodes = baseNode.findDescendantsOfType(ASTName.class); + List nameNodes = new ArrayList<>(); + baseNode.findDescendantsOfType(ASTName.class, nameNodes, true); for (ASTName nameNode : nameNodes) { if (target.equals(nameNode.getImage())) { boolean isPartOfStringConcatenation = isStringConcat(nameNode, baseNode); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java index a1e4a5f0c9..5296aff40d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java @@ -100,14 +100,16 @@ public class UnusedPrivateFieldRule extends AbstractLombokAwareRule { nodes.addAll(enumConstants); for (JavaNode node : nodes) { - List primarySuffixes = node.findDescendantsOfType(ASTPrimarySuffix.class); + List primarySuffixes = new ArrayList<>(); + node.findDescendantsOfType(ASTPrimarySuffix.class, primarySuffixes, true); for (ASTPrimarySuffix primarySuffix : primarySuffixes) { if (decl.getImage().equals(primarySuffix.getImage())) { return true; // No violation } } - List primaryPrefixes = node.findDescendantsOfType(ASTPrimaryPrefix.class); + List primaryPrefixes = new ArrayList<>(); + node.findDescendantsOfType(ASTPrimaryPrefix.class, primaryPrefixes, true); for (ASTPrimaryPrefix primaryPrefix : primaryPrefixes) { ASTName name = primaryPrefix.getFirstDescendantOfType(ASTName.class); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java index faf19b4dbb..e91af11fd2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java @@ -117,14 +117,9 @@ public class CommentDefaultAccessModifierRule extends AbstractCommentRule { if (parent != null) { List annotations = parent.findChildrenOfType(ASTAnnotation.class); for (ASTAnnotation annotation : annotations) { - List names = annotation.findDescendantsOfType(ASTName.class); - for (ASTName name : names) { - if (name.hasImageEqualTo("VisibleForTesting")) { - result = false; - break; - } - } - if (result == false) { + final ASTName name = annotation.getFirstDescendantOfType(ASTName.class); + if (name.hasImageEqualTo("VisibleForTesting")) { + result = false; break; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/TooManyFieldsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/TooManyFieldsRule.java index febbffd080..7bf464f7c7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/TooManyFieldsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/TooManyFieldsRule.java @@ -4,50 +4,37 @@ package net.sourceforge.pmd.lang.java.rule.design; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.properties.IntegerProperty; -import net.sourceforge.pmd.util.NumericConstants; public class TooManyFieldsRule extends AbstractJavaRule { private static final int DEFAULT_MAXFIELDS = 15; - private Map stats; - private Map nodes; - private static final IntegerProperty MAX_FIELDS_DESCRIPTOR = new IntegerProperty("maxfields", "Max allowable fields", 1, 300, DEFAULT_MAXFIELDS, 1.0f); public TooManyFieldsRule() { definePropertyDescriptor(MAX_FIELDS_DESCRIPTOR); + addRuleChainVisit(ASTClassOrInterfaceDeclaration.class); } @Override - public Object visit(ASTCompilationUnit node, Object data) { + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + final int maxFields = getProperty(MAX_FIELDS_DESCRIPTOR); + int counter = 0; - int maxFields = getProperty(MAX_FIELDS_DESCRIPTOR); - - stats = new HashMap<>(5); - nodes = new HashMap<>(5); - - List l = node.findDescendantsOfType(ASTFieldDeclaration.class); + final List l = node.findDescendantsOfType(ASTFieldDeclaration.class); for (ASTFieldDeclaration fd : l) { if (fd.isFinal() && fd.isStatic()) { continue; } - ASTClassOrInterfaceDeclaration clazz = fd.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class); - if (clazz != null && !clazz.isInterface()) { - bumpCounterFor(clazz); - } + counter++; } for (Map.Entry entry : stats.entrySet()) { int val = entry.getValue(); @@ -56,16 +43,7 @@ public class TooManyFieldsRule extends AbstractJavaRule { addViolation(data, n); } } + return data; } - - private void bumpCounterFor(ASTClassOrInterfaceDeclaration clazz) { - String key = clazz.getImage(); - if (!stats.containsKey(key)) { - stats.put(key, NumericConstants.ZERO); - nodes.put(key, clazz); - } - Integer i = Integer.valueOf(stats.get(key) + 1); - stats.put(key, i); - } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/AbstractCommentRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/AbstractCommentRule.java index 5fd1da2575..9c7a33da50 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/AbstractCommentRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/AbstractCommentRule.java @@ -199,22 +199,26 @@ public abstract class AbstractCommentRule extends AbstractJavaRule { SortedMap itemsByLineNumber = new TreeMap<>(); - List packageDecl = cUnit - .findDescendantsOfType(ASTClassOrInterfaceDeclaration.class); - addDeclarations(itemsByLineNumber, packageDecl); + List classDecl = new ArrayList<>(); + cUnit.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class, classDecl, true); + addDeclarations(itemsByLineNumber, classDecl); addDeclarations(itemsByLineNumber, cUnit.getComments()); - List fields = cUnit.findDescendantsOfType(ASTFieldDeclaration.class); + List fields = new ArrayList<>(); + cUnit.findDescendantsOfType(ASTFieldDeclaration.class, fields, true); addDeclarations(itemsByLineNumber, fields); - List methods = cUnit.findDescendantsOfType(ASTMethodDeclaration.class); + List methods = new ArrayList<>(); + cUnit.findDescendantsOfType(ASTMethodDeclaration.class, methods, true); addDeclarations(itemsByLineNumber, methods); - List constructors = cUnit.findDescendantsOfType(ASTConstructorDeclaration.class); + List constructors = new ArrayList<>(); + cUnit.findDescendantsOfType(ASTConstructorDeclaration.class, constructors, true); addDeclarations(itemsByLineNumber, constructors); - List enumDecl = cUnit.findDescendantsOfType(ASTEnumDeclaration.class); + List enumDecl = new ArrayList<>(); + cUnit.findDescendantsOfType(ASTEnumDeclaration.class, enumDecl, true); addDeclarations(itemsByLineNumber, enumDecl); return itemsByLineNumber; 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 1002ac1fa3..487f48d705 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 @@ -104,13 +104,13 @@ public class CloseResourceRule extends AbstractJavaRule { @Override public Object visit(ASTConstructorDeclaration node, Object data) { checkForResources(node, data); - return data; + return super.visit(node, data); } @Override public Object visit(ASTMethodDeclaration node, Object data) { checkForResources(node, data); - return data; + return super.visit(node, data); } private void checkForResources(Node node, Object data) { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorIdTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorIdTest.java index 299c4348f7..c85b99069b 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorIdTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorIdTest.java @@ -47,7 +47,8 @@ public class ASTVariableDeclaratorIdTest { @Test public void testLambdaWithType() throws Exception { ASTCompilationUnit acu = parseJava18(TEST_LAMBDA_WITH_TYPE); - ASTVariableDeclaratorId f = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(1); + ASTLambdaExpression lambda = acu.getFirstDescendantOfType(ASTLambdaExpression.class); + ASTVariableDeclaratorId f = lambda.getFirstDescendantOfType(ASTVariableDeclaratorId.class); assertEquals("File", f.getTypeNode().getTypeImage()); assertEquals("File", f.getTypeNameNode().jjtGetChild(0).getImage()); } @@ -55,7 +56,8 @@ public class ASTVariableDeclaratorIdTest { @Test public void testLambdaWithoutType() throws Exception { ASTCompilationUnit acu = parseJava18(TEST_LAMBDA_WITHOUT_TYPE); - ASTVariableDeclaratorId f = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(1); + ASTLambdaExpression lambda = acu.getFirstDescendantOfType(ASTLambdaExpression.class); + ASTVariableDeclaratorId f = lambda.getFirstDescendantOfType(ASTVariableDeclaratorId.class); assertNull(f.getTypeNode()); assertNull(f.getTypeNameNode()); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java index 11771f620e..e50c0c651d 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java @@ -17,6 +17,7 @@ import static org.junit.Assert.fail; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.List; import org.apache.commons.io.IOUtils; @@ -276,7 +277,8 @@ public class JDKVersionTest { @Test public final void jdk7PrivateMethodInnerClassInterface1() { ASTCompilationUnit acu = parseJava17(loadSource("private_method_in_inner_class_interface1.java")); - List methods = acu.findDescendantsOfType(ASTMethodDeclaration.class); + List methods = new ArrayList<>(); + acu.findDescendantsOfType(ASTMethodDeclaration.class, methods, true); assertEquals(3, methods.size()); for (ASTMethodDeclaration method : methods) { assertFalse(method.isInterfaceMember()); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java index 627e27ae7e..4ac457822b 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java @@ -18,6 +18,7 @@ import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTBlock; import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression; import net.sourceforge.pmd.lang.java.ast.ASTInitializer; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; @@ -129,7 +130,8 @@ public class AcceptanceTest extends STBBaseTst { @Test public void testInnerOuterClass() { parseCode(TEST_INNER_CLASS); - ASTVariableDeclaratorId vdi = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0); + ASTVariableDeclaratorId vdi = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(1) // get inner class + .findDescendantsOfType(ASTVariableDeclaratorId.class).get(0); // get first declaration List usages = vdi.getUsages(); assertEquals(2, usages.size()); assertEquals(5, usages.get(0).getLocation().getBeginLine()); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java index 09f57978fc..b541a1fd6e 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.symboltable; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -13,6 +14,8 @@ import org.junit.Test; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.java.JavaLanguageModule; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; @@ -65,7 +68,10 @@ public class ScopeAndDeclarationFinderTest extends STBBaseTst { ClassScope cs = (ClassScope) acu.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class).getScope(); Assert.assertEquals(1, cs.getClassDeclarations().size()); // There should be 1 anonymous class - List methods = acu.findDescendantsOfType(ASTMethodDeclarator.class); + List methods = new ArrayList<>(); + acu.getFirstDescendantOfType(ASTClassOrInterfaceBody.class) // outer class + .getFirstDescendantOfType(ASTClassOrInterfaceBody.class) // inner class + .findDescendantsOfType(ASTMethodDeclarator.class, methods, true); // inner class methods Assert.assertEquals(2, methods.size()); ClassScope scope1 = methods.get(0).getScope().getEnclosingScope(ClassScope.class); ClassScope scope2 = methods.get(1).getScope().getEnclosingScope(ClassScope.class); From 8b3fd24c5adb8ef2d769f715015e9138b4b44d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 5 Mar 2018 02:20:52 -0300 Subject: [PATCH 07/21] Simplify test --- .../pmd/typeresolution/ClassTypeResolverTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java index ed3203d271..024cbdc56c 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java @@ -39,6 +39,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; +import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; @@ -239,9 +240,8 @@ public class ClassTypeResolverTest { Node acu = parseAndTypeResolveForClass(NestedAnonymousClass.class, "1.8"); ASTAllocationExpression allocationExpression = acu.getFirstDescendantOfType(ASTAllocationExpression.class); ASTAllocationExpression nestedAllocation - = allocationExpression.getFirstChildOfType(ASTClassOrInterfaceBody.class) // get the declaration - .jjtGetChild(0).jjtGetChild(1) // into the declaration, through the boundary - .getFirstDescendantOfType(ASTAllocationExpression.class); + = allocationExpression.getFirstDescendantOfType(ASTClassOrInterfaceBodyDeclaration.class) // get the declaration (boundary) + .getFirstDescendantOfType(ASTAllocationExpression.class); // and dive for the nested allocation TypeNode child = (TypeNode) nestedAllocation.jjtGetChild(0); Assert.assertTrue(Converter.class.isAssignableFrom(child.getType())); Assert.assertSame(String.class, child.getTypeDefinition().getGenericType(0).getType()); From 240d26ef69e2dc9a9fe3593ae359d623bc015ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 5 Mar 2018 10:50:05 -0300 Subject: [PATCH 08/21] Remove unused imports --- .../sourceforge/pmd/typeresolution/ClassTypeResolverTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java index 024cbdc56c..2d3f6130ff 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/ClassTypeResolverTest.java @@ -38,7 +38,6 @@ import net.sourceforge.pmd.lang.java.ParserTstUtil; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; From 783b449d60cb487edb62857dece0612bc2f96152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 12 Mar 2018 01:41:09 -0300 Subject: [PATCH 09/21] Fix bad merge --- .../pmd/lang/java/rule/design/TooManyFieldsRule.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/TooManyFieldsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/TooManyFieldsRule.java index 7bf464f7c7..b0fc794f68 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/TooManyFieldsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/TooManyFieldsRule.java @@ -36,12 +36,9 @@ public class TooManyFieldsRule extends AbstractJavaRule { } counter++; } - for (Map.Entry entry : stats.entrySet()) { - int val = entry.getValue(); - Node n = nodes.get(entry.getKey()); - if (val > maxFields) { - addViolation(data, n); - } + + if (counter > maxFields) { + addViolation(data, node); } return data; From 0eef25e57b3ec74568bbbdf7546c6f083070f0a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 12 Mar 2018 16:53:38 -0300 Subject: [PATCH 10/21] Checkstyle fixes --- .../lang/java/rule/bestpractices/PreserveStackTraceRule.java | 2 +- .../lang/java/symboltable/ScopeAndDeclarationFinderTest.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java index 9fb38e8fee..889d28b385 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java @@ -141,7 +141,7 @@ public class PreserveStackTraceRule extends AbstractJavaRule { boolean match = false; if (target != null && baseNode != null) { List nameNodes = new ArrayList<>(); - baseNode.findDescendantsOfType(ASTName.class, nameNodes, true); + baseNode.findDescendantsOfType(ASTName.class, nameNodes, true); for (ASTName nameNode : nameNodes) { if (target.equals(nameNode.getImage())) { boolean isPartOfStringConcatenation = isStringConcat(nameNode, baseNode); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java index b541a1fd6e..4505ca8d15 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java @@ -15,7 +15,6 @@ import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.java.JavaLanguageModule; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; From 46ab578f28a290f1a22d45db2ec0c01bd94a04de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 19 Mar 2018 01:48:46 -0300 Subject: [PATCH 11/21] Simplify rules when possible --- .../rule/codestyle/OnlyOneReturnRule.java | 24 +------------------ .../java/rule/design/ImmutableFieldRule.java | 7 ++---- .../java/rule/design/SingularFieldRule.java | 4 +--- .../pmd/lang/java/ast/SimpleNodeTest.java | 7 ++---- 4 files changed, 6 insertions(+), 36 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/OnlyOneReturnRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/OnlyOneReturnRule.java index d2e126d813..3421f616ce 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/OnlyOneReturnRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/OnlyOneReturnRule.java @@ -4,13 +4,11 @@ package net.sourceforge.pmd.lang.java.rule.codestyle; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; @@ -31,9 +29,7 @@ public class OnlyOneReturnRule extends AbstractJavaRule { return data; } - List returnNodes = new ArrayList<>(); - node.findDescendantsOfType(ASTReturnStatement.class, returnNodes, false); - returnNodes = filterLambdaExpressions(returnNodes); + List returnNodes = node.findDescendantsOfType(ASTReturnStatement.class); if (returnNodes.size() > 1) { for (Iterator i = returnNodes.iterator(); i.hasNext();) { @@ -47,22 +43,4 @@ public class OnlyOneReturnRule extends AbstractJavaRule { } return data; } - - /** - * Checks whether the return statement is inside a lambda expression, and if - * so, this return statement is removed. - * - * @param returnNodes - * all the return statements inside the method - * @return all return statements, that are NOT within a lambda expression. - */ - private List filterLambdaExpressions(List returnNodes) { - List filtered = new ArrayList<>(); - for (ASTReturnStatement ret : returnNodes) { - if (ret.getFirstParentOfType(ASTLambdaExpression.class) == null) { - filtered.add(ret); - } - } - return filtered; - } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ImmutableFieldRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ImmutableFieldRule.java index a4004fdceb..f36e998798 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ImmutableFieldRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ImmutableFieldRule.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.java.rule.design; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -136,9 +135,7 @@ public class ImmutableFieldRule extends AbstractLombokAwareRule { } private List findAllConstructors(ASTClassOrInterfaceDeclaration node) { - List cons = new ArrayList<>(); - node.getFirstChildOfType(ASTClassOrInterfaceBody.class).findDescendantsOfType(ASTConstructorDeclaration.class, - cons, false); - return cons; + return node.getFirstChildOfType(ASTClassOrInterfaceBody.class) + .findDescendantsOfType(ASTConstructorDeclaration.class); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java index 6d0d4e0837..28c7b81859 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.java.rule.design; -import java.util.ArrayList; import java.util.List; import net.sourceforge.pmd.lang.ast.Node; @@ -161,8 +160,7 @@ public class SingularFieldRule extends AbstractLombokAwareRule { private boolean isInAssignment(Node potentialStatement) { if (potentialStatement instanceof ASTStatementExpression) { ASTStatementExpression statement = (ASTStatementExpression) potentialStatement; - List assignments = new ArrayList<>(); - statement.findDescendantsOfType(ASTAssignmentOperator.class, assignments, false); + List assignments = statement.findDescendantsOfType(ASTAssignmentOperator.class); return !assignments.isEmpty() && "=".equals(assignments.get(0).getImage()); } else { return false; diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java index 724f2d914c..e443c9f867 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/SimpleNodeTest.java @@ -13,7 +13,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -209,8 +208,7 @@ public class SimpleNodeTest { @Test public void testContainsNoInner() { ASTCompilationUnit c = getNodes(ASTCompilationUnit.class, CONTAINS_NO_INNER).iterator().next(); - List res = new ArrayList<>(); - c.findDescendantsOfType(ASTFieldDeclaration.class, res, false); + List res = c.findDescendantsOfType(ASTFieldDeclaration.class); assertTrue(res.isEmpty()); /* * String expectedXml = @@ -254,8 +252,7 @@ public class SimpleNodeTest { @Test public void testContainsNoInnerWithAnonInner() { ASTCompilationUnit c = getNodes(ASTCompilationUnit.class, CONTAINS_NO_INNER_WITH_ANON_INNER).iterator().next(); - List res = new ArrayList<>(); - c.findDescendantsOfType(ASTFieldDeclaration.class, res, false); + List res = c.findDescendantsOfType(ASTFieldDeclaration.class); assertTrue(res.isEmpty()); } From b3a9b9017a80635295bf334e638a1fb58f0aa0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Mon, 19 Mar 2018 17:17:52 -0300 Subject: [PATCH 12/21] Revamp changelog --- docs/pages/release_notes.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 15ee968466..d259d08664 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,9 +14,9 @@ This is a bug fixing release. * [New and noteworthy](#new-and-noteworthy) * [Fixed Issues](#fixed-issues) - * [Ecmascript (JavaScript)](#ecmascript-javascript) + * [Rhino library updated](#rhino-library-updated) * [Tree transversal revision](#tree-transversal-revision) - * [Disable Incremental Analysis](#disable-incremental-analysis) + * [Allow to Disable Incremental Analysis](#allow-to-disable-incremental-analysis) * [New Rules](#new-rules) * [Modified Rules](#modified-rules) * [API Changes](#api-changes) @@ -46,10 +46,10 @@ This change implies several false positives / unexpected results (ie: `ASTBlockS have been fixed; and lots of searches are now restricted to smaller search areas, which improves performance (depending on the project, we have measured up to 10% improvements during Type Resolution, Symbol Table analysis, and some rule's application). -### Disable Incremental Analysis +### Allow to disable Incremental Analysis Some time ago, we added support for [Incremental Analhysis](pmd_userdocs_getting_started.html). On PMD 6.0.0, we -started to add warns when not using it, as we strongly believe it's a great improvement to our user's experience as +started to add warnings when not using it, as we strongly believe it's a great improvement to our user's experience as analysis time is greatly reduced; and in the future we plan to have it enabled by default. However, we realize some scenarios don't benefit from it (ie: CI jobs), and having the warning logged can be noisy and cause confusion. @@ -58,6 +58,9 @@ the new `-no-cache` flag. On Ant, there is a `noCache` attribute for the `` On both scenarios, disabling the cache takes precedence over setting a cache location. +The only difference between using this flag and not setting up cache is the absence of the warning for the time being, +once we enable Incremental Analysis by default, this will effectively disable it. + #### New Rules * The new Java rule `MissingOverride` (category `bestpractices`) detects overridden and implemented methods, From a1ea36adc0afaa18590cbe5c9f17db69282796cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 23 Mar 2018 00:52:54 -0300 Subject: [PATCH 13/21] Simplify calls where possible --- .../pmd/lang/ast/AbstractNode.java | 7 +++++++ .../java/ast/ASTClassOrInterfaceType.java | 11 ++-------- .../bestpractices/PreserveStackTraceRule.java | 1 + .../bestpractices/UnusedPrivateFieldRule.java | 13 +++++------- .../documentation/AbstractCommentRule.java | 21 +++++-------------- .../pmd/lang/java/ast/JDKVersionTest.java | 4 +--- .../lang/java/symboltable/AcceptanceTest.java | 2 +- .../ScopeAndDeclarationFinderTest.java | 6 ++---- 8 files changed, 24 insertions(+), 41 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java index 8f9d12fa98..451100806a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java @@ -244,6 +244,13 @@ public abstract class AbstractNode implements Node { return list; } + // TODO : Add to Node interface in 7.0.0 + public List findDescendantsOfType(final Class targetType, final boolean crossBoundaries) { + final List list = new ArrayList<>(); + findDescendantsOfType(this, targetType, list, crossBoundaries); + return list; + } + @Override public void findDescendantsOfType(Class targetType, List results, boolean crossBoundaries) { findDescendantsOfType(this, targetType, results, crossBoundaries); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java index 4a3bb535c4..5ef2aa6b04 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java @@ -5,9 +5,6 @@ package net.sourceforge.pmd.lang.java.ast; -import java.util.ArrayList; -import java.util.List; - import net.sourceforge.pmd.lang.ast.Node; public class ASTClassOrInterfaceType extends AbstractJavaTypeNode { @@ -36,16 +33,12 @@ public class ASTClassOrInterfaceType extends AbstractJavaTypeNode { */ public boolean isReferenceToClassSameCompilationUnit() { ASTCompilationUnit root = getFirstParentOfType(ASTCompilationUnit.class); - List classes = new ArrayList<>(); - root.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class, classes, true); - for (ASTClassOrInterfaceDeclaration c : classes) { + for (ASTClassOrInterfaceDeclaration c : root.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class, true)) { if (c.hasImageEqualTo(getImage())) { return true; } } - List enums = new ArrayList<>(); - root.findDescendantsOfType(ASTEnumDeclaration.class, enums, true); - for (ASTEnumDeclaration e : enums) { + for (ASTEnumDeclaration e : root.findDescendantsOfType(ASTEnumDeclaration.class, true)) { if (e.hasImageEqualTo(getImage())) { return true; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java index 889d28b385..31293bd795 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java @@ -140,6 +140,7 @@ public class PreserveStackTraceRule extends AbstractJavaRule { private boolean checkForTargetUsage(String target, Node baseNode) { boolean match = false; if (target != null && baseNode != null) { + // TODO : use Node.findDescendantsOfType(ASTName.class, true) on 7.0.0 List nameNodes = new ArrayList<>(); baseNode.findDescendantsOfType(ASTName.class, nameNodes, true); for (ASTName nameNode : nameNodes) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java index 5296aff40d..1cdb9e1de1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java @@ -19,6 +19,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; +import net.sourceforge.pmd.lang.java.ast.AbstractJavaNode; import net.sourceforge.pmd.lang.java.ast.AccessNode; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.TypeNode; @@ -95,22 +96,18 @@ public class UnusedPrivateFieldRule extends AbstractLombokAwareRule { List classOrInterfaceBodyDeclarations = body .findChildrenOfType(ASTClassOrInterfaceBodyDeclaration.class); List enumConstants = body.findChildrenOfType(ASTEnumConstant.class); - List nodes = new ArrayList<>(); + List nodes = new ArrayList<>(); nodes.addAll(classOrInterfaceBodyDeclarations); nodes.addAll(enumConstants); - for (JavaNode node : nodes) { - List primarySuffixes = new ArrayList<>(); - node.findDescendantsOfType(ASTPrimarySuffix.class, primarySuffixes, true); - for (ASTPrimarySuffix primarySuffix : primarySuffixes) { + for (AbstractJavaNode node : nodes) { + for (ASTPrimarySuffix primarySuffix : node.findDescendantsOfType(ASTPrimarySuffix.class, true)) { if (decl.getImage().equals(primarySuffix.getImage())) { return true; // No violation } } - List primaryPrefixes = new ArrayList<>(); - node.findDescendantsOfType(ASTPrimaryPrefix.class, primaryPrefixes, true); - for (ASTPrimaryPrefix primaryPrefix : primaryPrefixes) { + for (ASTPrimaryPrefix primaryPrefix : node.findDescendantsOfType(ASTPrimaryPrefix.class, true)) { ASTName name = primaryPrefix.getFirstDescendantOfType(ASTName.class); if (name != null) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/AbstractCommentRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/AbstractCommentRule.java index 9c7a33da50..8771982767 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/AbstractCommentRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/AbstractCommentRule.java @@ -196,30 +196,19 @@ public abstract class AbstractCommentRule extends AbstractJavaRule { } protected SortedMap orderedCommentsAndDeclarations(ASTCompilationUnit cUnit) { - SortedMap itemsByLineNumber = new TreeMap<>(); - List classDecl = new ArrayList<>(); - cUnit.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class, classDecl, true); - addDeclarations(itemsByLineNumber, classDecl); + addDeclarations(itemsByLineNumber, cUnit.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class, true)); addDeclarations(itemsByLineNumber, cUnit.getComments()); - List fields = new ArrayList<>(); - cUnit.findDescendantsOfType(ASTFieldDeclaration.class, fields, true); - addDeclarations(itemsByLineNumber, fields); + addDeclarations(itemsByLineNumber, cUnit.findDescendantsOfType(ASTFieldDeclaration.class, true)); - List methods = new ArrayList<>(); - cUnit.findDescendantsOfType(ASTMethodDeclaration.class, methods, true); - addDeclarations(itemsByLineNumber, methods); + addDeclarations(itemsByLineNumber, cUnit.findDescendantsOfType(ASTMethodDeclaration.class, true)); - List constructors = new ArrayList<>(); - cUnit.findDescendantsOfType(ASTConstructorDeclaration.class, constructors, true); - addDeclarations(itemsByLineNumber, constructors); + addDeclarations(itemsByLineNumber, cUnit.findDescendantsOfType(ASTConstructorDeclaration.class, true)); - List enumDecl = new ArrayList<>(); - cUnit.findDescendantsOfType(ASTEnumDeclaration.class, enumDecl, true); - addDeclarations(itemsByLineNumber, enumDecl); + addDeclarations(itemsByLineNumber, cUnit.findDescendantsOfType(ASTEnumDeclaration.class, true)); return itemsByLineNumber; } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java index e50c0c651d..c93605ddb8 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java @@ -17,7 +17,6 @@ import static org.junit.Assert.fail; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.List; import org.apache.commons.io.IOUtils; @@ -277,8 +276,7 @@ public class JDKVersionTest { @Test public final void jdk7PrivateMethodInnerClassInterface1() { ASTCompilationUnit acu = parseJava17(loadSource("private_method_in_inner_class_interface1.java")); - List methods = new ArrayList<>(); - acu.findDescendantsOfType(ASTMethodDeclaration.class, methods, true); + List methods = acu.findDescendantsOfType(ASTMethodDeclaration.class, true); assertEquals(3, methods.size()); for (ASTMethodDeclaration method : methods) { assertFalse(method.isInterfaceMember()); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java index 4ac457822b..bf9c6cb991 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/AcceptanceTest.java @@ -131,7 +131,7 @@ public class AcceptanceTest extends STBBaseTst { public void testInnerOuterClass() { parseCode(TEST_INNER_CLASS); ASTVariableDeclaratorId vdi = acu.findDescendantsOfType(ASTClassOrInterfaceDeclaration.class).get(1) // get inner class - .findDescendantsOfType(ASTVariableDeclaratorId.class).get(0); // get first declaration + .getFirstDescendantOfType(ASTVariableDeclaratorId.class); // get first declaration List usages = vdi.getUsages(); assertEquals(2, usages.size()); assertEquals(5, usages.get(0).getLocation().getBeginLine()); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java index 4505ca8d15..ed0f727f4c 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinderTest.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.java.symboltable; -import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -67,10 +66,9 @@ public class ScopeAndDeclarationFinderTest extends STBBaseTst { ClassScope cs = (ClassScope) acu.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class).getScope(); Assert.assertEquals(1, cs.getClassDeclarations().size()); // There should be 1 anonymous class - List methods = new ArrayList<>(); - acu.getFirstDescendantOfType(ASTClassOrInterfaceBody.class) // outer class + List methods = acu.getFirstDescendantOfType(ASTClassOrInterfaceBody.class) // outer class .getFirstDescendantOfType(ASTClassOrInterfaceBody.class) // inner class - .findDescendantsOfType(ASTMethodDeclarator.class, methods, true); // inner class methods + .findDescendantsOfType(ASTMethodDeclarator.class, true); // inner class methods Assert.assertEquals(2, methods.size()); ClassScope scope1 = methods.get(0).getScope().getEnclosingScope(ClassScope.class); ClassScope scope2 = methods.get(1).getScope().getEnclosingScope(ClassScope.class); From 809310cbd2b91fb3dd606f8ae18b932bc0eb3718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 23 Mar 2018 01:17:05 -0300 Subject: [PATCH 14/21] Improve javadocs --- .../src/main/java/net/sourceforge/pmd/lang/ast/Node.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 256d80a92e..7d0a4f08e3 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 @@ -163,7 +163,7 @@ public interface Node { /** * Traverses down the tree to find all the descendant instances of type - * descendantType. + * descendantType without crossing find boundaries. * * @param targetType * class which you want to find. @@ -200,7 +200,7 @@ public interface Node { /** * Traverses down the tree to find the first descendant instance of type - * descendantType. + * descendantType without crossing find boundaries. * * @param descendantType * class which you want to find. @@ -210,7 +210,7 @@ public interface Node { T getFirstDescendantOfType(Class descendantType); /** - * Finds if this node contains a descendant of the given type. + * Finds if this node contains a descendant of the given type without crossing find boundaries. * * @param type * the node type to search From 257d11e4f127102eb796b2463d1c81f85ce45532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 23 Mar 2018 01:17:17 -0300 Subject: [PATCH 15/21] Add unit test for boundary checking --- .../lang/ast/AbstractNodeTransversalTest.java | 72 +++++++++++++++++++ .../sourceforge/pmd/lang/ast/DummyNode.java | 12 ++++ 2 files changed, 84 insertions(+) create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/AbstractNodeTransversalTest.java diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/AbstractNodeTransversalTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/AbstractNodeTransversalTest.java new file mode 100644 index 0000000000..221747193a --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/AbstractNodeTransversalTest.java @@ -0,0 +1,72 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.ast; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +/** + * Unit test for {@link AbstractNode} tree transversal methods + */ +public class AbstractNodeTransversalTest { + private int id; + private Node rootNode; + + private int nextId() { + return id++; + } + + private Node newDummyNode(boolean boundary) { + return new DummyNode(nextId(), boundary); + } + + private Node addChild(final Node parent, final Node child) { + parent.jjtAddChild(child, parent.jjtGetNumChildren()); // Append child at the end + child.jjtSetParent(parent); + return parent; + } + + @Before + public void setUpSampleNodeTree() { + id = 0; + rootNode = newDummyNode(false); + } + + @Test + public void testBoundaryIsHonored() { + addChild(rootNode, addChild(newDummyNode(true), newDummyNode(false))); + + List descendantsOfType = rootNode.findDescendantsOfType(DummyNode.class); + assertEquals(1, descendantsOfType.size()); + assertTrue(descendantsOfType.get(0).isFindBoundary()); + } + + @Test + public void testSearchFromBoundary() { + addChild(rootNode, addChild(newDummyNode(true), newDummyNode(false))); + + List descendantsOfType = rootNode.findDescendantsOfType(DummyNode.class).get(0).findDescendantsOfType(DummyNode.class); + assertEquals(1, descendantsOfType.size()); + assertFalse(descendantsOfType.get(0).isFindBoundary()); + } + + @Test + public void testSearchIgnoringBoundary() { + addChild(rootNode, addChild(newDummyNode(true), newDummyNode(false))); + + List descendantsOfType = new ArrayList<>(); + rootNode.findDescendantsOfType(DummyNode.class, descendantsOfType, true); + assertEquals(2, descendantsOfType.size()); + assertTrue(descendantsOfType.get(0).isFindBoundary()); + assertFalse(descendantsOfType.get(1).isFindBoundary()); + } +} 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 c17f306145..0f4bdf11fc 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 @@ -5,8 +5,15 @@ package net.sourceforge.pmd.lang.ast; public class DummyNode extends AbstractNode { + private final boolean findBoundary; + public DummyNode(int id) { + this(id, false); + } + + public DummyNode(int id, boolean findBoundary) { super(id); + this.findBoundary = findBoundary; } @Override @@ -18,4 +25,9 @@ public class DummyNode extends AbstractNode { public String getXPathNodeName() { return "dummyNode"; } + + @Override + public boolean isFindBoundary() { + return findBoundary; + } } From e9e0ac97c6c7a6ab377a62a86bde53b113941291 Mon Sep 17 00:00:00 2001 From: Ishan Srivastava Date: Mon, 26 Mar 2018 15:13:08 +0530 Subject: [PATCH 16/21] [doc] Delete duplicate page contributing as it is less maintained than contributing.md Closes https://github.com/pmd/pmd/issues/994 --- docs/_data/sidebars/pmd_sidebar.yml | 2 +- docs/pages/pmd/devdocs/contributing.md | 24 ------------------------ 2 files changed, 1 insertion(+), 25 deletions(-) delete mode 100644 docs/pages/pmd/devdocs/contributing.md diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index 2c80bf00c7..1c722c3d9e 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -308,7 +308,7 @@ entries: url: /pmd_devdocs_building.html output: web, pdf - title: Contributing - url: /pmd_devdocs_contributing.html + url: https://github.com/pmd/pmd/blob/master/CONTRIBUTING.md output: web, pdf - title: Writing documentation url: /pmd_devdocs_writing_documentation.html diff --git a/docs/pages/pmd/devdocs/contributing.md b/docs/pages/pmd/devdocs/contributing.md deleted file mode 100644 index a899b4eb55..0000000000 --- a/docs/pages/pmd/devdocs/contributing.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: Contributing to PMD -sidebar: pmd_sidebar -permalink: pmd_devdocs_contributing.html -folder: pmd/devdocs ---- - -## Contributing via pull requests - -First off, thanks for taking the time to contribute! - -* Please create your pull request against the `master` branch. We will rebase/merge it to the maintenance - branches, if necessary. Just fork the [pmd repo](https://github.com/pmd/pmd/) and - create a [pull request](https://github.com/pmd/pmd/pulls). - -* We are using [checkstyle](http://checkstyle.sourceforge.net/) to enforce a common code style. - The check is integrated into the default build - so, make sure, you can [build PMD](pmd_devdocs_building.html) - without errors. - - The following section goes into more details about our Checkstyle configuration. - -## Code style - -* Checkstyle From 4253e8717eab43f1d0bab398d6a6dcaf43c71b1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 26 Mar 2018 01:50:03 +0200 Subject: [PATCH 17/21] Improvements to designer syntax highlighting --- .../SimpleRegexSyntaxHighlighter.java | 25 ++++++++++ .../ApexSyntaxHighlighter.java | 15 ++---- .../syntaxhighlighting/HighlightClasses.java | 6 ++- .../JavaSyntaxHighlighter.java | 23 +++------- .../XPathSyntaxHighlighter.java | 46 +++++++++++++------ .../pmd/util/fxdesigner/css/editor-theme.css | 10 +++- 6 files changed, 79 insertions(+), 46 deletions(-) diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/SimpleRegexSyntaxHighlighter.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/SimpleRegexSyntaxHighlighter.java index 0b5bf1ceb4..dd249b0c07 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/SimpleRegexSyntaxHighlighter.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/SimpleRegexSyntaxHighlighter.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.util.fxdesigner.util.codearea; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -82,6 +83,30 @@ public abstract class SimpleRegexSyntaxHighlighter implements SyntaxHighlighter } + /** + * Returns a regex alternation for the given words. + * The words must not begin with an escaped character. + * + * @param alternatives Words to join + */ + protected static String alternation(String[] alternatives) { + // first characters of each alternative, to optimise the regex + String firstChars = Arrays.stream(alternatives) + .map(s -> s.substring(0, 1)) + .distinct() + .reduce((s1, s2) -> s1 + s2) + .get(); + + String alt = "(?=[" + firstChars + "])(?:" + String.join("|", alternatives) + ")"; + + return asWord(alt); + } + + + protected static String asWord(String regex) { + return "(?:\\b" + regex + "\\b)"; + } + /** * Gets a builder to make a grammar to build a highlighter. * diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/ApexSyntaxHighlighter.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/ApexSyntaxHighlighter.java index 618e113442..819a4df65e 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/ApexSyntaxHighlighter.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/ApexSyntaxHighlighter.java @@ -15,7 +15,6 @@ import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighti import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.SINGLEL_COMMENT; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.STRING; -import java.util.Arrays; import java.util.regex.Pattern; import net.sourceforge.pmd.util.fxdesigner.util.codearea.SimpleRegexSyntaxHighlighter; @@ -29,7 +28,7 @@ import net.sourceforge.pmd.util.fxdesigner.util.codearea.SimpleRegexSyntaxHighli public class ApexSyntaxHighlighter extends SimpleRegexSyntaxHighlighter { - private static final String[] KEYWORDS = new String[] { + private static final String[] KEYWORDS = { "abstract", "activate", "and", "any", "array", "as", "asc", "autonomous", "begin", "bigdecimal", "blob", "break", "bulk", "by", "byte", "case", "cast", "catch", @@ -55,24 +54,16 @@ public class ApexSyntaxHighlighter extends SimpleRegexSyntaxHighlighter { "last", "order", "sharing", "with", }; - - /** First characters of the keywords, used to optimise the regex. */ - private static final String KEYWORDS_START_CHARS = Arrays.stream(KEYWORDS) - .map(s -> s.substring(0, 1)) - .distinct() - .reduce((s1, s2) -> s1 + s2) - .get(); - private static final RegexHighlightGrammar GRAMMAR = grammarBuilder(SINGLEL_COMMENT.css, "//[^\r\n]*") .or(MULTIL_COMMENT.css, "/\\*.*?\\*/") - .or(KEYWORD.css, "\\b(?i)(?=[" + KEYWORDS_START_CHARS + "])(" + String.join("|", KEYWORDS) + ")\\b") + .or(KEYWORD.css, "(?i)" + alternation(KEYWORDS)) .or(PAREN.css, "[()]") .or(BRACE.css, "[{}]") .or(BRACKET.css, "[\\[]]") .or(SEMICOLON.css, ";") .or(STRING.css, "'[^'\\\\]*(\\\\.[^'\\\\]*)*'") - .or(BOOLEAN.css, "\\b(?i)true|false\\b") + .or(BOOLEAN.css, asWord("(?i)true|false")) .or(ANNOTATION.css, "@[\\w]+") .create(Pattern.DOTALL | Pattern.CASE_INSENSITIVE); diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/HighlightClasses.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/HighlightClasses.java index 96bad49f90..d1148ab687 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/HighlightClasses.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/HighlightClasses.java @@ -28,6 +28,7 @@ public enum HighlightClasses { LITERAL(Constants.LITERAL), BOOLEAN("boolean", Constants.LITERAL), STRING("string", Constants.LITERAL), + URI("uri", "string", Constants.LITERAL), CHAR("char", Constants.LITERAL), NULL("null", Constants.LITERAL), NUMBER("number", Constants.LITERAL), @@ -41,7 +42,8 @@ public enum HighlightClasses { XPATH_AXIS("axis", Constants.XPATH), XPATH_FUNCTION("function", Constants.XPATH), XPATH_PATH("path", Constants.XPATH, Constants.PUNCTUATION), - + XPATH_KIND_TEST("kind-test", "function", Constants.XPATH), + XML_CDATA_TAG("cdata-tag", Constants.XML), XML_CDATA_CONTENT("cdata-content", Constants.XML), XML_PROLOG("xml-prolog", Constants.XML), @@ -59,7 +61,7 @@ public enum HighlightClasses { } - private static class Constants { + private static final class Constants { static final String LITERAL = "literal"; static final String COMMENT = "comment"; static final String PUNCTUATION = "punctuation"; diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/JavaSyntaxHighlighter.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/JavaSyntaxHighlighter.java index 156d3405a3..af89cc07e9 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/JavaSyntaxHighlighter.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/JavaSyntaxHighlighter.java @@ -19,7 +19,6 @@ import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighti import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.SINGLEL_COMMENT; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.STRING; -import java.util.Arrays; import java.util.regex.Pattern; import net.sourceforge.pmd.util.fxdesigner.util.codearea.SimpleRegexSyntaxHighlighter; @@ -30,10 +29,10 @@ import net.sourceforge.pmd.util.fxdesigner.util.codearea.SimpleRegexSyntaxHighli * @author Clément Fournier * @since 6.0.0 */ -public class JavaSyntaxHighlighter extends SimpleRegexSyntaxHighlighter { +public final class JavaSyntaxHighlighter extends SimpleRegexSyntaxHighlighter { - private static final String[] KEYWORDS = new String[] { + private static final String[] KEYWORDS = { "public", "return", "final", "import", "static", "new", "extends", "int", "throws?", "void", "if", "this", "private", "class", "else", "case", "package", "abstract", @@ -48,29 +47,21 @@ public class JavaSyntaxHighlighter extends SimpleRegexSyntaxHighlighter { }; - /** First characters of the keywords, used to optimise the regex. */ - private static final String KEYWORDS_START_CHARS = Arrays.stream(KEYWORDS) - .map(s -> s.substring(0, 1)) - .distinct() - .reduce((s1, s2) -> s1 + s2) - .get(); - - private static final RegexHighlightGrammar GRAMMAR = grammarBuilder(SINGLEL_COMMENT.css, "//[^\n]*") .or(MULTIL_COMMENT.css, "/\\*.*?\\*/") .or(PAREN.css, "[()]") - .or(NUMBER.css, "\\b\\d+[fdlFDL]*\\b") + .or(NUMBER.css, asWord("\\d+[fdlFDL]*")) .or(BRACE.css, "[{}]") .or(BRACKET.css, "[\\[]]") .or(SEMICOLON.css, ";") - .or(KEYWORD.css, "\\b(?=[" + KEYWORDS_START_CHARS + "])(?:" + String.join("|", KEYWORDS) + ")\\b") + .or(KEYWORD.css, alternation(KEYWORDS)) .or(STRING.css, "\"[^\"\\\\]*(\\\\.[^\"\\\\]*)*\"") .or(CHAR.css, "'(?:[^']|\\\\(?:'|u\\w{4}))'") // char - .or(NULL.css, "\\bnull\\b") - .or(BOOLEAN.css, "\\btrue|false\\b") + .or(NULL.css, asWord("null")) + .or(BOOLEAN.css, asWord("true|false")) .or(ANNOTATION.css, "@[\\w]+") - .or(CLASS_IDENTIFIER.css, "\\b[A-Z][\\w_$]*\\b") + .or(CLASS_IDENTIFIER.css, asWord("[A-Z][\\w_$]*")) .create(Pattern.DOTALL); diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/XPathSyntaxHighlighter.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/XPathSyntaxHighlighter.java index 96c0559a3e..d196e6ba29 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/XPathSyntaxHighlighter.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/XPathSyntaxHighlighter.java @@ -6,13 +6,15 @@ package net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.BRACKET; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.KEYWORD; +import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.MULTIL_COMMENT; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.NUMBER; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.PAREN; -import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.SINGLEL_COMMENT; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.STRING; +import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.URI; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.XPATH_ATTRIBUTE; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.XPATH_AXIS; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.XPATH_FUNCTION; +import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.XPATH_KIND_TEST; import static net.sourceforge.pmd.util.fxdesigner.util.codearea.syntaxhighlighting.HighlightClasses.XPATH_PATH; import net.sourceforge.pmd.util.fxdesigner.util.codearea.SimpleRegexSyntaxHighlighter; @@ -23,29 +25,43 @@ import net.sourceforge.pmd.util.fxdesigner.util.codearea.SimpleRegexSyntaxHighli */ public class XPathSyntaxHighlighter extends SimpleRegexSyntaxHighlighter { - private static final String[] AXIS_NAMES = new String[] { + private static final String[] AXIS_NAMES = { "self", "child", "attribute", "descendant", "descendant-or-self", "ancestor", "ancestor-or-self", "following", "following-sibling", "namespace", "parent", "preceding-sibling", }; - private static final String[] KEYWORDS = new String[] { - "or", "and", "not", - }; + private static final String[] KEYWORDS = { + "or", "and", "not", "some", "in", "satisfies", + "as", "is", "for", "every", "cast", "castable", + "treat", "instance", "of", "to", "if", "then", "else", + "return", "let", + "intersect", "except", "union", "div", "idiv", "mod", + "ne", "eq", "lt", "le", "gt", "ge" + }; + + private static final String[] KIND_TESTS = { + "node", "document-node", "text", "comment", + "namespace-node", "processing-instruction", + "attribute", "schema-attribute", "element", + "schema-element", "function" + }; private static final RegexHighlightGrammar GRAMMAR = grammarBuilder(XPATH_ATTRIBUTE.css, "@[\\w]+") - .or(XPATH_AXIS.css, "(" + String.join("|", AXIS_NAMES) + ")(?=::)") - .or(KEYWORD.css, "\\b(" + String.join("|", KEYWORDS) + ")\\b") - .or(XPATH_FUNCTION.css, "[\\w-]+?(?=\\()") - .or(XPATH_PATH.css, "//?") - .or(PAREN.css, "[()]") - .or(BRACKET.css, "[\\[\\]]") - .or(NUMBER.css, "\\b\\d+\\b") - .or(STRING.css, "('([^'\\\\]|\\\\.)*')|(\"([^\"\\\\]|\\\\.)*\")") - .or(SINGLEL_COMMENT.css, "\\(:.*?:\\)") - .create(); + .or(XPATH_PATH.css, "//?") + .or(XPATH_AXIS.css, alternation(AXIS_NAMES) + "::") + .or(KEYWORD.css, alternation(KEYWORDS)) + .or(XPATH_KIND_TEST.css, alternation(KIND_TESTS) + "\\(\\)") + .or(XPATH_FUNCTION.css, "[\\w-]+?(?=\\()") + .or(MULTIL_COMMENT.css, "\\(:.*?:\\)") // comments can be nested but whatever + .or(PAREN.css, "[()]") + .or(BRACKET.css, "[\\[\\]]") + .or(NUMBER.css, "(\\.\\d++\\b|\\b\\d++\\.|(\\b\\d++(\\.\\d*+)?([eE][+-]?\\d+)?))") + .or(STRING.css, "('([^']|'')*')|(\"([^\"]|\"\")*\")") + .or(URI.css, "Q\\{[^{}]*}") + .create(); public XPathSyntaxHighlighter() { diff --git a/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/css/editor-theme.css b/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/css/editor-theme.css index bf88822893..080f190ea9 100644 --- a/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/css/editor-theme.css +++ b/pmd-ui/src/main/resources/net/sourceforge/pmd/util/fxdesigner/css/editor-theme.css @@ -91,7 +91,11 @@ } .styled-text-area .xpath.path { - -fx-font-weight: bolder; + -fx-font-weight: bold; +} + +.styled-text-area .xpath.axis { + -fx-fill: #B05A65; } .styled-text-area .xpath.bracket { @@ -102,6 +106,10 @@ -fx-fill: #B05A65; } +.styled-text-area .xpath.function { + -fx-fill: #cc971b; +} + /* XML specific */ .styled-text-area .xml.xml-prolog { From 8be7db8d3bf6337fd3f61e97cfc5db80a10795ad Mon Sep 17 00:00:00 2001 From: stonio Date: Tue, 27 Mar 2018 17:40:45 +0200 Subject: [PATCH 18/21] Fix closing tag for pmdVersion --- docs/pages/pmd/userdocs/tools/maven.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/pmd/userdocs/tools/maven.md b/docs/pages/pmd/userdocs/tools/maven.md index 5cbec2d703..34bd7123de 100644 --- a/docs/pages/pmd/userdocs/tools/maven.md +++ b/docs/pages/pmd/userdocs/tools/maven.md @@ -153,7 +153,7 @@ Maven plugin will use and benefit from the latest bugfixes and enhancements: ``` xml - ...choose your version... + ...choose your version... ... From a3e687d7ee1b4c115693d5c2902e53e2b0401fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 28 Mar 2018 00:57:37 +0200 Subject: [PATCH 19/21] Update release notes, refs #1008 --- docs/pages/release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 0699c44bce..0e2738b26c 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -24,3 +24,5 @@ This is a minor release. ### API Changes ### External Contributions + +* [#1008](https://github.com/pmd/pmd/pull/1008): \[core] DOC: fix closing tag for <pmdVersion> - [stonio](https://github.com/stonio) From 42bec12c58bdc09a3c99dc9adc9ff813b2d1ffe6 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Wed, 28 Mar 2018 09:15:46 +0200 Subject: [PATCH 20/21] Update changelog, refs #994 refs #1002 --- docs/pages/release_notes.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 916306bf83..abbbc6bb4b 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -108,6 +108,7 @@ On both scenarios, disabling the cache takes precedence over setting a cache loc * documentation * [#978](https://github.com/pmd/pmd/issues/978): \[core] Broken link in CONTRIBUTING.md * [#992](https://github.com/pmd/pmd/issues/992): \[core] Include info about rule doc generation in "Writing Documentation" md page + * [#994](https://github.com/pmd/pmd/issues/994): \[doc] Delete duplicate page contributing.md on the website ### API Changes @@ -136,4 +137,4 @@ On both scenarios, disabling the cache takes precedence over setting a cache loc * [#989](https://github.com/pmd/pmd/pull/989): \[core] Update Contribute.md to close Issue #978 - [Bolarinwa Saheed Olayemi](https://github.com/refactormyself) * [#990](https://github.com/pmd/pmd/pull/990): \[java] Updated Doc on AvoidThrowingNullPointerException to close Issue #832 - [Bolarinwa Saheed Olayemi](https://github.com/refactormyself) * [#993](https://github.com/pmd/pmd/pull/993): \[core] Update writing_documentation.md to fix Issue #992 - [Bolarinwa Saheed Olayemi](https://github.com/refactormyself) - +* [#1002](https://github.com/pmd/pmd/pull/1002): \ [doc] Delete duplicate page contributing.md on the website - [Ishan Srivastava](https://github.com/ishanSrt) From 5bc18b8298b71b8580e49336136aa21b453383b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Thu, 29 Mar 2018 02:12:02 -0300 Subject: [PATCH 21/21] Fix checkstyle warnings --- .../XPathSyntaxHighlighter.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/XPathSyntaxHighlighter.java b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/XPathSyntaxHighlighter.java index d196e6ba29..538905b9a4 100644 --- a/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/XPathSyntaxHighlighter.java +++ b/pmd-ui/src/main/java/net/sourceforge/pmd/util/fxdesigner/util/codearea/syntaxhighlighting/XPathSyntaxHighlighter.java @@ -29,22 +29,22 @@ public class XPathSyntaxHighlighter extends SimpleRegexSyntaxHighlighter { "self", "child", "attribute", "descendant", "descendant-or-self", "ancestor", "ancestor-or-self", "following", "following-sibling", "namespace", "parent", "preceding-sibling", - }; + }; private static final String[] KEYWORDS = { - "or", "and", "not", "some", "in", "satisfies", - "as", "is", "for", "every", "cast", "castable", - "treat", "instance", "of", "to", "if", "then", "else", - "return", "let", - "intersect", "except", "union", "div", "idiv", "mod", - "ne", "eq", "lt", "le", "gt", "ge" + "or", "and", "not", "some", "in", "satisfies", + "as", "is", "for", "every", "cast", "castable", + "treat", "instance", "of", "to", "if", "then", "else", + "return", "let", + "intersect", "except", "union", "div", "idiv", "mod", + "ne", "eq", "lt", "le", "gt", "ge", }; private static final String[] KIND_TESTS = { - "node", "document-node", "text", "comment", - "namespace-node", "processing-instruction", - "attribute", "schema-attribute", "element", - "schema-element", "function" + "node", "document-node", "text", "comment", + "namespace-node", "processing-instruction", + "attribute", "schema-attribute", "element", + "schema-element", "function", };