From df0a1832264b69307a8134a70781fa4575decb74 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 29 Mar 2019 14:24:17 +0100 Subject: [PATCH 001/235] [apex] Throw parse errors for invalid code --- .../pmd/lang/apex/ast/ApexParser.java | 2 +- .../pmd/lang/apex/ast/CompilerService.java | 1 + .../pmd/lang/apex/ast/ApexCompilerTest.java | 21 +++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCompilerTest.java diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java index 3cbd386de2..e63efa9cf0 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java @@ -55,7 +55,7 @@ public class ApexParser { } return treeBuilder.build(astRoot); - } catch (IOException e) { + } catch (IOException | apex.jorje.services.exception.ParseException e) { throw new ParseException(e); } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java index 2f5b3c0817..1655c57f2e 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java @@ -92,6 +92,7 @@ public class CompilerService { ApexCompiler compiler = ApexCompiler.builder().setInput(compilationInput).build(); compiler.compile(compilerStage); callAdditionalPassVisitor(compiler); + compiler.throwErrorsIfAny(); return compiler; } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCompilerTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCompilerTest.java new file mode 100644 index 0000000000..e7f91d271a --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCompilerTest.java @@ -0,0 +1,21 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import static net.sourceforge.pmd.lang.apex.ast.ApexParserTestHelpers.parse; + +import org.junit.Test; + +import net.sourceforge.pmd.lang.ast.ParseException; + +import apex.jorje.semantic.ast.compilation.Compilation; + +public class ApexCompilerTest { + + @Test(expected = ParseException.class) + public void compileShouldFail() { + ApexNode node = parse("public class Foo { private String myField = \"a\"; }"); + } +} From 463e26834155eb3974c3570aa9957e7afa4d0405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 22 Oct 2018 22:56:11 +0200 Subject: [PATCH 002/235] Remove unused rule classes --- .../java/rule/StringConcatenationRule.java | 29 ------- .../lang/java/rule/SymbolTableTestRule.java | 25 ------ .../rule/design/PositionalIteratorRule.java | 81 ------------------- .../documentation/CodeInCommentsRule.java | 16 ---- .../java/rule/documentation/JavadocRule.java | 9 --- 5 files changed, 160 deletions(-) delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/StringConcatenationRule.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/SymbolTableTestRule.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/PositionalIteratorRule.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CodeInCommentsRule.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/JavadocRule.java diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/StringConcatenationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/StringConcatenationRule.java deleted file mode 100644 index a0c9f51195..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/StringConcatenationRule.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.java.rule; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; -import net.sourceforge.pmd.lang.java.ast.ASTForStatement; - -//FUTURE This is not referenced by any RuleSet? -public class StringConcatenationRule extends AbstractJavaRule { - - @Override - public Object visit(ASTForStatement node, Object data) { - Node forLoopStmt = null; - for (int i = 0; i < 4; i++) { - forLoopStmt = node.jjtGetChild(i); - if (forLoopStmt instanceof ASTBlockStatement) { - break; - } - } - if (forLoopStmt == null) { - return data; - } - - return data; - } -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/SymbolTableTestRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/SymbolTableTestRule.java deleted file mode 100644 index 40a206c73b..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/SymbolTableTestRule.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.java.rule; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.symboltable.NameOccurrence; - -//FUTURE This is not referenced by any RuleSet? -public class SymbolTableTestRule extends AbstractJavaRule { - - @Override - public Object visit(ASTFieldDeclaration node, Object data) { - for (ASTVariableDeclaratorId declaration : node.findDescendantsOfType(ASTVariableDeclaratorId.class)) { - for (NameOccurrence no : declaration.getUsages()) { - Node location = no.getLocation(); - System.out.println(declaration.getImage() + " is used here: " + location.getImage()); - } - } - return data; - } -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/PositionalIteratorRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/PositionalIteratorRule.java deleted file mode 100644 index 09aa106952..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/PositionalIteratorRule.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.design; - -import java.util.ArrayList; -import java.util.List; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTName; -import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; - -public class PositionalIteratorRule extends AbstractJavaRule { - - @Override - public Object visit(ASTWhileStatement node, Object data) { - if (hasNameAsChild(node.jjtGetChild(0))) { - String exprName = getName(node.jjtGetChild(0)); - if (exprName.indexOf(".hasNext") != -1 && node.jjtGetNumChildren() > 1) { - - Node loopBody = node.jjtGetChild(1); - List names = new ArrayList<>(); - collectNames(getVariableName(exprName), names, loopBody); - int nextCount = 0; - for (String name : names) { - if (name.indexOf(".next") != -1) { - nextCount++; - } - } - - if (nextCount > 1) { - addViolation(data, node); - } - - } - } - return null; - } - - private String getVariableName(String exprName) { - return exprName.substring(0, exprName.indexOf('.')); - } - - private void collectNames(String target, List names, Node node) { - for (int i = 0; i < node.jjtGetNumChildren(); i++) { - Node child = node.jjtGetChild(i); - if (child.jjtGetNumChildren() > 0) { - collectNames(target, names, child); - } else { - if (child instanceof ASTName && isQualifiedName(child) - && target.equals(getVariableName(child.getImage()))) { - names.add(child.getImage()); - } - } - } - } - - private boolean hasNameAsChild(Node node) { - if (node.jjtGetNumChildren() > 0) { - if (node.jjtGetChild(0) instanceof ASTName) { - return true; - } else { - return hasNameAsChild(node.jjtGetChild(0)); - } - } - return false; - } - - private String getName(Node node) { - if (node.jjtGetNumChildren() > 0) { - if (node.jjtGetChild(0) instanceof ASTName) { - return ((ASTName) node.jjtGetChild(0)).getImage(); - } else { - return getName(node.jjtGetChild(0)); - } - } - throw new IllegalArgumentException("Check with hasNameAsChild() first!"); - } -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CodeInCommentsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CodeInCommentsRule.java deleted file mode 100644 index e7e37d5a1d..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CodeInCommentsRule.java +++ /dev/null @@ -1,16 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.documentation; - -/** - * - * @author Brian Remedios - */ -public class CodeInCommentsRule extends AbstractCommentRule { - - // private static final char[] SingleCharsAsCode = new char[] {'{', '}'}; - // private static final char[] LastCharTerminatorAsCode = new char[] { '{', - // '}', ';' }; -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/JavadocRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/JavadocRule.java deleted file mode 100644 index e25c8a1f23..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/JavadocRule.java +++ /dev/null @@ -1,9 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.documentation; - -public class JavadocRule extends AbstractCommentRule { - -} From d3c98dd14876b161c29904df8c2d9044c929c67f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 13 Sep 2019 03:20:20 +0200 Subject: [PATCH 003/235] Remove variable naming convention rules --- .../VariableNamingConventionsRule.java | 242 ------------ .../resources/category/apex/codestyle.xml | 28 -- .../VariableNamingConventionsTest.java | 11 - .../xml/VariableNamingConventions.xml | 323 --------------- .../VariableNamingConventionsRule.java | 252 ------------ .../resources/category/java/codestyle.xml | 28 -- .../VariableNamingConventionsTest.java | 11 - .../xml/VariableNamingConventions.xml | 373 ------------------ 8 files changed, 1268 deletions(-) delete mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/VariableNamingConventionsRule.java delete mode 100644 pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/VariableNamingConventionsTest.java delete mode 100644 pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/VariableNamingConventions.xml delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/VariableNamingConventionsRule.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/VariableNamingConventionsTest.java delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/VariableNamingConventions.xml diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/VariableNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/VariableNamingConventionsRule.java deleted file mode 100644 index b5ba653d29..0000000000 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/VariableNamingConventionsRule.java +++ /dev/null @@ -1,242 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.rule.codestyle; - -import static net.sourceforge.pmd.properties.PropertyFactory.booleanProperty; -import static net.sourceforge.pmd.properties.PropertyFactory.stringListProperty; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import net.sourceforge.pmd.lang.apex.ast.ASTField; -import net.sourceforge.pmd.lang.apex.ast.ASTParameter; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; -import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclaration; -import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclarationStatements; -import net.sourceforge.pmd.lang.apex.ast.ApexNode; -import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; -import net.sourceforge.pmd.properties.PropertyDescriptor; - -@Deprecated -public class VariableNamingConventionsRule extends AbstractApexRule { - - private boolean checkMembers; - private boolean checkLocals; - private boolean checkParameters; - private List staticPrefixes; - private List staticSuffixes; - private List memberPrefixes; - private List memberSuffixes; - private List localPrefixes; - private List localSuffixes; - private List parameterPrefixes; - private List parameterSuffixes; - - private static final PropertyDescriptor CHECK_MEMBERS_DESCRIPTOR = - booleanProperty("checkMembers") - .desc("Check member variables").defaultValue(true).build(); - - private static final PropertyDescriptor CHECK_LOCALS_DESCRIPTOR = - booleanProperty("checkLocals") - .desc("Check local variables").defaultValue(true).build(); - - private static final PropertyDescriptor CHECK_PARAMETERS_DESCRIPTOR = - booleanProperty("checkParameters") - .desc("Check constructor and method parameter variables").defaultValue(true).build(); - - private static final PropertyDescriptor> STATIC_PREFIXES_DESCRIPTOR = - stringListProperty("staticPrefix") - .desc("Static variable prefixes").defaultValues("").delim(',').build(); - - private static final PropertyDescriptor> STATIC_SUFFIXES_DESCRIPTOR = - stringListProperty("staticSuffix") - .desc("Static variable suffixes").defaultValues("").delim(',').build(); - - private static final PropertyDescriptor> MEMBER_PREFIXES_DESCRIPTOR = - stringListProperty("memberPrefix") - .desc("Member variable prefixes").defaultValues("").delim(',').build(); - - private static final PropertyDescriptor> MEMBER_SUFFIXES_DESCRIPTOR = - stringListProperty("memberSuffix") - .desc("Member variable suffixes").defaultValues("").delim(',').build(); - - private static final PropertyDescriptor> LOCAL_PREFIXES_DESCRIPTOR = - stringListProperty("localPrefix") - .desc("Local variable prefixes").defaultValues("").delim(',').build(); - - private static final PropertyDescriptor> LOCAL_SUFFIXES_DESCRIPTOR = - stringListProperty("localSuffix") - .desc("Local variable suffixes").defaultValues("").delim(',').build(); - - private static final PropertyDescriptor> PARAMETER_PREFIXES_DESCRIPTOR = - stringListProperty("parameterPrefix") - .desc("Method parameter variable prefixes") - .defaultValues("").delim(',').build(); - - private static final PropertyDescriptor> PARAMETER_SUFFIXES_DESCRIPTOR = - stringListProperty("parameterSuffix") - .desc("Method parameter variable suffixes") - .defaultValues("").delim(',').build(); - - - public VariableNamingConventionsRule() { - definePropertyDescriptor(CHECK_MEMBERS_DESCRIPTOR); - definePropertyDescriptor(CHECK_LOCALS_DESCRIPTOR); - definePropertyDescriptor(CHECK_PARAMETERS_DESCRIPTOR); - for (PropertyDescriptor> property : suffixOrPrefixProperties()) { - definePropertyDescriptor(property); - } - } - - private static List>> suffixOrPrefixProperties() { - List>> res = new ArrayList<>(); - res.add(STATIC_PREFIXES_DESCRIPTOR); - res.add(STATIC_SUFFIXES_DESCRIPTOR); - res.add(MEMBER_PREFIXES_DESCRIPTOR); - res.add(MEMBER_SUFFIXES_DESCRIPTOR); - res.add(LOCAL_PREFIXES_DESCRIPTOR); - res.add(LOCAL_SUFFIXES_DESCRIPTOR); - res.add(PARAMETER_PREFIXES_DESCRIPTOR); - res.add(PARAMETER_SUFFIXES_DESCRIPTOR); - return res; - } - - @Override - public Object visit(ASTUserClass node, Object data) { - init(); - return super.visit(node, data); - } - - @Override - public Object visit(ASTUserInterface node, Object data) { - init(); - return super.visit(node, data); - } - - protected void init() { - checkMembers = getProperty(CHECK_MEMBERS_DESCRIPTOR); - checkLocals = getProperty(CHECK_LOCALS_DESCRIPTOR); - checkParameters = getProperty(CHECK_PARAMETERS_DESCRIPTOR); - staticPrefixes = getProperty(STATIC_PREFIXES_DESCRIPTOR); - staticSuffixes = getProperty(STATIC_SUFFIXES_DESCRIPTOR); - memberPrefixes = getProperty(MEMBER_PREFIXES_DESCRIPTOR); - memberSuffixes = getProperty(MEMBER_SUFFIXES_DESCRIPTOR); - localPrefixes = getProperty(LOCAL_PREFIXES_DESCRIPTOR); - localSuffixes = getProperty(LOCAL_SUFFIXES_DESCRIPTOR); - parameterPrefixes = getProperty(PARAMETER_PREFIXES_DESCRIPTOR); - parameterSuffixes = getProperty(PARAMETER_SUFFIXES_DESCRIPTOR); - } - - @Override - public Object visit(ASTField node, Object data) { - if (!checkMembers) { - return data; - } - boolean isStatic = node.getModifiers().isStatic(); - boolean isFinal = node.getModifiers().isFinal(); - - return checkName(isStatic ? staticPrefixes : memberPrefixes, isStatic ? staticSuffixes : memberSuffixes, node, - isStatic, isFinal, data); - } - - @Override - public Object visit(ASTVariableDeclaration node, Object data) { - - if (!checkLocals) { - return data; - } - - boolean isFinal = node.getFirstParentOfType(ASTVariableDeclarationStatements.class).getModifiers().isFinal(); - return checkName(localPrefixes, localSuffixes, node, false, isFinal, data); - } - - @Override - public Object visit(ASTParameter node, Object data) { - if (!checkParameters) { - return data; - } - - boolean isFinal = node.getModifiers().isFinal(); - return checkName(parameterPrefixes, parameterSuffixes, node, false, isFinal, data); - } - - private Object checkName(List prefixes, List suffixes, ApexNode node, boolean isStatic, boolean isFinal, - Object data) { - - String varName = node.getImage(); - - // Skip on null (with exception classes) and serialVersionUID - if (varName == null || "serialVersionUID".equals(varName)) { - return data; - } - - // Static finals should be uppercase - if (isStatic && isFinal) { - if (!varName.equals(varName.toUpperCase(Locale.ROOT))) { - addViolationWithMessage(data, node, - "Variables that are final and static should be all capitals, ''{0}'' is not all capitals.", - new Object[] { varName }); - } - return data; - } else if (!isFinal) { - String normalizedVarName = normalizeVariableName(varName, prefixes, suffixes); - - if (normalizedVarName.indexOf('_') >= 0) { - addViolationWithMessage(data, node, - "Only variables that are final should contain underscores (except for underscores in standard prefix/suffix), ''{0}'' is not final.", - new Object[] { varName }); - } - if (Character.isUpperCase(varName.charAt(0))) { - addViolationWithMessage(data, node, - "Variables should start with a lowercase character, ''{0}'' starts with uppercase character.", - new Object[] { varName }); - } - } - return data; - } - - private String normalizeVariableName(String varName, List prefixes, List suffixes) { - return stripSuffix(stripPrefix(varName, prefixes), suffixes); - } - - private String stripSuffix(String varName, List suffixes) { - if (suffixes != null) { - for (String suffix : suffixes) { - if (varName.endsWith(suffix)) { - return varName.substring(0, varName.length() - suffix.length()); - } - } - } - return varName; - } - - private String stripPrefix(String varName, List prefixes) { - if (prefixes != null) { - for (String prefix : prefixes) { - if (varName.startsWith(prefix)) { - return varName.substring(prefix.length()); - } - } - } - return varName; - } - - public boolean hasPrefixesOrSuffixes() { - for (PropertyDescriptor> desc : suffixOrPrefixProperties()) { - if (!getProperty(desc).isEmpty()) { - return true; - } - } - return false; - } - - @Override - public String dysfunctionReason() { - return hasPrefixesOrSuffixes() ? null : "No prefixes or suffixes specified"; - } - -} diff --git a/pmd-apex/src/main/resources/category/apex/codestyle.xml b/pmd-apex/src/main/resources/category/apex/codestyle.xml index 262b6f9757..fea01c375b 100644 --- a/pmd-apex/src/main/resources/category/apex/codestyle.xml +++ b/pmd-apex/src/main/resources/category/apex/codestyle.xml @@ -303,34 +303,6 @@ public class Foo { - - -A variable naming conventions rule - customize this to your liking. Currently, it -checks for final variables that should be fully capitalized and non-final variables -that should not include underscores. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the more general rules {% rule "apex/codestyle/FieldNamingConventions" %}, -{% rule "apex/codestyle/FormalParameterNamingConventions" %}, -{% rule "apex/codestyle/LocalVariableNamingConventions" %}, and -{% rule "apex/codestyle/PropertyNamingConventions" %}. - - 1 - - - - - - - - - member level, final statics should be all caps - 1 - - - - - member level, non-finals shouldn't have underscores - 1 - - - - - local level, non-finals shouldn't have underscores - 1 - - - - - method level, non-finals shouldn't have underscores - 2 - - - - - constructor level, non-finals shouldn't have underscores - 2 - - - - - member level, variables names should start with lowercase character - 1 - - - - - local level, variables names should start with lowercase character - 1 - - - - - method level, variables names should start with lowercase character - 1 - - - - - constructor level, variables names should start with lowercase character - 1 - - - - - all is well - 0 - - - - - local finals are ok - 0 - - - - - serialVersionUID is OK - 0 - - - - - final non-statics need not be all caps - 0 - - - - - variables in inner classes should not trigger problems in parent declaration - 0 - - - - - Rule property control - 5 - - - - - Check prefixes - s_ - m_ - l_ - p_ - 0 - - - - - Check suffixes - _s - _m - _l - _p - 0 - - - - - Check members disabled - false - 3 - - - - - Check locals disabled - false - 4 - - - - - Check parameters disabled - false - 3 - - - - - False - with non primitive fields (Bug 2225474) - 1 - - - - - #1349 VariableNamingConventions : underscore in final but at first position ? - 0 - - - - - Inner exception - 0 - - - - - Exception - 0 - - - - - Enum members - 0 - - - diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/VariableNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/VariableNamingConventionsRule.java deleted file mode 100644 index 4ec8326aad..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/VariableNamingConventionsRule.java +++ /dev/null @@ -1,252 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codestyle; - -import static net.sourceforge.pmd.properties.PropertyFactory.booleanProperty; - -import java.util.List; -import java.util.Locale; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; -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.ast.ASTFormalParameter; -import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; -import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.properties.PropertyDescriptor; -import net.sourceforge.pmd.properties.StringMultiProperty; - -@Deprecated -public class VariableNamingConventionsRule extends AbstractJavaRule { - - private boolean checkMembers; - private boolean checkLocals; - private boolean checkParameters; - private boolean checkNativeMethodParameters; - private List staticPrefixes; - private List staticSuffixes; - private List memberPrefixes; - private List memberSuffixes; - private List localPrefixes; - private List localSuffixes; - private List parameterPrefixes; - private List parameterSuffixes; - - private static final PropertyDescriptor CHECK_MEMBERS_DESCRIPTOR = booleanProperty("checkMembers").defaultValue(true).desc("Check member variables").build(); - - private static final PropertyDescriptor CHECK_LOCALS_DESCRIPTOR = booleanProperty("checkLocals").defaultValue(true).desc("Check local variables").build(); - - private static final PropertyDescriptor CHECK_PARAMETERS_DESCRIPTOR = booleanProperty("checkParameters").defaultValue(true).desc("Check constructor and method parameter variables").build(); - - private static final PropertyDescriptor CHECK_NATIVE_METHOD_PARAMETERS_DESCRIPTOR = booleanProperty("checkNativeMethodParameters").defaultValue(true).desc("Check method parameter of native methods").build(); - - // the rule is deprecated and will be removed so its properties won't be converted - private static final StringMultiProperty STATIC_PREFIXES_DESCRIPTOR = new StringMultiProperty("staticPrefix", - "Static variable prefixes", new String[] { "" }, 4.0f, ','); - - private static final StringMultiProperty STATIC_SUFFIXES_DESCRIPTOR = new StringMultiProperty("staticSuffix", - "Static variable suffixes", new String[] { "" }, 5.0f, ','); - - private static final StringMultiProperty MEMBER_PREFIXES_DESCRIPTOR = new StringMultiProperty("memberPrefix", - "Member variable prefixes", new String[] { "" }, 6.0f, ','); - - private static final StringMultiProperty MEMBER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("memberSuffix", - "Member variable suffixes", new String[] { "" }, 7.0f, ','); - - private static final StringMultiProperty LOCAL_PREFIXES_DESCRIPTOR = new StringMultiProperty("localPrefix", - "Local variable prefixes", new String[] { "" }, 8.0f, ','); - - private static final StringMultiProperty LOCAL_SUFFIXES_DESCRIPTOR = new StringMultiProperty("localSuffix", - "Local variable suffixes", new String[] { "" }, 9.0f, ','); - - private static final StringMultiProperty PARAMETER_PREFIXES_DESCRIPTOR = new StringMultiProperty("parameterPrefix", - "Method parameter variable prefixes", new String[] { "" }, 10.0f, ','); - - private static final StringMultiProperty PARAMETER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("parameterSuffix", - "Method parameter variable suffixes", new String[] { "" }, 11.0f, ','); - - public VariableNamingConventionsRule() { - definePropertyDescriptor(CHECK_MEMBERS_DESCRIPTOR); - definePropertyDescriptor(CHECK_LOCALS_DESCRIPTOR); - definePropertyDescriptor(CHECK_PARAMETERS_DESCRIPTOR); - definePropertyDescriptor(CHECK_NATIVE_METHOD_PARAMETERS_DESCRIPTOR); - definePropertyDescriptor(STATIC_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(STATIC_SUFFIXES_DESCRIPTOR); - definePropertyDescriptor(MEMBER_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(MEMBER_SUFFIXES_DESCRIPTOR); - definePropertyDescriptor(LOCAL_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(LOCAL_SUFFIXES_DESCRIPTOR); - definePropertyDescriptor(PARAMETER_PREFIXES_DESCRIPTOR); - definePropertyDescriptor(PARAMETER_SUFFIXES_DESCRIPTOR); - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - init(); - return super.visit(node, data); - } - - protected void init() { - checkMembers = getProperty(CHECK_MEMBERS_DESCRIPTOR); - checkLocals = getProperty(CHECK_LOCALS_DESCRIPTOR); - checkParameters = getProperty(CHECK_PARAMETERS_DESCRIPTOR); - checkNativeMethodParameters = getProperty(CHECK_NATIVE_METHOD_PARAMETERS_DESCRIPTOR); - staticPrefixes = getProperty(STATIC_PREFIXES_DESCRIPTOR); - staticSuffixes = getProperty(STATIC_SUFFIXES_DESCRIPTOR); - memberPrefixes = getProperty(MEMBER_PREFIXES_DESCRIPTOR); - memberSuffixes = getProperty(MEMBER_SUFFIXES_DESCRIPTOR); - localPrefixes = getProperty(LOCAL_PREFIXES_DESCRIPTOR); - localSuffixes = getProperty(LOCAL_SUFFIXES_DESCRIPTOR); - parameterPrefixes = getProperty(PARAMETER_PREFIXES_DESCRIPTOR); - parameterSuffixes = getProperty(PARAMETER_SUFFIXES_DESCRIPTOR); - } - - @Override - public Object visit(ASTFieldDeclaration node, Object data) { - if (!checkMembers) { - return data; - } - boolean isStatic = node.isStatic(); - boolean isFinal = node.isFinal(); - - Node type = node.jjtGetParent().jjtGetParent().jjtGetParent(); - // Anything from an interface is necessarily static and final - // Anything inside an annotation type is also static and final - if (type instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) type).isInterface() - || type instanceof ASTAnnotationTypeDeclaration) { - isStatic = true; - isFinal = true; - } - return checkVariableDeclarators(node.isStatic() ? staticPrefixes : memberPrefixes, - isStatic ? staticSuffixes : memberSuffixes, node, isStatic, isFinal, data); - } - - @Override - public Object visit(ASTLocalVariableDeclaration node, Object data) { - if (!checkLocals) { - return data; - } - return checkVariableDeclarators(localPrefixes, localSuffixes, node, false, node.isFinal(), data); - } - - @Override - public Object visit(ASTFormalParameters node, Object data) { - if (!checkParameters) { - return data; - } - ASTMethodDeclaration methodDeclaration = node.getFirstParentOfType(ASTMethodDeclaration.class); - if (!checkNativeMethodParameters && methodDeclaration.isNative()) { - return data; - } - - for (ASTFormalParameter formalParameter : node.findChildrenOfType(ASTFormalParameter.class)) { - for (ASTVariableDeclaratorId variableDeclaratorId : formalParameter - .findChildrenOfType(ASTVariableDeclaratorId.class)) { - checkVariableDeclaratorId(parameterPrefixes, parameterSuffixes, false, formalParameter.isFinal(), - variableDeclaratorId, data); - } - } - return data; - } - - private Object checkVariableDeclarators(List prefixes, List suffixes, Node root, boolean isStatic, - boolean isFinal, Object data) { - for (ASTVariableDeclarator variableDeclarator : root.findChildrenOfType(ASTVariableDeclarator.class)) { - for (ASTVariableDeclaratorId variableDeclaratorId : variableDeclarator - .findChildrenOfType(ASTVariableDeclaratorId.class)) { - checkVariableDeclaratorId(prefixes, suffixes, isStatic, isFinal, variableDeclaratorId, data); - } - } - return data; - } - - private Object checkVariableDeclaratorId(List prefixes, List suffixes, boolean isStatic, - boolean isFinal, ASTVariableDeclaratorId variableDeclaratorId, Object data) { - - // Get the variable name - String varName = variableDeclaratorId.getImage(); - - // Skip serialVersionUID - if ("serialVersionUID".equals(varName)) { - return data; - } - - // Static finals should be uppercase - if (isStatic && isFinal) { - if (!varName.equals(varName.toUpperCase(Locale.ROOT))) { - addViolationWithMessage(data, variableDeclaratorId, - "Variables that are final and static should be all capitals, ''{0}'' is not all capitals.", - new Object[] { varName }); - } - return data; - } else if (!isFinal) { - String normalizedVarName = normalizeVariableName(varName, prefixes, suffixes); - - if (normalizedVarName.indexOf('_') >= 0) { - addViolationWithMessage(data, variableDeclaratorId, - "Only variables that are final should contain underscores (except for underscores in standard prefix/suffix), ''{0}'' is not final.", - new Object[] { varName }); - } - if (Character.isUpperCase(varName.charAt(0))) { - addViolationWithMessage(data, variableDeclaratorId, - "Variables should start with a lowercase character, ''{0}'' starts with uppercase character.", - new Object[] { varName }); - } - } - return data; - } - - private String normalizeVariableName(String varName, List prefixes, List suffixes) { - return stripSuffix(stripPrefix(varName, prefixes), suffixes); - } - - private String stripSuffix(String varName, List suffixes) { - if (suffixes != null) { - for (String suffix : suffixes) { - if (varName.endsWith(suffix)) { - varName = varName.substring(0, varName.length() - suffix.length()); - break; - } - } - } - return varName; - } - - private String stripPrefix(String varName, List prefixes) { - if (prefixes != null) { - for (String prefix : prefixes) { - if (varName.startsWith(prefix)) { - return varName.substring(prefix.length()); - } - } - } - return varName; - } - - public boolean hasPrefixesOrSuffixes() { - - for (PropertyDescriptor desc : getPropertyDescriptors()) { - if (desc instanceof StringMultiProperty) { - List values = getProperty((StringMultiProperty) desc); - if (!values.isEmpty()) { - return true; - } - } - } - return false; - } - - @Override - public String dysfunctionReason() { - return hasPrefixesOrSuffixes() ? null : "No prefixes or suffixes specified"; - } - -} diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index d6b5793180..ea44f41073 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -2164,34 +2164,6 @@ Foo[] x = { ... }; //Equivalent to above line - - -A variable naming conventions rule - customize this to your liking. Currently, it -checks for final variables that should be fully capitalized and non-final variables -that should not include underscores. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the more general rules {% rule java/codestyle/FieldNamingConventions %}, -{% rule java/codestyle/FormalParameterNamingConventions %}, and -{% rule java/codestyle/LocalVariableNamingConventions %}. - - 1 - - - - - - - - - 1 - - - - - 1 - - - - - 1 - - - - - 2 - - - - - 2 - - - - - 1 - - - - - 1 - - - - - 1 - - - - - 1 - - - - - 0 - - - - - 0 - - - - - 0 - - - - - 1 - - - - - 0 - - - - - 0 - - - - - 5 - - - - - s_ - m_ - l_ - p_ - 0 - - - - - _s - _m - _l - _p - 0 - - - - - false - 3 - - - - - false - 4 - - - - - false - 3 - - - - - 1 - - - - #1058 False positive for VariableNamingConventions - 0 - (); -} - ]]> - java 1.7 - - - #1293 Disable VariableNamingConventions for native methods - false - 0 - - - - #1293 Disable VariableNamingConventions for native methods - prevent false negative - true - 2 - 2,3 - - - - #1346 VariableNamingConventions do not work for method parameters - true - false - 1 - 3 - - - - #1349 VariableNamingConventions : underscore in final but at first position ? - 0 - - - - #1399 False positive for VariableNamingConventions with annotation @interface - 0 - - - From b5104768dfc5e762e3bcc4578d5aac91f98cf384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 13 Sep 2019 03:23:18 +0200 Subject: [PATCH 004/235] Remove old cyclo rules --- .../ModifiedCyclomaticComplexityRule.java | 30 --- .../design/StdCyclomaticComplexityRule.java | 251 ------------------ .../main/resources/category/java/design.xml | 117 -------- .../ModifiedCyclomaticComplexityTest.java | 11 - .../design/StdCyclomaticComplexityTest.java | 44 --- .../xml/ModifiedCyclomaticComplexity.xml | 111 -------- .../design/xml/StdCyclomaticComplexity.xml | 176 ------------ 7 files changed, 740 deletions(-) delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ModifiedCyclomaticComplexityRule.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/StdCyclomaticComplexityRule.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/ModifiedCyclomaticComplexityTest.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/StdCyclomaticComplexityTest.java delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ModifiedCyclomaticComplexity.xml delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/StdCyclomaticComplexity.xml diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ModifiedCyclomaticComplexityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ModifiedCyclomaticComplexityRule.java deleted file mode 100644 index 92d70d285a..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ModifiedCyclomaticComplexityRule.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.design; - -import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; -import net.sourceforge.pmd.lang.java.ast.JavaNode; - -/** - * Implements the modified cyclomatic complexity rule - *

- * Modified rules: Same as standard cyclomatic complexity, but switch statement - * plus all cases count as 1. - * - * @author Alan Hohn, based on work by Donald A. Leckie - * - * @since June 18, 2014 - */ -@Deprecated -public class ModifiedCyclomaticComplexityRule extends StdCyclomaticComplexityRule { - - @Override - public Object visit(ASTSwitchStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - visit((JavaNode) node, data); - return data; - } - -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/StdCyclomaticComplexityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/StdCyclomaticComplexityRule.java deleted file mode 100644 index d659ddf25a..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/StdCyclomaticComplexityRule.java +++ /dev/null @@ -1,251 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.design; - -import static net.sourceforge.pmd.properties.constraints.NumericConstraints.positive; - -import java.util.ArrayDeque; -import java.util.Deque; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; -import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; -import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; -import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTForStatement; -import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; -import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel; -import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; -import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.properties.BooleanProperty; -import net.sourceforge.pmd.properties.PropertyDescriptor; -import net.sourceforge.pmd.properties.PropertyFactory; - - -/** - * Implements the standard cyclomatic complexity rule - *

- * Standard rules: +1 for each decision point, including case statements but not - * including boolean operators unlike CyclomaticComplexityRule. - * - * @author Alan Hohn, based on work by Donald A. Leckie - * - * @since June 18, 2014 - */ -@Deprecated -public class StdCyclomaticComplexityRule extends AbstractJavaRule { - - public static final PropertyDescriptor REPORT_LEVEL_DESCRIPTOR - = PropertyFactory.intProperty("reportLevel") - .desc("Cyclomatic Complexity reporting threshold") - .require(positive()).defaultValue(10).build(); - - public static final BooleanProperty SHOW_CLASSES_COMPLEXITY_DESCRIPTOR = new BooleanProperty( - "showClassesComplexity", "Add class average violations to the report", true, 2.0f); - - public static final BooleanProperty SHOW_METHODS_COMPLEXITY_DESCRIPTOR = new BooleanProperty( - "showMethodsComplexity", "Add method average violations to the report", true, 3.0f); - - private int reportLevel; - private boolean showClassesComplexity = true; - private boolean showMethodsComplexity = true; - - protected static class Entry { - private Node node; - private int decisionPoints = 1; - public int highestDecisionPoints; - public int methodCount; - - private Entry(Node node) { - this.node = node; - } - - public void bumpDecisionPoints() { - decisionPoints++; - } - - public void bumpDecisionPoints(int size) { - decisionPoints += size; - } - - public int getComplexityAverage() { - return (double) methodCount == 0 ? 1 : (int) Math.rint((double) decisionPoints / (double) methodCount); - } - } - - protected Deque entryStack = new ArrayDeque<>(); - - public StdCyclomaticComplexityRule() { - definePropertyDescriptor(REPORT_LEVEL_DESCRIPTOR); - definePropertyDescriptor(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); - definePropertyDescriptor(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR); - showClassesComplexity = getProperty(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR); - showMethodsComplexity = getProperty(SHOW_METHODS_COMPLEXITY_DESCRIPTOR); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTIfStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTCatchStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTForStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTDoStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTSwitchStatement node, Object data) { - Entry entry = entryStack.peek(); - - int childCount = node.jjtGetNumChildren(); - int lastIndex = childCount - 1; - for (int n = 0; n < lastIndex; n++) { - Node childNode = node.jjtGetChild(n); - if (childNode instanceof ASTSwitchLabel) { - // default is generally not considered a decision (same as - // "else") - ASTSwitchLabel sl = (ASTSwitchLabel) childNode; - if (!sl.isDefault()) { - childNode = node.jjtGetChild(n + 1); - if (childNode instanceof ASTBlockStatement) { - entry.bumpDecisionPoints(); - } - } - } - } - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTWhileStatement node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTConditionalExpression node, Object data) { - entryStack.peek().bumpDecisionPoints(); - super.visit(node, data); - return data; - } - - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry classEntry = entryStack.pop(); - if (showClassesComplexity) { - if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { - addViolation(data, node, new String[] { "class", node.getImage(), - classEntry.getComplexityAverage() + " (Highest = " + classEntry.highestDecisionPoints + ')', }); - } - } - return data; - } - - @Override - public Object visit(ASTMethodDeclaration node, Object data) { - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry methodEntry = entryStack.pop(); - if (!isSuppressed(node)) { - int methodDecisionPoints = methodEntry.decisionPoints; - Entry classEntry = entryStack.peek(); - classEntry.methodCount++; - classEntry.bumpDecisionPoints(methodDecisionPoints); - - if (methodDecisionPoints > classEntry.highestDecisionPoints) { - classEntry.highestDecisionPoints = methodDecisionPoints; - } - - ASTMethodDeclarator methodDeclarator = null; - for (int n = 0; n < node.jjtGetNumChildren(); n++) { - Node childNode = node.jjtGetChild(n); - if (childNode instanceof ASTMethodDeclarator) { - methodDeclarator = (ASTMethodDeclarator) childNode; - break; - } - } - - if (showMethodsComplexity && methodEntry.decisionPoints >= reportLevel) { - addViolation(data, node, - new String[] { "method", methodDeclarator == null ? "" : methodDeclarator.getImage(), - String.valueOf(methodEntry.decisionPoints), }); - } - } - return data; - } - - @Override - public Object visit(ASTEnumDeclaration node, Object data) { - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry classEntry = entryStack.pop(); - if (classEntry.getComplexityAverage() >= reportLevel || classEntry.highestDecisionPoints >= reportLevel) { - addViolation(data, node, new String[] { "class", node.getImage(), - classEntry.getComplexityAverage() + "(Highest = " + classEntry.highestDecisionPoints + ')', }); - } - return data; - } - - @Override - public Object visit(ASTConstructorDeclaration node, Object data) { - entryStack.push(new Entry(node)); - super.visit(node, data); - Entry constructorEntry = entryStack.pop(); - if (!isSuppressed(node)) { - int constructorDecisionPointCount = constructorEntry.decisionPoints; - Entry classEntry = entryStack.peek(); - classEntry.methodCount++; - classEntry.decisionPoints += constructorDecisionPointCount; - if (constructorDecisionPointCount > classEntry.highestDecisionPoints) { - classEntry.highestDecisionPoints = constructorDecisionPointCount; - } - if (showMethodsComplexity && constructorEntry.decisionPoints >= reportLevel) { - addViolation(data, node, new String[] { "constructor", classEntry.node.getImage(), - String.valueOf(constructorDecisionPointCount), }); - } - } - return data; - } -} diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index bb4444cd0d..d2f5303bec 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -894,65 +894,6 @@ public class Bar { - - -Complexity directly affects maintenance costs is determined by the number of decision points in a method -plus one for the method entry. The decision points include 'if', 'while', 'for', and 'case labels' calls. -Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote -high complexity, and 11+ is very high complexity. Modified complexity treats switch statements as a single -decision point. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the rule {% rule java/design/CyclomaticComplexity %}. - - 3 - - - - - - - -Complexity directly affects maintenance costs is determined by the number of decision points in a method -plus one for the method entry. The decision points include 'if', 'while', 'for', and 'case labels' calls. -Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote -high complexity, and 11+ is very high complexity. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the rule {% rule java/design/CyclomaticComplexity %}. - - 3 - - - - - bug #1501 - */ - @Test - public void entryStackMustBeEmpty() { - StdCyclomaticComplexityRule rule = new StdCyclomaticComplexityRule(); - rule.setProperty(StdCyclomaticComplexityRule.SHOW_CLASSES_COMPLEXITY_DESCRIPTOR, Boolean.FALSE); - - RuleContext ctx = new RuleContext(); - LanguageVersion javaLanguageVersion = LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.8"); - ParserOptions parserOptions = javaLanguageVersion.getLanguageVersionHandler().getDefaultParserOptions(); - Parser parser = javaLanguageVersion.getLanguageVersionHandler().getParser(parserOptions); - Node node = parser.parse("test", new StringReader("public class SampleClass {}")); - - rule.apply(Arrays.asList(node), ctx); - - Assert.assertTrue(rule.entryStack.isEmpty()); - } -} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ModifiedCyclomaticComplexity.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ModifiedCyclomaticComplexity.xml deleted file mode 100644 index 993c523944..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ModifiedCyclomaticComplexity.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - Simple method - 1 - 2 - - The class 'Foo' has a Modified Cyclomatic Complexity of 2 (Highest = 1). - The method 'foo' has a Modified Cyclomatic Complexity of 1. - - - - - testLessComplicatedThanReportLevel - 10 - 0 - - - - Complicated method - 8 - 2 - - The class 'Foo' has a Modified Cyclomatic Complexity of 10 (Highest = 9). - The method 'example' has a Modified Cyclomatic Complexity of 9. - - - - - Constructor - 1 - 2 - - The class 'Foo' has a Modified Cyclomatic Complexity of 2 (Highest = 1). - The constructor 'Foo' has a Modified Cyclomatic Complexity of 1. - - - - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/StdCyclomaticComplexity.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/StdCyclomaticComplexity.xml deleted file mode 100644 index 6287af2087..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/StdCyclomaticComplexity.xml +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - - Simple method - 1 - 2 - - The class 'Foo' has a Standard Cyclomatic Complexity of 2 (Highest = 1). - The method 'foo' has a Standard Cyclomatic Complexity of 1. - - - - - Simple method - 10 - 0 - - - - Complicated method - 10 - 2 - - The class 'Foo' has a Standard Cyclomatic Complexity of 12 (Highest = 11). - The method 'example' has a Standard Cyclomatic Complexity of 11. - - - - - Constructor - 1 - 2 - - The class 'Foo' has a Standard Cyclomatic Complexity of 2 (Highest = 1). - The constructor 'Foo' has a Standard Cyclomatic Complexity of 1. - - - - - Testing new parameter showClassMethods - false - 1 - - - - Testing new parameter showMethodsMethods - false - 1 - - - - Testing default value of showClassMethods and showClassesComplexity - 2 - - - - - #984 Cyclomatic complexity should treat constructors like methods: 1 - showMethodsComplexity=true - false - true - 1 - 1 - - - - #984 Cyclomatic complexity should treat constructors like methods: 2 - showMethodsComplexity=false - false - false - 1 - 0 - - - - #985 Suppressed methods shouldn't affect avg CyclomaticComplexity - 2 - 0 - - - From 551eb83470278ab97abf622525781fc38749820d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 18 Sep 2019 22:17:44 +0200 Subject: [PATCH 005/235] Remove useless assignment --- .../pmd/lang/java/rule/UselessAssignment.java | 101 ------------------ 1 file changed, 101 deletions(-) delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/UselessAssignment.java diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/UselessAssignment.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/UselessAssignment.java deleted file mode 100644 index 61b7a1950b..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/UselessAssignment.java +++ /dev/null @@ -1,101 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.dfa.DataFlowNode; -import net.sourceforge.pmd.lang.dfa.VariableAccess; -import net.sourceforge.pmd.lang.dfa.pathfinder.CurrentPath; -import net.sourceforge.pmd.lang.dfa.pathfinder.DAAPathFinder; -import net.sourceforge.pmd.lang.dfa.pathfinder.Executable; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; - -//FUTURE This is not referenced by any RuleSet? -public class UselessAssignment extends AbstractJavaRule implements Executable { - - private RuleContext rc; - - @Override - public Object visit(ASTMethodDeclaration node, Object data) { - this.rc = (RuleContext) data; - - /* - * IDataFlowNode n1 = node.getDataFlowNode(); List f = n1.getFlow(); for - * (Iterator i = f.iterator(); i.hasNext();) { DataFlowNode dfan = - * (DataFlowNode)i.next(); System.out.println(dfan); List va = - * dfan.getVariableAccess(); for (Iterator j = va.iterator(); - * j.hasNext();) { VariableAccess o = (VariableAccess)j.next(); - * System.out.println(o); } } - */ - - DAAPathFinder a = new DAAPathFinder(node.getDataFlowNode().getFlow().get(0), this); - a.run(); - - return data; - } - - private static class Usage { - public int accessType; - public DataFlowNode node; - - Usage(int accessType, DataFlowNode node) { - this.accessType = accessType; - this.node = node; - } - - @Override - public String toString() { - return "accessType = " + accessType + ", line = " + node.getLine(); - } - } - - @Override - public void execute(CurrentPath path) { - Map hash = new HashMap<>(); - // System.out.println("path size is " + path.size()); - for (Iterator i = path.iterator(); i.hasNext();) { - // System.out.println("i = " + i); - DataFlowNode inode = i.next(); - if (inode.getVariableAccess() == null) { - continue; - } - for (int j = 0; j < inode.getVariableAccess().size(); j++) { - VariableAccess va = inode.getVariableAccess().get(j); - // System.out.println("inode = " + inode + ", va = " + va); - Usage u = hash.get(va.getVariableName()); - if (u != null) { - // At some point investigate and possibly reintroduce this - // line2 thing - // int line2 = ((Integer) array.get(1)).intValue(); - - // DD - definition followed by another definition - // FIXME need to check for assignment as well! - if (va.isDefinition() && va.accessTypeMatches(u.accessType)) { - // System.out.println(va.getVariableName() + ":" + u); - addViolation(rc, u.node.getNode(), va.getVariableName()); - } - /* - * // UR - ?? else if (last == VariableAccess.UNDEFINITION - * && va.isReference()) { - * //this.rc.getReport().addRuleViolation( - * createRuleViolation(rc, inode.getNode(), - * va.getVariableName(), "UR")); } // DU - variable is - * defined and then goes out of scope // i.e., unused - * parameter else if (last == VariableAccess.DEFINITION && - * va.isUndefinition()) { if (inode.getNode() != null) { - * this.rc.getReport().addRuleViolation(createRuleViolation( - * rc, tmp, va.getVariableName(), "DU")); } } - */ - } - u = new Usage(va.getAccessType(), inode); - hash.put(va.getVariableName(), u); - } - } - } -} From f615b9df176a69f54f429d469820b7d2fdb5e1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 19 Sep 2019 00:55:52 +0200 Subject: [PATCH 006/235] Remove more unused rules with old properties --- .../java/rule/GenericLiteralCheckerRule.java | 61 ------ .../rule/design/GenericClassCounterRule.java | 178 ------------------ .../documentation/HeaderCommentsRule.java | 69 ------- 3 files changed, 308 deletions(-) delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/GenericLiteralCheckerRule.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GenericClassCounterRule.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/HeaderCommentsRule.java diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/GenericLiteralCheckerRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/GenericLiteralCheckerRule.java deleted file mode 100644 index 8407ee22fc..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/GenericLiteralCheckerRule.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule; - -import java.util.regex.Pattern; - -import net.sourceforge.pmd.lang.java.ast.ASTLiteral; -import net.sourceforge.pmd.lang.java.rule.regex.RegexHelper; -import net.sourceforge.pmd.properties.StringProperty; - -/** - * This class allow to match a Literal (most likely a String) with a regex - * pattern. Obviously, there are many applications of it (such as - * basic.xml/AvoidUsingHardCodedIP). - * - * @author Romain PELISSE, belaran@gmail.com - */ -// FUTURE This is not referenced by any RuleSet? -public class GenericLiteralCheckerRule extends AbstractJavaRule { - - private Pattern pattern; - - private static final String PROPERTY_NAME = "regexPattern"; - - // The rule is unused - private static final StringProperty REGEX_PROPERTY = new StringProperty(PROPERTY_NAME, "Regular expression", "", - 1.0f); - - public GenericLiteralCheckerRule() { - definePropertyDescriptor(REGEX_PROPERTY); - } - - private void init() { - if (pattern == null) { - // Retrieve the regex pattern set by user - String stringPattern = super.getProperty(REGEX_PROPERTY); - // Compile the pattern only once - if (stringPattern != null && stringPattern.length() > 0) { - pattern = Pattern.compile(stringPattern); - } else { - throw new IllegalArgumentException("Must provide a value for the '" + PROPERTY_NAME + "' property."); - } - } - } - - /** - * This method checks if the Literal matches the pattern. If it does, a - * violation is logged. - */ - @Override - public Object visit(ASTLiteral node, Object data) { - init(); - String image = node.getImage(); - if (image != null && image.length() > 0 && RegexHelper.isMatch(this.pattern, image)) { - addViolation(data, node); - } - return data; - } -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GenericClassCounterRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GenericClassCounterRule.java deleted file mode 100644 index 44849f2132..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GenericClassCounterRule.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.java.rule.design; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicLong; -import java.util.regex.Pattern; - -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; -import net.sourceforge.pmd.lang.java.rule.regex.RegexHelper; -import net.sourceforge.pmd.properties.StringMultiProperty; -import net.sourceforge.pmd.properties.StringProperty; - -/** - *

- * A generic rule that can be configured to "count" classes of certain type - * based on either their name (full name, prefix, suffixes anything can be - * matched with a regex), and/or their type. - *

- * - *

Example of configurations:

- * - *
- *     <!-- Property order is MANDATORY !!! -->
- *     <!-- Several regexes may be provided to ensure a match... -->
- *     <property name="nameMatch" description="a regex on which to match"
- *         value="^Abstract.*Bean*$,^*EJB*$"/>
- *     <!-- An operand to refine match strategy TODO: Not implemented yet !!! -->
- *     <property name"operand" description=""
- *         value="and"/> <!-- possible values are and/or -->
- *     <!-- Must be a full name to ensure type control !!! -->
- *     <property name="typeMatch" description="a regex to match on implements/extends classname"
- *         value="javax.servlet.Filter"/>
- *     <!-- Define after how many occurences one should log a violation -->
- *     <property name="threshold" description="Defines how many occurences are legal"
- *         value="2"/>
- *     <!-- TODO: Add a parameter to allow "ignore" pattern based on name -->
- * 
- * - * @author Ryan Gutafson, rgustav@users.sourceforge.net - * @author Romain PELISSE, belaran@gmail.com - * - */ -public class GenericClassCounterRule extends AbstractJavaRule { - - // Class is unused, properties won't be converted - private static final StringMultiProperty NAME_MATCH_DESCRIPTOR = new StringMultiProperty("nameMatch", - "A series of regex, separated by ',' to match on the classname", new String[] { "" }, 1.0f, ','); - - private static final StringProperty OPERAND_DESCRIPTOR = new StringProperty("operand", - "or/and value to refined match criteria", new String(), 2.0f); - - private static final StringMultiProperty TYPE_MATCH_DESCRIPTOR = new StringMultiProperty("typeMatch", - "A series of regex, separated by ',' to match on implements/extends classname", new String[] { "" }, 3.0f, - ','); - - // TODO - this should be an IntegerProperty instead? - private static final StringProperty THRESHOLD_DESCRIPTOR = new StringProperty("threshold", - "Defines how many occurences are legal", new String(), 4.0f); - - private List namesMatch = new ArrayList<>(0); - private List typesMatch = new ArrayList<>(0); - private List matches = new ArrayList<>(0); - private List simpleClassname = new ArrayList<>(0); - - // When the rule is finished, this field will be used. - @SuppressWarnings("PMD") - private String operand; - private int threshold; - - private static String counterLabel; - - public GenericClassCounterRule() { - definePropertyDescriptor(NAME_MATCH_DESCRIPTOR); - definePropertyDescriptor(OPERAND_DESCRIPTOR); - definePropertyDescriptor(TYPE_MATCH_DESCRIPTOR); - definePropertyDescriptor(THRESHOLD_DESCRIPTOR); - } - - protected void init() { - // Creating the attribute name for the rule context - counterLabel = this.getClass().getSimpleName() + ".number of match"; - // Constructing the request from the input parameters - this.namesMatch = RegexHelper.compilePatternsFromList(getProperty(NAME_MATCH_DESCRIPTOR)); - this.operand = getProperty(OPERAND_DESCRIPTOR); - this.typesMatch = RegexHelper.compilePatternsFromList(getProperty(TYPE_MATCH_DESCRIPTOR)); - String thresholdAsString = getProperty(THRESHOLD_DESCRIPTOR); - this.threshold = Integer.valueOf(thresholdAsString); - // Initializing list of match - this.matches = new ArrayList<>(); - - } - - @Override - public void start(RuleContext ctx) { - // Adding the proper attribute to the context - ctx.setAttribute(counterLabel, new AtomicLong()); - super.start(ctx); - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - init(); - return super.visit(node, data); - } - - @Override - public Object visit(ASTImportDeclaration node, Object data) { - // Is there any imported types that match ? - for (Pattern pattern : this.typesMatch) { - if (RegexHelper.isMatch(pattern, node.getImportedName())) { - if (simpleClassname == null) { - simpleClassname = new ArrayList<>(1); - } - simpleClassname.add(node.getImportedName()); - } - // FIXME: use type resolution framework to deal with star import ? - } - return super.visit(node, data); - } - - @Override - public Object visit(ASTClassOrInterfaceType classType, Object data) { - // Is extends/implements list using one of the previous match on import ? - // FIXME: use type resolution framework to deal with star import ? - for (String matchType : simpleClassname) { - if (searchForAMatch(matchType, classType)) { - addAMatch(classType, data); - } - } - // TODO: implements the "operand" functionnality - // Is there any names that actually match ? - for (Pattern pattern : this.namesMatch) { - if (RegexHelper.isMatch(pattern, classType.getImage())) { - addAMatch(classType, data); - } - } - return super.visit(classType, data); - } - - private void addAMatch(Node node, Object data) { - // We have a match, we increment - RuleContext ctx = (RuleContext) data; - AtomicLong total = (AtomicLong) ctx.getAttribute(counterLabel); - total.incrementAndGet(); - // And we keep a ref on the node for the report generation - this.matches.add(node); - } - - private boolean searchForAMatch(String matchType, Node node) { - String xpathQuery = "//ClassOrInterfaceDeclaration[(./ExtendsList/ClassOrInterfaceType[@Image = '" + matchType - + "']) or (./ImplementsList/ClassOrInterfaceType[@Image = '" + matchType + "'])]"; - - return node.hasDescendantMatchingXPath(xpathQuery); - } - - @Override - public void end(RuleContext ctx) { - AtomicLong total = (AtomicLong) ctx.getAttribute(counterLabel); - // Do we have a violation ? - if (total.get() > this.threshold) { - for (Node node : this.matches) { - addViolation(ctx, node, new Object[] { total }); - } - // Cleaning the context for the others rules - ctx.removeAttribute(counterLabel); - super.end(ctx); - } - } -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/HeaderCommentsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/HeaderCommentsRule.java deleted file mode 100644 index c1a7acb12a..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/HeaderCommentsRule.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.documentation; - -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; -import net.sourceforge.pmd.properties.EnumeratedProperty; -import net.sourceforge.pmd.properties.StringMultiProperty; - -/** - * Restrictions regarding the legal placement and content of the file header. - * - * @author Brian Remedios - */ -public class HeaderCommentsRule extends AbstractCommentRule { - - // Rule is not used and not implemented, properties won't be converted - - private static final String[] REQUIRED_WORKDS = new String[] { "copyright" }; - private static final String[] REQUIRED_TAGS = new String[] { "author", "version" }; - - public static final StringMultiProperty REQUIRED_TERMS_DESCRIPTOR = new StringMultiProperty("requiredTerms", - "Expected terms or phrases in the code header", REQUIRED_WORKDS, 1.0f, '|'); - - public static final StringMultiProperty REQUIRED_TAGS_DESCRIPTOR = new StringMultiProperty("requiredTags", - "Expected tags in the header", REQUIRED_TAGS, 2.0f, '|'); - - enum RequiredHeaderPlacement { - BeforePackageDeclaration("Before package"), - BeforeImportStatements("Before imports"), - BeforeTypeDeclaration("Before types"), - Anywhere("Anywhere"); - - private final String label; - - RequiredHeaderPlacement(String theLabel) { - label = theLabel; - } - - public static String[] labels() { - String[] labels = new String[values().length]; - int i = 0; - for (RequiredHeaderPlacement placement : values()) { - labels[i++] = placement.label; - } - return labels; - } - } - - public static final EnumeratedProperty HEADER_PLACEMENT_DESCRIPTOR = new EnumeratedProperty<>( - "headerPlacement", "Placement of the header comment", RequiredHeaderPlacement.labels(), - RequiredHeaderPlacement.values(), 0, RequiredHeaderPlacement.class, 3.0f); - - public HeaderCommentsRule() { - definePropertyDescriptor(REQUIRED_TERMS_DESCRIPTOR); - definePropertyDescriptor(REQUIRED_TAGS_DESCRIPTOR); - definePropertyDescriptor(HEADER_PLACEMENT_DESCRIPTOR); - } - - @Override - public Object visit(ASTCompilationUnit cUnit, Object data) { - - // SortedMap itemsByLineNumber = - // orderedCommentsAndDeclarations(cUnit); - - return super.visit(cUnit, data); - } -} From df6b166ce0f8caef2fa7309df199ab75d2bb30a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 19 Sep 2019 01:00:42 +0200 Subject: [PATCH 007/235] Fix apex tests --- pmd-apex/src/main/resources/rulesets/apex/ruleset.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pmd-apex/src/main/resources/rulesets/apex/ruleset.xml b/pmd-apex/src/main/resources/rulesets/apex/ruleset.xml index 257b5e659d..9f1302647e 100644 --- a/pmd-apex/src/main/resources/rulesets/apex/ruleset.xml +++ b/pmd-apex/src/main/resources/rulesets/apex/ruleset.xml @@ -23,9 +23,6 @@ - - 3 - From 95eeb53941ee4aab35690b727037c761da394fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 24 Sep 2019 03:08:04 +0200 Subject: [PATCH 008/235] Fix old rulesets --- pmd-java/src/main/resources/rulesets/java/codesize.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pmd-java/src/main/resources/rulesets/java/codesize.xml b/pmd-java/src/main/resources/rulesets/java/codesize.xml index deb749adb7..a30b20aa4f 100644 --- a/pmd-java/src/main/resources/rulesets/java/codesize.xml +++ b/pmd-java/src/main/resources/rulesets/java/codesize.xml @@ -15,10 +15,8 @@ The Code Size ruleset contains rules that find problems related to code size or - - From 8a8e0646a8d4a75acf8c645f5dd407929bcc6635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 24 Sep 2019 03:42:15 +0200 Subject: [PATCH 009/235] Remove deprecated rules of java/codestyle.xml * AbstractNaming * AvoidFinalLocalVariable * AvoidPrefixingMethodParameters * ForLoopsMustUseBraces * IfElseStmtsMustUseBraces * IfStmtsMustUseBraces * MIsLeadingVariableName * SuspiciousConstantFieldName * WhileLoopsMustUseBraces --- .../main/resources/rulesets/apex/style.xml | 2 +- .../main/resources/rulesets/releases/34.xml | 2 +- .../main/resources/rulesets/releases/41.xml | 6 +- .../main/resources/rulesets/releases/50.xml | 2 +- .../main/resources/rulesets/releases/512.xml | 4 +- .../main/resources/rulesets/releases/550.xml | 2 +- .../resources/category/java/codestyle.xml | 379 +----------------- .../main/resources/rulesets/java/braces.xml | 17 - .../resources/rulesets/java/controversial.xml | 2 - .../main/resources/rulesets/java/naming.xml | 6 - .../resources/rulesets/java/quickstart.xml | 4 +- .../rule/codestyle/AbstractNamingTest.java | 11 - .../AvoidFinalLocalVariableTest.java | 11 - .../AvoidPrefixingMethodParametersTest.java | 11 - .../codestyle/ForLoopsMustUseBracesTest.java | 11 - .../IfElseStmtsMustUseBracesTest.java | 11 - .../codestyle/IfStmtsMustUseBracesTest.java | 11 - .../codestyle/MIsLeadingVariableNameTest.java | 11 - .../SuspiciousConstantFieldNameTest.java | 11 - .../WhileLoopsMustUseBracesTest.java | 11 - .../rule/codestyle/xml/AbstractNaming.xml | 50 --- .../codestyle/xml/AvoidFinalLocalVariable.xml | 70 ---- .../xml/AvoidPrefixingMethodParameters.xml | 71 ---- .../codestyle/xml/ForLoopsMustUseBraces.xml | 77 ---- .../xml/IfElseStmtsMustUseBraces.xml | 128 ------ .../codestyle/xml/IfStmtsMustUseBraces.xml | 49 --- .../codestyle/xml/MIsLeadingVariableName.xml | 44 -- .../xml/SuspiciousConstantFieldName.xml | 65 --- .../codestyle/xml/WhileLoopsMustUseBraces.xml | 37 -- 29 files changed, 16 insertions(+), 1100 deletions(-) delete mode 100644 pmd-java/src/main/resources/rulesets/java/braces.xml delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AbstractNamingTest.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AvoidFinalLocalVariableTest.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AvoidPrefixingMethodParametersTest.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/ForLoopsMustUseBracesTest.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/IfElseStmtsMustUseBracesTest.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/IfStmtsMustUseBracesTest.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/MIsLeadingVariableNameTest.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/SuspiciousConstantFieldNameTest.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/WhileLoopsMustUseBracesTest.java delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AbstractNaming.xml delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AvoidFinalLocalVariable.xml delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AvoidPrefixingMethodParameters.xml delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/ForLoopsMustUseBraces.xml delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IfElseStmtsMustUseBraces.xml delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IfStmtsMustUseBraces.xml delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MIsLeadingVariableName.xml delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/SuspiciousConstantFieldName.xml delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/WhileLoopsMustUseBraces.xml diff --git a/pmd-apex/src/main/resources/rulesets/apex/style.xml b/pmd-apex/src/main/resources/rulesets/apex/style.xml index 00f1c198a2..0e20621929 100644 --- a/pmd-apex/src/main/resources/rulesets/apex/style.xml +++ b/pmd-apex/src/main/resources/rulesets/apex/style.xml @@ -10,7 +10,7 @@ The Style Ruleset contains rules regarding preferred usage of names and identifi - + diff --git a/pmd-core/src/main/resources/rulesets/releases/34.xml b/pmd-core/src/main/resources/rulesets/releases/34.xml index 8b61c84fcb..6bd6183f19 100644 --- a/pmd-core/src/main/resources/rulesets/releases/34.xml +++ b/pmd-core/src/main/resources/rulesets/releases/34.xml @@ -17,7 +17,7 @@ This ruleset contains links to rules that are new in PMD v3.4 - + diff --git a/pmd-core/src/main/resources/rulesets/releases/41.xml b/pmd-core/src/main/resources/rulesets/releases/41.xml index e04c7862e8..b6819f114c 100644 --- a/pmd-core/src/main/resources/rulesets/releases/41.xml +++ b/pmd-core/src/main/resources/rulesets/releases/41.xml @@ -11,7 +11,7 @@ This ruleset contains links to rules that are new in PMD v4.1 - + @@ -19,7 +19,7 @@ This ruleset contains links to rules that are new in PMD v4.1 - + @@ -27,4 +27,4 @@ This ruleset contains links to rules that are new in PMD v4.1 - + diff --git a/pmd-core/src/main/resources/rulesets/releases/50.xml b/pmd-core/src/main/resources/rulesets/releases/50.xml index 6be499cf4c..e98718a9a2 100644 --- a/pmd-core/src/main/resources/rulesets/releases/50.xml +++ b/pmd-core/src/main/resources/rulesets/releases/50.xml @@ -25,7 +25,7 @@ This ruleset contains links to rules that are new in PMD v5.0 - + diff --git a/pmd-core/src/main/resources/rulesets/releases/512.xml b/pmd-core/src/main/resources/rulesets/releases/512.xml index d22d43ac4a..ca15347b4b 100644 --- a/pmd-core/src/main/resources/rulesets/releases/512.xml +++ b/pmd-core/src/main/resources/rulesets/releases/512.xml @@ -8,8 +8,8 @@ This ruleset contains links to rules that are new in PMD v5.1.2 - - + + diff --git a/pmd-core/src/main/resources/rulesets/releases/550.xml b/pmd-core/src/main/resources/rulesets/releases/550.xml index d7ac9f868f..a3df927ec1 100644 --- a/pmd-core/src/main/resources/rulesets/releases/550.xml +++ b/pmd-core/src/main/resources/rulesets/releases/550.xml @@ -22,7 +22,7 @@ This ruleset contains links to rules that are new in PMD v5.5.0 - + diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index ea44f41073..513938deb8 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -9,45 +9,6 @@ Rules which enforce a specific coding style. - - -Abstract classes should be named 'AbstractXXX'. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by {% rule java/codestyle/ClassNamingConventions %}. - - 3 - - - - - - - - - - - - - - - -Avoid using final local variables, turn them into fields. - -Note that this is a controversial rule which is merely useful to enforce a certain code style -(which is contradictory to good coding practices in most of the cases it's applied to) and -avoid local literals being declared in a scope smaller than the class. - -Also note, that this rule is the opposite of {% rule "java/codestyle/LocalVariableCouldBeFinal" %}. -Having both rules enabled results in contradictory violations being reported. - -This rule is deprecated and will be removed with PMD 7.0.0. There is no replacement planned. -If the goal is to avoid defining constants in a scope smaller than the class, then the rule -{% rule "java/errorprone/AvoidDuplicateLiterals" %} should be used instead. - - 3 - - - - - - - - - - - - - - -Prefixing parameters by 'in' or 'out' pollutes the name of the parameters and reduces code readability. -To indicate whether or not a parameter will be modify in a method, its better to document method -behavior with Javadoc. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the more general rule {% rule java/codestyle/FormalParameterNamingConventions %}. - - 4 - - - - - - - - - - - - - - - - - -Avoid using 'for' statements without using curly braces. If the code formatting or -indentation is lost then it becomes difficult to separate the code being controlled -from the rest. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the rule {% rule java/codestyle/ControlStatementBraces %}. - - 3 - - - //ForStatement[not(Statement/Block)] - - - - - - - 1 + string-length(@Image) > 1 or string:upper-case(@Image) != @Image ] @@ -926,86 +749,6 @@ try { - - -Avoid using if..else statements without using surrounding braces. If the code formatting -or indentation is lost then it becomes difficult to separate the code being controlled -from the rest. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the rule {% rule java/codestyle/ControlStatementBraces %}. - - 3 - - - - - - - - - - - - - - -Avoid using if statements without using braces to surround the code block. If the code -formatting or indentation is lost then it becomes difficult to separate the code being -controlled from the rest. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the rule {% rule java/codestyle/ControlStatementBraces %}. - - 3 - - - - - - - - - - - - - - -Detects when a non-field has a name starting with 'm_'. This usually denotes a field and could be confusing. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the more general rule -{% rule java/codestyle/LocalVariableNamingConventions %}. - - 3 - - - - - - - - - - - - - - -Field names using all uppercase characters - Sun's Java naming conventions indicating constants - should -be declared as final. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the more general rule {% rule java/codestyle/FieldNamingConventions %}. - - 3 - - - - - - - - - - - - -If you overuse the static import feature, it can make your program unreadable and -unmaintainable, polluting its namespace with all the static members you import. -Readers of your code (including you, a few months after you wrote it) will not know +If you overuse the static import feature, it can make your program unreadable and +unmaintainable, polluting its namespace with all the static members you import. +Readers of your code (including you, a few months after you wrote it) will not know which class a static member comes from (Sun 1.5 Language Guide). 3 - @@ -2160,39 +1826,6 @@ E.g. `int[] x = new int[] { 1, 2, 3 };` can be written as `int[] x = { 1, 2, 3 } - - - - - -Avoid using 'while' statements without using braces to surround the code block. If the code -formatting or indentation is lost then it becomes difficult to separate the code being -controlled from the rest. - -This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced -by the rule {% rule java/codestyle/ControlStatementBraces %}. - - 3 - - - //WhileStatement[not(Statement/Block)] - - - - diff --git a/pmd-java/src/main/resources/rulesets/java/braces.xml b/pmd-java/src/main/resources/rulesets/java/braces.xml deleted file mode 100644 index e0ce7deec3..0000000000 --- a/pmd-java/src/main/resources/rulesets/java/braces.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - -The Braces ruleset contains rules regarding the use and placement of braces. - - - - - - - - - diff --git a/pmd-java/src/main/resources/rulesets/java/controversial.xml b/pmd-java/src/main/resources/rulesets/java/controversial.xml index 769016eb02..9f6ce5b57f 100644 --- a/pmd-java/src/main/resources/rulesets/java/controversial.xml +++ b/pmd-java/src/main/resources/rulesets/java/controversial.xml @@ -21,8 +21,6 @@ They are held here to allow people to include them as they see fit within their - - diff --git a/pmd-java/src/main/resources/rulesets/java/naming.xml b/pmd-java/src/main/resources/rulesets/java/naming.xml index 64931996c4..667cca11d8 100644 --- a/pmd-java/src/main/resources/rulesets/java/naming.xml +++ b/pmd-java/src/main/resources/rulesets/java/naming.xml @@ -15,21 +15,15 @@ The Naming Ruleset contains rules regarding preferred usage of names and identif - - - - - - diff --git a/pmd-java/src/main/resources/rulesets/java/quickstart.xml b/pmd-java/src/main/resources/rulesets/java/quickstart.xml index 8eb2ea16f0..05238e8184 100644 --- a/pmd-java/src/main/resources/rulesets/java/quickstart.xml +++ b/pmd-java/src/main/resources/rulesets/java/quickstart.xml @@ -80,7 +80,6 @@ - @@ -103,7 +102,6 @@ - @@ -274,7 +272,7 @@ - + diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AbstractNamingTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AbstractNamingTest.java deleted file mode 100644 index 5f19656e15..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AbstractNamingTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codestyle; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class AbstractNamingTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AvoidFinalLocalVariableTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AvoidFinalLocalVariableTest.java deleted file mode 100644 index 1bddcf45da..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AvoidFinalLocalVariableTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codestyle; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class AvoidFinalLocalVariableTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AvoidPrefixingMethodParametersTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AvoidPrefixingMethodParametersTest.java deleted file mode 100644 index 24c2337d7e..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/AvoidPrefixingMethodParametersTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codestyle; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class AvoidPrefixingMethodParametersTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/ForLoopsMustUseBracesTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/ForLoopsMustUseBracesTest.java deleted file mode 100644 index 76ce00748a..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/ForLoopsMustUseBracesTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codestyle; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class ForLoopsMustUseBracesTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/IfElseStmtsMustUseBracesTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/IfElseStmtsMustUseBracesTest.java deleted file mode 100644 index 957035bb8d..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/IfElseStmtsMustUseBracesTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codestyle; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class IfElseStmtsMustUseBracesTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/IfStmtsMustUseBracesTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/IfStmtsMustUseBracesTest.java deleted file mode 100644 index cbbf424654..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/IfStmtsMustUseBracesTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codestyle; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class IfStmtsMustUseBracesTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/MIsLeadingVariableNameTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/MIsLeadingVariableNameTest.java deleted file mode 100644 index 56db10643a..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/MIsLeadingVariableNameTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codestyle; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class MIsLeadingVariableNameTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/SuspiciousConstantFieldNameTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/SuspiciousConstantFieldNameTest.java deleted file mode 100644 index 7e8b484c1c..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/SuspiciousConstantFieldNameTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codestyle; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class SuspiciousConstantFieldNameTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/WhileLoopsMustUseBracesTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/WhileLoopsMustUseBracesTest.java deleted file mode 100644 index 4aa0611c11..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/WhileLoopsMustUseBracesTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.codestyle; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class WhileLoopsMustUseBracesTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AbstractNaming.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AbstractNaming.xml deleted file mode 100644 index 27a2b4095b..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AbstractNaming.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - 0 - - - - - 1 - - - - - false - 0 - - - - - 0 - - - - #1344 AbstractNaming should check reverse - 1 - - - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AvoidFinalLocalVariable.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AvoidFinalLocalVariable.xml deleted file mode 100644 index 4c14b2291c..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AvoidFinalLocalVariable.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - 1 - - - - - - - - 0 - - - - - - 1 - - - - - #1095 AvoidFinalLocalVariable false positive - 0 - - - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AvoidPrefixingMethodParameters.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AvoidPrefixingMethodParameters.xml deleted file mode 100644 index 2d0164f968..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/AvoidPrefixingMethodParameters.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - 1 - - - - - - 0 - - - - - - 1 - - - - - - 2 - - - - - - 0 - - - - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/ForLoopsMustUseBraces.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/ForLoopsMustUseBraces.xml deleted file mode 100644 index 4662e6e6da..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/ForLoopsMustUseBraces.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 1 - - - - - 1 - - - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IfElseStmtsMustUseBraces.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IfElseStmtsMustUseBraces.xml deleted file mode 100644 index 8fdcb439f3..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IfElseStmtsMustUseBraces.xml +++ /dev/null @@ -1,128 +0,0 @@ - - - - - 1 - - - - - 0 - - - - - 2 - - - - - 1 - - - - - 0 - - - - - 1 - - - - - 0 - - - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IfStmtsMustUseBraces.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IfStmtsMustUseBraces.xml deleted file mode 100644 index 06ec73363e..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/IfStmtsMustUseBraces.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - 1 - - - - - 0 - - - - - 1 - - - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MIsLeadingVariableName.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MIsLeadingVariableName.xml deleted file mode 100644 index a512f670c2..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MIsLeadingVariableName.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - 1 - - - - - 1 - - - - - 0 - - - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/SuspiciousConstantFieldName.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/SuspiciousConstantFieldName.xml deleted file mode 100644 index dd928e9c9a..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/SuspiciousConstantFieldName.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - 0 - - - - - 1 - - - - - 2 - - - - - 0 - - - - - 0 - - - diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/WhileLoopsMustUseBraces.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/WhileLoopsMustUseBraces.xml deleted file mode 100644 index 35df65ded0..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/WhileLoopsMustUseBraces.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - 1 - - - - - 0 - - - From 96eaa32b68c3fb8f0f53b86b7dd41c2cbf2ce4a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 24 Sep 2019 03:51:05 +0200 Subject: [PATCH 010/235] Remove deprecated rules of java/multithreading.xml * UnsynchronizedStaticDateFormatter --- .../main/resources/rulesets/releases/36.xml | 2 +- ...UnsynchronizedStaticDateFormatterRule.java | 30 --- .../resources/category/java/errorprone.xml | 2 +- .../category/java/multithreading.xml | 33 +--- .../main/resources/rulesets/java/design.xml | 2 +- ...UnsynchronizedStaticDateFormatterTest.java | 11 -- .../xml/UnsynchronizedStaticDateFormatter.xml | 171 ------------------ 7 files changed, 4 insertions(+), 247 deletions(-) delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticDateFormatterRule.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticDateFormatterTest.java delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticDateFormatter.xml diff --git a/pmd-core/src/main/resources/rulesets/releases/36.xml b/pmd-core/src/main/resources/rulesets/releases/36.xml index 8f60abd594..f83d3c8791 100644 --- a/pmd-core/src/main/resources/rulesets/releases/36.xml +++ b/pmd-core/src/main/resources/rulesets/releases/36.xml @@ -9,7 +9,7 @@ This ruleset contains links to rules that are new in PMD v3.6 - + diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticDateFormatterRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticDateFormatterRule.java deleted file mode 100644 index eb577cbc83..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticDateFormatterRule.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.multithreading; - -import java.text.DateFormat; - -/** - * Using a DateFormatter (SimpleDateFormatter) which is static can cause - * unexpected results when used in a multi-threaded environment. This rule will - * find static (Simple)DateFormatters which are used in an unsynchronized - * manner. - * - *

Refer to these Bug Parade issues: - * 4093418 - * 4228335 - * 4261469

- * - * @author Allan Caplan - * @see feature #226 Check for SimpleDateFormat as singleton? - * @deprecated This rule is being replaced by {@link UnsynchronizedStaticFormatterRule}. The rule will be removed with PMD 7.0.0. - */ -@Deprecated -public class UnsynchronizedStaticDateFormatterRule extends UnsynchronizedStaticFormatterRule { - - public UnsynchronizedStaticDateFormatterRule() { - super(DateFormat.class); - } -} diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml index 74e40ae08e..b3eb0442b6 100644 --- a/pmd-java/src/main/resources/category/java/errorprone.xml +++ b/pmd-java/src/main/resources/category/java/errorprone.xml @@ -190,7 +190,7 @@ for (int i = 0; i < 10; i++) { The method Object.finalize() is called by the garbage collector on an object when garbage collection determines that there are no more references to the object. It should not be invoked by application logic. - + Note that Oracle has declared Object.finalize() as deprecated since JDK 9. 3 diff --git a/pmd-java/src/main/resources/category/java/multithreading.xml b/pmd-java/src/main/resources/category/java/multithreading.xml index 95460df02a..a259cd8b63 100644 --- a/pmd-java/src/main/resources/category/java/multithreading.xml +++ b/pmd-java/src/main/resources/category/java/multithreading.xml @@ -257,37 +257,6 @@ public static Foo getFoo() {
- - -SimpleDateFormat instances are not synchronized. Sun recommends using separate format instances -for each thread. If multiple threads must access a static formatter, the formatter must be -synchronized on block level. - -This rule has been deprecated in favor of the rule {% rule UnsynchronizedStaticFormatter %}. - - 3 - - - - - - \ No newline at end of file + diff --git a/pmd-java/src/main/resources/rulesets/java/design.xml b/pmd-java/src/main/resources/rulesets/java/design.xml index d9be5f1eda..8e1b2de0f9 100644 --- a/pmd-java/src/main/resources/rulesets/java/design.xml +++ b/pmd-java/src/main/resources/rulesets/java/design.xml @@ -54,7 +54,7 @@ are suggested. - + diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticDateFormatterTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticDateFormatterTest.java deleted file mode 100644 index 16a92e05fd..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticDateFormatterTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.multithreading; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class UnsynchronizedStaticDateFormatterTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticDateFormatter.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticDateFormatter.xml deleted file mode 100644 index 98ccfcd6de..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticDateFormatter.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - - Format called from non-synchronized block - 1 - - - - 2, No call to format - 0 - - - - 3, Instance synchronized, Not OK - see #1815 - 1 - - - - 4, Inside synchronized, OK - 0 - - - - 5, Use DateFormat with instance Synchronized, not ok - 1 - - - - 5a, Use DateFormat with synchronized block, ok - 0 - - - - 6, Use DateFormat, fail - 1 - - - - - #940 False positive on UnsynchronizedStaticDateFormatter - 0 - - - - - #1815 static synchronized, Not OK - 1 - - - - - #1815 static synchronized, also Not OK - 1 - - - - - #1815 static synchronized, OK - 0 - - - From 9cff38b4ac738827a37d39169ca799cd0aae0990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 24 Sep 2019 03:52:48 +0200 Subject: [PATCH 011/235] Remove deprecated rules of java/errorprone.xml * LoggerIsNotStaticFinal --- .../resources/category/java/errorprone.xml | 39 ------------- .../resources/rulesets/java/logging-java.xml | 1 - .../LoggerIsNotStaticFinalTest.java | 11 ---- .../errorprone/xml/LoggerIsNotStaticFinal.xml | 57 ------------------- 4 files changed, 108 deletions(-) delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/LoggerIsNotStaticFinalTest.java delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/LoggerIsNotStaticFinal.xml diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml index b3eb0442b6..ab6adb1fe8 100644 --- a/pmd-java/src/main/resources/category/java/errorprone.xml +++ b/pmd-java/src/main/resources/category/java/errorprone.xml @@ -2196,45 +2196,6 @@ public class Foo extends TestCase { - - -In most cases, the Logger reference can be declared as static and final. - -This rule is deprecated and will be removed with PMD 7.0.0. -The rule is replaced by {% rule java/errorprone/ProperLogger %}. - - 2 - - - - - - - - - - - - - diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/LoggerIsNotStaticFinalTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/LoggerIsNotStaticFinalTest.java deleted file mode 100644 index c3f990070d..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/LoggerIsNotStaticFinalTest.java +++ /dev/null @@ -1,11 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.rule.errorprone; - -import net.sourceforge.pmd.testframework.PmdRuleTst; - -public class LoggerIsNotStaticFinalTest extends PmdRuleTst { - // no additional unit tests -} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/LoggerIsNotStaticFinal.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/LoggerIsNotStaticFinal.xml deleted file mode 100644 index e90d037ab9..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/LoggerIsNotStaticFinal.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - 0 - - - - - 2 - - - - - 0 - - - - - 0 - - - From b97f5652daabbf8faa11f013d481b5567b1c0073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 25 Sep 2019 23:11:18 +0200 Subject: [PATCH 012/235] Remove isSuppressed --- .../sourceforge/pmd/lang/java/rule/AbstractJavaRule.java | 9 --------- 1 file changed, 9 deletions(-) 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 8e4c688fb4..5fc196f73c 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 @@ -83,15 +83,6 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse return false; } - /** - * @deprecated Not useful, and suppression should happen transparently to rule implementations. - * This will be removed with 7.0.0 - */ - @Deprecated - protected boolean isSuppressed(Node node) { - return JavaRuleViolation.isSupressed(node, this); - } - @Override public final boolean dependsOn(AstProcessingStage stage) { From fcd446fcfd86515288b9fbb02c647dc4e431a80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 27 Dec 2019 12:15:41 +0100 Subject: [PATCH 013/235] Fix dead links --- docs/pages/next_major_development.md | 2 +- docs/pages/release_notes_old.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/next_major_development.md b/docs/pages/next_major_development.md index bab3db43af..76cae86b70 100644 --- a/docs/pages/next_major_development.md +++ b/docs/pages/next_major_development.md @@ -563,7 +563,7 @@ large projects, with many duplications, it was causing `OutOfMemoryError`s (see * The Java rules `GuardDebugLogging` (ruleset `java-logging-jakarta-commons`) and `GuardLogStatementJavaUtil` (ruleset `java-logging-java`) have been deprecated. Use the rule {% rule java/bestpractices/GuardLogStatement %}, which covers all cases regardless of the logging framework. -* The Java rule {% rule "java/multithreading/UnsynchronizedStaticDateFormatter" %} has been deprecated and +* The Java rule "java/multithreading/UnsynchronizedStaticDateFormatter" has been deprecated and will be removed with PMD 7.0.0. The rule is replaced by the more general {% rule "java/multithreading/UnsynchronizedStaticFormatter" %}. diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index 1ae58be360..1c5127bef5 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -2311,7 +2311,7 @@ versions, please let us know [on our Issue Tracker](https://github.com/pmd/pmd/i #### Deprecated Rules -* The Java rule [AbstractNaming](pmd_rules_java_codestyle.html#abstractnaming) (`java-codestyle`) is deprecated +* The Java rule AbstractNaming (`java-codestyle`) is deprecated in favour of [ClassNamingConventions](pmd_rules_java_codestyle.html#classnamingconventions). See [Naming rules enhancements](#naming-rules-enhancements). From 19d35ff9e2866b299bce258bc2301c02ff779072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 17 Jan 2020 17:42:23 +0100 Subject: [PATCH 014/235] Don't use ClassNotFoundException to report unresolved classes This speeds up type resolution by a factor of 2. --- .../typeresolution/ClassTypeResolver.java | 86 +++++-------------- .../typeresolution/PMDASMClassLoader.java | 28 +++--- .../main/resources/category/java/security.xml | 2 +- 3 files changed, 40 insertions(+), 76 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java index e4031b9930..fb57427a60 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/ClassTypeResolver.java @@ -1417,49 +1417,27 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { qualifiedName = className; } if (qualifiedName != null) { - try { - /* - * TODO - the map right now contains just class names. if we - * use a map of classname/class then we don't have to hit - * the class loader for every type - much faster - */ - myType = pmdClassLoader.loadClass(qualifiedName); - } catch (ClassNotFoundException e) { + /* + * TODO - the map right now contains just class names. if we + * use a map of classname/class then we don't have to hit + * the class loader for every type - much faster + */ + myType = pmdClassLoader.loadClassOrNull(qualifiedName); + if (myType == null) { myType = processOnDemand(qualifiedName); - } catch (LinkageError e) { - // we found the class, but there is a problem with it (see https://github.com/pmd/pmd/issues/1131) - if (LOG.isLoggable(Level.FINE)) { - LOG.log(Level.FINE, "Tried to load class " + qualifiedName + " from on demand import, " - + "with an incomplete classpath.", e); - } - return; } } } if (myType == null && qualifiedName != null && qualifiedName.contains(".")) { // try if the last part defines a inner class String qualifiedNameInner = qualifiedName.substring(0, qualifiedName.lastIndexOf('.')) + "$" - + qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1); - try { - myType = pmdClassLoader.loadClass(qualifiedNameInner); - } catch (ClassNotFoundException ignored) { - // ignored, we'll try again with a different package name/fqcn - } catch (LinkageError e) { - // we found the class, but there is a problem with it (see https://github.com/pmd/pmd/issues/1131) - if (LOG.isLoggable(Level.FINE)) { - LOG.log(Level.FINE, "Tried to load class " + qualifiedNameInner + " from on demand import, " - + "with an incomplete classpath.", e); - } - return; - } + + qualifiedName.substring(qualifiedName.lastIndexOf('.') + 1); + myType = pmdClassLoader.loadClassOrNull(qualifiedNameInner); + } if (myType == null && qualifiedName != null && !qualifiedName.contains(".")) { // try again with java.lang.... - try { - myType = pmdClassLoader.loadClass("java.lang." + qualifiedName); - } catch (Exception ignored) { - // ignored, we'll try again with generics - } + myType = pmdClassLoader.loadClassOrNull("java.lang." + qualifiedName); } // try generics @@ -1506,44 +1484,21 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { * Check whether the supplied class name exists. */ public boolean classNameExists(String fullyQualifiedClassName) { - try { - pmdClassLoader.loadClass(fullyQualifiedClassName); - return true; // Class found - } catch (ClassNotFoundException e) { - return false; - } catch (LinkageError e2) { - // Class exists, but may be invalid (see https://github.com/pmd/pmd/issues/1131) - return true; - } + return pmdClassLoader.loadClassOrNull(fullyQualifiedClassName) != null; } public Class loadClass(String fullyQualifiedClassName) { - try { - return pmdClassLoader.loadClass(fullyQualifiedClassName); - } catch (ClassNotFoundException e) { - return null; - } catch (LinkageError e2) { - if (LOG.isLoggable(Level.FINE)) { - LOG.log(Level.FINE, "Tried to load class " + fullyQualifiedClassName + " from on demand import, " - + "with an incomplete classpath.", e2); - } - return null; - } + return pmdClassLoader.loadClassOrNull(fullyQualifiedClassName); } private Class processOnDemand(String qualifiedName) { for (String entry : importedOnDemand) { String fullClassName = entry + "." + qualifiedName; - try { - return pmdClassLoader.loadClass(fullClassName); - } catch (ClassNotFoundException ignored) { - // ignored - } catch (LinkageError e) { - if (LOG.isLoggable(Level.FINE)) { - LOG.log(Level.FINE, "Tried to load class " + fullClassName + " from on demand import, " - + "with an incomplete classpath.", e); - } + Class aClass = pmdClassLoader.loadClassOrNull(fullClassName); + if (aClass != null) { + return aClass; } + } return null; } @@ -1614,7 +1569,10 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter { private void populateClassName(ASTCompilationUnit node, String className) throws ClassNotFoundException { - node.setType(pmdClassLoader.loadClass(className)); - importedClasses.putAll(pmdClassLoader.getImportedClasses(className)); + Class type = pmdClassLoader.loadClassOrNull(className); + if (type != null) { + node.setType(type); + importedClasses.putAll(pmdClassLoader.getImportedClasses(className)); + } } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java index 9ab049f6b1..553a8ed672 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java @@ -30,7 +30,7 @@ import net.sourceforge.pmd.lang.java.typeresolution.visitors.PMDASMVisitor; * the negative cases only. The cache is shared between loadClass and getImportedClasses, * as they are using the same (parent) class loader, e.g. if the class foo.Bar cannot be loaded, * then the resource foo/Bar.class will not exist, too. - * + * * Note: since git show 46ad3a4700b7a233a177fa77d08110127a85604c the cache is using * a concurrent hash map to avoid synchronizing on the class loader instance. */ @@ -70,21 +70,27 @@ public final class PMDASMClassLoader extends ClassLoader { @Override public Class loadClass(String name) throws ClassNotFoundException { - if (dontBother.containsKey(name)) { + Class aClass = loadClassOrNull(name); + if (aClass == null) { throw new ClassNotFoundException(name); } + return aClass; + } + + /** + * Not throwing CNFEs to represent failure makes a huge performance + * difference. Typeres as a whole is 2x faster. + */ + public Class loadClassOrNull(String name) { + if (dontBother.containsKey(name)) { + return null; + } try { return super.loadClass(name); - } catch (ClassNotFoundException e) { + } catch (ClassNotFoundException | LinkageError e) { dontBother.put(name, Boolean.TRUE); - throw e; - } catch (NoClassDefFoundError e) { - dontBother.put(name, Boolean.TRUE); - // rethrow as ClassNotFoundException, as the remaining part just - // deals with that - // see also: https://sourceforge.net/p/pmd/bugs/1319/ - throw new ClassNotFoundException(name, e); + return null; } } @@ -93,7 +99,7 @@ public final class PMDASMClassLoader extends ClassLoader { * doesn't know for sure it will fail). Notice, that the ability to resolve * a class does not imply that the class will actually be found and * resolved. - * + * * @param name * the name of the class * @return whether the class can be resolved diff --git a/pmd-java/src/main/resources/category/java/security.xml b/pmd-java/src/main/resources/category/java/security.xml index 8c81f3b7c8..cc6af00573 100644 --- a/pmd-java/src/main/resources/category/java/security.xml +++ b/pmd-java/src/main/resources/category/java/security.xml @@ -53,7 +53,7 @@ public class Foo { void bad() { byte[] iv = new byte[] { 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, }; } - + void alsoBad() { byte[] iv = "secret iv in here".getBytes(); } From 84b59c335058766d41b2b2f6cc05e265124cf97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 19 Jan 2020 10:07:41 +0100 Subject: [PATCH 015/235] Add DataMap on Node --- .../pmd/lang/ast/AbstractNode.java | 17 +++- .../net/sourceforge/pmd/lang/ast/Node.java | 10 ++ .../net/sourceforge/pmd/util/DataMap.java | 94 +++++++++++++++++++ 3 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/util/DataMap.java 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 df223b717b..8e6c1de943 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 @@ -26,6 +26,9 @@ import net.sourceforge.pmd.lang.ast.xpath.Attribute; import net.sourceforge.pmd.lang.ast.xpath.AttributeAxisIterator; import net.sourceforge.pmd.lang.ast.xpath.DocumentNavigator; import net.sourceforge.pmd.lang.dfa.DataFlowNode; +import net.sourceforge.pmd.util.DataMap; +import net.sourceforge.pmd.util.DataMap.DataKey; +import net.sourceforge.pmd.util.DataMap.SimpleDataKey; /** @@ -42,6 +45,10 @@ public abstract class AbstractNode implements Node { private static final Logger LOG = Logger.getLogger(AbstractNode.class.getName()); + private static final SimpleDataKey LEGACY_USER_DATA = DataMap.simpleDataKey("legacy user data"); + + private final DataMap> userData = DataMap.newDataMap(); + /** * @deprecated Use {@link #getParent()} */ @@ -73,7 +80,6 @@ public abstract class AbstractNode implements Node { @Deprecated protected GenericToken lastToken; private DataFlowNode dataFlowNode; - private Object userData; // @Deprecated? private String image; @@ -522,12 +528,17 @@ public abstract class AbstractNode implements Node { @Override public Object getUserData() { - return userData; + return userData.get(LEGACY_USER_DATA); } @Override public void setUserData(final Object userData) { - this.userData = userData; + this.userData.set(LEGACY_USER_DATA, userData); + } + + @Override + public DataMap> getUserMap() { + return userData; } /** 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 e1571e8a5f..03a7bcbcfc 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 @@ -14,6 +14,8 @@ import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.xpath.Attribute; import net.sourceforge.pmd.lang.ast.xpath.internal.DeprecatedAttribute; import net.sourceforge.pmd.lang.dfa.DataFlowNode; +import net.sourceforge.pmd.util.DataMap; +import net.sourceforge.pmd.util.DataMap.DataKey; /** * Root interface for all AST nodes. This interface provides only the API @@ -413,6 +415,14 @@ public interface Node { void removeChildAtIndex(int childIndex); + /** + * Returns a data map used to store additional information on this node. + * This replaces the legacy {@link #getUserData()}/{@link #setUserData(Object)}. + * + * @return The user data map of this node + */ + DataMap> getUserMap(); + /** * Returns the parent of this node, or null if this is the {@linkplain RootNode root} * of the tree. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/DataMap.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/DataMap.java new file mode 100644 index 0000000000..7a38e975bc --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/DataMap.java @@ -0,0 +1,94 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util; + +import java.util.IdentityHashMap; +import java.util.Map; + +/** + * An opaque, strongly typed heterogeneous data container. + * + * @param Type of keys in this map + */ +public class DataMap { + + private final Map, Object> map = new IdentityHashMap<>(); + + private DataMap() { + + } + + /** + * Set the mapping to the given data. + * + * @param key Key + * @param data Data mapped to the key + * @param Type of the data + * + * @return Previous value associated with the key (nullable) + */ + @SuppressWarnings("unchecked") + public T set(DataKey key, T data) { + return (T) map.put(key, data); + } + + /** + * Retrieves the data currently mapped to the key. + * + * @param key Key + * @param Type of the data + * + * @return Value associated with the key (nullable) + */ + @SuppressWarnings("unchecked") + public T get(DataKey key) { + return (T) map.get(key); + } + + /** + * Returns true if the given key has a non-null value in the map. + * + * @param key Key + * + * @return True if some value is set + */ + public boolean isSet(DataKey key) { + return map.containsKey(key); + } + + public static DataMap newDataMap() { + return new DataMap<>(); + } + + public static SimpleDataKey simpleDataKey(final String name) { + return new SimpleDataKey<>(name); + } + + /** + * A key for type-safe access into a {@link DataMap}. Data keys use + * reference identity and are only compared by reference within + * {@link DataMap}. + * + * @param Type of the family of keys this is a part of + * @param Type of the addressed data + */ + public interface DataKey, T> { + + } + + public static class SimpleDataKey implements DataKey, T> { + + private final String name; + + SimpleDataKey(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } +} From 2123ab3d5d7dcfc867ada3af119c3d3e9cb6183e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 19 Jan 2020 11:41:42 +0100 Subject: [PATCH 016/235] Simplify metrics framework --- docs/pages/release_notes.md | 6 + .../pmd/lang/apex/metrics/ApexMetrics.java | 46 ++++-- .../apex/metrics/ApexMetricsComputer.java | 17 +- .../lang/apex/metrics/ApexMetricsFacade.java | 8 +- .../apex/metrics/ApexMetricsProvider.java | 12 +- .../rule/design/CyclomaticComplexityRule.java | 7 +- .../lang/apex/metrics/ApexMetricsHook.java | 25 --- .../apex/metrics/ApexProjectMirrorTest.java | 12 +- .../apex/metrics/impl/AllMetricsTest.java | 10 -- .../rule/design/CyclomaticComplexityTest.java | 7 - .../net/sourceforge/pmd/lang/ast/Node.java | 2 + .../pmd/lang/ast/QualifiableNode.java | 3 + .../pmd/lang/ast/QualifiedName.java | 2 + .../lang/metrics/AbstractMetricsComputer.java | 77 +-------- .../lang/metrics/AbstractMetricsFacade.java | 47 +----- .../pmd/lang/metrics/BasicMetricMemoizer.java | 2 + .../lang/metrics/BasicProjectMemoizer.java | 3 + .../lang/metrics/LanguageMetricsProvider.java | 6 - .../pmd/lang/metrics/MetricKey.java | 3 +- .../pmd/lang/metrics/MetricMemoizer.java | 2 + .../pmd/lang/metrics/MetricsComputer.java | 2 + .../pmd/lang/metrics/MetricsUtil.java | 155 ++++++++++++++++++ .../lang/metrics/ParameterizedMetricKey.java | 8 +- .../pmd/lang/metrics/ProjectMemoizer.java | 2 + .../AbstractLanguageMetricsProvider.java | 18 +- .../metrics/internal/DummyMetricMemoizer.java | 44 ----- .../internal/DummyProjectMemoizer.java | 45 ----- .../pmd/lang/metrics/package-info.java | 16 ++ .../pmd/processor/AbstractPMDProcessor.java | 26 +-- .../net/sourceforge/pmd/util/DataMap.java | 9 +- .../pmd/lang/java/metrics/JavaMetrics.java | 54 +++--- .../java/metrics/JavaMetricsComputer.java | 26 +-- .../lang/java/metrics/JavaMetricsFacade.java | 39 ----- .../java/metrics/JavaMetricsProvider.java | 12 +- .../java/metrics/JavaProjectMemoizer.java | 18 -- .../impl/AbstractJavaOperationMetric.java | 1 + .../rule/design/CyclomaticComplexityRule.java | 5 +- .../lang/java/rule/design/DataClassRule.java | 18 +- .../lang/java/rule/design/GodClassRule.java | 8 +- .../java/rule/design/NPathComplexityRule.java | 5 +- .../lang/java/rule/design/NcssCountRule.java | 5 +- .../pmd/lang/java/xpath/MetricFunction.java | 16 +- .../pmd/lang/java/metrics/MetricsHook.java | 23 --- .../java/metrics/ProjectMemoizerTest.java | 12 +- .../metrics/impl/AbstractMetricTestRule.java | 5 +- .../java/metrics/impl/AllMetricsTest.java | 10 -- .../rule/design/CyclomaticComplexityTest.java | 7 - .../java/rule/design/NPathComplexityTest.java | 7 - .../lang/java/rule/design/NcssCountTest.java | 7 - 49 files changed, 357 insertions(+), 543 deletions(-) delete mode 100644 pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsHook.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyMetricMemoizer.java delete mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyProjectMemoizer.java create mode 100644 pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/package-info.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsFacade.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaProjectMemoizer.java delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/MetricsHook.java diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 69bf8669f2..4849eb3e9a 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -135,6 +135,10 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * Many methods on the {% jdoc core::lang.ast.Node %} interface and {% jdoc core::lang.ast.AbstractNode %} base class. See their javadoc for details. * {% jdoc !!core::lang.ast.Node#isFindBoundary() %} is deprecated for XPath queries. + * Many APIs of {% jdoc_package core::lang.metrics %}, though most of them were internal and + probably not used directly outside of PMD. Use {% jdoc core::lang.metrics.MetricsUtil %} as + a replacement for the language-specific façades too. + * {% jdoc core::lang.ast.QualifiableNode %}, {% jdoc core::lang.ast.QualifiedName %} * pmd-java * {% jdoc java::lang.java.AbstractJavaParser %} * {% jdoc java::lang.java.AbstractJavaHandler %} @@ -162,6 +166,8 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati following nodes: WhileStatement, DoStatement, ForStatement, IfStatement, AssertStatement, ConditionalExpression. * {% jdoc java::lang.java.ast.ASTYieldStatement %} will not implement {% jdoc java::lang.java.ast.TypeNode %} anymore come 7.0.0. Test the type of the expression nested within it. + * {% jdoc core::lang.java.metrics.JavaMetrics %}, {% jdoc core::lang.java.metrics.JavaMetricsComputer %}, + {% jdoc core::lang.java.metrics.JavaMetricsProvider %} ### External Contributions diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java index 30d1fae6a1..3b05c8e8ef 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java @@ -4,11 +4,17 @@ package net.sourceforge.pmd.lang.apex.metrics; +import java.util.ArrayList; +import java.util.List; + +import org.checkerframework.checker.nullness.qual.NonNull; + import net.sourceforge.pmd.lang.apex.ast.ASTMethod; import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface; import net.sourceforge.pmd.lang.metrics.MetricKey; import net.sourceforge.pmd.lang.metrics.MetricOptions; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.lang.metrics.ResultOption; /** @@ -16,7 +22,10 @@ import net.sourceforge.pmd.lang.metrics.ResultOption; * * @author Clément Fournier * @since 6.0.0 + * + * @deprecated Use {@link MetricsUtil} */ +@Deprecated public final class ApexMetrics { private static final ApexMetricsFacade FACADE = new ApexMetricsFacade(); @@ -32,20 +41,12 @@ public final class ApexMetrics { * * @return The facade */ + @Deprecated public static ApexMetricsFacade getFacade() { return FACADE; } - /** - * Resets the entire data structure. - * This needs to be done in case PMD is executed multiple times within one JVM run. - */ - static void reset() { - FACADE.reset(); - } - - /** * Computes the standard value of the metric identified by its code on a class AST node. * @@ -55,7 +56,7 @@ public final class ApexMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey> key, ASTUserClass node) { - return FACADE.computeForType(key, node, MetricOptions.emptyOptions()); + return MetricsUtil.computeMetric(key, node, MetricOptions.emptyOptions()); } @@ -70,7 +71,7 @@ public final class ApexMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey> key, ASTUserClass node, MetricOptions options) { - return FACADE.computeForType(key, node, options); + return MetricsUtil.computeMetric(key, node, options); } @@ -83,7 +84,7 @@ public final class ApexMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, ASTMethod node) { - return FACADE.computeForOperation(key, node, MetricOptions.emptyOptions()); + return MetricsUtil.computeMetric(key, node, MetricOptions.emptyOptions()); } @@ -98,7 +99,7 @@ public final class ApexMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, ASTMethod node, MetricOptions options) { - return FACADE.computeForOperation(key, node, options); + return MetricsUtil.computeMetric(key, node, options); } @@ -111,10 +112,10 @@ public final class ApexMetrics { * @param resultOption The result option to use * * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed or {@code option} is - * {@code null} + * {@code null} */ public static double get(MetricKey key, ASTUserClassOrInterface node, ResultOption resultOption) { - return FACADE.computeWithResultOption(key, node, MetricOptions.emptyOptions(), resultOption); + return MetricsUtil.computeAggregate(key, findOps(node), resultOption); } @@ -128,12 +129,23 @@ public final class ApexMetrics { * @param resultOption The result option to use * * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed or {@code option} is - * {@code null} + * {@code null} */ public static double get(MetricKey key, ASTUserClassOrInterface node, MetricOptions options, ResultOption resultOption) { - return FACADE.computeWithResultOption(key, node, options, resultOption); + return MetricsUtil.computeAggregate(key, findOps(node), options, resultOption); } + @NonNull + static List findOps(ASTUserClassOrInterface node) { + List candidates = node.findChildrenOfType(ASTMethod.class); + List result = new ArrayList<>(candidates); + for (ASTMethod method : candidates) { + if (method.getImage().matches("(||clone)")) { + result.remove(method); + } + } + return result; + } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java index 63ccc76f74..0092bc1394 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.apex.metrics; -import java.util.ArrayList; import java.util.List; import net.sourceforge.pmd.annotation.InternalApi; @@ -21,22 +20,14 @@ public class ApexMetricsComputer extends AbstractMetricsComputer findOperations(ASTUserClassOrInterface node) { + return ApexMetrics.findOps(node); + } @InternalApi public static ApexMetricsComputer getInstance() { return INSTANCE; } - - @Override - protected List findOperations(ASTUserClassOrInterface node) { - List candidates = node.findChildrenOfType(ASTMethod.class); - List result = new ArrayList<>(candidates); - for (ASTMethod method : candidates) { - if (method.getImage().matches("(||clone)")) { - result.remove(method); - } - } - return result; - } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java index 4ed4fa23d3..ddb45dcaa0 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java @@ -13,18 +13,14 @@ import net.sourceforge.pmd.lang.metrics.MetricsComputer; * Backs the static façade. * * @author Clément Fournier + * @deprecated Not useful anymore */ +@Deprecated public class ApexMetricsFacade extends AbstractMetricsFacade, ASTMethod> { private final ApexProjectMemoizer memoizer = new ApexProjectMemoizer(); - /** Resets the entire project mirror. Used for tests. */ - void reset() { - memoizer.reset(); - } - - @Override protected MetricsComputer, ASTMethod> getLanguageSpecificComputer() { return ApexMetricsComputer.getInstance(); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsProvider.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsProvider.java index c3a227b24c..b7b5d852b4 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsProvider.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsProvider.java @@ -18,12 +18,7 @@ public class ApexMetricsProvider extends AbstractLanguageMetricsProvider>) (Object) ASTUserClassOrInterface.class, ASTMethod.class, ApexMetricsComputer.getInstance()); - } - - @Override - public void initialize() { - ApexMetrics.reset(); + super((Class>) (Object) ASTUserClassOrInterface.class, ASTMethod.class); } @Override @@ -32,6 +27,11 @@ public class ApexMetricsProvider extends AbstractLanguageMetricsProvider findOps(ASTUserClassOrInterface astUserClassOrInterface) { + return ApexMetrics.findOps(astUserClassOrInterface); + } + @Override public List getAvailableOperationMetrics() { return Arrays.asList(ApexOperationMetricKey.values()); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java index 8bb26c4d7b..a10676b530 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java @@ -16,6 +16,7 @@ import net.sourceforge.pmd.lang.apex.metrics.ApexMetrics; import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey; import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.lang.metrics.ResultOption; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; @@ -23,7 +24,7 @@ import net.sourceforge.pmd.properties.PropertyFactory; /** * Cyclomatic complexity rule using metrics. Uses Wmc to report classes. - * + * * @author Clément Fournier */ public class CyclomaticComplexityRule extends AbstractApexRule { @@ -69,7 +70,7 @@ public class CyclomaticComplexityRule extends AbstractApexRule { classNames.pop(); if (ApexClassMetricKey.WMC.supports(node)) { - int classWmc = (int) ApexMetrics.get(ApexClassMetricKey.WMC, node); + int classWmc = (int) MetricsUtil.computeMetric(ApexClassMetricKey.WMC, node); if (classWmc >= getProperty(CLASS_LEVEL_DESCRIPTOR)) { int classHighest = (int) ApexMetrics.get(ApexOperationMetricKey.CYCLO, node, ResultOption.HIGHEST); @@ -89,7 +90,7 @@ public class CyclomaticComplexityRule extends AbstractApexRule { @Override public final Object visit(ASTMethod node, Object data) { - int cyclo = (int) ApexMetrics.get(ApexOperationMetricKey.CYCLO, node); + int cyclo = (int) MetricsUtil.computeMetric(ApexOperationMetricKey.CYCLO, node); if (cyclo >= getProperty(METHOD_LEVEL_DESCRIPTOR)) { String opType = inTrigger ? "trigger" : node.getImage().equals(classNames.peek()) ? "constructor" diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsHook.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsHook.java deleted file mode 100644 index c376addaab..0000000000 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsHook.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.apex.metrics; - - -/** - * Provides a hook into package-private methods of {@code apex.metrics}. - * - * @author Clément Fournier - */ -public class ApexMetricsHook { - - private ApexMetricsHook() { - - } - - - public static void reset() { - ApexMetrics.reset(); - } - - -} 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 97832b1e2c..9fdb994e88 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 @@ -24,8 +24,8 @@ 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; import net.sourceforge.pmd.lang.metrics.MetricKeyUtil; -import net.sourceforge.pmd.lang.metrics.MetricMemoizer; import net.sourceforge.pmd.lang.metrics.MetricOptions; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import apex.jorje.semantic.ast.compilation.Compilation; @@ -71,25 +71,19 @@ public class ApexProjectMirrorTest extends ApexParserTestBase { private List visitWith(ApexNode acu, final boolean force) { - final ApexProjectMemoizer toplevel = ApexMetrics.getFacade().getLanguageSpecificProjectMemoizer(); - final List result = new ArrayList<>(); acu.jjtAccept(new ApexParserVisitorAdapter() { @Override public Object visit(ASTMethod node, Object data) { - MetricMemoizer op = toplevel.getOperationMemoizer(node.getQualifiedName()); - result.add((int) ApexMetricsComputer.getInstance().computeForOperation(opMetricKey, node, force, - MetricOptions.emptyOptions(), op)); + result.add((int) MetricsUtil.computeMetric(opMetricKey, node, MetricOptions.emptyOptions(), force)); return super.visit(node, data); } @Override public Object visit(ASTUserClass node, Object data) { - MetricMemoizer> clazz = toplevel.getClassMemoizer(node.getQualifiedName()); - result.add((int) ApexMetricsComputer.getInstance().computeForType(classMetricKey, node, force, - MetricOptions.emptyOptions(), clazz)); + result.add((int) MetricsUtil.computeMetric(classMetricKey, node, MetricOptions.emptyOptions(), force)); return super.visit(node, data); } }, null); diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AllMetricsTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AllMetricsTest.java index b11423671f..4f60d06fa6 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AllMetricsTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AllMetricsTest.java @@ -4,8 +4,6 @@ package net.sourceforge.pmd.lang.apex.metrics.impl; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.lang.apex.metrics.ApexMetricsHook; import net.sourceforge.pmd.testframework.SimpleAggregatorTst; /** @@ -18,14 +16,6 @@ public class AllMetricsTest extends SimpleAggregatorTst { private static final String RULESET = "rulesets/apex/metrics_test.xml"; - - @Override - protected Rule reinitializeRule(Rule rule) { - ApexMetricsHook.reset(); - return rule; - } - - @Override public void setUp() { addRule(RULESET, "CycloTest"); diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityTest.java index d667350887..50ffb556ea 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityTest.java @@ -4,14 +4,7 @@ package net.sourceforge.pmd.lang.apex.rule.design; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.lang.apex.metrics.ApexMetricsHook; import net.sourceforge.pmd.testframework.PmdRuleTst; public class CyclomaticComplexityTest extends PmdRuleTst { - @Override - protected Rule reinitializeRule(Rule rule) { - ApexMetricsHook.reset(); - return super.reinitializeRule(rule); - } } 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 03a7bcbcfc..22eb9b5fe8 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 @@ -373,6 +373,7 @@ public interface Node { * unless it has been set via {@link #setUserData(Object)}. * * @return The user data set on this node. + * @deprecated Use {@link #getUserMap()} */ Object getUserData(); @@ -389,6 +390,7 @@ public interface Node { * * @param userData * The data to set on this node. + * @deprecated Use {@link #getUserMap()} */ void setUserData(Object userData); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/QualifiableNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/QualifiableNode.java index 1548cc9cfe..a4b379d084 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/QualifiableNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/QualifiableNode.java @@ -8,7 +8,10 @@ package net.sourceforge.pmd.lang.ast; * Nodes that can be described with a qualified name. * * @author Clément Fournier + * + * @deprecated Not useful anymore */ +@Deprecated public interface QualifiableNode extends Node { /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/QualifiedName.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/QualifiedName.java index 69d5f386ab..670215b544 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/QualifiedName.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/QualifiedName.java @@ -12,7 +12,9 @@ package net.sourceforge.pmd.lang.ast; * from QualifiedName to e.g. JavaQualifiedName. * * @author Clément Fournier + * @deprecated Not useful anymore */ +@Deprecated public interface QualifiedName { @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/AbstractMetricsComputer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/AbstractMetricsComputer.java index d933b4d352..b6cfde2815 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/AbstractMetricsComputer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/AbstractMetricsComputer.java @@ -4,7 +4,6 @@ package net.sourceforge.pmd.lang.metrics; -import java.util.ArrayList; import java.util.List; import net.sourceforge.pmd.lang.ast.QualifiableNode; @@ -17,25 +16,16 @@ import net.sourceforge.pmd.lang.ast.QualifiableNode; * * @author Clément Fournier * @since 6.0.0 + * @deprecated See package description */ +@Deprecated public abstract class AbstractMetricsComputer implements MetricsComputer { @Override public double computeForType(MetricKey key, T node, boolean force, MetricOptions options, MetricMemoizer memoizer) { - - ParameterizedMetricKey paramKey = ParameterizedMetricKey.getInstance(key, options); - // if memo.get(key) == null then the metric has never been computed. NaN is a valid value. - Double prev = memoizer.getMemo(paramKey); - if (!force && prev != null) { - return prev; - } - - double val = key.getCalculator().computeFor(node, options); - memoizer.memoize(paramKey, val); - - return val; + return MetricsUtil.computeMetric(key, node, options); } @@ -43,46 +33,14 @@ public abstract class AbstractMetricsComputer key, O node, boolean force, MetricOptions options, MetricMemoizer memoizer) { - ParameterizedMetricKey paramKey = ParameterizedMetricKey.getInstance(key, options); - Double prev = memoizer.getMemo(paramKey); - if (!force && prev != null) { - return prev; - } - - double val = key.getCalculator().computeFor(node, options); - memoizer.memoize(paramKey, val); - return val; + return MetricsUtil.computeMetric(key, node, options); } @Override public double computeWithResultOption(MetricKey key, T node, boolean force, MetricOptions options, ResultOption option, ProjectMemoizer stats) { - - List ops = findOperations(node); - - List values = new ArrayList<>(); - for (O op : ops) { - if (key.supports(op)) { - MetricMemoizer opStats = stats.getOperationMemoizer(op.getQualifiedName()); - double val = this.computeForOperation(key, op, force, options, opStats); - if (val != Double.NaN) { - values.add(val); - } - } - } - - // FUTURE use streams to do that when we upgrade the compiler to 1.8 - switch (option) { - case SUM: - return sum(values); - case HIGHEST: - return highest(values); - case AVERAGE: - return average(values); - default: - return Double.NaN; - } + return MetricsUtil.computeAggregate(key, findOperations(node), options, option); } @@ -97,29 +55,4 @@ public abstract class AbstractMetricsComputer findOperations(T node); // TODO:cf this one is computed every time - private static double sum(List values) { - double sum = 0; - for (double val : values) { - sum += val; - } - return sum; - } - - - private static double highest(List values) { - double highest = Double.NEGATIVE_INFINITY; - for (double val : values) { - if (val > highest) { - highest = val; - } - } - return highest == Double.NEGATIVE_INFINITY ? 0 : highest; - } - - - private static double average(List values) { - return sum(values) / values.size(); - } - - } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/AbstractMetricsFacade.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/AbstractMetricsFacade.java index 4b165a51dd..a75a522d32 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/AbstractMetricsFacade.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/AbstractMetricsFacade.java @@ -4,8 +4,6 @@ package net.sourceforge.pmd.lang.metrics; -import java.util.Objects; - import net.sourceforge.pmd.lang.ast.QualifiableNode; /** @@ -17,19 +15,18 @@ import net.sourceforge.pmd.lang.ast.QualifiableNode; * * @author Clément Fournier * @since 6.0.0 + * @deprecated See package description */ +@Deprecated public abstract class AbstractMetricsFacade { - private static final String NULL_KEY_MESSAGE = "The metric key must not be null"; - private static final String NULL_OPTIONS_MESSAGE = "The metric options must not be null"; - private static final String NULL_NODE_MESSAGE = "The node must not be null"; - /** * Gets the language specific metrics computer. * * @return The metrics computer */ + @Deprecated protected abstract MetricsComputer getLanguageSpecificComputer(); @@ -38,6 +35,7 @@ public abstract class AbstractMetricsFacade getLanguageSpecificProjectMemoizer(); @@ -52,20 +50,7 @@ public abstract class AbstractMetricsFacade key, T node, MetricOptions options) { - - Objects.requireNonNull(key, NULL_KEY_MESSAGE); - Objects.requireNonNull(options, NULL_OPTIONS_MESSAGE); - Objects.requireNonNull(node, NULL_NODE_MESSAGE); - - if (!key.supports(node)) { - return Double.NaN; - } - - MetricMemoizer memoizer = getLanguageSpecificProjectMemoizer().getClassMemoizer(node.getQualifiedName()); - - return memoizer == null ? Double.NaN - : getLanguageSpecificComputer().computeForType(key, node, false, - options, memoizer); + return MetricsUtil.computeMetric(key, node, options); } @@ -79,22 +64,7 @@ public abstract class AbstractMetricsFacade key, O node, MetricOptions options) { - - Objects.requireNonNull(key, NULL_KEY_MESSAGE); - Objects.requireNonNull(options, NULL_OPTIONS_MESSAGE); - Objects.requireNonNull(node, NULL_NODE_MESSAGE); - - - if (!key.supports(node)) { - return Double.NaN; - } - - MetricMemoizer memoizer = getLanguageSpecificProjectMemoizer().getOperationMemoizer(node.getQualifiedName()); - - return memoizer == null ? Double.NaN - : getLanguageSpecificComputer().computeForOperation(key, node, false, - options, memoizer); - + return MetricsUtil.computeMetric(key, node, options); } @@ -113,11 +83,6 @@ public abstract class AbstractMetricsFacade key, T node, MetricOptions options, ResultOption resultOption) { - Objects.requireNonNull(key, NULL_KEY_MESSAGE); - Objects.requireNonNull(options, NULL_OPTIONS_MESSAGE); - Objects.requireNonNull(node, NULL_NODE_MESSAGE); - Objects.requireNonNull(resultOption, "The result option must not be null"); - return getLanguageSpecificComputer().computeWithResultOption(key, node, false, options, resultOption, getLanguageSpecificProjectMemoizer()); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/BasicMetricMemoizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/BasicMetricMemoizer.java index 8ae0139593..97ba54f533 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/BasicMetricMemoizer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/BasicMetricMemoizer.java @@ -16,7 +16,9 @@ import net.sourceforge.pmd.lang.ast.Node; * * @author Clément Fournier * @since 6.0.0 + * @deprecated See package description */ +@Deprecated public class BasicMetricMemoizer implements MetricMemoizer { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/BasicProjectMemoizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/BasicProjectMemoizer.java index e5b6a7463d..c5830b277b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/BasicProjectMemoizer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/BasicProjectMemoizer.java @@ -21,7 +21,10 @@ import net.sourceforge.pmd.lang.ast.QualifiedName; * * @author Clément Fournier * @since 6.0.0 + * + * @deprecated See package description */ +@Deprecated public abstract class BasicProjectMemoizer implements ProjectMemoizer { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/LanguageMetricsProvider.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/LanguageMetricsProvider.java index a1b84240ce..ec57cceff9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/LanguageMetricsProvider.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/LanguageMetricsProvider.java @@ -31,12 +31,6 @@ import net.sourceforge.pmd.lang.ast.QualifiableNode; @Experimental public interface LanguageMetricsProvider { - /** - * Provides a hook to do any initializing before the first file is processed by PMD. - * This can be used by the metrics implementations to reset the cache. - */ - void initialize(); - /** * Returns a list of all supported type metric keys * for the language. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricKey.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricKey.java index 2259ed8956..ead1c63e9e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricKey.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricKey.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.metrics; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.util.DataMap.DataKey; /** * Key identifying a metric. Such keys must implement the hashCode method. Enums are well fitted to serve as @@ -14,7 +15,7 @@ import net.sourceforge.pmd.lang.ast.Node; * @author Clément Fournier * @since 5.8.0 */ -public interface MetricKey { +public interface MetricKey extends DataKey, Double> { /** * Returns the name of the metric. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricMemoizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricMemoizer.java index a41f8c6a65..bea9041e3d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricMemoizer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricMemoizer.java @@ -14,7 +14,9 @@ import net.sourceforge.pmd.lang.ast.Node; * * @author Clément Fournier * @since 6.0.0 + * @deprecated See package description */ +@Deprecated public interface MetricMemoizer { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsComputer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsComputer.java index 5626539ada..0951822782 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsComputer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsComputer.java @@ -16,7 +16,9 @@ import net.sourceforge.pmd.lang.ast.QualifiableNode; * * @author Clément Fournier * @since 6.0.0 + * @deprecated See package description */ +@Deprecated public interface MetricsComputer { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java new file mode 100644 index 0000000000..65db7403ab --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java @@ -0,0 +1,155 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.metrics; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import net.sourceforge.pmd.lang.ast.Node; + +/** + * Utilities to use {@link Metric} instances. + */ +public final class MetricsUtil { + + static final String NULL_KEY_MESSAGE = "The metric key must not be null"; + static final String NULL_OPTIONS_MESSAGE = "The metric options must not be null"; + static final String NULL_NODE_MESSAGE = "The node must not be null"; + + private MetricsUtil() { + // util class + } + + public static double computeAggregate(MetricKey key, Iterable ops, ResultOption resultOption) { + return computeAggregate(key, ops, MetricOptions.emptyOptions(), resultOption); + } + + /** + * Computes an aggregate result for a metric, identified with a {@link ResultOption}. + * + * @param key The metric to compute + * @param ops List of nodes for which to aggregate the metric + * @param options The options of the metric + * @param resultOption The type of aggregation to perform + * + * @return The result of the computation, or {@code Double.NaN} if it couldn't be performed + */ + public static double computeAggregate(MetricKey key, Iterable ops, MetricOptions options, ResultOption resultOption) { + + + Objects.requireNonNull(key, NULL_KEY_MESSAGE); + Objects.requireNonNull(options, NULL_OPTIONS_MESSAGE); + Objects.requireNonNull(ops, NULL_NODE_MESSAGE); + Objects.requireNonNull(resultOption, "The result option must not be null"); + + + List values = new ArrayList<>(); + for (O op : ops) { + if (key.supports(op)) { + double val = computeMetric(key, op, options); + if (!Double.isNaN(val)) { + values.add(val); + } + } + } + + // FUTURE use streams to do that when we upgrade the compiler to 1.8 + switch (resultOption) { + case SUM: + return sum(values); + case HIGHEST: + return highest(values); + case AVERAGE: + return average(values); + default: + return Double.NaN; + } + } + + /** + * Computes a metric identified by its code on a node, with the default options. + * + * @param key The key identifying the metric to be computed + * @param node The node on which to compute the metric + * + * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed + */ + public static double computeMetric(MetricKey key, N node) { + return computeMetric(key, node, MetricOptions.emptyOptions()); + } + + /** + * Computes a metric identified by its code on a node, possibly + * selecting a variant with the {@code options} parameter. + * + * @param key The key identifying the metric to be computed + * @param node The node on which to compute the metric + * @param options The options of the metric + * + * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed + */ + public static double computeMetric(MetricKey key, N node, MetricOptions options) { + return computeMetric(key, node, options, false); + } + + /** + * Computes a metric identified by its code on a node, possibly + * selecting a variant with the {@code options} parameter. + * + * @param key The key identifying the metric to be computed + * @param node The node on which to compute the metric + * @param options The options of the metric + * @param forceRecompute Force recomputation of the result + * + * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed + */ + public static double computeMetric(MetricKey key, N node, MetricOptions options, boolean forceRecompute) { + Objects.requireNonNull(key, NULL_KEY_MESSAGE); + Objects.requireNonNull(options, NULL_OPTIONS_MESSAGE); + Objects.requireNonNull(node, NULL_NODE_MESSAGE); + + + if (!key.supports(node)) { + return Double.NaN; + } + + ParameterizedMetricKey paramKey = ParameterizedMetricKey.getInstance(key, options); + Double prev = node.getUserMap().get(paramKey); + if (!forceRecompute && prev != null) { + return prev; + } + + double val = key.getCalculator().computeFor(node, options); + node.getUserMap().set(paramKey, val); + return val; + } + + private static double sum(List values) { + double sum = 0; + for (double val : values) { + sum += val; + } + return sum; + } + + + private static double highest(List values) { + double highest = Double.NEGATIVE_INFINITY; + for (double val : values) { + if (val > highest) { + highest = val; + } + } + return highest == Double.NEGATIVE_INFINITY ? 0 : highest; + } + + + private static double average(List values) { + return sum(values) / values.size(); + } + + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKey.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKey.java index e0a8dbb799..474852c8ec 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKey.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKey.java @@ -7,7 +7,9 @@ package net.sourceforge.pmd.lang.metrics; import java.util.HashMap; import java.util.Map; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.util.DataMap.DataKey; /** * Represents a key parameterized with its options. Used to index memoization maps. @@ -16,8 +18,11 @@ import net.sourceforge.pmd.lang.ast.Node; * * @author Clément Fournier * @since 5.8.0 + * @deprecated Is internal API */ -public final class ParameterizedMetricKey { +@InternalApi +@Deprecated +public final class ParameterizedMetricKey implements DataKey, Double> { private static final Map, ParameterizedMetricKey> POOL = new HashMap<>(); @@ -65,6 +70,7 @@ public final class ParameterizedMetricKey { */ @SuppressWarnings("PMD.SingletonClassReturningNewInstance") public static ParameterizedMetricKey getInstance(MetricKey key, MetricOptions options) { + // sharing instances allows using DataMap, which uses reference identity ParameterizedMetricKey tmp = new ParameterizedMetricKey<>(key, options); if (!POOL.containsKey(tmp)) { POOL.put(tmp, tmp); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ProjectMemoizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ProjectMemoizer.java index 04651b2a32..d4e889ed2d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ProjectMemoizer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ProjectMemoizer.java @@ -19,7 +19,9 @@ import net.sourceforge.pmd.lang.ast.QualifiedName; * * @author Clément Fournier * @since 6.0.0 + * @deprecated See package description */ +@Deprecated public interface ProjectMemoizer { /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/AbstractLanguageMetricsProvider.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/AbstractLanguageMetricsProvider.java index d6f46e0d7a..05a4ce33dc 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/AbstractLanguageMetricsProvider.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/AbstractLanguageMetricsProvider.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.metrics.internal; import java.util.HashMap; +import java.util.List; import java.util.Map; import net.sourceforge.pmd.lang.ast.Node; @@ -12,7 +13,7 @@ import net.sourceforge.pmd.lang.ast.QualifiableNode; import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider; import net.sourceforge.pmd.lang.metrics.MetricKey; import net.sourceforge.pmd.lang.metrics.MetricOptions; -import net.sourceforge.pmd.lang.metrics.MetricsComputer; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.lang.metrics.ResultOption; @@ -26,15 +27,12 @@ public abstract class AbstractLanguageMetricsProvider tClass; private final Class oClass; - private final MetricsComputer myComputer; protected AbstractLanguageMetricsProvider(Class tClass, - Class oClass, - MetricsComputer computer) { + Class oClass) { this.tClass = tClass; this.oClass = oClass; - this.myComputer = computer; } @@ -52,21 +50,23 @@ public abstract class AbstractLanguageMetricsProvider key, T node, MetricOptions options) { - return myComputer.computeForType(key, node, true, options, DummyMetricMemoizer.getInstance()); + return MetricsUtil.computeMetric(key, node, options, true); } @Override public double computeForOperation(MetricKey key, O node, MetricOptions options) { - return myComputer.computeForOperation(key, node, true, options, DummyMetricMemoizer.getInstance()); + return MetricsUtil.computeMetric(key, node, options, true); } @Override - public double computeWithResultOption(MetricKey key, T node, MetricOptions options, ResultOption option) { - return myComputer.computeWithResultOption(key, node, true, options, option, DummyProjectMemoizer.getInstance()); + public double computeWithResultOption(MetricKey key, T node, MetricOptions options, ResultOption resultOption) { + return MetricsUtil.computeAggregate(key, findOps(node), options, resultOption); } + protected abstract List findOps(T t); + @Override public Map, Double> computeAllMetricsFor(Node node) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyMetricMemoizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyMetricMemoizer.java deleted file mode 100644 index 1d6cae45a1..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyMetricMemoizer.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.metrics.internal; - -import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.metrics.MetricMemoizer; -import net.sourceforge.pmd.lang.metrics.ParameterizedMetricKey; - - -/** - * Memoizes nothing. - * - * @author Clément Fournier - * @since 6.11.0 - */ -public final class DummyMetricMemoizer implements MetricMemoizer { - - private static final DummyMetricMemoizer INSTANCE = new DummyMetricMemoizer<>(); - - - private DummyMetricMemoizer() { - - } - - - @Override - public Double getMemo(ParameterizedMetricKey key) { - return null; - } - - - @Override - public void memoize(ParameterizedMetricKey key, double value) { - // do nothing - } - - - @SuppressWarnings("unchecked") - public static DummyMetricMemoizer getInstance() { - return (DummyMetricMemoizer) INSTANCE; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyProjectMemoizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyProjectMemoizer.java deleted file mode 100644 index 10abe75a9e..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/internal/DummyProjectMemoizer.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.metrics.internal; - -import net.sourceforge.pmd.lang.ast.QualifiableNode; -import net.sourceforge.pmd.lang.ast.QualifiedName; -import net.sourceforge.pmd.lang.metrics.MetricMemoizer; -import net.sourceforge.pmd.lang.metrics.ProjectMemoizer; - - -/** - * Memoizes nothing. - * - * @author Clément Fournier - * @since 6.11.0 - */ -public final class DummyProjectMemoizer implements ProjectMemoizer { - - private static final DummyProjectMemoizer INSTANCE = new DummyProjectMemoizer<>(); - - - private DummyProjectMemoizer() { - - } - - - @Override - public MetricMemoizer getOperationMemoizer(QualifiedName qname) { - return DummyMetricMemoizer.getInstance(); - } - - - @Override - public MetricMemoizer getClassMemoizer(QualifiedName qname) { - return DummyMetricMemoizer.getInstance(); - } - - - @SuppressWarnings("unchecked") - public static DummyProjectMemoizer getInstance() { - return (DummyProjectMemoizer) INSTANCE; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/package-info.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/package-info.java new file mode 100644 index 0000000000..e42b2b08fc --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/package-info.java @@ -0,0 +1,16 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +/** + * Language-independent framework to represent code metrics. If you want + * to compute code metrics in your rules, then you should find the language-specific + * enums containing {@link net.sourceforge.pmd.lang.metrics.MetricKey}s + * in the relevant language modules. + * + *

Metrics are cached by default on the nodes they're computed on. + * Many APIs here are deprecated, this is because metrics were previously + * cached in big static maps, which is replaced by caching on nodes. + * + */ +package net.sourceforge.pmd.lang.metrics; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/processor/AbstractPMDProcessor.java b/pmd-core/src/main/java/net/sourceforge/pmd/processor/AbstractPMDProcessor.java index ee0bb7f382..f6518a2d2a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/processor/AbstractPMDProcessor.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/processor/AbstractPMDProcessor.java @@ -24,9 +24,6 @@ import net.sourceforge.pmd.SourceCodeProcessor; import net.sourceforge.pmd.benchmark.TimeTracker; import net.sourceforge.pmd.benchmark.TimedOperation; import net.sourceforge.pmd.benchmark.TimedOperationCategory; -import net.sourceforge.pmd.lang.Language; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.util.datasource.DataSource; @@ -37,7 +34,7 @@ import net.sourceforge.pmd.util.datasource.DataSource; public abstract class AbstractPMDProcessor { private static final Logger LOG = Logger.getLogger(AbstractPMDProcessor.class.getName()); - + protected final PMDConfiguration configuration; public AbstractPMDProcessor(PMDConfiguration configuration) { @@ -56,7 +53,7 @@ public abstract class AbstractPMDProcessor { } /** - * + * * @deprecated this method will be removed. It was once used to determine a short filename * for the file being analyzed, so that shortnames can be reported. But the logic has * been moved to the renderers. @@ -78,15 +75,15 @@ public abstract class AbstractPMDProcessor { */ protected RuleSets createRuleSets(RuleSetFactory factory, Report report) { final RuleSets rs = RulesetsFactoryUtils.getRuleSets(configuration.getRuleSets(), factory); - + final Set brokenRules = removeBrokenRules(rs); for (final Rule rule : brokenRules) { report.addConfigError(new Report.ConfigurationError(rule, rule.dysfunctionReason())); } - + return rs; } - + /** * Remove and return the misconfigured rules from the rulesets and log them * for good measure. @@ -117,8 +114,6 @@ public abstract class AbstractPMDProcessor { configuration.getAnalysisCache().checkValidity(rs, configuration.getClassLoader()); final SourceCodeProcessor processor = new SourceCodeProcessor(configuration); - resetMetrics(); - for (final DataSource dataSource : files) { // this is the real, canonical and absolute filename (not shortened) String realFileName = dataSource.getNiceFileName(false, null); @@ -128,7 +123,7 @@ public abstract class AbstractPMDProcessor { // render base report first - general errors renderReports(renderers, ctx.getReport()); - + // then add analysis results per file collectReports(renderers); @@ -139,15 +134,6 @@ public abstract class AbstractPMDProcessor { } } - private void resetMetrics() { - for (Language language : LanguageRegistry.getLanguages()) { - LanguageMetricsProvider languageMetricsProvider = language.getDefaultVersion().getLanguageVersionHandler().getLanguageMetricsProvider(); - if (languageMetricsProvider != null) { - languageMetricsProvider.initialize(); - } - } - } - protected abstract void runAnalysis(PmdRunnable runnable); protected abstract void collectReports(List renderers); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/DataMap.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/DataMap.java index 7a38e975bc..05d4bcd2c5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/DataMap.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/DataMap.java @@ -8,11 +8,14 @@ import java.util.IdentityHashMap; import java.util.Map; /** - * An opaque, strongly typed heterogeneous data container. + * An opaque, strongly typed heterogeneous data container. Data maps can + * be set to accept only a certain type of key, with the type parameter. + * The key can itself constrain the type of values, using its own type + * parameter {@code T}. * - * @param Type of keys in this map + * @param Type of keys in this map. */ -public class DataMap { +public final class DataMap { private final Map, Object> map = new IdentityHashMap<>(); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java index de4282675d..8d2247fdc0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java @@ -5,11 +5,16 @@ package net.sourceforge.pmd.lang.java.metrics; +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; import net.sourceforge.pmd.lang.metrics.MetricKey; import net.sourceforge.pmd.lang.metrics.MetricOptions; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.lang.metrics.ResultOption; @@ -17,36 +22,17 @@ import net.sourceforge.pmd.lang.metrics.ResultOption; * User bound façade of the Metrics Framework. Provides a uniform interface for the calculation of metrics. * * @author Clément Fournier + * @deprecated Use {@link MetricsUtil} */ +@Deprecated public final class JavaMetrics { - private static final JavaMetricsFacade FACADE = new JavaMetricsFacade(); - private JavaMetrics() { // Cannot be instantiated } - /** - * Returns the underlying façade. - * - * @return The underlying façade instance - */ - static JavaMetricsFacade getFacade() { - return FACADE; - } - - - /** - * Resets the entire data structure. - * This needs to be done in case PMD is executed multiple times within one JVM run. - */ - static void reset() { - FACADE.reset(); - } - - /** * Computes the standard value of the metric identified by its code on a class AST node. * @@ -56,7 +42,7 @@ public final class JavaMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, ASTAnyTypeDeclaration node) { - return FACADE.computeForType(key, node, MetricOptions.emptyOptions()); + return MetricsUtil.computeMetric(key, node); } @@ -71,7 +57,7 @@ public final class JavaMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, ASTAnyTypeDeclaration node, MetricOptions options) { - return FACADE.computeForType(key, node, options); + return MetricsUtil.computeMetric(key, node, options); } @@ -84,14 +70,14 @@ public final class JavaMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, MethodLikeNode node) { - return FACADE.computeForOperation(key, node, MetricOptions.emptyOptions()); + return MetricsUtil.computeMetric(key, node); } /** * @see #get(MetricKey, MethodLikeNode) * @deprecated Provided here for backwards binary compatibility with {@link #get(MetricKey, MethodLikeNode)}. - * Please explicitly link your code to that method and recompile your code. Will be remove with 7.0.0 + * Please explicitly link your code to that method and recompile your code. Will be remove with 7.0.0 */ public static double get(MetricKey key, ASTMethodOrConstructorDeclaration node) { return get(key, (MethodLikeNode) node); @@ -101,7 +87,7 @@ public final class JavaMetrics { /** * @see #get(MetricKey, MethodLikeNode, MetricOptions) * @deprecated Provided here for backwards binary compatibility with {@link #get(MetricKey, MethodLikeNode, MetricOptions)}. - * Please explicitly link your code to that method and recompile your code. Will be remove with 7.0.0 + * Please explicitly link your code to that method and recompile your code. Will be remove with 7.0.0 */ @Deprecated public static double get(MetricKey key, ASTMethodOrConstructorDeclaration node, MetricOptions options) { @@ -118,7 +104,7 @@ public final class JavaMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, MethodLikeNode node, MetricOptions options) { - return FACADE.computeForOperation(key, node, options); + return MetricsUtil.computeMetric(key, node, options); } @@ -133,7 +119,7 @@ public final class JavaMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, ASTAnyTypeDeclaration node, ResultOption resultOption) { - return FACADE.computeWithResultOption(key, node, MetricOptions.emptyOptions(), resultOption); + return MetricsUtil.computeAggregate(key, findOps(node), resultOption); } @@ -150,7 +136,17 @@ public final class JavaMetrics { */ public static double get(MetricKey key, ASTAnyTypeDeclaration node, MetricOptions options, ResultOption resultOption) { - return FACADE.computeWithResultOption(key, node, options, resultOption); + return MetricsUtil.computeAggregate(key, findOps(node), options, resultOption); } + static List findOps(ASTAnyTypeDeclaration node) { + List operations = new ArrayList<>(); + + for (ASTAnyTypeBodyDeclaration decl : node.getDeclarations()) { + if (decl.getNumChildren() > 0 && decl.getDeclarationNode() instanceof ASTMethodOrConstructorDeclaration) { + operations.add((MethodLikeNode) decl.getChild(0)); + } + } + return operations; + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsComputer.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsComputer.java index 8c6934f352..65b4ddeaeb 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsComputer.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsComputer.java @@ -4,21 +4,21 @@ package net.sourceforge.pmd.lang.java.metrics; -import java.util.ArrayList; import java.util.List; import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer; +import net.sourceforge.pmd.lang.metrics.MetricsComputer; /** * Computes a metric. * * @author Clément Fournier + * @deprecated See {@link MetricsComputer} */ +@Deprecated public final class JavaMetricsComputer extends AbstractMetricsComputer { private static final JavaMetricsComputer INSTANCE = new JavaMetricsComputer(); @@ -27,25 +27,15 @@ public final class JavaMetricsComputer extends AbstractMetricsComputer findOperations(ASTAnyTypeDeclaration node) { + return JavaMetrics.findOps(node); + } @InternalApi public static JavaMetricsComputer getInstance() { return INSTANCE; } - - // TODO: doesn't consider lambdas - @Override - protected List findOperations(ASTAnyTypeDeclaration node) { - - List operations = new ArrayList<>(); - - for (ASTAnyTypeBodyDeclaration decl : node.getDeclarations()) { - if (decl.getNumChildren() > 0 && decl.getChild(0) instanceof ASTMethodOrConstructorDeclaration) { - operations.add((MethodLikeNode) decl.getChild(0)); - } - } - return operations; - } - } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsFacade.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsFacade.java deleted file mode 100644 index f239407db7..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsFacade.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.metrics; - -import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; -import net.sourceforge.pmd.lang.metrics.AbstractMetricsFacade; -import net.sourceforge.pmd.lang.metrics.MetricsComputer; - -/** - * Inner façade of the Java metrics framework. The static façade delegates to an instance of this class. - * - * @author Clément Fournier - */ -class JavaMetricsFacade extends AbstractMetricsFacade { - - private final JavaProjectMemoizer memoizer = new JavaProjectMemoizer(); - - - /** Resets the entire data structure. Used for tests. */ - void reset() { - memoizer.reset(); - } - - - @Override - public JavaProjectMemoizer getLanguageSpecificProjectMemoizer() { - return memoizer; - } - - - @Override - protected MetricsComputer getLanguageSpecificComputer() { - return JavaMetricsComputer.getInstance(); - } - -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProvider.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProvider.java index 8070454c64..8f73f937d8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProvider.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProvider.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.metrics; import java.util.Arrays; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey; @@ -14,15 +15,20 @@ import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey; import net.sourceforge.pmd.lang.metrics.MetricKey; import net.sourceforge.pmd.lang.metrics.internal.AbstractLanguageMetricsProvider; +/** + * @deprecated This is internal API + */ +@Deprecated +@InternalApi public class JavaMetricsProvider extends AbstractLanguageMetricsProvider { public JavaMetricsProvider() { - super(ASTAnyTypeDeclaration.class, MethodLikeNode.class, JavaMetricsComputer.getInstance()); + super(ASTAnyTypeDeclaration.class, MethodLikeNode.class); } @Override - public void initialize() { - JavaMetrics.reset(); + protected List findOps(ASTAnyTypeDeclaration astAnyTypeDeclaration) { + return JavaMetrics.findOps(astAnyTypeDeclaration); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaProjectMemoizer.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaProjectMemoizer.java deleted file mode 100644 index 0d30549a51..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaProjectMemoizer.java +++ /dev/null @@ -1,18 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.metrics; - -import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; -import net.sourceforge.pmd.lang.metrics.BasicProjectMemoizer; - -/** - * Shorthand for a project memoizer parameterized with Java-specific node types. - * - * @author Clément Fournier - */ -class JavaProjectMemoizer extends BasicProjectMemoizer { - -} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/AbstractJavaOperationMetric.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/AbstractJavaOperationMetric.java index f9eed4f242..264d9e3c1e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/AbstractJavaOperationMetric.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/AbstractJavaOperationMetric.java @@ -26,6 +26,7 @@ public abstract class AbstractJavaOperationMetric extends AbstractJavaMetric= classReportLevel) { int classHighest = (int) JavaMetrics.get(JavaOperationMetricKey.CYCLO, node, cycloOptions, ResultOption.HIGHEST); @@ -144,7 +145,7 @@ public class CyclomaticComplexityRule extends AbstractJavaMetricsRule { @Override public final Object visit(MethodLikeNode node, Object data) { - int cyclo = (int) JavaMetrics.get(JavaOperationMetricKey.CYCLO, node, cycloOptions); + int cyclo = (int) MetricsUtil.computeMetric(JavaOperationMetricKey.CYCLO, node, cycloOptions); if (cyclo >= methodReportLevel) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/DataClassRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/DataClassRule.java index 780831ac46..608fa7f9d6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/DataClassRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/DataClassRule.java @@ -5,9 +5,9 @@ package net.sourceforge.pmd.lang.java.rule.design; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; -import net.sourceforge.pmd.lang.java.metrics.JavaMetrics; import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey; import net.sourceforge.pmd.lang.java.rule.AbstractJavaMetricsRule; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.util.StringUtil; /** @@ -30,10 +30,10 @@ public class DataClassRule extends AbstractJavaMetricsRule { boolean isDataClass = interfaceRevealsData(node) && classRevealsDataAndLacksComplexity(node); if (isDataClass) { - double woc = JavaMetrics.get(JavaClassMetricKey.WOC, node); - int nopa = (int) JavaMetrics.get(JavaClassMetricKey.NOPA, node); - int noam = (int) JavaMetrics.get(JavaClassMetricKey.NOAM, node); - int wmc = (int) JavaMetrics.get(JavaClassMetricKey.WMC, node); + double woc = MetricsUtil.computeMetric(JavaClassMetricKey.WOC, node); + int nopa = (int) MetricsUtil.computeMetric(JavaClassMetricKey.NOPA, node); + int noam = (int) MetricsUtil.computeMetric(JavaClassMetricKey.NOAM, node); + int wmc = (int) MetricsUtil.computeMetric(JavaClassMetricKey.WMC, node); addViolation(data, node, new Object[] {node.getSimpleName(), StringUtil.percentageString(woc, 3), @@ -45,15 +45,15 @@ public class DataClassRule extends AbstractJavaMetricsRule { private boolean interfaceRevealsData(ASTAnyTypeDeclaration node) { - double woc = JavaMetrics.get(JavaClassMetricKey.WOC, node); + double woc = MetricsUtil.computeMetric(JavaClassMetricKey.WOC, node); return woc < WOC_LEVEL; } private boolean classRevealsDataAndLacksComplexity(ASTAnyTypeDeclaration node) { - int nopa = (int) JavaMetrics.get(JavaClassMetricKey.NOPA, node); - int noam = (int) JavaMetrics.get(JavaClassMetricKey.NOAM, node); - int wmc = (int) JavaMetrics.get(JavaClassMetricKey.WMC, node); + int nopa = (int) MetricsUtil.computeMetric(JavaClassMetricKey.NOPA, node); + int noam = (int) MetricsUtil.computeMetric(JavaClassMetricKey.NOAM, node); + int wmc = (int) MetricsUtil.computeMetric(JavaClassMetricKey.WMC, node); return nopa + noam > ACCESSOR_OR_FIELD_FEW_LEVEL && wmc < WMC_HIGH_LEVEL || nopa + noam > ACCESSOR_OR_FIELD_MANY_LEVEL && wmc < WMC_VERY_HIGH_LEVEL; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GodClassRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GodClassRule.java index 8e610ee758..38f309fa74 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GodClassRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GodClassRule.java @@ -6,9 +6,9 @@ package net.sourceforge.pmd.lang.java.rule.design; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.metrics.JavaMetrics; import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.util.StringUtil; @@ -41,9 +41,9 @@ public class GodClassRule extends AbstractJavaRule { @Override public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - int wmc = (int) JavaMetrics.get(JavaClassMetricKey.WMC, node); - double tcc = JavaMetrics.get(JavaClassMetricKey.TCC, node); - int atfd = (int) JavaMetrics.get(JavaClassMetricKey.ATFD, node); + int wmc = (int) MetricsUtil.computeMetric(JavaClassMetricKey.WMC, node); + double tcc = MetricsUtil.computeMetric(JavaClassMetricKey.TCC, node); + int atfd = (int) MetricsUtil.computeMetric(JavaClassMetricKey.ATFD, node); super.visit(node, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityRule.java index 895f5f0609..37c8774949 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityRule.java @@ -11,11 +11,10 @@ import java.util.logging.Logger; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; -import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; import net.sourceforge.pmd.lang.java.ast.internal.PrettyPrintingUtil; -import net.sourceforge.pmd.lang.java.metrics.JavaMetrics; import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey; import net.sourceforge.pmd.lang.java.rule.AbstractJavaMetricsRule; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; @@ -72,7 +71,7 @@ public class NPathComplexityRule extends AbstractJavaMetricsRule { @Override public final Object visit(ASTMethodOrConstructorDeclaration node, Object data) { - int npath = (int) JavaMetrics.get(JavaOperationMetricKey.NPATH, (MethodLikeNode) node); + int npath = (int) MetricsUtil.computeMetric(JavaOperationMetricKey.NPATH, node); if (npath >= reportLevel) { addViolation(data, node, new String[]{node instanceof ASTMethodDeclaration ? "method" : "constructor", PrettyPrintingUtil.displaySignature(node), "" + npath, }); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountRule.java index a90e4ddd59..b2dc4b0642 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountRule.java @@ -22,6 +22,7 @@ import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey; import net.sourceforge.pmd.lang.java.metrics.impl.NcssMetric.NcssOption; import net.sourceforge.pmd.lang.java.rule.AbstractJavaMetricsRule; import net.sourceforge.pmd.lang.metrics.MetricOptions; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.lang.metrics.ResultOption; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; @@ -94,7 +95,7 @@ public final class NcssCountRule extends AbstractJavaMetricsRule { super.visit(node, data); if (JavaClassMetricKey.NCSS.supports(node)) { - int classSize = (int) JavaMetrics.get(JavaClassMetricKey.NCSS, node, ncssOptions); + int classSize = (int) MetricsUtil.computeMetric(JavaClassMetricKey.NCSS, node, ncssOptions); int classHighest = (int) JavaMetrics.get(JavaOperationMetricKey.NCSS, node, ncssOptions, ResultOption.HIGHEST); if (classSize >= classReportLevel) { @@ -112,7 +113,7 @@ public final class NcssCountRule extends AbstractJavaMetricsRule { @Override public Object visit(ASTMethodOrConstructorDeclaration node, Object data) { - int methodSize = (int) JavaMetrics.get(JavaOperationMetricKey.NCSS, node, ncssOptions); + int methodSize = (int) MetricsUtil.computeMetric(JavaOperationMetricKey.NCSS, node, ncssOptions); if (methodSize >= methodReportLevel) { addViolation(data, node, new String[] {node instanceof ASTMethodDeclaration ? "method" : "constructor", PrettyPrintingUtil.displaySignature(node), "" + methodSize, }); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java index 29e9c2bb69..5969ff7780 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java @@ -19,9 +19,9 @@ 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; -import net.sourceforge.pmd.lang.java.metrics.JavaMetrics; import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey; import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; /** @@ -82,9 +82,9 @@ public class MetricFunction implements Function { public static double getMetric(Node n, String metricKeyName) { if (n instanceof ASTAnyTypeDeclaration) { - return getClassMetric((ASTAnyTypeDeclaration) n, getClassMetricKey(metricKeyName)); + return MetricsUtil.computeMetric(getClassMetricKey(metricKeyName), (ASTAnyTypeDeclaration) n); } else if (n instanceof MethodLikeNode) { - return getOpMetric((MethodLikeNode) n, getOperationMetricKey(metricKeyName)); + return MetricsUtil.computeMetric(getOperationMetricKey(metricKeyName), (MethodLikeNode) n); } else { throw new IllegalStateException(genericBadNodeMessage()); } @@ -109,16 +109,6 @@ public class MetricFunction implements Function { } - private static double getOpMetric(MethodLikeNode node, JavaOperationMetricKey key) { - return JavaMetrics.get(key, node); - } - - - private static double getClassMetric(ASTAnyTypeDeclaration node, JavaClassMetricKey key) { - return JavaMetrics.get(key, node); - } - - public static void registerSelfInSimpleContext() { ((SimpleFunctionContext) XPathFunctionContext.getInstance()).registerFunction(null, "metric", diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/MetricsHook.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/MetricsHook.java deleted file mode 100644 index b24e0b81f1..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/MetricsHook.java +++ /dev/null @@ -1,23 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.metrics; - -/** - * Provides a hook into package-private methods of {@code java.metrics}. - * - * @author Clément Fournier - */ -public class MetricsHook { - - private MetricsHook() { - - } - - - public static void reset() { - JavaMetrics.reset(); - } - -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java index 62418ba82b..e77ab3fc4b 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java @@ -25,8 +25,8 @@ import net.sourceforge.pmd.lang.java.metrics.testdata.MetricsVisitorTestData; import net.sourceforge.pmd.lang.java.symboltable.BaseNonParserTest; import net.sourceforge.pmd.lang.metrics.MetricKey; import net.sourceforge.pmd.lang.metrics.MetricKeyUtil; -import net.sourceforge.pmd.lang.metrics.MetricMemoizer; import net.sourceforge.pmd.lang.metrics.MetricOptions; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; /** * @author Clément Fournier @@ -66,25 +66,19 @@ public class ProjectMemoizerTest extends BaseNonParserTest { private List visitWith(ASTCompilationUnit acu, final boolean force) { - final JavaProjectMemoizer toplevel = JavaMetrics.getFacade().getLanguageSpecificProjectMemoizer(); - final List result = new ArrayList<>(); acu.jjtAccept(new JavaParserVisitorReducedAdapter() { @Override public Object visit(ASTMethodOrConstructorDeclaration node, Object data) { - MetricMemoizer op = toplevel.getOperationMemoizer(node.getQualifiedName()); - result.add((int) JavaMetricsComputer.getInstance().computeForOperation(opMetricKey, node, force, - MetricOptions.emptyOptions(), op)); + result.add((int) MetricsUtil.computeMetric(opMetricKey, node, MetricOptions.emptyOptions(), force)); return super.visit(node, data); } @Override public Object visit(ASTAnyTypeDeclaration node, Object data) { - MetricMemoizer clazz = toplevel.getClassMemoizer(node.getQualifiedName()); - result.add((int) JavaMetricsComputer.getInstance().computeForType(classMetricKey, node, force, - MetricOptions.emptyOptions(), clazz)); + result.add((int) MetricsUtil.computeMetric(classMetricKey, node, MetricOptions.emptyOptions(), force)); return super.visit(node, data); } }, null); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/impl/AbstractMetricTestRule.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/impl/AbstractMetricTestRule.java index afd8f068fa..7c1c6aaab6 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/impl/AbstractMetricTestRule.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/impl/AbstractMetricTestRule.java @@ -18,6 +18,7 @@ import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey; import net.sourceforge.pmd.lang.java.rule.AbstractJavaMetricsRule; import net.sourceforge.pmd.lang.metrics.MetricOption; import net.sourceforge.pmd.lang.metrics.MetricOptions; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.lang.metrics.ResultOption; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; @@ -151,7 +152,7 @@ public abstract class AbstractMetricTestRule extends AbstractJavaMetricsRule { @Override public Object visit(ASTAnyTypeDeclaration node, Object data) { if (classKey != null && reportClasses && classKey.supports(node)) { - double classValue = JavaMetrics.get(classKey, node, metricOptions); + double classValue = MetricsUtil.computeMetric(classKey, node, metricOptions); String valueReport = niceDoubleString(classValue); @@ -170,7 +171,7 @@ public abstract class AbstractMetricTestRule extends AbstractJavaMetricsRule { @Override public Object visit(MethodLikeNode node, Object data) { if (opKey != null && reportMethods && opKey.supports(node)) { - double methodValue = JavaMetrics.get(opKey, node, metricOptions); + double methodValue = MetricsUtil.computeMetric(opKey, node, metricOptions); if (methodValue >= reportLevel) { addViolation(data, node, new String[] {node.getQualifiedName().toString(), "" + niceDoubleString(methodValue), }); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/impl/AllMetricsTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/impl/AllMetricsTest.java index 2614a4a6e4..f9e96dff5b 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/impl/AllMetricsTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/impl/AllMetricsTest.java @@ -4,8 +4,6 @@ package net.sourceforge.pmd.lang.java.metrics.impl; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.lang.java.metrics.MetricsHook; import net.sourceforge.pmd.testframework.SimpleAggregatorTst; /** @@ -18,14 +16,6 @@ public class AllMetricsTest extends SimpleAggregatorTst { private static final String RULESET = "rulesets/java/metrics_test.xml"; - - @Override - protected Rule reinitializeRule(Rule rule) { - MetricsHook.reset(); - return rule; - } - - @Override public void setUp() { addRule(RULESET, "CycloTest"); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/CyclomaticComplexityTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/CyclomaticComplexityTest.java index 2a922b0d8f..0555622065 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/CyclomaticComplexityTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/CyclomaticComplexityTest.java @@ -4,14 +4,7 @@ package net.sourceforge.pmd.lang.java.rule.design; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.lang.java.metrics.MetricsHook; import net.sourceforge.pmd.testframework.PmdRuleTst; public class CyclomaticComplexityTest extends PmdRuleTst { - @Override - protected Rule reinitializeRule(Rule rule) { - MetricsHook.reset(); - return rule; - } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityTest.java index 7cfb3bc81d..085c1be123 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityTest.java @@ -4,14 +4,7 @@ package net.sourceforge.pmd.lang.java.rule.design; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.lang.java.metrics.MetricsHook; import net.sourceforge.pmd.testframework.PmdRuleTst; public class NPathComplexityTest extends PmdRuleTst { - @Override - protected Rule reinitializeRule(Rule rule) { - MetricsHook.reset(); - return rule; - } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountTest.java index 7a70967a7d..a9d4359f97 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountTest.java @@ -4,14 +4,7 @@ package net.sourceforge.pmd.lang.java.rule.design; -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.lang.java.metrics.MetricsHook; import net.sourceforge.pmd.testframework.PmdRuleTst; public class NcssCountTest extends PmdRuleTst { - @Override - protected Rule reinitializeRule(Rule rule) { - MetricsHook.reset(); - return rule; - } } From f282a3ad5c8da5fb37a1a9d9cecb3bd164b79980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 19 Jan 2020 12:47:45 +0100 Subject: [PATCH 017/235] Move metric providers back into language handlers Reverts part of #2231 --- docs/pages/release_notes.md | 6 ++- .../pmd/lang/apex/ApexHandler.java | 32 +++++++++++++- .../pmd/lang/apex/metrics/ApexMetrics.java | 3 +- .../apex/metrics/ApexMetricsComputer.java | 3 ++ .../apex/metrics/ApexMetricsProvider.java | 39 ---------------- .../apex/metrics/ApexProjectMemoizer.java | 1 + .../pmd/lang/java/AbstractJavaHandler.java | 2 +- .../pmd/lang/java/JavaLanguageHandler.java | 33 ++++++++++++++ .../pmd/lang/java/metrics/JavaMetrics.java | 2 +- .../java/metrics/JavaMetricsProvider.java | 44 ------------------- 10 files changed, 75 insertions(+), 90 deletions(-) delete mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsProvider.java delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProvider.java diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 4849eb3e9a..58dc1d97ff 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -166,8 +166,10 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati following nodes: WhileStatement, DoStatement, ForStatement, IfStatement, AssertStatement, ConditionalExpression. * {% jdoc java::lang.java.ast.ASTYieldStatement %} will not implement {% jdoc java::lang.java.ast.TypeNode %} anymore come 7.0.0. Test the type of the expression nested within it. - * {% jdoc core::lang.java.metrics.JavaMetrics %}, {% jdoc core::lang.java.metrics.JavaMetricsComputer %}, - {% jdoc core::lang.java.metrics.JavaMetricsProvider %} + * {% jdoc java::lang.java.metrics.JavaMetrics %}, {% jdoc java::lang.java.metrics.JavaMetricsComputer %} +* pmd-apex + * {% jdoc java::lang.apex.metrics.ApexMetrics %}, {% jdoc java::lang.java.metrics.JavaMetricsComputer %} + ### External Contributions diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java index 9862a8515b..3ab43d784c 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java @@ -5,6 +5,8 @@ package net.sourceforge.pmd.lang.apex; import java.io.Writer; +import java.util.Arrays; +import java.util.List; import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler; import net.sourceforge.pmd.lang.Parser; @@ -15,11 +17,14 @@ import net.sourceforge.pmd.lang.apex.ast.ASTMethod; import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface; import net.sourceforge.pmd.lang.apex.ast.ApexNode; import net.sourceforge.pmd.lang.apex.ast.DumpFacade; -import net.sourceforge.pmd.lang.apex.metrics.ApexMetricsProvider; +import net.sourceforge.pmd.lang.apex.metrics.ApexMetrics; +import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey; +import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey; import net.sourceforge.pmd.lang.apex.multifile.ApexMultifileVisitorFacade; import net.sourceforge.pmd.lang.apex.rule.ApexRuleViolationFactory; import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler; import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider; +import net.sourceforge.pmd.lang.metrics.internal.AbstractLanguageMetricsProvider; import net.sourceforge.pmd.lang.rule.RuleViolationFactory; @@ -65,4 +70,29 @@ public class ApexHandler extends AbstractLanguageVersionHandler { public LanguageMetricsProvider, ASTMethod> getLanguageMetricsProvider() { return myMetricsProvider; } + + private static class ApexMetricsProvider extends AbstractLanguageMetricsProvider, ASTMethod> { + + @SuppressWarnings("unchecked") + public ApexMetricsProvider() { + // a wild double cast + super((Class>) (Object) ASTUserClassOrInterface.class, ASTMethod.class); + } + + @Override + public List getAvailableTypeMetrics() { + return Arrays.asList(ApexClassMetricKey.values()); + } + + + @Override + protected List findOps(ASTUserClassOrInterface astUserClassOrInterface) { + return ApexMetrics.findOps(astUserClassOrInterface); + } + + @Override + public List getAvailableOperationMetrics() { + return Arrays.asList(ApexOperationMetricKey.values()); + } + } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java index 3b05c8e8ef..8ac1fe2bb9 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java @@ -22,7 +22,6 @@ import net.sourceforge.pmd.lang.metrics.ResultOption; * * @author Clément Fournier * @since 6.0.0 - * * @deprecated Use {@link MetricsUtil} */ @Deprecated @@ -138,7 +137,7 @@ public final class ApexMetrics { @NonNull - static List findOps(ASTUserClassOrInterface node) { + public static List findOps(ASTUserClassOrInterface node) { List candidates = node.findChildrenOfType(ASTMethod.class); List result = new ArrayList<>(candidates); for (ASTMethod method : candidates) { diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java index 0092bc1394..705995babc 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java @@ -10,12 +10,15 @@ import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.apex.ast.ASTMethod; import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface; import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer; +import net.sourceforge.pmd.lang.metrics.MetricsComputer; /** * Computes metrics for the Apex framework. * * @author Clément Fournier + * @deprecated See {@link MetricsComputer} */ +@Deprecated public class ApexMetricsComputer extends AbstractMetricsComputer, ASTMethod> { private static final ApexMetricsComputer INSTANCE = new ApexMetricsComputer(); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsProvider.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsProvider.java deleted file mode 100644 index b7b5d852b4..0000000000 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsProvider.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.apex.metrics; - -import java.util.Arrays; -import java.util.List; - -import net.sourceforge.pmd.lang.apex.ast.ASTMethod; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface; -import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey; -import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey; -import net.sourceforge.pmd.lang.metrics.internal.AbstractLanguageMetricsProvider; - -public class ApexMetricsProvider extends AbstractLanguageMetricsProvider, ASTMethod> { - - @SuppressWarnings("unchecked") - public ApexMetricsProvider() { - // a wild double cast - super((Class>) (Object) ASTUserClassOrInterface.class, ASTMethod.class); - } - - @Override - public List getAvailableTypeMetrics() { - return Arrays.asList(ApexClassMetricKey.values()); - } - - - @Override - protected List findOps(ASTUserClassOrInterface astUserClassOrInterface) { - return ApexMetrics.findOps(astUserClassOrInterface); - } - - @Override - public List getAvailableOperationMetrics() { - return Arrays.asList(ApexOperationMetricKey.values()); - } -} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMemoizer.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMemoizer.java index 6e71251ee8..85c3d9f2cf 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMemoizer.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMemoizer.java @@ -13,5 +13,6 @@ import net.sourceforge.pmd.lang.metrics.BasicProjectMemoizer; * * @author Clément Fournier */ +@Deprecated class ApexProjectMemoizer extends BasicProjectMemoizer, ASTMethod> { } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java index 59ab1ca3b7..76e6e72caa 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java @@ -21,7 +21,7 @@ import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; import net.sourceforge.pmd.lang.java.dfa.DataFlowFacade; import net.sourceforge.pmd.lang.java.dfa.JavaDFAGraphRule; -import net.sourceforge.pmd.lang.java.metrics.JavaMetricsProvider; +import net.sourceforge.pmd.lang.java.JavaLanguageHandler.JavaMetricsProvider; import net.sourceforge.pmd.lang.java.multifile.MultifileVisitorFacade; import net.sourceforge.pmd.lang.java.qname.QualifiedNameResolver; import net.sourceforge.pmd.lang.java.rule.JavaRuleViolationFactory; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageHandler.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageHandler.java index 3ae9f92f42..6272373562 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageHandler.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageHandler.java @@ -4,10 +4,20 @@ package net.sourceforge.pmd.lang.java; +import java.util.Arrays; +import java.util.List; + import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; +import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; +import net.sourceforge.pmd.lang.java.metrics.JavaMetrics; +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.internal.AbstractLanguageMetricsProvider; /** * @deprecated This is internal API, use {@link LanguageVersion#getLanguageVersionHandler()}. @@ -31,4 +41,27 @@ public class JavaLanguageHandler extends AbstractJavaHandler { public Parser getParser(ParserOptions parserOptions) { return new JavaLanguageParser(jdkVersion, preview, parserOptions); } + + public static class JavaMetricsProvider extends AbstractLanguageMetricsProvider { + + public JavaMetricsProvider() { + super(ASTAnyTypeDeclaration.class, MethodLikeNode.class); + } + + @Override + protected List findOps(ASTAnyTypeDeclaration astAnyTypeDeclaration) { + return JavaMetrics.findOps(astAnyTypeDeclaration); + } + + @Override + public List> getAvailableTypeMetrics() { + return Arrays.asList(JavaClassMetricKey.values()); + } + + + @Override + public List> getAvailableOperationMetrics() { + return Arrays.asList(JavaOperationMetricKey.values()); + } + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java index 8d2247fdc0..50c5dd1f69 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java @@ -139,7 +139,7 @@ public final class JavaMetrics { return MetricsUtil.computeAggregate(key, findOps(node), options, resultOption); } - static List findOps(ASTAnyTypeDeclaration node) { + public static List findOps(ASTAnyTypeDeclaration node) { List operations = new ArrayList<>(); for (ASTAnyTypeBodyDeclaration decl : node.getDeclarations()) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProvider.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProvider.java deleted file mode 100644 index 8f73f937d8..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.metrics; - -import java.util.Arrays; -import java.util.List; - -import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; -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.internal.AbstractLanguageMetricsProvider; - -/** - * @deprecated This is internal API - */ -@Deprecated -@InternalApi -public class JavaMetricsProvider extends AbstractLanguageMetricsProvider { - - public JavaMetricsProvider() { - super(ASTAnyTypeDeclaration.class, MethodLikeNode.class); - } - - @Override - protected List findOps(ASTAnyTypeDeclaration astAnyTypeDeclaration) { - return JavaMetrics.findOps(astAnyTypeDeclaration); - } - - @Override - public List> getAvailableTypeMetrics() { - return Arrays.asList(JavaClassMetricKey.values()); - } - - - @Override - public List> getAvailableOperationMetrics() { - return Arrays.asList(JavaOperationMetricKey.values()); - } -} From b707e6e9ffe3d86f60d0448aa7883548b1437566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 19 Jan 2020 13:04:22 +0100 Subject: [PATCH 018/235] Fix caching Non supported nodes produce NaN which is converted to zero when converting to int --- .../pmd/lang/apex/metrics/ApexProjectMirrorTest.java | 8 ++++++-- .../pmd/lang/java/metrics/ProjectMemoizerTest.java | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) 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 9fdb994e88..204bc20b7c 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 @@ -76,14 +76,18 @@ public class ApexProjectMirrorTest extends ApexParserTestBase { acu.jjtAccept(new ApexParserVisitorAdapter() { @Override public Object visit(ASTMethod node, Object data) { - result.add((int) MetricsUtil.computeMetric(opMetricKey, node, MetricOptions.emptyOptions(), force)); + if (opMetricKey.supports(node)) { + result.add((int) MetricsUtil.computeMetric(opMetricKey, node, MetricOptions.emptyOptions(), force)); + } return super.visit(node, data); } @Override public Object visit(ASTUserClass node, Object data) { - result.add((int) MetricsUtil.computeMetric(classMetricKey, node, MetricOptions.emptyOptions(), force)); + if (classMetricKey.supports(node)) { + result.add((int) MetricsUtil.computeMetric(classMetricKey, node, MetricOptions.emptyOptions(), force)); + } return super.visit(node, data); } }, null); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java index e77ab3fc4b..91058a3e56 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/metrics/ProjectMemoizerTest.java @@ -71,14 +71,18 @@ public class ProjectMemoizerTest extends BaseNonParserTest { acu.jjtAccept(new JavaParserVisitorReducedAdapter() { @Override public Object visit(ASTMethodOrConstructorDeclaration node, Object data) { - result.add((int) MetricsUtil.computeMetric(opMetricKey, node, MetricOptions.emptyOptions(), force)); + if (opMetricKey.supports(node)) { + result.add((int) MetricsUtil.computeMetric(opMetricKey, node, MetricOptions.emptyOptions(), force)); + } return super.visit(node, data); } @Override public Object visit(ASTAnyTypeDeclaration node, Object data) { - result.add((int) MetricsUtil.computeMetric(classMetricKey, node, MetricOptions.emptyOptions(), force)); + if (classMetricKey.supports(node)) { + result.add((int) MetricsUtil.computeMetric(classMetricKey, node, MetricOptions.emptyOptions(), force)); + } return super.visit(node, data); } }, null); From f87fc16ed3ec18ae4f31fb181258e95f134ceab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 19 Jan 2020 15:10:30 +0100 Subject: [PATCH 019/235] Fix tests The tests were wrong, so this changeset actually fixes a bug in metrics --- .../net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java | 4 ++-- .../sourceforge/pmd/lang/java/metrics/impl/xml/AtfdTest.xml | 4 ++-- .../sourceforge/pmd/lang/java/metrics/impl/xml/CfoTest.xml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java index 50c5dd1f69..2f70a75931 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java @@ -143,8 +143,8 @@ public final class JavaMetrics { List operations = new ArrayList<>(); for (ASTAnyTypeBodyDeclaration decl : node.getDeclarations()) { - if (decl.getNumChildren() > 0 && decl.getDeclarationNode() instanceof ASTMethodOrConstructorDeclaration) { - operations.add((MethodLikeNode) decl.getChild(0)); + if (decl.getDeclarationNode() instanceof ASTMethodOrConstructorDeclaration) { + operations.add((MethodLikeNode) decl.getDeclarationNode()); } } return operations; diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/AtfdTest.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/AtfdTest.xml index d6615dbbe5..bb7a5fe84c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/AtfdTest.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/AtfdTest.xml @@ -129,7 +129,7 @@ public class StatementAndBraceFinder extends JavaParserVisitorAdapter { Full example 7 - 'StatementAndBraceFinder' has value 10 highest 6. + 'StatementAndBraceFinder' has value 36 highest 18. 'StatementAndBraceFinder#buildDataFlowFor(JavaNode)' has value 6. 'StatementAndBraceFinder#tryToLog(String, NodeType, Node)' has value 4. 'StatementAndBraceFinder#tryToLog(NodeType, Node)' has value 0. @@ -222,4 +222,4 @@ public class Foo { } ]]> - \ No newline at end of file + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/CfoTest.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/CfoTest.xml index 3e30b62d83..0da4746b3c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/CfoTest.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/CfoTest.xml @@ -43,7 +43,7 @@ public class Foo { Full example with default options 6 - 'Foo' has value 7 highest 1. + 'Foo' has value 7 highest 2. 'Foo#Foo(Data)' has value 1. 'Foo#foo(List)' has value 2. 'Foo#getMapSize()' has value 1. @@ -58,7 +58,7 @@ public class Foo { includeJavaLang 6 - 'Foo' has value 12 highest 1. + 'Foo' has value 12 highest 5. 'Foo#Foo(Data)' has value 1. 'Foo#foo(List)' has value 5. 'Foo#getMapSize()' has value 1. From f576bc561a0b553f860494a1fabdcd7a8c2ee54c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 19 Jan 2020 16:13:02 +0100 Subject: [PATCH 020/235] checkstyle --- .../net/sourceforge/pmd/lang/java/AbstractJavaHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java index 76e6e72caa..58485f357a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java @@ -21,7 +21,6 @@ import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; import net.sourceforge.pmd.lang.java.dfa.DataFlowFacade; import net.sourceforge.pmd.lang.java.dfa.JavaDFAGraphRule; -import net.sourceforge.pmd.lang.java.JavaLanguageHandler.JavaMetricsProvider; import net.sourceforge.pmd.lang.java.multifile.MultifileVisitorFacade; import net.sourceforge.pmd.lang.java.qname.QualifiedNameResolver; import net.sourceforge.pmd.lang.java.rule.JavaRuleViolationFactory; @@ -49,7 +48,7 @@ import net.sf.saxon.sxpath.IndependentContext; @Deprecated public abstract class AbstractJavaHandler extends AbstractLanguageVersionHandler { - private final LanguageMetricsProvider myMetricsProvider = new JavaMetricsProvider(); + private final LanguageMetricsProvider myMetricsProvider = new JavaLanguageHandler.JavaMetricsProvider(); @Override public DataFlowHandler getDataFlowHandler() { From 055ae4abf0aa4d87437c58b692ddd06204556f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 20 Jan 2020 00:57:22 +0100 Subject: [PATCH 021/235] Checkstyle --- .../main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java | 2 +- .../java/net/sourceforge/pmd/lang/java/JavaLanguageHandler.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java index 3ab43d784c..561ec95e63 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ApexHandler.java @@ -74,7 +74,7 @@ public class ApexHandler extends AbstractLanguageVersionHandler { private static class ApexMetricsProvider extends AbstractLanguageMetricsProvider, ASTMethod> { @SuppressWarnings("unchecked") - public ApexMetricsProvider() { + ApexMetricsProvider() { // a wild double cast super((Class>) (Object) ASTUserClassOrInterface.class, ASTMethod.class); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageHandler.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageHandler.java index 6272373562..f383c4e4e6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageHandler.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageHandler.java @@ -44,7 +44,7 @@ public class JavaLanguageHandler extends AbstractJavaHandler { public static class JavaMetricsProvider extends AbstractLanguageMetricsProvider { - public JavaMetricsProvider() { + JavaMetricsProvider() { super(ASTAnyTypeDeclaration.class, MethodLikeNode.class); } From 8fe0fe8bc7dd166f5ca894ea36642376aae83a10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 20 Jan 2020 21:25:04 +0100 Subject: [PATCH 022/235] Update documentation --- .../adding_new_metrics_framework.md | 70 ++----------------- 1 file changed, 6 insertions(+), 64 deletions(-) diff --git a/docs/pages/pmd/devdocs/major_contributions/adding_new_metrics_framework.md b/docs/pages/pmd/devdocs/major_contributions/adding_new_metrics_framework.md index f0b5b9d727..c545c7815e 100644 --- a/docs/pages/pmd/devdocs/major_contributions/adding_new_metrics_framework.md +++ b/docs/pages/pmd/devdocs/major_contributions/adding_new_metrics_framework.md @@ -10,27 +10,10 @@ permalink: pmd_devdocs_major_adding_new_metrics_framework.html author: Clément Fournier --- - ## Internal architecture of the metrics framework -### Overview of the Java framework - -The framework has several subsystems, the two most easily identifiable being: -* A **project memoizer** (`ProjectMemoizer`). When a metric is computed, it's stored back in this structure and can be -reused later. This - reduces the overhead on the calculation of e.g. aggregate results (`ResultOption` calculations). The contents of - this data structure are indexed with fully qualified names (`JavaQualifiedName`), which must identify unambiguously - classes and methods. - -* The **façade**. The static end-user façade (`JavaMetrics`) is backed by an instance of a `JavaMetricsFaçade`. This - allows us to abstract the functionality of the façade into `pmd-core` for other frameworks to use. The façade - instance contains a project memoizer for the analysed project, and a metrics computer - (`JavaMetricsComputer`). It's this last object which really computes the metric and stores back its result in the - project mirror, while the façade only handles parameters. - -Metrics (`Metric`) plug in to this static system and only provide behaviour that's executed by the metrics computer. -Internally, metric keys (`MetricKey`) are parameterized with their version (`MetricVersion`) to index memoisation -maps (see `ParameterizedMetricKey`). This allows us to memoise several versions of the same metric without conflict. +The framework is pretty simple. On a high level, a `Metric` describes some numeric computation on a node of type `N`. +You should wrap it into a `MetricKey`, so that it can be cached on nodes (implemented by {%jdoc core::lang.metrics.MetricsUtil %}). At the very least, a metrics framework has those two components and is just a convenient way to compute and memoize metrics on a single file. The expressive power of metrics can be improved by implementing *signature matching* capabilities, @@ -38,53 +21,12 @@ which allows a metric to count signatures matching a specific pattern (a mask) o designed to work across files, given a working usage resolution. However, making that work with incremental analysis is harder than it looks, and has been rescheduled to another project. - -### Abstraction layer - -As you may have seen, most of the functionality of the first two components are abstracted into `pmd-core`. This -allows us to implement new metrics frameworks quite quickly. These abstract components are parameterized by the -node types of the class and operation AST nodes. Moreover, it makes the external behaviour of the framework very -stable across languages, yet each component can easily be customized by adding methods or overriding existing ones. - -The signature matching aspect is framed by generic interfaces, but it can't really be abstracted more -than that. The info given in the signatures is usually very language specific, as it includes info about e.g. -visibility modifiers. So more work is required to implement that, but it can already be used to implement -sophisticated metrics, that already give access to detection strategies. - ## Implementation of a new framework -### 1. Groundwork - -* Create a class implementing `QualifiedName`. This implementation must be tailored to the target language so - that it can indentify unambiguously any class and operation in the analysed project. You - must implement `equals`, `hashCode` and `toString`. - [Example](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaQualifiedName.java) -* Determine the AST nodes that correspond to class and method declaration in your language. These types are - referred hereafter as `T` and `O`, respectively. Both these types must implement the interface `QualifiableNode`, - which means they must expose a `getQualifiedName` method to give access to their qualified name. - -### 2. Implement the façade -* Create a class extending `AbstractMetricsComputer`. This object will be responsible for calculating metrics - given a memoizer, a node and info about the metric. Typically, this object is stateless so you might as well make it - a singleton. -* Create a class extending `BasicProjectMemoizer`. There's no abstract functionality to implement. - [Example](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaProjectMemoizer.java) - [Example](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsComputer.java) -* Create a class extending `AbstractMetricsFacade`. This class needs a reference to your `ProjectMemoizer` and - your `MetricsComputer`. It backs the real end user façade, and handles user provided parameters before delegating to - your `MetricsComputer`. - [Example](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetricsFacade.java) -* Create the static façade of your framework. This one has an instance of your `MetricsFaçade` object and delegates - static methods to that instance. - [Example](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java) -* Create classes `AbstractOperationMetric` and `AbstractClassMetric`. These must implement `Metric` and - `Metric`, respectively. They typically provide defaults for the `supports` method of each metric. - [Example](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/impl/AbstractJavaOperationMetric.java) -* Create enums `ClassMetricKey` and `OperationMetricKey`. These must implement `MetricKey` and `MetricKey`. The - enums list all available metric keys for your language. - [Example](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/api/JavaOperationMetricKey.java) -* Create metrics by extending your base classes, reference them in your enums, and you can start using them with your - façade! +* Implement metrics (typically in an internal package) +* Create some public enums/ utility classes to expose metric keys +* Implement a {%jdoc core::lang.metrics.LanguageMetricsProvider %}, to expose your metrics to the designer +* Use your metric keys in rules with {%jdoc core::lang.metrics.MetricsUtil %} ### Optional: Signature matching From 08544a7539624689f235042892ee7e17105deb1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 20 Jan 2020 21:45:08 +0100 Subject: [PATCH 023/235] Throw on metric not supported --- .../pmd/lang/apex/metrics/ApexMetrics.java | 8 +-- .../rule/design/CyclomaticComplexityRule.java | 20 +++--- .../impl/AbstractApexMetricTestRule.java | 5 +- .../pmd/lang/metrics/MetricsUtil.java | 51 +++++++++++++-- .../pmd/lang/java/metrics/JavaMetrics.java | 8 +-- .../rule/design/CyclomaticComplexityRule.java | 27 ++++---- .../lang/java/rule/design/DataClassRule.java | 28 ++++++--- .../lang/java/rule/design/GodClassRule.java | 15 +++-- .../java/rule/design/NPathComplexityRule.java | 12 ++-- .../lang/java/rule/design/NcssCountRule.java | 62 +++++++++---------- .../pmd/lang/java/xpath/MetricFunction.java | 9 ++- 11 files changed, 156 insertions(+), 89 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java index 8ac1fe2bb9..d8dd2ec984 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java @@ -55,7 +55,7 @@ public final class ApexMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey> key, ASTUserClass node) { - return MetricsUtil.computeMetric(key, node, MetricOptions.emptyOptions()); + return get(key, node, MetricOptions.emptyOptions()); } @@ -70,7 +70,7 @@ public final class ApexMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey> key, ASTUserClass node, MetricOptions options) { - return MetricsUtil.computeMetric(key, node, options); + return MetricsUtil.computeMetricOrNaN(key, node, options); } @@ -83,7 +83,7 @@ public final class ApexMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, ASTMethod node) { - return MetricsUtil.computeMetric(key, node, MetricOptions.emptyOptions()); + return get(key, node, MetricOptions.emptyOptions()); } @@ -98,7 +98,7 @@ public final class ApexMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, ASTMethod node, MetricOptions options) { - return MetricsUtil.computeMetric(key, node, options); + return MetricsUtil.computeMetricOrNaN(key, node, options); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java index a10676b530..c742a7e7f4 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CyclomaticComplexityRule.java @@ -90,16 +90,18 @@ public class CyclomaticComplexityRule extends AbstractApexRule { @Override public final Object visit(ASTMethod node, Object data) { - int cyclo = (int) MetricsUtil.computeMetric(ApexOperationMetricKey.CYCLO, node); - if (cyclo >= getProperty(METHOD_LEVEL_DESCRIPTOR)) { - String opType = inTrigger ? "trigger" - : node.getImage().equals(classNames.peek()) ? "constructor" - : "method"; + if (ApexOperationMetricKey.CYCLO.supports(node)) { + int cyclo = (int) MetricsUtil.computeMetric(ApexOperationMetricKey.CYCLO, node); + if (cyclo >= getProperty(METHOD_LEVEL_DESCRIPTOR)) { + String opType = inTrigger ? "trigger" + : node.getImage().equals(classNames.peek()) ? "constructor" + : "method"; - addViolation(data, node, new String[]{opType, - node.getQualifiedName().getOperation(), - "", - "" + cyclo, }); + addViolation(data, node, new String[] {opType, + node.getQualifiedName().getOperation(), + "", + "" + cyclo, }); + } } return data; diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AbstractApexMetricTestRule.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AbstractApexMetricTestRule.java index 290ffa897e..e63478a0df 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AbstractApexMetricTestRule.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AbstractApexMetricTestRule.java @@ -16,6 +16,7 @@ import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; import net.sourceforge.pmd.lang.metrics.MetricOption; import net.sourceforge.pmd.lang.metrics.MetricOptions; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.lang.metrics.ResultOption; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; @@ -134,7 +135,7 @@ public abstract class AbstractApexMetricTestRule extends AbstractApexRule { } if (classKey != null && reportClasses && classKey.supports(node)) { - int classValue = (int) ApexMetrics.get(classKey, node, metricOptions); + int classValue = (int) MetricsUtil.computeMetric(classKey, node, metricOptions); String valueReport = String.valueOf(classValue); @@ -153,7 +154,7 @@ public abstract class AbstractApexMetricTestRule extends AbstractApexRule { @Override public Object visit(ASTMethod node, Object data) { if (opKey != null && reportMethods && opKey.supports(node)) { - int methodValue = (int) ApexMetrics.get(opKey, node, metricOptions); + int methodValue = (int) MetricsUtil.computeMetric(opKey, node, metricOptions); if (methodValue >= reportLevel) { addViolation(data, node, new String[] {node.getQualifiedName().toString(), "" + methodValue}); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java index 65db7403ab..39c108721a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java @@ -23,6 +23,15 @@ public final class MetricsUtil { // util class } + public static boolean supportsAll(N node, MetricKey... metrics) { + for (MetricKey metric : metrics) { + if (!metric.supports(node)) { + return false; + } + } + return true; + } + public static double computeAggregate(MetricKey key, Iterable ops, ResultOption resultOption) { return computeAggregate(key, ops, MetricOptions.emptyOptions(), resultOption); } @@ -50,9 +59,7 @@ public final class MetricsUtil { for (O op : ops) { if (key.supports(op)) { double val = computeMetric(key, op, options); - if (!Double.isNaN(val)) { - values.add(val); - } + values.add(val); } } @@ -65,7 +72,7 @@ public final class MetricsUtil { case AVERAGE: return average(values); default: - return Double.NaN; + throw new IllegalArgumentException("Unknown result option " + resultOption); } } @@ -90,6 +97,33 @@ public final class MetricsUtil { * @param options The options of the metric * * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed + * + * @deprecated This is provided for compatibility with pre 6.21.0 + * behavior. Users of a metric should always check beforehand if + * the metric supports the argument. + */ + @Deprecated + public static double computeMetricOrNaN(MetricKey key, N node, MetricOptions options) { + if (!key.supports(node)) { + return Double.NaN; + } + return computeMetric(key, node, options, false); + } + + /** + * Computes a metric identified by its code on a node, possibly + * selecting a variant with the {@code options} parameter. + * + *

Note that contrary to the previous behaviour, this method + * throws an exception if the metric does not support the node. + * + * @param key The key identifying the metric to be computed + * @param node The node on which to compute the metric + * @param options The options of the metric + * + * @return The value of the metric + * + * @throws IllegalArgumentException If the metric does not support the given node */ public static double computeMetric(MetricKey key, N node, MetricOptions options) { return computeMetric(key, node, options, false); @@ -99,12 +133,17 @@ public final class MetricsUtil { * Computes a metric identified by its code on a node, possibly * selecting a variant with the {@code options} parameter. * + *

Note that contrary to the previous behaviour, this method + * throws an exception if the metric does not support the node. + * * @param key The key identifying the metric to be computed * @param node The node on which to compute the metric * @param options The options of the metric * @param forceRecompute Force recomputation of the result * - * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed + * @return The value of the metric + * + * @throws IllegalArgumentException If the metric does not support the given node */ public static double computeMetric(MetricKey key, N node, MetricOptions options, boolean forceRecompute) { Objects.requireNonNull(key, NULL_KEY_MESSAGE); @@ -113,7 +152,7 @@ public final class MetricsUtil { if (!key.supports(node)) { - return Double.NaN; + throw new IllegalArgumentException(key + " cannot be computed on " + node); } ParameterizedMetricKey paramKey = ParameterizedMetricKey.getInstance(key, options); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java index 2f70a75931..800f732a8b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/JavaMetrics.java @@ -42,7 +42,7 @@ public final class JavaMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, ASTAnyTypeDeclaration node) { - return MetricsUtil.computeMetric(key, node); + return get(key, node, MetricOptions.emptyOptions()); } @@ -57,7 +57,7 @@ public final class JavaMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, ASTAnyTypeDeclaration node, MetricOptions options) { - return MetricsUtil.computeMetric(key, node, options); + return MetricsUtil.computeMetricOrNaN(key, node, options); } @@ -70,7 +70,7 @@ public final class JavaMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, MethodLikeNode node) { - return MetricsUtil.computeMetric(key, node); + return get(key, node, MetricOptions.emptyOptions()); } @@ -104,7 +104,7 @@ public final class JavaMetrics { * @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed */ public static double get(MetricKey key, MethodLikeNode node, MetricOptions options) { - return MetricsUtil.computeMetric(key, node, options); + return MetricsUtil.computeMetricOrNaN(key, node, options); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/CyclomaticComplexityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/CyclomaticComplexityRule.java index 4a2c2167c8..60de77b4ac 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/CyclomaticComplexityRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/CyclomaticComplexityRule.java @@ -145,25 +145,26 @@ public class CyclomaticComplexityRule extends AbstractJavaMetricsRule { @Override public final Object visit(MethodLikeNode node, Object data) { - int cyclo = (int) MetricsUtil.computeMetric(JavaOperationMetricKey.CYCLO, node, cycloOptions); - if (cyclo >= methodReportLevel) { + if (JavaOperationMetricKey.CYCLO.supports(node)) { + int cyclo = (int) MetricsUtil.computeMetric(JavaOperationMetricKey.CYCLO, node, cycloOptions); + if (cyclo >= methodReportLevel) { - String opname = node instanceof ASTMethodOrConstructorDeclaration - ? PrettyPrintingUtil.displaySignature((ASTMethodOrConstructorDeclaration) node) - : "lambda"; + String opname = node instanceof ASTMethodOrConstructorDeclaration + ? PrettyPrintingUtil.displaySignature((ASTMethodOrConstructorDeclaration) node) + : "lambda"; - String kindname = node instanceof ASTMethodOrConstructorDeclaration - ? node instanceof ASTConstructorDeclaration ? "constructor" : "method" - : "lambda"; + String kindname = node instanceof ASTMethodOrConstructorDeclaration + ? node instanceof ASTConstructorDeclaration ? "constructor" : "method" + : "lambda"; - addViolation(data, node, new String[] {kindname, - opname, - "", - "" + cyclo, }); + addViolation(data, node, new String[] {kindname, + opname, + "", + "" + cyclo, }); + } } - return data; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/DataClassRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/DataClassRule.java index 608fa7f9d6..09072cae8c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/DataClassRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/DataClassRule.java @@ -4,8 +4,12 @@ package net.sourceforge.pmd.lang.java.rule.design; +import static net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey.NOAM; +import static net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey.NOPA; +import static net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey.WMC; +import static net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey.WOC; + import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; -import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey; import net.sourceforge.pmd.lang.java.rule.AbstractJavaMetricsRule; import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.util.StringUtil; @@ -27,13 +31,17 @@ public class DataClassRule extends AbstractJavaMetricsRule { @Override public Object visit(ASTAnyTypeDeclaration node, Object data) { + if (!MetricsUtil.supportsAll(node, NOAM, NOPA, WMC, WOC)) { + return super.visit(node, data); + } + boolean isDataClass = interfaceRevealsData(node) && classRevealsDataAndLacksComplexity(node); if (isDataClass) { - double woc = MetricsUtil.computeMetric(JavaClassMetricKey.WOC, node); - int nopa = (int) MetricsUtil.computeMetric(JavaClassMetricKey.NOPA, node); - int noam = (int) MetricsUtil.computeMetric(JavaClassMetricKey.NOAM, node); - int wmc = (int) MetricsUtil.computeMetric(JavaClassMetricKey.WMC, node); + double woc = MetricsUtil.computeMetric(WOC, node); + int nopa = (int) MetricsUtil.computeMetric(NOPA, node); + int noam = (int) MetricsUtil.computeMetric(NOAM, node); + int wmc = (int) MetricsUtil.computeMetric(WMC, node); addViolation(data, node, new Object[] {node.getSimpleName(), StringUtil.percentageString(woc, 3), @@ -45,15 +53,15 @@ public class DataClassRule extends AbstractJavaMetricsRule { private boolean interfaceRevealsData(ASTAnyTypeDeclaration node) { - double woc = MetricsUtil.computeMetric(JavaClassMetricKey.WOC, node); + double woc = MetricsUtil.computeMetric(WOC, node); return woc < WOC_LEVEL; } - private boolean classRevealsDataAndLacksComplexity(ASTAnyTypeDeclaration node) { - int nopa = (int) MetricsUtil.computeMetric(JavaClassMetricKey.NOPA, node); - int noam = (int) MetricsUtil.computeMetric(JavaClassMetricKey.NOAM, node); - int wmc = (int) MetricsUtil.computeMetric(JavaClassMetricKey.WMC, node); + + int nopa = (int) MetricsUtil.computeMetric(NOPA, node); + int noam = (int) MetricsUtil.computeMetric(NOAM, node); + int wmc = (int) MetricsUtil.computeMetric(WMC, node); return nopa + noam > ACCESSOR_OR_FIELD_FEW_LEVEL && wmc < WMC_HIGH_LEVEL || nopa + noam > ACCESSOR_OR_FIELD_MANY_LEVEL && wmc < WMC_VERY_HIGH_LEVEL; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GodClassRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GodClassRule.java index 38f309fa74..e019eaa3c9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GodClassRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/GodClassRule.java @@ -5,8 +5,11 @@ package net.sourceforge.pmd.lang.java.rule.design; +import static net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey.ATFD; +import static net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey.TCC; +import static net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey.WMC; + import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.metrics.MetricsUtil; import net.sourceforge.pmd.util.StringUtil; @@ -41,9 +44,13 @@ public class GodClassRule extends AbstractJavaRule { @Override public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - int wmc = (int) MetricsUtil.computeMetric(JavaClassMetricKey.WMC, node); - double tcc = MetricsUtil.computeMetric(JavaClassMetricKey.TCC, node); - int atfd = (int) MetricsUtil.computeMetric(JavaClassMetricKey.ATFD, node); + if (!MetricsUtil.supportsAll(node, WMC, TCC, ATFD)) { + return super.visit(node, data); + } + + int wmc = (int) MetricsUtil.computeMetric(WMC, node); + double tcc = MetricsUtil.computeMetric(TCC, node); + int atfd = (int) MetricsUtil.computeMetric(ATFD, node); super.visit(node, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityRule.java index 37c8774949..9260ae6b4f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NPathComplexityRule.java @@ -31,8 +31,8 @@ public class NPathComplexityRule extends AbstractJavaMetricsRule { @Deprecated private static final PropertyDescriptor MINIMUM_DESCRIPTOR - = PropertyFactory.doubleProperty("minimum").desc("Deprecated! Minimum reporting threshold") - .require(positive()).defaultValue(200d).build(); + = PropertyFactory.doubleProperty("minimum").desc("Deprecated! Minimum reporting threshold") + .require(positive()).defaultValue(200d).build(); private static final PropertyDescriptor REPORT_LEVEL_DESCRIPTOR @@ -71,10 +71,14 @@ public class NPathComplexityRule extends AbstractJavaMetricsRule { @Override public final Object visit(ASTMethodOrConstructorDeclaration node, Object data) { + if (!JavaOperationMetricKey.NPATH.supports(node)) { + return data; + } + int npath = (int) MetricsUtil.computeMetric(JavaOperationMetricKey.NPATH, node); if (npath >= reportLevel) { - addViolation(data, node, new String[]{node instanceof ASTMethodDeclaration ? "method" : "constructor", - PrettyPrintingUtil.displaySignature(node), "" + npath, }); + addViolation(data, node, new String[] {node instanceof ASTMethodDeclaration ? "method" : "constructor", + PrettyPrintingUtil.displaySignature(node), "" + npath, }); } return data; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountRule.java index b2dc4b0642..f457967747 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountRule.java @@ -15,6 +15,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; import net.sourceforge.pmd.lang.java.ast.internal.PrettyPrintingUtil; import net.sourceforge.pmd.lang.java.metrics.JavaMetrics; import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey; @@ -37,40 +38,37 @@ public final class NcssCountRule extends AbstractJavaMetricsRule { private static final PropertyDescriptor METHOD_REPORT_LEVEL_DESCRIPTOR = - PropertyFactory.intProperty("methodReportLevel") - .desc("NCSS reporting threshold for methods") - .require(positive()) - .defaultValue(60) - .build(); + PropertyFactory.intProperty("methodReportLevel") + .desc("NCSS reporting threshold for methods") + .require(positive()) + .defaultValue(60) + .build(); private static final PropertyDescriptor CLASS_REPORT_LEVEL_DESCRIPTOR = - PropertyFactory.intProperty("classReportLevel") - .desc("NCSS reporting threshold for classes") - .require(positive()) - .defaultValue(1500) - .build(); - - private static final Map OPTION_MAP; - - - static { - OPTION_MAP = new HashMap<>(); - OPTION_MAP.put(NcssOption.COUNT_IMPORTS.valueName(), NcssOption.COUNT_IMPORTS); - } - - - private static final PropertyDescriptor> NCSS_OPTIONS_DESCRIPTOR = - PropertyFactory.enumListProperty("ncssOptions", OPTION_MAP) - .desc("Choose options for the computation of Ncss") - .emptyDefaultValue() - .build(); - + PropertyFactory.intProperty("classReportLevel") + .desc("NCSS reporting threshold for classes") + .require(positive()) + .defaultValue(1500) + .build(); + private static final PropertyDescriptor> NCSS_OPTIONS_DESCRIPTOR; private int methodReportLevel; private int classReportLevel; private MetricOptions ncssOptions; + static { + Map options = new HashMap<>(); + options.put(NcssOption.COUNT_IMPORTS.valueName(), NcssOption.COUNT_IMPORTS); + + NCSS_OPTIONS_DESCRIPTOR = PropertyFactory.enumListProperty("ncssOptions", options) + .desc("Choose options for the computation of Ncss") + .emptyDefaultValue() + .build(); + + } + + public NcssCountRule() { definePropertyDescriptor(METHOD_REPORT_LEVEL_DESCRIPTOR); definePropertyDescriptor(CLASS_REPORT_LEVEL_DESCRIPTOR); @@ -113,12 +111,14 @@ public final class NcssCountRule extends AbstractJavaMetricsRule { @Override public Object visit(ASTMethodOrConstructorDeclaration node, Object data) { - int methodSize = (int) MetricsUtil.computeMetric(JavaOperationMetricKey.NCSS, node, ncssOptions); - if (methodSize >= methodReportLevel) { - addViolation(data, node, new String[] {node instanceof ASTMethodDeclaration ? "method" : "constructor", - PrettyPrintingUtil.displaySignature(node), "" + methodSize, }); + if (JavaOperationMetricKey.NCSS.supports((MethodLikeNode) node)) { + int methodSize = (int) MetricsUtil.computeMetric(JavaOperationMetricKey.NCSS, node, ncssOptions); + if (methodSize >= methodReportLevel) { + addViolation(data, node, new String[] { + node instanceof ASTMethodDeclaration ? "method" : "constructor", + PrettyPrintingUtil.displaySignature(node), "" + methodSize, }); + } } - return data; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java index 5969ff7780..03de85754d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/MetricFunction.java @@ -21,6 +21,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; 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; @@ -82,14 +83,18 @@ public class MetricFunction implements Function { public static double getMetric(Node n, String metricKeyName) { if (n instanceof ASTAnyTypeDeclaration) { - return MetricsUtil.computeMetric(getClassMetricKey(metricKeyName), (ASTAnyTypeDeclaration) n); + return computeMetric(getClassMetricKey(metricKeyName), (ASTAnyTypeDeclaration) n); } else if (n instanceof MethodLikeNode) { - return MetricsUtil.computeMetric(getOperationMetricKey(metricKeyName), (MethodLikeNode) n); + return computeMetric(getOperationMetricKey(metricKeyName), (MethodLikeNode) n); } else { throw new IllegalStateException(genericBadNodeMessage()); } } + private static double computeMetric(MetricKey metricKey, T n) { + return metricKey.supports(n) ? MetricsUtil.computeMetric(metricKey, n) : Double.NaN; + } + private static JavaClassMetricKey getClassMetricKey(String s) { String constantName = s.toUpperCase(Locale.ROOT); From 87ce7e1040d0960078f5d5aae38b4cb48c313f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20=C5=BBygie=C5=82o?= Date: Sat, 25 Jan 2020 12:10:45 +0100 Subject: [PATCH 024/235] Add test case for MisplacedNullCheck/#2242 --- .../rule/errorprone/xml/MisplacedNullCheck.xml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml index 5291a2822a..70bf00fd10 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml @@ -83,6 +83,23 @@ public class Test { } } } +]]> + + + #2242 False-positive MisplacedNullCheck reported + 0 + From 47aa8807cad102322fcb6c0f89430baf784184a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20=C5=BBygie=C5=82o?= Date: Sat, 25 Jan 2020 18:04:40 +0100 Subject: [PATCH 025/235] Second TC, with only reordered conditions --- .../errorprone/xml/MisplacedNullCheck.xml | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml index 70bf00fd10..3194f0b654 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml @@ -86,7 +86,7 @@ public class Test { ]]> - #2242 False-positive MisplacedNullCheck reported + #2242 False-positive MisplacedNullCheck reported (1) 0 + + #2242 False-positive MisplacedNullCheck reported (2) + 0 + + + From e0e858d39ebc13c13fed0cf3126c5c14676cc4a2 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 26 Jan 2020 20:14:27 +0100 Subject: [PATCH 026/235] [java] InvalidLogMessageFormat false-positive for a lambda argument Fixes #2255 This is actually only a workaround - lambda parameters are ignored now. --- docs/pages/release_notes.md | 1 + .../InvalidLogMessageFormatRule.java | 23 +++++++++++++++- .../xml/InvalidLogMessageFormat.xml | 26 ++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index ed2b154b84..61e627ae02 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -23,6 +23,7 @@ For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designe * java-errorprone * [#2250](https://github.com/pmd/pmd/issues/2250): \[java] InvalidLogMessageFormat flags logging calls using a slf4j-Marker + * [#2255](https://github.com/pmd/pmd/issues/2255): \[java] InvalidLogMessageFormat false-positive for a lambda argument ### API Changes 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 46101bdff2..ad45ebb133 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 @@ -158,11 +158,32 @@ public class InvalidLogMessageFormatRule extends AbstractJavaRule { int lastIndex = params.size() - 1; ASTPrimaryExpression last = params.get(lastIndex).getFirstDescendantOfType(ASTPrimaryExpression.class); - if (isNewThrowable(last) || hasTypeThrowable(last) || isReferencingThrowable(last)) { + if (isNewThrowable(last) || hasTypeThrowable(last) || isReferencingThrowable(last) || isLambdaParameter(last)) { params.remove(lastIndex); } } + private boolean isLambdaParameter(ASTPrimaryExpression last) { + String varName = null; + ASTPrimaryPrefix prefix = last.getFirstChildOfType(ASTPrimaryPrefix.class); + if (prefix != null) { + ASTName name = prefix.getFirstChildOfType(ASTName.class); + if (name != null) { + varName = name.getImage(); + } + } + for (NameDeclaration decl : prefix.getScope().getDeclarations().keySet()) { + if (decl.getName().equals(varName)) { + if (decl.getNode().getParent() instanceof ASTLambdaExpression) { + // If the last parameter is a lambda parameter, then we also ignore it - regardless of the type. + // This is actually a workaround, since type resolution doesn't resolve the types of lambda parameters. + return true; + } + } + } + return false; + } + private String getExpectedMessage(final List params, final int expectedArguments) { return " expected " + expectedArguments + (expectedArguments > 1 ? " arguments " : " argument ") + "but have " + params.size(); diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml index 8f0db82778..ccfd273601 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml @@ -785,7 +785,7 @@ public class InvalidLogMessageFormatTest { - ignore slf4j-Markers when detecting the number of arguments + ignore slf4j-Markers when detecting the number of arguments #2250 2 11,17 + + + + [java] InvalidLogMessageFormat false-positive for a lambda argument #2255 + 0 + LOGGER.error("Foo", exception)); + } + + private static void foo(Consumer consumer) { + consumer.accept(new IllegalArgumentException()); + } } ]]> From dd87753f1a867fe7821e507bfad4fda2336d7653 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 31 Jan 2020 15:39:58 +0100 Subject: [PATCH 027/235] [java] InvalidLogMessageFormat: add disabled false-negative test case --- .../xml/InvalidLogMessageFormat.xml | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml index ccfd273601..dd0b03c1b9 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml @@ -831,6 +831,36 @@ class InvalidLogMessageFormatTest { private static void foo(Consumer consumer) { consumer.accept(new IllegalArgumentException()); } +} + ]]> + + + + [java] InvalidLogMessageFormat false-negative for a lambda argument #2255 + 3 + 11,13,16 + LOGGER.error("Foo", arg)); // missing violation: extra argument, that is not a exception + // explicit cast helps type resolution + foo((String arg) -> LOGGER.error("Foo", arg)); // violation: extra argument, that is not a exception + foo((String arg) -> LOGGER.error("Foo {}", arg)); // no violation: correct number of arguments + foo(arg -> LOGGER.error("Foo {}", arg)); // no violation: correct number of arguments + foo(arg -> LOGGER.error("Foo {} {}", arg)); // violation: missing argument + } + + private static void foo(Consumer consumer) { + consumer.accept("bar"); + } } ]]> From dd7f62d1c288b37d44b7c77c86345a0a0e0383d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 26 Jun 2018 10:23:01 +0200 Subject: [PATCH 028/235] Rewrite XPath rule guide to add info about the designer --- docs/_includes/custom/faq_entry.html | 21 ++ docs/_plugins/custom_filters.rb | 4 + .../designer-overview-with-numbers.png | Bin 0 -> 278609 bytes .../pmd/userdocs/extending/designer_usage.md | 77 ++++++ .../userdocs/extending/writing_rules_intro.md | 25 ++ .../userdocs/extending/writing_xpath_rules.md | 253 +++++++----------- 6 files changed, 224 insertions(+), 156 deletions(-) create mode 100644 docs/_includes/custom/faq_entry.html create mode 100644 docs/images/userdocs/designer-overview-with-numbers.png create mode 100644 docs/pages/pmd/userdocs/extending/designer_usage.md create mode 100644 docs/pages/pmd/userdocs/extending/writing_rules_intro.md diff --git a/docs/_includes/custom/faq_entry.html b/docs/_includes/custom/faq_entry.html new file mode 100644 index 0000000000..1cbb2560ec --- /dev/null +++ b/docs/_includes/custom/faq_entry.html @@ -0,0 +1,21 @@ + + + + + + +{% assign panel_id = 8 | random_alphabetic %} + +

+ +
+
+ {{ include.answer | render_markdown }} +
+
+
\ No newline at end of file diff --git a/docs/_plugins/custom_filters.rb b/docs/_plugins/custom_filters.rb index 42ca4b0fef..922071297c 100644 --- a/docs/_plugins/custom_filters.rb +++ b/docs/_plugins/custom_filters.rb @@ -91,6 +91,10 @@ module CustomFilters end end + def random_alphabetic(length) + ('a'..'z').to_a.shuffle[0, length].join + end + private diff --git a/docs/images/userdocs/designer-overview-with-numbers.png b/docs/images/userdocs/designer-overview-with-numbers.png new file mode 100644 index 0000000000000000000000000000000000000000..0dcff489ff42712757cdf829b130b844e40829ec GIT binary patch literal 278609 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�}S9Q{5PGF=QHkX1HLW9av!`L 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°p>!YMuh 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 z + + + diff --git a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md new file mode 100644 index 0000000000..5174fca383 --- /dev/null +++ b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md @@ -0,0 +1,25 @@ +--- +title: Intro to writing PMD rules +tags: [extending, userdocs] +summary: "Writing your own PMD rules TODO" +last_updated: July 2018 (6.6.0) +permalink: pmd_userdocs_extending_writing_rules_intro.html +author: Clément Fournier +--- + + +## Why write custom rules? + +## How rules work: the AST + +Before running rules, PMD parses the source file into a data structure called an *abstract syntax tree* (AST). This tree represents the syntactic structure of the code, and encodes syntactic relations between source code elements. For instance, in Java, method declarations belong to a class: in the AST, the nodes representing method declarations will be descendants of a node representing the declaration of their enclosing class. This representation is thus much richer than the original source code (which, for a program, is just a chain of characters), or the token chain produced by a lexer. + +Conceptually, PMD rules work by *matching a "pattern" against the AST* of a file. Rules explore the AST and find nodes that satisfy some conditions that are characteristic of the specific thing the rule is trying to flag. Rules then report a violation on these nodes. + +## Defining rules + +PMD supports two ways to define rules: using an **XPath query**, or using a **Java visitor**. XPath rules are much easier to set up, since they're defined directly in your ruleset XML, and are expressive enough for most tasks. + +On the other hand, some parts of PMD's API are only accessible from Java, e.g. accessing the usages of a declaration. And Java rules allow you to do some complicated processing, to which an XPath rule couldn't scale. + +In the end, choosing one strategy or the other depends on the difficulty of what your rule does. I'd advise to keep to XPath unless you have no other choice. diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index eccfa41d86..32b293ec6c 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -1,198 +1,139 @@ --- -title: Writing XPath rules +title: Writing XPath rules with the Designer tags: [extending, userdocs] -summary: "Writing XPath rules for PMD" -last_updated: July 3, 2016 +summary: "Writing XPath rules with the Designer" +last_updated: July 2018 (6.6.0) permalink: pmd_userdocs_extending_writing_xpath_rules.html author: Miguel Griffa --- -# XPath Rule tutorial - {% include note.html content="For a translation to Georgian, see [webhostinggeeks.com/science/xpath-sourceforge-ka](http://webhostinggeeks.com/science/xpath-sourceforge-ka)" %} -Writing PMD rules with XPath can be a bit easier than writing rules with Java code. Here’s an introduction on how to do that. +Since the AST is a tree, conceptually similar to a DOM, it can be queried with an *XPath expression* that matches the nodes your rule is looking for. XPath rules are defined using a single XPath expression, specified directly in the ruleset XML. The next section walks you through the development of an XPath rule. -## Introduction +{% include note.html content="This page assumes you already know what XPath is and how to read basic XPath queries. W3C has a good tutorial [here](https://www.w3schools.com/xml/xpath_syntax.asp) if you don't." %} -PMD provides a very handy method for writing rules by writing an XPath query. When the XPath query finds a match, a violation is added to the report. This document focuses on XPath rules. You can go [here](pmd_userdocs_extending_writing_pmd_rules.html) for more information about writing a rule. -## What is the Abstract Syntax Tree (AST)? -From [FOLDOC](http://foldoc.org/abstract+syntax+tree) an AST is +## The Rule Designer -> A data structure representing something which has been parsed, often used as a compiler or interpreter’s internal representation of a program while it is being optimised and from which code generation is performed. -In our context, this means that we basically have a tree representation of the Java source file. This tree can viewed as a structured document - just like XML. And since it’s conceptually similar to XML, it can be queried with XPath to find a pattern. +> See [Designer Reference](pmd_userdocs_extending_designer_reference.html) for a more detailed explanation on how to use the designer. -## Using Designer +The rule designer is a tool that packs a lot of features to help you develop XPath rules quickly and painlessly. Basically, it allows you to examine the AST of a code snippet and evaluate an XPath expression against it. -PMD comes with a handy tool that you will love if you want to write an XPath rule. Designer, runnable from a script in `bin/`, is a very simple and useful utility for writing rules. +As for PMD and CPD, you can launch it using `run.sh designer` on Linux/Unix and `designer.bat` on Windows. The interface looks like the following: -The basic steps involved in writing XPath rules are these: +{% include image.html file="userdocs/designer-overview-with-numbers.png" alt="Designer overview" %} -1. Write a simple Java example source snippet in Designer -2. See the AST for the class you wrote -3. Write an XPath expression that matches the violation you are searching -4. Modify the Java class and go back to previous step to refine the XPath expression +The zone (1) is the **main editor**. If you write a code snippet in it, you'll see that the zone (2) will be updated automatically: it's the AST of the code. Note that the code snippet must be a syntactically valid compilation unit for the language you've chosen, e.g. for Java, a compilation unit necessarily has a top-level type declaration. -See [Designer Reference](pmd_userdocs_extending_designer_reference.html) for a more detailed explanation on how to use the designer. +If you select a node in the AST, its specific properties will also be displayed on the left (panel (3)): they're the XPath attributes of the node. -## Simple XPath expressions +The zone (4) is the **XPath editor**. If you enter an XPath query in that area, it will be evaluated on the current AST and the results will be added to the list in zone (5). -This section provides hands-on examples of XPath queries over the AST. You will probably find this section more useful if you follow it with Designer and copy/paste the examples. +In the center of the window, a toolbar lets you *select the language version* and *XPath version* you want to use. -Copy the following Java source code to Designer: + +### Rule development process + + +The basic development process is straightforward: + +1. Write a code snippet in the main editor that features the offending code you're looking for +2. Examine the AST and determine what node the violation should be reported on +3. Write an XPath expression matching that node in the XPath editor +4. Refine the XPath expression iteratively using different code snippets, so that it matches violation cases, but no other node +5. Export your XPath expression to an XML rule element, and place it in your ruleset + +In the following sections, we walk through several examples to refine your rule. + +## A simple rule + +Let's say you want to prevent your coding team from naming variables of type `short` after your boss, whose name is Bill. You try the designer on the following offending code snippet: ```java -public class a { - int fOne; - int fTwo; - private void run() { - int one; - int two; +public class KeepingItSerious { + + public void method() { + short bill; // LocalVariableDeclaration } + +} + +``` + +Examining the AST, you find out that the LocalVariableDeclaration has a VariableDeclaratorId descendant, whose `Image` XPath attribute is exactly `bill`. You thus write your first attempt in the XPath editor: +```xpath +//VariableDeclaratorId[@Image = "bill"] +``` + +You can see the XPath result list is updated with the variable declarator. +If you try the query against the following updated snippet though, you can +see that the field declaration id is matched even though it's not of type `short`. + +```java +public class KeepingItSerious { + + Delegator bill; // FieldDeclaration + + public void method() { + short bill; // LocalVariableDeclaration + } + } ``` -Let’s assume you want to match something on class variable names. You see in the ASTVviewer that VariableDeclaratorId contains the variable name - in XML terms, the name is in the `@Image` attribute. So you try an XPath expression as follows: -`//VariableDeclaratorId` - -If you try this expression you’ll see that variables declared in methods are also matched. A more precise expression for matching field declarations is, well, using the FieldDeclaration node. This expression matches only the two fields declared in the class: - -`//FieldDeclaration` - -In a similar way, you can match only local variables with this expression - -`//LocalVariableDeclaration` - -With local variables we need to be more careful. Consider the following class: - -```java -public class a { - private void run() { - final int one; - int two; - - { - int a; - } - } -} -``` - -Local variable declarations will match ‘a’, since it is a perfectly legal Java local variable. Now, a more interesting expression is to match variables declared in a method, and not on an internal block, nor in the class. Maybe you’ll start with an expression like this: - -`//MethodDeclaration//LocalVariableDeclaration` - -You’ll quickly see that all three local variables are matched. A possible solution for this is to request that the parent of the local variable declaration is the MethodDeclaration node: - -`//LocalVariableDeclaration[name(../../..) = 'MethodDeclaration']` - -## Matching variables by name - -Let’s consider that we are writing rules for logger. Let’s assume we use the Java logging API and we want to find all classes that have more than one logger. The following expression returns all variable declarations whose type is ‘Logger’. - -`//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='Logger']]` - -Finding a class with more than one logger is quite easy now. This expression matches the classes we are looking for. +You thus refine your XPath expression with an additional predicate, +based on your examination of the Type node of the field and local variable +declaration nodes. ```xpath -TypeDeclaration[count(//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='Logger']])>1 +//VariableDeclaratorId[@Image = "bill" and ../../Type[@TypeImage = "short"]] ``` -But let’s refine this expression a little bit more. Consider the following class: +### Exporting to XML -```java -public class a { - Logger log = null; - Logger log = null; - int b; +You estimate that your rule is now production ready, and you'd like to use it in your ruleset. +The `File > Export XPath to rule...` allows you to do that in a few clicks: just enter some +additional metadata for your rule, and the popup will generate an XML element that you can +copy-paste into your ruleset XML. The resulting element looks like so: - void myMethod() { - Logger log = null; - int a; - } - class c { - Logger a; - Logger a; - } -} -``` - -With this class we will only be matching one violation, when we probably would have wanted to produce two violations (one for each class). The following refined expression matches classes that contain more than one logger. - -```xpath -//ClassOrInterfaceBodyDeclaration[count(//VariableDeclarator[../Type/ReferenceType/ClassOrInterfaceType[@Image='Logger']])>1] -``` - -Let’s assume we have a Factory class, that could be always declared final. We’ll search an xpath expression that matches all declarations of Factory and reports a violation if it is not declared final. Consider the following class: - -```java -public class a { - Factory f1; - - void myMethod() { - Factory f2; - int a; - } -} -``` - -The following expression does the magic we need: - -```xpath -//VariableDeclarator - [../Type/ReferenceType/ClassOrInterfaceType - [@Image = 'Factory'] and ..[@Final='false']] -``` - -We recommend at this point that you experiment with Designer putting the final modifier to the Factory and verifying that the results produced are those expected. - -## Creating a new rule definition - -To actually use your new XPath rule, it needs to be in a ruleset. You can create a new custom ruleset which just -contains your new XPath rule. You can use the following template. Just make sure, to replace the `xpath` property, -the example code and give your rule a useful name and message. - -``` xml - - - +```xml + -Custom rules +TODO - - - -Rule Description - - 3 - - - - - - - 3 + + + + - - - + + + + ``` +You can notice that your XPath expression ends up inside a [property](pmd_userdocs_configuring_rules.html#rule-properties) of a rule of type XPathRule, which is how XPath rules are implemented. + +### Defining rule properties + +Some time later, your boss' boss decides he doesn't want to be called short in Java too, and would like you to add him to the rule. There are several ways to do that, but you decide to use a rule property to make your rule extensible. Doing that directly in the XML is [explained on that page](pmd_userdocs_extending_defining_properties.html#for-xpath-rules), and we'll explain here how to do that in the designer. + +The zone (6) in the screenshot above is a list of properties defined for your rule. Right-clicking the table and selecting "Add property..", you may add a property of type `List[String]` to represent your boss names. You can then use it in your XPath query with a dollar prefix, i.e. + +```xpath +//VariableDeclaratorId[@Image = $bossNames and ../../Type[@TypeImage = "short"]] +``` + + +{% include note.html content="Using a property of type `List[String]` requires you to use XPath 2.0" %} From 45291fb6d8ef18a2639fe74b77f185f845735c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Tue, 5 Mar 2019 20:49:35 +0100 Subject: [PATCH 029/235] Update screenshot --- .../designer-overview-with-numbers.png | Bin 278609 -> 0 bytes .../userdocs/designer-overview-with-nums.png | Bin 0 -> 254594 bytes .../userdocs/extending/writing_rules_intro.md | 31 +++++++-- .../userdocs/extending/writing_xpath_rules.md | 59 +++++++++++++----- 4 files changed, 69 insertions(+), 21 deletions(-) delete mode 100644 docs/images/userdocs/designer-overview-with-numbers.png create mode 100644 docs/images/userdocs/designer-overview-with-nums.png diff --git a/docs/images/userdocs/designer-overview-with-numbers.png b/docs/images/userdocs/designer-overview-with-numbers.png deleted file mode 100644 index 0dcff489ff42712757cdf829b130b844e40829ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 278609 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�}S9Q{5PGF=QHkX1HLW9av!`L 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 R{r%y;B;Lu2mcG^Z`#(ZPcKiSU literal 0 HcmV?d00001 diff --git a/docs/pages/pmd/userdocs/extending/designer_usage.md b/docs/pages/pmd/userdocs/extending/designer_usage.md new file mode 100644 index 0000000000..5ea442d373 --- /dev/null +++ b/docs/pages/pmd/userdocs/extending/designer_usage.md @@ -0,0 +1,77 @@ +--- +title: Using the Rule Designer +short_title: Using the Rule Designer +tags: [userdocs, extending, designer] +summary: "Learn how to use the designer" +last_updated: July 2018 (6.6.0) +permalink: pmd_userdocs_extending_designer_usage.html +author: Clément Fournier +--- + +## Getting around + +We here explain the global organisation of the UI. + +{% include image.html file="userdocs/designer-overview-with-numbers.png" alt="Designer overview" %} + +### Examining the AST + +The code in zone (1) on the image will be parsed automatically, and its AST rendered +in zone (2). You can examine each node of the AST individually by clicking on it. +Node-specific information will be displayed in zone (3). In that panel, you can view +in different tabs: +* The XPath attributes of the node and their value. These are the attributes accessible +via XPath, but for some languages are also accessible as methods of the node for your Java rules. +* The scope hierarchy of the node, for languages that support it (e.g. Java). This will +be a tree of the scopes that enclose the node and their declarations. +* The value of metrics on the node, for languages that support it (Java and Apex). Note that +metrics can only be computed on a few node types, e.g. class or method declarations. + + +### XPath tools + +The bottom panel has a tab with tools to develop XPath rules. In zone (4), you can edit an +XPath expression that will be automatically evaluated on the current AST. The results will +be displayed in zone (5), and highlighted on the main code area (1). + + +#### Editing properties + +The table in zone (6) allows you to define properties for your XPath rule and change their +values. This is good practice if you want to develop a configurable rule. To add a property, +right-click on the table and select "Add property...". A pop-up will allow you to set the +name, type, and other attributes of the property. + +Properties can then be referenced in your XPath query by their name prefixed with a dollar symbol, +e.g. `$myProperty`. + +## FAQ + + +

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°p>!YMuh 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 z

{{ fun.name }}

+ +{{ fun.description }} {{ fun.notes }} + +{% unless fun.parameters.size == 0 %} + +
Parameters
+ + + + {% for param in fun.parameters %} + + + + + + + {% endfor %} + +
{{ param.name }}{{ param.description }}
+ +{% endunless %} + +{% unless fun.examples.size == 0 %} + +
Examples
+ + + + {% for example in fun.examples %} + + + + + + + {% endfor %} +
{{ example.code }}{{ example.description }}
+ +{% endunless %} + +{% endfor %} + + + +{% endfor %} diff --git a/docs/_plugins/javadoc_tag.rb b/docs/_plugins/javadoc_tag.rb index 940c2826e2..11fc919b94 100644 --- a/docs/_plugins/javadoc_tag.rb +++ b/docs/_plugins/javadoc_tag.rb @@ -161,7 +161,7 @@ class JavadocTag < Liquid::Tag end def markup_link(rname, link) - "[`#{rname}`](#{link})" + "
#{rname}" end diff --git a/docs/_plugins/render_block.rb b/docs/_plugins/render_block.rb new file mode 100644 index 0000000000..671484ce98 --- /dev/null +++ b/docs/_plugins/render_block.rb @@ -0,0 +1,19 @@ +require 'pp' +# +# Tags to create a complex object inline in JSON. +# +class RenderBlock < Liquid::Block + + def initialize(tag_name, arg, tokens) + super + @body = tokens + end + + def render(context) + template = @body.render(context) + pp template + pp Liquid::Template.parse(template).render(context) + end +end + +Liquid::Template.register_tag('render', RenderBlock) diff --git a/docs/pages/pmd/userdocs/extending/designer_intro.md b/docs/pages/pmd/userdocs/extending/designer_intro.md new file mode 100644 index 0000000000..43d41c95ac --- /dev/null +++ b/docs/pages/pmd/userdocs/extending/designer_intro.md @@ -0,0 +1,157 @@ +--- +title: Using the Rule Designer +tags: [extending, userdocs] +summary: "This page is a gentle introduction to the Rule Designer, a tool made +to help developers write new rules." +last_updated: July 2018 (6.6.0) +permalink: pmd_userdocs_extending_designer_intro.html +author: Miguel Griffa +--- + +This page is a gentle introduction to the Rule Designer, a tool made to help +developers write new rules. Using the designer is useful both to write Java +rules and XPath rules, but it's more specifically geared towards XPath rules. +This page uses a simple XPath rule to illustrate the common workflow. We assume +here that you already know what XPath is and how to read basic XPath queries. W3C +has a good tutorial [here](https://www.w3schools.com/xml/xpath_syntax.asp) if you don't. + +## The Rule Designer + +The rule designer is a tool that packs a lot of features to help you develop XPath +rules quickly and painlessly. Basically, it allows you to examine the AST of a code +snippet and evaluate an XPath expression against it. + +Like for PMD and CPD, you can launch it using `run.sh designer` on Linux/Unix +and `designer.bat` on Windows. The interface looks like the following: + +{% include image.html file="userdocs/designer-overview-with-nums.png" alt="Designer overview" %} + +The zone (2) is the **main editor**. When you write a code snippet in the + code area to the left, you'll see that the tree to the right will be updated + automatically: it's the AST of the code. + Note that the code snippet must be a syntactically valid compilation unit for the + language you've chosen, e.g. for Java, a compilation unit necessarily has a top-level + type declaration. + +If you select a node in the AST, its specific properties will also be displayed +in the panel (1): they're the XPath attributes of the node. More on that later. + +The zone (3) is the **XPath editor**. If you enter an XPath query in that area, +it will be evaluated on the current AST and the results will be displayed in the +list to the bottom right. + +### Rule development process + + +The basic development process is straightforward: + +1. Write a code snippet in the main editor that features the offending code you're looking for +2. Examine the AST and determine what node the violation should be reported on +3. Write an XPath expression matching that node in the XPath editor +4. Refine the XPath expression iteratively using different code snippets, so that + it matches violation cases, but no other node +5. Export your XPath expression to an XML rule element, and place it in your ruleset + +In the following sections, we walk through several examples to refine your rule. + +## A simple rule + +Let's say you want to prevent your coding team from naming variables of type +`short` after your boss, whose name is Bill. You try the designer on the following + offending code snippet: + +```java + +public class KeepingItSerious { + + public void method() { + short bill; // LocalVariableDeclaration + } + +} + +``` + +Examining the AST, you find out that the LocalVariableDeclaration has a VariableDeclaratorId +descendant, whose `Image` XPath attribute is exactly `bill`. You thus write your first attempt +in the XPath editor: +```xpath +//VariableDeclaratorId[@Image = "bill"] +``` + +You can see the XPath result list is updated with the variable declarator. +If you try the query against the following updated snippet though, you can +see that the field declaration id is matched even though it's not of type `short`. + +```java +public class KeepingItSerious { + + Delegator bill; // FieldDeclaration + + public void method() { + short bill; // LocalVariableDeclaration + } + +} +``` + + +You thus refine your XPath expression with an additional predicate, +based on your examination of the Type node of the field and local variable +declaration nodes. + +```xpath +//VariableDeclaratorId[@Image = "bill" and ../../Type[@TypeImage = "short"]] +``` + +### Exporting to XML + +You estimate that your rule is now production ready, and you'd like to use it in your ruleset. +The `File > Export XPath to rule...` allows you to do that in a few clicks: just enter some +additional metadata for your rule, and the popup will generate an XML element that you can +copy-paste into your ruleset XML. The resulting element looks like so: + +```xml + + +TODO + + 3 + + + + + + + + +``` + +You can notice that your XPath expression ends up inside a [property](pmd_userdocs_configuring_rules.html#rule-properties) +of a rule of type XPathRule, which is how XPath rules are implemented. + +### Defining rule properties + +Some time later, your boss' boss decides he doesn't want to be called short in Java +too, and would like you to add him to the rule. There are several ways to do that, +but you decide to use a rule property to make your rule extensible. Doing that +directly in the XML is [explained on that page](pmd_userdocs_extending_defining_properties.html#for-xpath-rules), + and we'll explain here how to do that in the designer. + +The table to the left of the zone (3) in the screenshot above is a list of +properties defined for your rule. +Right-clicking the table and selecting "Add property..", you may add a property of +type `List[String]` to represent your boss names. You can then use it in your XPath +query with a dollar prefix, i.e. + +```xpath +//VariableDeclaratorId[@Image = $bossNames and ../../Type[@TypeImage = "short"]] +``` + + +{% include note.html content="Using a property of type `List[String]` requires you to use XPath 2.0" %} diff --git a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md index 3a87bfa491..d6b4f57d05 100644 --- a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md +++ b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md @@ -27,11 +27,11 @@ Conceptually, PMD rules work by *matching a "pattern" against the AST* of a file Rules explore the AST and find nodes that satisfy some conditions that are characteristic of the specific thing the rule is trying to flag. Rules then report a violation on these nodes. -## Defining rules +## Writing new rules PMD supports two ways to define rules: using an **XPath query**, or using a **Java visitor**. XPath rules are much easier to set up, since they're defined -directly in your ruleset XML, and are expressive enough for most tasks. +directly in your ruleset XML, and are expressive enough for nearly any task. On the other hand, some parts of PMD's API are only accessible from Java, e.g. accessing the usages of a declaration. And Java rules allow you to do some diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index a597e34d6b..6a7d537489 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -1,23 +1,63 @@ --- -title: Writing XPath rules with the Designer +title: Writing XPath rules tags: [extending, userdocs] -summary: "Writing XPath rules with the Designer" +summary: "This page describes XPath rule support in more details" last_updated: July 2018 (6.6.0) permalink: pmd_userdocs_extending_writing_xpath_rules.html -author: Miguel Griffa +author: Miguel Griffa , Clément Fournier --- -TODO create more technical reference page for XPath rules -{% include note.html content="For a translation to Georgian, see [webhostinggeeks.com/science/xpath-sourceforge-ka](http://webhostinggeeks.com/science/xpath-sourceforge-ka)" %} +{% jdoc_nspace :coremx core::lang.metrics %} +{% jdoc_nspace :coreast core::lang.ast %} +{% jdoc_nspace :jmx java::lang.java.metrics %} +{% jdoc_nspace :jast java::lang.java.ast %} -Since the AST is a tree, conceptually similar to a DOM, it can be queried with an - *XPath expression* that matches the nodes your rule is looking for. XPath rules - are defined using a single XPath expression, specified directly in the ruleset - XML. The next section walks you through the development of an XPath rule. -{% include note.html content="This page assumes you already know what XPath is and how to read basic XPath queries. W3C has a good tutorial [here](https://www.w3schools.com/xml/xpath_syntax.asp) if you don't." %} +## PMD extension functions + +PMD provides some language-specific XPath functions to access semantic +information from the AST. + +On XPath 2.0, the namespace must be explicitly provided. + +### Java + +Java functions are in the namespace `pmd-java`. + +| Function name | Arguments | Returns | Notes | +|-----------------|----------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------| +| `typeIs` | 1: the qualified name of a class, possibly with pairs of brackets to indicate an array type. Can also be a primitive type name. | True if the context node's static type is a subtype of the given type | The context node must be a {% jdoc jast::TypeNode %} | +| `typeIsExactly` | (Same as for `typeIs`) | True if the context node's static type is exactly the given type. In particular, returns false if the context node's type is a subtype of the given type. | (Same as for `typeIs`) | +| `metric` | 1: the name of an enum constant in {% jdoc jmx::api.JavaOperationMetricKey %} or {% jdoc jmx::api.JavaClassMetricKey %} | A decimal value representing the value of the metric as evaluated on the context node | The context node must be a {% jdoc jast::ASTAnyTypeDeclaration %} or a {% jdoc jast::MethodLikeNode %} | + +{% render %} +{% include custom/xpath_fun_doc.html %} + {% endrender %} + +There is also a `typeOf` function which is deprecated and whose usages +should be replaced with uses of `typeIs` or `typeIsExactly`. That one will +be removed with PMD 7.0.0. + +## XPath version + +PMD supports three XPath versions: 1.0, 2.0, and 1.0 compatibility mode. The +version can be specified with the `version` property in the rule definition, +like so: + +```xml + +``` + +As of PMD version 6.13.0, XPath versions 1.0 and the 1.0 compatibility mode are +deprecated. It is recommended that you migrate to 2.0, which shouldn't be too +hard. + +### Migrating + +TODO + From 79f47134c3f8065f41bc9c40561a6213ed6b5031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 6 Mar 2019 02:22:36 +0100 Subject: [PATCH 031/235] Finish xpath spec page --- docs/_data/xpath_funs.yml | 11 +- docs/_includes/custom/xpath_fun_doc.html | 82 ++++--- docs/_plugins/render_block.rb | 3 +- .../pmd/userdocs/extending/designer_intro.md | 5 +- .../userdocs/extending/writing_xpath_rules.md | 200 +++--------------- 5 files changed, 90 insertions(+), 211 deletions(-) diff --git a/docs/_data/xpath_funs.yml b/docs/_data/xpath_funs.yml index ac403fb965..404e749726 100644 --- a/docs/_data/xpath_funs.yml +++ b/docs/_data/xpath_funs.yml @@ -26,4 +26,13 @@ langs: notes: "The context node must be a {% jdoc jast::ASTAnyTypeDeclaration %} or a {% jdoc jast::MethodLikeNode %}" parameters: - name: "metricKey" - type: "xs:string" \ No newline at end of file + type: "xs:string" + description: "The name of an enum constant in {% jdoc jmx::api.JavaOperationMetricKey %} or {% jdoc jmx::api.JavaClassMetricKey %}" + + examples: + - code: '//FormalParameter[pmd-java:typeIs("java.lang.String[]")]' + outcome: "Matches formal parameters of type `String[]` (including vararg parameters)" + - code: '//VariableDeclaratorId[pmd-java:typeIs("java.lang.List")]' + outcome: "Matches variable declarators of type `List` or any of its subtypes (including e.g. `ArrayList`)" + - code: '//VariableDeclaratorId[pmd-java:typeIsExactly("java.lang.List")]' + outcome: "Matches variable declarators of type `List` (but not e.g. `ArrayList`)" \ No newline at end of file diff --git a/docs/_includes/custom/xpath_fun_doc.html b/docs/_includes/custom/xpath_fun_doc.html index b81ee2e1c0..a063a06ed2 100644 --- a/docs/_includes/custom/xpath_fun_doc.html +++ b/docs/_includes/custom/xpath_fun_doc.html @@ -4,53 +4,67 @@ {{ lang.name }} functions are in the namespace `{{ lang.ns }}`. -{% for fun in lang.funs %} +
+ + + + + + + + + + + {% for fun in lang.funs %} -

{{ fun.name }}

+ -{{ fun.description }} {{ fun.notes }} + + + + + -{% unless fun.parameters.size == 0 %} + {% endfor %} -
Parameters
+
Function nameParametersDescriptionNotes
{{ fun.name }} + {% if fun.parameters.size == 0 %} + None + {% elsif fun.params_are_same_as %} + (Same as for `{{ fun.params_are_same_as }}`) + {% elsif fun.parameters.size == 1 %} + 0: {{ fun.parameters[0].description }} + {% else %} +
    + {% for i in 0..fun.parameters.size %} + {{ assign param = fun.parameters[i] }} +
  • {{ i }} : {{ param.description }}
  • + {% endfor %} +
+ {% endif %} +
{{ fun.description }} + {% if fun.notes_are_same_as %} + (Same as for `{{ fun.notes_are_same_as }}`) + {% else %} + {{ fun.notes }} + {% endif %} +
- + - {% for param in fun.parameters %} +{% unless lang.examples.size == 0 %} - - - - +#### Examples - {% endfor %} - -
{{ param.name }}{{ param.description }}
- -{% endunless %} - -{% unless fun.examples.size == 0 %} - -
Examples
- - - - {% for example in fun.examples %} - - - - - - - {% endfor %} -
{{ example.code }}{{ example.description }}
- -{% endunless %} +{% for example in lang.examples %} +* `{{ example.code }}`
    {{example.outcome }} {% endfor %} +{% endunless %} + {% endfor %} diff --git a/docs/_plugins/render_block.rb b/docs/_plugins/render_block.rb index 671484ce98..49f3fa8cfb 100644 --- a/docs/_plugins/render_block.rb +++ b/docs/_plugins/render_block.rb @@ -11,8 +11,7 @@ class RenderBlock < Liquid::Block def render(context) template = @body.render(context) - pp template - pp Liquid::Template.parse(template).render(context) + Liquid::Template.parse(template).render(context) end end diff --git a/docs/pages/pmd/userdocs/extending/designer_intro.md b/docs/pages/pmd/userdocs/extending/designer_intro.md index 43d41c95ac..1bfa5fee36 100644 --- a/docs/pages/pmd/userdocs/extending/designer_intro.md +++ b/docs/pages/pmd/userdocs/extending/designer_intro.md @@ -13,7 +13,10 @@ developers write new rules. Using the designer is useful both to write Java rules and XPath rules, but it's more specifically geared towards XPath rules. This page uses a simple XPath rule to illustrate the common workflow. We assume here that you already know what XPath is and how to read basic XPath queries. W3C -has a good tutorial [here](https://www.w3schools.com/xml/xpath_syntax.asp) if you don't. +has a good tutorial [here](https://www.w3schools.com/xml/xpath_syntax.asp) if +you don't (in the context of XML only), and [the Saxon documentation](https://www.saxonica.com/documentation/index.html#!expressions) +features a comprehensive but approachable description of the syntax of XPath +expressions. ## The Rule Designer diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index 6a7d537489..d9827bf665 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -14,193 +14,47 @@ author: Miguel Griffa , Clément Fournier ## XPath version -PMD supports three XPath versions: 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 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: ```xml ``` As of PMD version 6.13.0, XPath versions 1.0 and the 1.0 compatibility mode are -deprecated. It is recommended that you migrate to 2.0, which shouldn't be too -hard. +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. The +following section describes incompatibilities between 1.0 and 2.0 for PMD rules. ### Migrating TODO +## PMD extension functions + +PMD provides some language-specific XPath functions to access semantic +information from the AST. + +On XPath 2.0, the namespace of custom PMD function must be explicitly mentioned. + +{% render %} +{% include custom/xpath_fun_doc.html %} +{% endrender %} + +There is also a `typeOf` function which is deprecated and whose usages +should be replaced with uses of `typeIs` or `typeIsExactly`. That one will +be removed with PMD 7.0.0. - -## The Rule Designer - - -> See [Designer Reference](pmd_userdocs_extending_designer_reference.html) for a more detailed explanation on how to use the designer. - - -The rule designer is a tool that packs a lot of features to help you develop XPath -rules quickly and painlessly. Basically, it allows you to examine the AST of a code -snippet and evaluate an XPath expression against it. - -As for PMD and CPD, you can launch it using `run.sh designer` on Linux/Unix and -`designer.bat` on Windows. The interface looks like the following: - -{% include image.html file="userdocs/designer-overview-with-nums.png" alt="Designer overview" %} - -The zone (2) is the **main editor**. When you write a code snippet in the - code area to the left, you'll see that the tree to the right will be updated - automatically: it's the AST of the code. - Note that the code snippet must be a syntactically valid compilation unit for the - language you've chosen, e.g. for Java, a compilation unit necessarily has a top-level - type declaration. - -If you select a node in the AST, its specific properties will also be displayed -on the left (panel (1)): they're the XPath attributes of the node. - -The zone (3) is the **XPath editor**. If you enter an XPath query in that area, -it will be evaluated on the current AST and the results will be added to the -list to the bottom right. - -### Rule development process - - -The basic development process is straightforward: - -1. Write a code snippet in the main editor that features the offending code you're looking for -2. Examine the AST and determine what node the violation should be reported on -3. Write an XPath expression matching that node in the XPath editor -4. Refine the XPath expression iteratively using different code snippets, so that - it matches violation cases, but no other node -5. Export your XPath expression to an XML rule element, and place it in your ruleset - -In the following sections, we walk through several examples to refine your rule. - -## A simple rule - -Let's say you want to prevent your coding team from naming variables of type -`short` after your boss, whose name is Bill. You try the designer on the following - offending code snippet: - -```java - -public class KeepingItSerious { - - public void method() { - short bill; // LocalVariableDeclaration - } - -} - -``` - -Examining the AST, you find out that the LocalVariableDeclaration has a VariableDeclaratorId -descendant, whose `Image` XPath attribute is exactly `bill`. You thus write your first attempt -in the XPath editor: -```xpath -//VariableDeclaratorId[@Image = "bill"] -``` - -You can see the XPath result list is updated with the variable declarator. -If you try the query against the following updated snippet though, you can -see that the field declaration id is matched even though it's not of type `short`. - -```java -public class KeepingItSerious { - - Delegator bill; // FieldDeclaration - - public void method() { - short bill; // LocalVariableDeclaration - } - -} -``` - - -You thus refine your XPath expression with an additional predicate, -based on your examination of the Type node of the field and local variable -declaration nodes. - -```xpath -//VariableDeclaratorId[@Image = "bill" and ../../Type[@TypeImage = "short"]] -``` - -### Exporting to XML - -You estimate that your rule is now production ready, and you'd like to use it in your ruleset. -The `File > Export XPath to rule...` allows you to do that in a few clicks: just enter some -additional metadata for your rule, and the popup will generate an XML element that you can -copy-paste into your ruleset XML. The resulting element looks like so: - -```xml - - -TODO - - 3 - - - - - - - - -``` - -You can notice that your XPath expression ends up inside a [property](pmd_userdocs_configuring_rules.html#rule-properties) -of a rule of type XPathRule, which is how XPath rules are implemented. - -### Defining rule properties - -Some time later, your boss' boss decides he doesn't want to be called short in Java -too, and would like you to add him to the rule. There are several ways to do that, -but you decide to use a rule property to make your rule extensible. Doing that -directly in the XML is [explained on that page](pmd_userdocs_extending_defining_properties.html#for-xpath-rules), - and we'll explain here how to do that in the designer. - -The zone (6) in the screenshot above is a list of properties defined for your rule. -Right-clicking the table and selecting "Add property..", you may add a property of -type `List[String]` to represent your boss names. You can then use it in your XPath -query with a dollar prefix, i.e. - -```xpath -//VariableDeclaratorId[@Image = $bossNames and ../../Type[@TypeImage = "short"]] -``` - - -{% include note.html content="Using a property of type `List[String]` requires you to use XPath 2.0" %} From 77b7db9dab0490cd3b61fa64accc1f2a39abc643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 6 Mar 2019 02:56:37 +0100 Subject: [PATCH 032/235] Document XPath migration --- .../userdocs/extending/writing_xpath_rules.md | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index d9827bf665..00450b1dff 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -28,6 +28,8 @@ The version can be specified with the `version` property in the rule definition, ``` +The default has always been version 1.0. + As of PMD version 6.13.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 @@ -38,9 +40,40 @@ 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. The following section describes incompatibilities between 1.0 and 2.0 for PMD rules. -### Migrating +### 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. + +The incompatibilities that are most relevant to migrating your rules are not +caused by the specification, but by the different engines we use to run +XPath 1.0 and 2.0 queries. Here's a list of known incompatibilities: + +* The namespace prefixes `fn:` and `string:` should not be mentioned explicitly. +In XPath 2.0 mode, the engine will complain about an undeclared namespace, but +the functions are in the default namespace. Removing the namespace prefixes fixes it. + * fn:substring("Foo", 1) → `substring("Foo", 1)` +* Conversely, calls to custom PMD functions like `typeIs` *must* be prefixed +with the namespace of the declaring module (`pmd-java`). + * `typeIs("Foo")` → pmd-java:typeIs("Foo") +* Boolean attribute values on our 1.0 engine are represented as the string values +`"true"` and `"false"`. In 2.0 mode though, boolean values are truly represented +as boolean values, which in XPath may only be obtained through the functions +`true()` and `false()`. +If your XPath 1.0 rule tests an attribute like `@Private="true"`, then it just +needs to be changed to `@Private=true()` when migrating. A type error will warn +you that you must update the comparison. More is explained on [issue #1244](https://github.com/pmd/pmd/issues/1244). + * `"true"`, `'true'` → `true()` + * `"false"`, `'false'` → `false()` + +* In XPath 1.0, comparing a number to a string coerces the string to a number. +In XPath 2.0, a type error occurs. Like for boolean values, numeric values are +represented by our 1.0 implementation as strings, meaning that `@BeginLine > "1"` +worked ---that's not the case in 2.0 mode. + * @ArgumentCount > '1' → `@ArgumentCount > 1` + -TODO ## PMD extension functions From ae73bf369280976202db8d27c4f2cd2c1da27b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 6 Mar 2019 03:16:33 +0100 Subject: [PATCH 033/235] Review intro of defining rule properties --- .../userdocs/extending/defining_properties.md | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/defining_properties.md b/docs/pages/pmd/userdocs/extending/defining_properties.md index 8b455d7c28..25f5d8b1dc 100644 --- a/docs/pages/pmd/userdocs/extending/defining_properties.md +++ b/docs/pages/pmd/userdocs/extending/defining_properties.md @@ -10,11 +10,16 @@ author: Hooper Bloob , Romain Pelisse modeProperty Note that you're required to fill in the type of the values too, using `type()`. -#### Example +### Example You can see an example of properties used in a PMD rule [here](https://github.com/pmd/pmd/blob/ac2ff0f6af8d16f739584ba8d00b7ea1a6311ccc/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/AvoidDeeplyNestedIfStmtsRule.java#L17). There are several things to notice here: @@ -110,7 +115,7 @@ There are several things to notice here: -### For XPath rules +## For XPath rules XPath rules can also define their own properties. To do so, you must add a `property` element in the `properties` element of your rule, which **declares the `type` attribute**. This attribute conditions what type the underlying property has, and can have the following values: @@ -150,7 +155,7 @@ You can then use the property in XPath with the syntax `$propertyName`, for exam ``` -#### Multivalued properties +### Multivalued properties Multivalued properties are also allowed and their `type` attribute has the form `List[Boolean]` or `List[Character]`, with every above type allowed. These properties **require XPath 2.0** to work properly, and make use of the **sequence datatype** provided by that language. You thus need to set the `version` property to `2.0` to use them. Properties can also declare the `delimiter` attribute. From af612751dafca866e83264ed3444feaf320d4c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 6 Mar 2019 03:29:47 +0100 Subject: [PATCH 034/235] Add resource index --- .../userdocs/extending/defining_properties.md | 6 ++--- .../userdocs/extending/writing_rules_intro.md | 23 +++++++++++++++---- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/defining_properties.md b/docs/pages/pmd/userdocs/extending/defining_properties.md index 25f5d8b1dc..8358773149 100644 --- a/docs/pages/pmd/userdocs/extending/defining_properties.md +++ b/docs/pages/pmd/userdocs/extending/defining_properties.md @@ -11,13 +11,13 @@ author: Hooper Bloob , Romain Pelisse Date: Wed, 6 Mar 2019 04:14:34 +0100 Subject: [PATCH 035/235] Update the defining properties page --- docs/_includes/custom/xpath_fun_doc.html | 4 +- .../userdocs/extending/defining_properties.md | 144 +++++++++++------- .../userdocs/extending/writing_xpath_rules.md | 8 +- 3 files changed, 95 insertions(+), 61 deletions(-) diff --git a/docs/_includes/custom/xpath_fun_doc.html b/docs/_includes/custom/xpath_fun_doc.html index a063a06ed2..e65392ab97 100644 --- a/docs/_includes/custom/xpath_fun_doc.html +++ b/docs/_includes/custom/xpath_fun_doc.html @@ -28,12 +28,12 @@ {% elsif fun.params_are_same_as %} (Same as for `{{ fun.params_are_same_as }}`) {% elsif fun.parameters.size == 1 %} - 0: {{ fun.parameters[0].description }} + 1: {{ fun.parameters[0].description }} {% else %}
    {% for i in 0..fun.parameters.size %} {{ assign param = fun.parameters[i] }} -
  • {{ i }} : {{ param.description }}
  • +
  • {{ i + 1 }} : {{ param.description }}
  • {% endfor %}
{% endif %} diff --git a/docs/pages/pmd/userdocs/extending/defining_properties.md b/docs/pages/pmd/userdocs/extending/defining_properties.md index 8358773149..5a4039f79a 100644 --- a/docs/pages/pmd/userdocs/extending/defining_properties.md +++ b/docs/pages/pmd/userdocs/extending/defining_properties.md @@ -9,6 +9,7 @@ author: Hooper Bloob , Romain Pelisse | *E* -|StringProperty|String -|BooleanProperty|boolean -|CharacterProperty|char -|FileProperty|java.io.File -|MethodProperty|java.lang.reflect.Method -|TypeProperty|java.lang.Class\ -|RegexProperty|java.util.regex.Pattern +|Value type|Factory method| +|----------|--------------| +| int |{% jdoc :PF#intProperty(java.lang.String) %}| +| double |{% jdoc :PF#doubleProperty(java.lang.String) %}| +| long |{% jdoc :PF#longProperty(java.lang.String) %}| +| char |{% jdoc :PF#charProperty(java.lang.String) %}| +| boolean |{% jdoc :PF#booleanProperty(java.lang.String) %}| +| String |{% jdoc :PF#stringProperty(java.lang.String) %}| +| java.util.regex.Pattern |{% jdoc :PF#regexProperty(java.lang.String) %}| +| *anything* |{% jdoc :PF#enumProperty(java.lang.String,java.util.Map) %}| -Each of these is complemented by a multivalued variant, whose name ends with "MultiProperty", and which returns a list of values, e.g. +Each of these is complemented by a multivalued variant, whose value is a list, e.g. -|Class name|Value type| -|----------|----------| -|LongMultiProperty | List\ -|EnumeratedMultiProperty\<*E*\>| List\<*E*\> +|Value type|Factory method| +|----------|--------------| +| List\ |{% jdoc :PF#intListProperty(java.lang.String) %}| +| List\<*E*\> |{% jdoc :PF#enumListProperty(java.lang.String,java.util.Map) %}| -Note that RegexProperty doesn't have a multivalued variant, since the delimiters could be part of a specific value. +Note that no multivalue property is available for regex properties, since the +delimiters could be part of a specific value. ## For Java rules @@ -64,28 +62,45 @@ You can then retrieve the value of the property at any time using {% jdoc !a!pro ### Creating a descriptor -From version 6.0.0 on, properties can be built using specific **builders**. For example, to build a string property, you'd call +Properties can be built using type-specific **builders**, which can be obtained +from the factory methods of {% jdoc :PF %}. For example, to build a +string property, you'd call ```java -StringProperty.named("myProperty") - .desc("This is my property") - .defaultValue("foo") - .build(); +PropertyFactory.stringProperty("myProperty") + .desc("This is my property") + .defaultValue("foo") + .build(); ``` This is fairly more readable than a constructor call, but keep in mind the description and the default value are not optional. -{%include note.html content="The constructors may be deprecated in a future release, so please use the builders instead." %} +{%include note.html +content='As of version 6.10.0, all property concrete classes are deprecated for +removal in 7.0.0. See the detailed list of planned removals for +information about how to migrate.' %} -For **numeric properties**, you'd add a call to `range` to define the range of acceptable values, e.g. + +For **numeric properties**, you can add constraints on the range of acceptable values, e.g. ```java -IntegerProperty.named("myIntProperty") +PropertyFactory.intProperty("myIntProperty") .desc("This is my property") .defaultValue(3) + .require(positive()) .range(0, 100) .build(); ``` -**Enumerated properties** are a bit less straightforward to define, though they are arguably more powerful. These properties don't have a specific value type, instead, you can choose any type of value, provided the values are from a closed set. To make that actionable, you give string labels to each of the acceptable values, and the user will provide one of those labels as a value in the XML. The property will give you back the associated value, not the label. Here's an example: +The {% jdoc props::constraints.NumericConstraints#positive() %} method is part of +the {% jdoc props::constraints.NumericConstraints %} class, which provides some +other constraints. The constraint mechanism will be completely unlocked with 7.0.0, +since we'll be migrating our API to Java 8. + +**Enumerated properties** are a bit less straightforward to define, though they are +arguably more powerful. These properties don't have a specific value type, instead, +you can choose any type of value, provided the values are from a closed set. To make +that actionable, you give string labels to each of the acceptable values, and the user +will provide one of those labels as a value in the XML. The property will give you back +the associated value, not the label. Here's an example: ```java static Map map = new HashMap<>(); @@ -94,24 +109,25 @@ static { map.put("hardMode", new HardStrategy()); } -static EnumeratedProperty modeProperty - = EnumeratedProperty.named("modeProperty") - .desc("This is my property") - .defaultValue(new EasyStrategy()) - .mappings(map) - .type(ModeStrategy.class) - .build(); +static PropertyDescriptor modeProperty + = PropertyFactory.enumProperty("modeProperty", map) + .desc("This is my property") + .defaultValue(new EasyStrategy()) + .build(); ``` -Note that you're required to fill in the type of the values too, using `type()`. - ### Example -You can see an example of properties used in a PMD rule [here](https://github.com/pmd/pmd/blob/ac2ff0f6af8d16f739584ba8d00b7ea1a6311ccc/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/complexity/AvoidDeeplyNestedIfStmtsRule.java#L17). +You can see an example of properties used in a PMD rule [here](https://github.com/pmd/pmd/blob/5d86217871f086f8223da327099d1d67a6e45dab/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java#L41-L42). There are several things to notice here: -* The property descriptor is declared `static final`, which should generally be the case, as descriptors are immutable and can be shared between instances of the same rule; -* The property is declared using `definePropertyDescriptor` *in the constructor*, which ensures the property gets recognised by PMD; -* The value of the property is *not retrieved in the constructor*, but in one of the `visit` methods (typically on the highest node in the tree, since the property doesn't change). +* The property descriptors are declared `static final`, which should generally be +the case, as descriptors are immutable and can be shared between instances of the same rule; +* The property is declared using {% jdoc props::PropertySource#definePropertyDescriptor(props::PropertyDescriptor) %}` *in the constructor*, +which ensures the property gets recognised by PMD at the time the properties +are overridden (which happens before rule execution); +* The value of the property is *not retrieved in the constructor*, but in one of +the `visit` methods (typically on the highest node in the tree, since the property +doesn't change). @@ -119,21 +135,28 @@ There are several things to notice here: XPath rules can also define their own properties. To do so, you must add a `property` element in the `properties` element of your rule, which **declares the `type` attribute**. This attribute conditions what type the underlying property has, and can have the following values: -| `type` attribute | Property type| +| `type` attribute | XSD type |----------|----------| -|Integer|IntegerProperty -|Double | DoubleProperty -|Float|FloatProperty -|Long| LongProperty -|String|StringProperty -|Character|CharacterProperty -|Boolean|BooleanProperty -|Class|TypeProperty -|Regex|RegexProperty +|Integer | xs:integer +|Long | xs:integer +|Double | xs:decimal +|Boolean | xs:boolean +|String | xs:string +|Character| xs:string +|Regex | xs:string + +{% include note.html + content="In XPath 1.0 mode, all values are actually represented as + string values, which is mostly fine as there is no type + checking. This is a problem when [migrating from XPath 1.0 + to 2.0](pmd_userdocs_extending_writing_xpath_rules.html#migrating-from-10-to-20) though" %} + Note that enumerated properties are not available in XPath rules (yet?). -Properties defined in XPath also *must* declare the `description` attribute. Numeric properties also expect the `min` and `max` attributes. Here are a few examples to sum it up: +Properties defined in XPath also *must* declare the `description` attribute. +Numeric properties also expect the `min` and `max` attributes for now. Here are +a few examples to sum it up: ```xml @@ -157,7 +180,12 @@ You can then use the property in XPath with the syntax `$propertyName`, for exam ### Multivalued properties -Multivalued properties are also allowed and their `type` attribute has the form `List[Boolean]` or `List[Character]`, with every above type allowed. These properties **require XPath 2.0** to work properly, and make use of the **sequence datatype** provided by that language. You thus need to set the `version` property to `2.0` to use them. Properties can also declare the `delimiter` attribute. +Multivalued properties are also allowed and their `type` attribute has the form +`List[Boolean]` or `List[Character]`, with every above type allowed. These +properties **require XPath 2.0** to work properly, and make use of the +**sequence datatype** provided by that language. You thus need to set the +`version` property to `2.0` to use them. Properties can also declare the +`delimiter` attribute. @@ -176,5 +204,9 @@ Multivalued properties are also allowed and their `type` attribute has the form ``` -Notice that in the example above, `@Image = $reportedIdentifiers` doesn't test `@Image` for equality with the whole sequence `('foo', 'bar')`, it tests whether the sequence *contains* `@Image`. That is, the above rule will report all variables named `foo` or `bar`. All other XPath 2.0 [functions operating on sequences](https://www.w3.org/TR/xpath-functions/#sequence-functions) are supported. +Notice that in the example above, `@Image = $reportedIdentifiers` doesn't test +`@Image` for equality with the whole sequence `('foo', 'bar')`, it tests whether +the sequence *contains* `@Image`. That is, the above rule will report all variables +named `foo` or `bar`. All other XPath 2.0 [functions operating on sequences](https://www.w3.org/TR/xpath-functions/#sequence-functions) +are supported. diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index 00450b1dff..8824768156 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -19,6 +19,8 @@ also [the tutorial about how to write an XPath rule](pmd_userdocs_extending_desi + + ## XPath version PMD supports three XPath versions for now: 1.0, 2.0, and 1.0 compatibility mode. @@ -86,8 +88,8 @@ On XPath 2.0, the namespace of custom PMD function must be explicitly mentioned. {% include custom/xpath_fun_doc.html %} {% endrender %} -There is also a `typeOf` function which is deprecated and whose usages -should be replaced with uses of `typeIs` or `typeIsExactly`. That one will -be removed with PMD 7.0.0. +{% include note.html content='There is also a `typeOf` function which is +deprecated and whose usages should be replaced with uses of `typeIs` or +`typeIsExactly`. That one will be removed with PMD 7.0.0.' %} From 6fcc57db81a76aff9541f603743787402b83599d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 6 Mar 2019 04:26:26 +0100 Subject: [PATCH 036/235] Delete a bunch of useless guidelines --- .../pmd/userdocs/extending/rule_guidelines.md | 39 +------------------ 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/rule_guidelines.md b/docs/pages/pmd/userdocs/extending/rule_guidelines.md index c01423b3d1..c01e8ca4f1 100644 --- a/docs/pages/pmd/userdocs/extending/rule_guidelines.md +++ b/docs/pages/pmd/userdocs/extending/rule_guidelines.md @@ -1,15 +1,12 @@ --- title: Rule guidelines tags: [extending, userdocs] -summary: Rule Guidelines +summary: "Rule Guidelines, or the last touches to a rule" last_updated: July 3, 2016 permalink: pmd_userdocs_extending_rule_guidelines.html author: Xavier Le Vourch, Ryan Gustafson, Romain Pelisse --- -# Rule Guidelines - -Or - Last touches to a rules Here is a bunch of thing to do you may consider once your rule is “up and running”. @@ -25,15 +22,6 @@ Rule priority may, of course, changes a lot depending on the context of the proj For instance, let’s take the ExplicitCallToGC rule (“Do not explicitly trigger a garbage collection.”). Calling GC is a bad idea, but it doesn’t break the application. So we skip priority one. However, as explicit call to gc may really hinder application performances, we set for the priority 2. -## Code formatting - -We try to keep a consistent code formatting through out PMD code base to ensure an easier maintenance and also make -the pull request as readable as possible. - -In order to ensure this, we use a PMD specific Eclipse formatter configuration, which is maintained in a -separate project - "build-tools": [eclipse-code-formatter.xml](https://github.com/pmd/build-tools/blob/master/eclipse/pmd-eclipse-code-formatter.xml). -Please do not forget to use it before committing or any source code! - ## Correctness You should try to run the rule on a large code base, like the jdk source code for instance. This will help ensure that the rule does not raise exceptions when dealing with unusual constructs. @@ -47,28 +35,3 @@ When writing a new rule, using command line option “-benchmark” on a few rul Rules which use the RuleChain to visit the AST are faster than rules which perform manual visitation of the AST. The difference is small for an individual Java rule, but when running 100s of rules, it is measurable. For XPath rules, the difference is extremely noticeable due to Jaxen overhead for AST navigation. Make sure your XPath rules using the RuleChain. (TODO How does one know except by running in a debugger or horrendous performance?). - -## Adding test cases - -See [Testing your rules](pmd_userdocs_extending_testing.html) for the general documentation - -### … for a rule I want to submit (in a patch) - -Figure out the category to which you want to the rule. Then add your rule to the appropriate test class for -the category and add the XML test data in the correct xml subpackage. - -### … for something too specific, that I won’t be able to submit - -See [Using the test framework externally](pmd_userdocs_extending_testing.html#using-the-test-framework-externally) - -## Code quality - -If you want to contribute a java rule to PMD, you should run PMD on it (Using the dogfood rulesets), to ensure that you rule follow the rules defined by the PMD community. - -Also note, that if this is not a strong policy, most developers uses the berkeley braces syntax. - -## Committing - -Before committing changes, make sure the verify phase of a maven build succeeds without test failures. Drink a beer while you wait for it to finish. - -Then read the output to make sure no fatal errors are present. From 9adea8b166bdf2f98959ea62b896b89be3f5cf06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 6 Mar 2019 05:16:32 +0100 Subject: [PATCH 037/235] Start working on java rules --- docs/_data/sidebars/pmd_sidebar.yml | 3 + .../pmd/userdocs/extending/designer_intro.md | 3 + .../userdocs/extending/writing_java_rules.md | 265 ++++++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 docs/pages/pmd/userdocs/extending/writing_java_rules.md diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index a3cc8c24a4..78c9fdadd1 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -73,6 +73,9 @@ entries: - title: Writing XPath rules url: /pmd_userdocs_extending_writing_xpath_rules.html output: web, pdf + - title: Writing Java rules + url: /pmd_userdocs_extending_writing_java_rules.html + output: web, pdf - title: Rule designer reference url: /pmd_userdocs_extending_designer_reference.html output: web, pdf diff --git a/docs/pages/pmd/userdocs/extending/designer_intro.md b/docs/pages/pmd/userdocs/extending/designer_intro.md index 1bfa5fee36..babe31139a 100644 --- a/docs/pages/pmd/userdocs/extending/designer_intro.md +++ b/docs/pages/pmd/userdocs/extending/designer_intro.md @@ -55,6 +55,9 @@ The basic development process is straightforward: it matches violation cases, but no other node 5. Export your XPath expression to an XML rule element, and place it in your ruleset +Each time you test your rule against a different snippet, it's a good idea to +save it to [make test cases](pmd_userdocs_extending_testing.html). + In the following sections, we walk through several examples to refine your rule. ## A simple rule diff --git a/docs/pages/pmd/userdocs/extending/writing_java_rules.md b/docs/pages/pmd/userdocs/extending/writing_java_rules.md new file mode 100644 index 0000000000..7bcdde04a3 --- /dev/null +++ b/docs/pages/pmd/userdocs/extending/writing_java_rules.md @@ -0,0 +1,265 @@ +--- +title: Writing a custom rule +tags: [extending, userdocs] +summary: "Learn how to write a custom rule for PMD" +last_updated: July 3, 2016 +permalink: pmd_userdocs_extending_writing_java_rules.html +author: Tom Copeland +--- + +{% jdoc_nspace :coremx core::lang.metrics %} +{% jdoc_nspace :coreast core::lang.ast %} +{% jdoc_nspace :jmx java::lang.java.metrics %} +{% jdoc_nspace :jast java::lang.java.ast %} +{% jdoc_nspace :jrule java::lang.java.rule %} + +This page covers the specifics of writing a rule in Java. The basic development +process is very similar to the process for XPath rules, which is described in +[Using the Designer](pmd_userdocs_extending_designer_intro.html#rule-development-process). + +Basically, you open the designer, look at the structure of the AST, and refine +your rule as you add test cases. + +All rules ultimately implement the interface {% jdoc core::Rule %}. Each +language implementation provides a specific base rule class to ease your pain, +e.g. {% jdoc jrule::AbstractJavaRule %}. + +In this page we'll talk about rules for the Java language, but the process is +very similar for other languages. + +## Rule instantiation + +Rules need to define a no-arg constructor, that will be + +## Rule execution + +### Tree traversal + +When a rule is applied to a file, it's handed the root of the AST and told +to traverse all the tree to look for violations. Each rule defines a specific +`visit` method for each type of node that can be found in the Java AST, which +by default just visits the children. + +So the following rule would traverse the whole tree and do nothing: + +```java +public class MyRule extends AbstractJavaRule { + // all methods are default implementations! +} +``` + +Generally, a rule wants to check for only some node types. In our XPath example +in [Using the Designer](pmd_userdocs_extending_designer_intro.html#a-simple-rule), +we wanted to check for some `VariableDeclaratorId` nodes. That's the XPath name, +but in Java, you'll get access to the {% jdoc jast::ASTVariableDeclaratorId %} +full API. + +If you want to check for some specific node types, you can override the +corresponding `visit` method: + +```java +public class MyRule extends AbstractJavaRule { + + @Override + public Object visit(ASTVariableDeclaratorId node, Object data) { + // This method is called on each node of type ASTVariableDeclaratorId + // in the AST + + + return super.visit(node, data); + } +} +``` + +The `super.visit(node, data)` call is super common in rule implementations, +because it makes the traversal continue by visiting all the descendants of the +current node. + +#### Stopping the traversal + +Sometimes you have checked all you needed and you're sure that the descendants +of a node may not contain violations. In that case, you can avoid calling the +`super` implementation and the traversal will not continue further down. This +means that your callbacks (`visit` implementations) won't be called on the rest +of the subtree. The siblings of the current node may be visited +recursively nevertheless. + +#### Economic traversal: the rulechain + +If you don't care about the order in which the nodes are traversed (e.g. your +rule doesn't maintain any state between visits), then you can monumentally +speed-up your rule by using the **rulechain**. + +That mechanism doesn't recurse on all the tree, instead, your rule will only be +passed the nodes it is interested in. To use the rulechain correctly: +* Your rule must register those node types by calling {% jdoc core::Rule#addRuleChainVisit(java.lang.Class) %} +in its constructor. +* Your visit methods **must not recurse!** In effect, you should call never +call `super.visit` in the methods. + +### Execution across files, thread-safety and statefulness + +When starting execution, PMD will instantiate a new instance of your rule. +If PMD is executed in multiple threads, then each thread is using its own +instance of the rule. This means, that the rule implementation **does not need to care about +threading issues**, as PMD makes sure, that a single instance is not used concurrently +by multiple threads. + +However, for performance reasons, the rule instances are used for multiple files. +This means, that the constructor of the rule is only executed once (per thread) +and the rule instance is reused. If you rely on a proper initialization of instance +properties, you can do the initialization e.g. in the visit-method of the {% jdoc jast::ASTCompilationUnit %} +node - which is visited first and only once per file. However, this +solution would only work for rules written for the Java language. A language +independent way is to override the method `apply` of the rule (and call super). +The apply method is called exactly once per file. + + + + + + + +## Put the WhileLoopsMustUseBracesRule rule in a ruleset file + +Now our rule is written - at least, the shell of it is - and now we need to tell PMD about it. We need to add it to a ruleset XML file. Look at `pmd-java/src/main/resources/category/java/bestpractices.xml`; it’s got lots of rule definitions in it. Copy and paste one of these rules into a new ruleset - call it `mycustomrules.xml` or something. Then fill in the elements and attributes: + +* name - WhileLoopsMustUseBracesRule +* message - Use braces for while loops +* class - Wherever you put the rule. Note this doesn’t have to be in `net.sourceforge.pmd`; it can be in `com.yourcompany.util.pmd` or whereever you want +* description - Use braces for while loops +* example - A little code snippet in CDATA tags that shows a rule violation + +The whole ruleset file should look something like this: + +```xml + + + + + Avoid using 'while' statements without using curly braces + + 3 + + + + + + +``` + +## Run PMD using your new ruleset + +OK, let’s run the new rule so we can see something work. Like this: + +```DOS +pmd.bat c:\path\to\my\src xml c:\path\to\mycustomrules.xml +``` + + +This time your “hello world” will show up right after the AST gets printed out. If it doesn’t, post a message to [the forum](http://sourceforge.net/p/pmd/discussion/188192) so we can improve this document :-) + +## Write code to add rule violations where appropriate + +Now that we’ve identified our problem, recognized the AST pattern that illustrates the problem, written a new rule, and plugged it into a ruleset, we need to actually make our rule find the problem, create a `RuleViolation`, and put it in the `Report`, which is attached to the `RuleContext`. Like this: + +```java +import net.sourceforge.pmd.lang.ast.*; +import net.sourceforge.pmd.lang.java.ast.*; +import net.sourceforge.pmd.lang.java.rule.*; + +public class WhileLoopsMustUseBracesRule extends AbstractJavaRule { + public Object visit(ASTWhileStatement node, Object data) { + Node firstStmt = node.jjtGetChild(1); + if (!hasBlockAsFirstChild(firstStmt)) { + addViolation(data, node); + } + return super.visit(node,data); + } + private boolean hasBlockAsFirstChild(Node node) { + return (node.jjtGetNumChildren() != 0 && (node.jjtGetChild(0) instanceof ASTBlock)); + } +} +``` + +## I need some kind of Type Resolution for my rule! + +### Inside an XPath query + +PMD's XPath extensions include two functions called `typeIs` and `typeIsExactly`, +which determine if a node is of a specific type (either any subtype or exactly, +respectively). + +Here a an example of use, inside an XPath query: + +```ruby +//ClassOrInterfaceDeclaration/ExtendsList/ClassOrInterfaceType[typeIs('junit.framework.TestCase')] +``` + +This query will for instance match the following class declaration: + +```java +import junit.framework.TestCase; + +public class Foo extends TestCase { } +``` + +It will also match against classes which extend a *subtype* of `junit.framework.TestCase`, +i.e. a base class itself extending `TestCase` transitively. If you don't want this behaviour, +then use `typeIsExactly` instead of `typeIs`. + +Checking against an array type is possible with the double bracket syntax. +An array type is denoted by just appending `[]` to the fully qualified class name +of the component type. These can be repeated for arrays of arrays +(e.g. `byte[][]` or `java.lang.String[]`). + + +### With Java code + +Below an other sample of use of type resolution inside a java code: + +```java +/** + * A simple to detect the use of the class 'com.forbidden.class'. + */ +@SuppressWarnings("unchecked") +public Object visit(ASTClassOrInterfaceType type, Object ruleCtx) { + Class clazz = type.getType(); + if ("com.forbidden.class".equals(clazz.getName())) { + addViolation(ruleCtx,type); + } + return super.visit(type, ruleCtx); +} +```` + +>Note, that this will only work, if the auxiliary classpath for PMD is setup correctly, so that PMD can actually find the (compiled) class “com.forbidden.class” and you get the actual Class instance by calling getType(). + +Otherwise, you’ll have to string-compare the image, e.g. `"com.forbidden.class".equals(node.getImage())` + +## Thread safety, concurrency issues and reuse of rule instances + +## Bundle it up + +To use your rules as part of a nightly build or whatever, it’s helpful to bundle up both the rule and the ruleset.xml file in a jar file. Then you can put that jar file on the CLASSPATH of your build. Setting up a script or an Ant task to do this can save you some tedious typing. + +## Repeat as necessary + +I’ve found that my rules usually don’t work the first time, and so I have to go back and tweak them a couple times. That’s OK, if we were perfect programmers PMD would be useless anyhow :-). + +As an acceptance test of sorts, I usually run a rule on the JDK 1.4 source code and make sure that a random sampling of the problems found are in fact legitimate rule violations. This also ensures that the rule doesn’t get confused by nested inner classes or any of the other oddities that appear at various points in the JDK source. + +You’re rolling now. If you think a rule would benefit the Java development community as a whole, post a message to [the forum](http://sourceforge.net/p/pmd/discussion/188192) so we can get the rule moved into one of the core rulesets. + +Or, if you can improve one of the existing rules, that’d be great too! Thanks! + +Finally, for many more details on writing rules, pick up [PMD Applied](http://pmdapplied.com/)! From 465dca240cad8c19a70a1790d5b9b14764aace50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 6 Mar 2019 10:05:46 +0100 Subject: [PATCH 038/235] Document rule lifecycle --- .../userdocs/extending/writing_java_rules.md | 56 +++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/writing_java_rules.md b/docs/pages/pmd/userdocs/extending/writing_java_rules.md index 7bcdde04a3..e76ad984da 100644 --- a/docs/pages/pmd/userdocs/extending/writing_java_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_java_rules.md @@ -13,6 +13,8 @@ author: Tom Copeland {% jdoc_nspace :jast java::lang.java.ast %} {% jdoc_nspace :jrule java::lang.java.rule %} +{% include note.html content="All that should be written in the Javadocs.." %} + This page covers the specifics of writing a rule in Java. The basic development process is very similar to the process for XPath rules, which is described in [Using the Designer](pmd_userdocs_extending_designer_intro.html#rule-development-process). @@ -27,10 +29,6 @@ e.g. {% jdoc jrule::AbstractJavaRule %}. In this page we'll talk about rules for the Java language, but the process is very similar for other languages. -## Rule instantiation - -Rules need to define a no-arg constructor, that will be - ## Rule execution ### Tree traversal @@ -118,6 +116,56 @@ The apply method is called exactly once per file. +## Rule lifecycle reference + +### Construction + +Exactly once: + +1. The rule's no-arg constructor is called when loading the ruleset. +The rule's constructor must define: + * [Rulechain visits](#economic-traversal-the-rulechain) + * [Property descriptors](pmd_userdocs_extending_defining_properties#for-java-rules) +2. If the rule was included in the ruleset as a rule reference, +some properties [may be overridden](pmd_userdocs_configuring_rules.html#rule-properties). +If an overridden property is unknown, an error is reported. +3. Misconfigured rules are removed from the ruleset + +### Execution + +For each thread, a deep copy of the rule is created. +Then, for each thread, for each analysed file: + +3. {% jdoc core::Rule#start(core::RuleContext) %} is called once, before parsing +4. {% jdoc core::Rule#apply(java.util.List,core::RuleContext) %} is called with the root +of the AST. That method performs the AST traversal that ultimately calls visit methods. +It's not called for RuleChain rules. +5. {% jdoc core::Rule#end(core::RuleContext) %} is called when the rule is done processing +the file + +### FIXME + +without specific order: +* There's no hook for "after construction", or "after analysis" we only have "before file" +and "after file" +* What's the point of having `Rule#start` ? The globally accepted pattern is to override +the visit method for the root node. We have `visit()`, `apply`, and `start` +that are called at the same lifecycle point... +* Rule#apply is not called for RuleChain visits +* Why is Rule#apply overridable? Anyone can break it +* Sooo much code is duplicated everywhere in rulechain visitor implementations, which are +all the same modulo a cast... +* Converting a rule to the rulechain shouldn't force removing `super.visit` calls... We +could just provide a base class for rulechain rules that overrides eg `visit(JavaNode)` +to be a noop +* RuleSets is unnecessary, we should just rely on a good RuleSet implementation +* Initializer.initialize() is called for each file instead of once per language module loading +* For each file all the rules in all rulesets are checked to use typeres or other +analysis passes + + + + ## Put the WhileLoopsMustUseBracesRule rule in a ruleset file From 43680dee4a841f901362cee306ff6af6f7a154e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 6 Mar 2019 20:21:49 +0100 Subject: [PATCH 039/235] Remove useless stuff --- .../userdocs/extending/writing_java_rules.md | 152 +----------------- .../userdocs/extending/writing_pmd_rules.md | 3 + 2 files changed, 6 insertions(+), 149 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/writing_java_rules.md b/docs/pages/pmd/userdocs/extending/writing_java_rules.md index e76ad984da..3a32b5d080 100644 --- a/docs/pages/pmd/userdocs/extending/writing_java_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_java_rules.md @@ -13,7 +13,9 @@ author: Tom Copeland {% jdoc_nspace :jast java::lang.java.ast %} {% jdoc_nspace :jrule java::lang.java.rule %} -{% include note.html content="All that should be written in the Javadocs.." %} +{% include note.html content="TODO All that should be written in the Javadocs, +not sure we even need a doc page. Would be simpler to maintain too" %} +{% include warning.html content="WIP lots of stuff missing" %} This page covers the specifics of writing a rule in Java. The basic development process is very similar to the process for XPath rules, which is described in @@ -163,151 +165,3 @@ to be a noop * For each file all the rules in all rulesets are checked to use typeres or other analysis passes - - - - - -## Put the WhileLoopsMustUseBracesRule rule in a ruleset file - -Now our rule is written - at least, the shell of it is - and now we need to tell PMD about it. We need to add it to a ruleset XML file. Look at `pmd-java/src/main/resources/category/java/bestpractices.xml`; it’s got lots of rule definitions in it. Copy and paste one of these rules into a new ruleset - call it `mycustomrules.xml` or something. Then fill in the elements and attributes: - -* name - WhileLoopsMustUseBracesRule -* message - Use braces for while loops -* class - Wherever you put the rule. Note this doesn’t have to be in `net.sourceforge.pmd`; it can be in `com.yourcompany.util.pmd` or whereever you want -* description - Use braces for while loops -* example - A little code snippet in CDATA tags that shows a rule violation - -The whole ruleset file should look something like this: - -```xml - - - - - Avoid using 'while' statements without using curly braces - - 3 - - - - - - -``` - -## Run PMD using your new ruleset - -OK, let’s run the new rule so we can see something work. Like this: - -```DOS -pmd.bat c:\path\to\my\src xml c:\path\to\mycustomrules.xml -``` - - -This time your “hello world” will show up right after the AST gets printed out. If it doesn’t, post a message to [the forum](http://sourceforge.net/p/pmd/discussion/188192) so we can improve this document :-) - -## Write code to add rule violations where appropriate - -Now that we’ve identified our problem, recognized the AST pattern that illustrates the problem, written a new rule, and plugged it into a ruleset, we need to actually make our rule find the problem, create a `RuleViolation`, and put it in the `Report`, which is attached to the `RuleContext`. Like this: - -```java -import net.sourceforge.pmd.lang.ast.*; -import net.sourceforge.pmd.lang.java.ast.*; -import net.sourceforge.pmd.lang.java.rule.*; - -public class WhileLoopsMustUseBracesRule extends AbstractJavaRule { - public Object visit(ASTWhileStatement node, Object data) { - Node firstStmt = node.jjtGetChild(1); - if (!hasBlockAsFirstChild(firstStmt)) { - addViolation(data, node); - } - return super.visit(node,data); - } - private boolean hasBlockAsFirstChild(Node node) { - return (node.jjtGetNumChildren() != 0 && (node.jjtGetChild(0) instanceof ASTBlock)); - } -} -``` - -## I need some kind of Type Resolution for my rule! - -### Inside an XPath query - -PMD's XPath extensions include two functions called `typeIs` and `typeIsExactly`, -which determine if a node is of a specific type (either any subtype or exactly, -respectively). - -Here a an example of use, inside an XPath query: - -```ruby -//ClassOrInterfaceDeclaration/ExtendsList/ClassOrInterfaceType[typeIs('junit.framework.TestCase')] -``` - -This query will for instance match the following class declaration: - -```java -import junit.framework.TestCase; - -public class Foo extends TestCase { } -``` - -It will also match against classes which extend a *subtype* of `junit.framework.TestCase`, -i.e. a base class itself extending `TestCase` transitively. If you don't want this behaviour, -then use `typeIsExactly` instead of `typeIs`. - -Checking against an array type is possible with the double bracket syntax. -An array type is denoted by just appending `[]` to the fully qualified class name -of the component type. These can be repeated for arrays of arrays -(e.g. `byte[][]` or `java.lang.String[]`). - - -### With Java code - -Below an other sample of use of type resolution inside a java code: - -```java -/** - * A simple to detect the use of the class 'com.forbidden.class'. - */ -@SuppressWarnings("unchecked") -public Object visit(ASTClassOrInterfaceType type, Object ruleCtx) { - Class clazz = type.getType(); - if ("com.forbidden.class".equals(clazz.getName())) { - addViolation(ruleCtx,type); - } - return super.visit(type, ruleCtx); -} -```` - ->Note, that this will only work, if the auxiliary classpath for PMD is setup correctly, so that PMD can actually find the (compiled) class “com.forbidden.class” and you get the actual Class instance by calling getType(). - -Otherwise, you’ll have to string-compare the image, e.g. `"com.forbidden.class".equals(node.getImage())` - -## Thread safety, concurrency issues and reuse of rule instances - -## Bundle it up - -To use your rules as part of a nightly build or whatever, it’s helpful to bundle up both the rule and the ruleset.xml file in a jar file. Then you can put that jar file on the CLASSPATH of your build. Setting up a script or an Ant task to do this can save you some tedious typing. - -## Repeat as necessary - -I’ve found that my rules usually don’t work the first time, and so I have to go back and tweak them a couple times. That’s OK, if we were perfect programmers PMD would be useless anyhow :-). - -As an acceptance test of sorts, I usually run a rule on the JDK 1.4 source code and make sure that a random sampling of the problems found are in fact legitimate rule violations. This also ensures that the rule doesn’t get confused by nested inner classes or any of the other oddities that appear at various points in the JDK source. - -You’re rolling now. If you think a rule would benefit the Java development community as a whole, post a message to [the forum](http://sourceforge.net/p/pmd/discussion/188192) so we can get the rule moved into one of the core rulesets. - -Or, if you can improve one of the existing rules, that’d be great too! Thanks! - -Finally, for many more details on writing rules, pick up [PMD Applied](http://pmdapplied.com/)! diff --git a/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md b/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md index aaf3d6c22c..1919e1c039 100644 --- a/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md @@ -7,6 +7,9 @@ permalink: pmd_userdocs_extending_writing_pmd_rules.html author: Tom Copeland --- + +{% include warning.html content="This is going away" %} + # How to write a PMD rule Writing PMD rules is cool because you don’t have to wait for us to get around to implementing feature requests. From f496ce8be7b2a7f3c419db94b3c31bc9ed884dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 5 Apr 2019 11:43:07 +0200 Subject: [PATCH 040/235] Make xpath fun rows expandable --- docs/_includes/custom/xpath_fun_doc.html | 18 ++++++++++++++++-- docs/css/pmd-customstyles.css | 5 +++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/_includes/custom/xpath_fun_doc.html b/docs/_includes/custom/xpath_fun_doc.html index e65392ab97..1fe1ca896d 100644 --- a/docs/_includes/custom/xpath_fun_doc.html +++ b/docs/_includes/custom/xpath_fun_doc.html @@ -1,10 +1,12 @@ {% for lang in site.data.xpath_funs.langs %} + + ### {{ lang.name }} {{ lang.name }} functions are in the namespace `{{ lang.ns }}`. -
+
@@ -19,7 +21,9 @@ {% for fun in lang.funs %} - + {% capture fun_id %}{{ lang.ns | append: '-' | append: fun.name | pp }}{% endcapture %} + + + + + + + {% endfor %}
{{ fun.name }} @@ -48,6 +52,16 @@
+
+

{{ fun.name }}

+

This is a fun function

+
+
diff --git a/docs/css/pmd-customstyles.css b/docs/css/pmd-customstyles.css index 2738de8db1..db83a50f50 100644 --- a/docs/css/pmd-customstyles.css +++ b/docs/css/pmd-customstyles.css @@ -52,3 +52,8 @@ details[open] summary { background-color: #347DBE; color: white; } + + +.hiddenRow { + padding: 0 !important; +} From 7573fd94d988151bb9f7e6406e3735b42eee6e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 5 Apr 2019 14:13:39 +0200 Subject: [PATCH 041/235] Use expandable row for xpath funs --- docs/_data/xpath_funs.yml | 25 ++++-- docs/_includes/custom/xpath_fun_doc.html | 98 ++++++++++++++++-------- docs/_plugins/custom_filters.rb | 31 ++++---- docs/css/pmd-customstyles.css | 24 ++++++ 4 files changed, 126 insertions(+), 52 deletions(-) diff --git a/docs/_data/xpath_funs.yml b/docs/_data/xpath_funs.yml index 404e749726..07f70a472f 100644 --- a/docs/_data/xpath_funs.yml +++ b/docs/_data/xpath_funs.yml @@ -1,27 +1,36 @@ +aliases: + - &qname_param + name: javaQualifiedName + type: "xs:string" + description: "The qualified name of a class, possibly with pairs of brackets to indicate an array type. + Can also be a primitive type name." + - &needs_typenode "The context node must be a {% jdoc jast::TypeNode %}" + langs: - name: "Java" ns: "pmd-java" funs: - name: typeIs returnType: "xs:boolean" + shortDescription: "Tests a node's static type" description: "Returns true if the context node's static type is a subtype of the given type" - notes: "The context node must be a {% jdoc jast::TypeNode %}" + notes: *needs_typenode parameters: - - name: javaQualifiedName - type: "xs:string" - description: "the qualified name of a class, possibly with pairs of brackets to indicate an array type. - Can also be a primitive type name." + - *qname_param - name: typeIsExactly returnType: "xs:boolean" + shortDescription: "Tests a node's static type, ignoring subtypes" description: "Returns true if the context node's static type is exactly the given type. In particular, returns false if the context node's type is a subtype of the given type." - notes_are_same_as: typeIs - params_are_same_as: typeIs + notes: *needs_typenode + parameters: + - *qname_param - name: metric returnType: "xs:decimal?" + shortDescription: "Computes and returns the value of a metric" description: "Returns the value of the metric as evaluated on the context node" notes: "The context node must be a {% jdoc jast::ASTAnyTypeDeclaration %} or a {% jdoc jast::MethodLikeNode %}" parameters: @@ -35,4 +44,4 @@ langs: - code: '//VariableDeclaratorId[pmd-java:typeIs("java.lang.List")]' outcome: "Matches variable declarators of type `List` or any of its subtypes (including e.g. `ArrayList`)" - code: '//VariableDeclaratorId[pmd-java:typeIsExactly("java.lang.List")]' - outcome: "Matches variable declarators of type `List` (but not e.g. `ArrayList`)" \ No newline at end of file + outcome: "Matches variable declarators of type `List` (but not e.g. `ArrayList`)" diff --git a/docs/_includes/custom/xpath_fun_doc.html b/docs/_includes/custom/xpath_fun_doc.html index 1fe1ca896d..e56f97b9ef 100644 --- a/docs/_includes/custom/xpath_fun_doc.html +++ b/docs/_includes/custom/xpath_fun_doc.html @@ -6,57 +6,93 @@ {{ lang.name }} functions are in the namespace `{{ lang.ns }}`. -
- +
+
- - + {% for fun in lang.funs %} - {% capture fun_id %}{{ lang.ns | append: '-' | append: fun.name | pp }}{% endcapture %} + {% capture fun_id %}{{ lang.ns | append: '-' | append: fun.name }}{% endcapture %} - + + - - diff --git a/docs/_plugins/custom_filters.rb b/docs/_plugins/custom_filters.rb index 922071297c..2b3067e21a 100644 --- a/docs/_plugins/custom_filters.rb +++ b/docs/_plugins/custom_filters.rb @@ -44,16 +44,23 @@ module CustomFilters end + def xpath_fun_type(fun_yaml) + + res = '(' + + params = fun_yaml['parameters'] + + res += params.map {|it| it['type']}.join(', ') if params + + res + ') as ' + fun_yaml['returnType'] + end + def regex_replace(str, regex, subst) - if str && regex - str.gsub(Regexp::new(regex), subst || "") - end + str.gsub(Regexp.new(regex), subst || '') if str && regex end def regex_split(str, regex = nil) - if str - str.split(regex && Regexp::new(regex)) - end + str.split(regex && Regexp.new(regex)) if str end # Takes an array of strings and maps every element x to {{ x | append: suffix }} @@ -63,9 +70,7 @@ module CustomFilters # Returns the initial argument only if the second argument is truthy def keep_if(any, test) - if test - any - end + any if test end # Append the suffix only if the condition argument is truthy @@ -100,9 +105,9 @@ module CustomFilters def flatten_rec(seq) seq.map {|h| - if (subs = h["folderitems"] || h["subfolderitems"] || h["subfolders"]) + if (subs = h['folderitems'] || h['subfolderitems'] || h['subfolders']) flatten_rec(subs).flatten - elsif (page = h["url"]) + elsif (page = h['url']) page end }.flatten @@ -110,10 +115,10 @@ module CustomFilters def rank_lookup_from_sidebar(sidebar) - folders = sidebar["entries"][0]["folders"] + folders = sidebar['entries'][0]['folders'] ordered = flatten_rec(folders).select {|url| - url && url.end_with?(".html") + url && url.end_with?('.html') } Hash[ordered.zip (0...ordered.size)] diff --git a/docs/css/pmd-customstyles.css b/docs/css/pmd-customstyles.css index db83a50f50..ae1bfcd073 100644 --- a/docs/css/pmd-customstyles.css +++ b/docs/css/pmd-customstyles.css @@ -57,3 +57,27 @@ details[open] summary { .hiddenRow { padding: 0 !important; } + +.xpath-fun-doc .fun-name { + font-weight: bold; +} + +.xpath-fun-doc .fun-details-header { + font-family: monospace; + font-size: larger; +} + +.xpath-fun-doc .fun-ns { + color: darkgray; +} + +.xpath-fun-doc span.param-name { + font-weight: normal; + +} + +.xpath-fun-doc span.param-type { + font-weight: lighter; + font-style: italic; + color: darkgray; +} From abe26203d5f47e0deeb859e5e08d5c6dc9764251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 7 Apr 2019 18:00:02 +0200 Subject: [PATCH 042/235] Add examples --- docs/_data/xpath_funs.yml | 25 +++++---- docs/_includes/custom/xpath_fun_doc.html | 51 +++++++------------ docs/css/pmd-customstyles.css | 3 ++ .../userdocs/extending/writing_xpath_rules.md | 5 +- 4 files changed, 37 insertions(+), 47 deletions(-) diff --git a/docs/_data/xpath_funs.yml b/docs/_data/xpath_funs.yml index 07f70a472f..2b56bfb2bf 100644 --- a/docs/_data/xpath_funs.yml +++ b/docs/_data/xpath_funs.yml @@ -2,7 +2,7 @@ aliases: - &qname_param name: javaQualifiedName type: "xs:string" - description: "The qualified name of a class, possibly with pairs of brackets to indicate an array type. + description: "The qualified name of a Java class, possibly with pairs of brackets to indicate an array type. Can also be a primitive type name." - &needs_typenode "The context node must be a {% jdoc jast::TypeNode %}" @@ -13,10 +13,19 @@ langs: - name: typeIs returnType: "xs:boolean" shortDescription: "Tests a node's static type" - description: "Returns true if the context node's static type is a subtype of the given type" + description: "Returns true if the context node's static Java type is a subtype of the given type. + This tests for the resolved type of the Java construct, not the type of the AST node. + For example, the AST node for a literal (e.g. `5d`) has type ASTLiteral, however this + function will compare the type of the literal (eg here, `double`) against the argument." notes: *needs_typenode parameters: - *qname_param + examples: + - code: '//FormalParameter[pmd-java:typeIs("java.lang.String[]")]' + outcome: "Matches formal parameters of type `String[]` (including vararg parameters)" + - code: '//VariableDeclaratorId[pmd-java:typeIs("java.lang.List")]' + outcome: "Matches variable declarators of type `List` or any of its subtypes (including e.g. `ArrayList`)" + - name: typeIsExactly returnType: "xs:boolean" @@ -27,6 +36,10 @@ langs: notes: *needs_typenode parameters: - *qname_param + examples: + - code: '//VariableDeclaratorId[pmd-java:typeIsExactly("java.lang.List")]' + outcome: "Matches variable declarators of type `List` (but not e.g. `ArrayList`)" + - name: metric returnType: "xs:decimal?" @@ -37,11 +50,3 @@ langs: - name: "metricKey" type: "xs:string" description: "The name of an enum constant in {% jdoc jmx::api.JavaOperationMetricKey %} or {% jdoc jmx::api.JavaClassMetricKey %}" - - examples: - - code: '//FormalParameter[pmd-java:typeIs("java.lang.String[]")]' - outcome: "Matches formal parameters of type `String[]` (including vararg parameters)" - - code: '//VariableDeclaratorId[pmd-java:typeIs("java.lang.List")]' - outcome: "Matches variable declarators of type `List` or any of its subtypes (including e.g. `ArrayList`)" - - code: '//VariableDeclaratorId[pmd-java:typeIsExactly("java.lang.List")]' - outcome: "Matches variable declarators of type `List` (but not e.g. `ArrayList`)" diff --git a/docs/_includes/custom/xpath_fun_doc.html b/docs/_includes/custom/xpath_fun_doc.html index e56f97b9ef..5865e37f0e 100644 --- a/docs/_includes/custom/xpath_fun_doc.html +++ b/docs/_includes/custom/xpath_fun_doc.html @@ -12,7 +12,7 @@ - + @@ -51,7 +51,7 @@
Remarks
{{ fun.notes }}
- {% unless fun.parameters.size == 0 %} + {% if fun.parameters.size > 0 %}
Parameters
@@ -69,28 +69,24 @@ - {% endunless %} + {% endif %} - {% unless fun.examples.size == 0 %} + {% if fun.examples.size > 0 %} +
Examples
+ +
+
+
+ {% for example in fun.examples %} +
{{ example.code }}
+
{% render %}{{ example.outcome }}{%endrender%}
+ {% endfor %} +
+
+
+ {% endif %} - - -
Examples
- -
Function nameParameters DescriptionNotes
{{ fun.name }}{{ fun.shortDescription }} - {% if fun.parameters.size == 0 %} - None - {% elsif fun.params_are_same_as %} - (Same as for `{{ fun.params_are_same_as }}`) - {% elsif fun.parameters.size == 1 %} - 1: {{ fun.parameters[0].description }} - {% else %} -
    - {% for i in 0..fun.parameters.size %} - {{ assign param = fun.parameters[i] }} -
  • {{ i + 1 }} : {{ param.description }}
  • - {% endfor %} -
- {% endif %} -
{{ fun.description }} - {% if fun.notes_are_same_as %} - (Same as for `{{ fun.notes_are_same_as }}`) - {% else %} - {{ fun.notes }} - {% endif %} +
-
-

{{ fun.name }}

-

This is a fun function

+
+ +
+ +

+ {{ lang.ns | append: ':' }}{{ fun.name }}{{ fun | xpath_fun_type }} +

+ +
+ +
+
{{ fun.description }}
+
Remarks
+
{{ fun.notes }}
+ + {% unless fun.parameters.size == 0 %} + +
Parameters
+ +
+
+
+ {% for param in fun.parameters %} +
+ {{ param.name }} + as {{ param.type }} +
+
{{ param.description }}
+ {% endfor %} +
+
+
+ + {% endunless %} + + {% unless fun.examples.size == 0 %} + +
+ + +
Examples
+ + + + {% for example in fun.examples %} + + + + + + + {% endfor %} +
{{ example.code }}{{ example.description }}
+ + {% endunless %} +
+
Function nameDescriptionDescription (click for details)
- - {% for example in fun.examples %} - - - - - - - {% endfor %} -
{{ example.code }}{{ example.description }}
- - {% endunless %}
@@ -104,17 +100,4 @@
-{% unless lang.examples.size == 0 %} - -#### Examples - - -{% for example in lang.examples %} -* `{{ example.code }}`
    {{example.outcome }} -{% endfor %} - - -{% endunless %} - - {% endfor %} diff --git a/docs/css/pmd-customstyles.css b/docs/css/pmd-customstyles.css index ae1bfcd073..7683ae54d8 100644 --- a/docs/css/pmd-customstyles.css +++ b/docs/css/pmd-customstyles.css @@ -81,3 +81,6 @@ details[open] summary { font-style: italic; color: darkgray; } +.xpath-fun-doc .code-examples dt { + font-weight: normal; +} diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index 8824768156..0887b3d73b 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -32,12 +32,11 @@ The version can be specified with the `version` property in the rule definition, The default has always been version 1.0. -As of PMD version 6.13.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 +**As of PMD version 6.13.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. The following section describes incompatibilities between 1.0 and 2.0 for PMD rules. From b2f061b58aa58b9db29b7e53056378cd23764e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 7 Apr 2019 18:25:14 +0200 Subject: [PATCH 043/235] Render markdown in descriptions --- docs/_includes/custom/xpath_fun_doc.html | 42 +++++++++++------------- docs/_plugins/custom_filters.rb | 6 ++++ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/docs/_includes/custom/xpath_fun_doc.html b/docs/_includes/custom/xpath_fun_doc.html index 5865e37f0e..12a7781adf 100644 --- a/docs/_includes/custom/xpath_fun_doc.html +++ b/docs/_includes/custom/xpath_fun_doc.html @@ -38,7 +38,9 @@
-

+ + +

{{ lang.ns | append: ':' }}{{ fun.name }}{{ fun | xpath_fun_type }} @@ -47,26 +49,24 @@
-
{{ fun.description }}
+
{{ fun.description | render_markdown }}
Remarks
-
{{ fun.notes }}
+
{{ fun.notes | render_markdown }}
{% if fun.parameters.size > 0 %}
Parameters
-
-
- {% for param in fun.parameters %} -
- {{ param.name }} - as {{ param.type }} -
-
{{ param.description }}
- {% endfor %} -
-
+
+ {% for param in fun.parameters %} +
+ {{ param.name }} + as {{ param.type }} +
+
{{ param.description | render_markdown }}
+ {% endfor %} +
{% endif %} @@ -76,14 +76,12 @@
Examples
-
-
- {% for example in fun.examples %} -
{{ example.code }}
-
{% render %}{{ example.outcome }}{%endrender%}
- {% endfor %} -
-
+
+ {% for example in fun.examples %} +
{{ example.code }}
+
{{ example.outcome | render_markdown }}
+ {% endfor %} +
{% endif %}
diff --git a/docs/_plugins/custom_filters.rb b/docs/_plugins/custom_filters.rb index 2b3067e21a..c3cdec7a0a 100644 --- a/docs/_plugins/custom_filters.rb +++ b/docs/_plugins/custom_filters.rb @@ -1,3 +1,5 @@ +require 'kramdown' + module CustomFilters # set intersection @@ -44,6 +46,10 @@ module CustomFilters end + def render_markdown(text) + Kramdown::Document.new(text).to_html + end + def xpath_fun_type(fun_yaml) res = '(' From 000376f2d299e1fcd50c2f4c14c6f6b85cc4b530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 24 Jan 2020 17:24:58 +0100 Subject: [PATCH 044/235] Update --- docs/Gemfile.lock | 147 +++++++++--------- docs/_data/sidebars/pmd_sidebar.yml | 8 +- .../userdocs/extending/defining_properties.md | 25 +-- .../pmd/userdocs/extending/designer_usage.md | 77 --------- .../userdocs/extending/writing_java_rules.md | 63 ++++---- .../userdocs/extending/writing_rules_intro.md | 81 +++++++++- .../userdocs/extending/writing_xpath_rules.md | 59 ++++++- .../{designer_intro.md => your_first_rule.md} | 12 +- 8 files changed, 248 insertions(+), 224 deletions(-) delete mode 100644 docs/pages/pmd/userdocs/extending/designer_usage.md rename docs/pages/pmd/userdocs/extending/{designer_intro.md => your_first_rule.md} (94%) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 778952c1e0..b8dfb746e2 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,11 +1,12 @@ GEM remote: https://rubygems.org/ specs: - activesupport (4.2.11.1) - i18n (~> 0.7) + activesupport (6.0.2.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 0.7, < 2) minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) + zeitwerk (~> 2.2) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) coffee-script (2.4.1) @@ -25,33 +26,32 @@ GEM ffi (>= 1.3.0) eventmachine (1.2.7) execjs (2.7.0) - faraday (0.16.2) + faraday (1.0.0) multipart-post (>= 1.2, < 3) - ffi (1.11.1) + ffi (1.12.1) forwardable-extended (2.6.0) gemoji (3.0.1) - github-pages (200) - activesupport (= 4.2.11.1) + github-pages (203) github-pages-health-check (= 1.16.1) jekyll (= 3.8.5) - jekyll-avatar (= 0.6.0) + jekyll-avatar (= 0.7.0) jekyll-coffeescript (= 1.1.1) - jekyll-commonmark-ghpages (= 0.1.5) + jekyll-commonmark-ghpages (= 0.1.6) jekyll-default-layout (= 0.1.4) - jekyll-feed (= 0.11.0) + jekyll-feed (= 0.13.0) jekyll-gist (= 1.5.0) jekyll-github-metadata (= 2.12.1) - jekyll-mentions (= 1.4.1) - jekyll-optional-front-matter (= 0.3.0) + jekyll-mentions (= 1.5.1) + jekyll-optional-front-matter (= 0.3.2) jekyll-paginate (= 1.1.0) - jekyll-readme-index (= 0.2.0) - jekyll-redirect-from (= 0.14.0) - jekyll-relative-links (= 0.6.0) - jekyll-remote-theme (= 0.4.0) + jekyll-readme-index (= 0.3.0) + jekyll-redirect-from (= 0.15.0) + jekyll-relative-links (= 0.6.1) + jekyll-remote-theme (= 0.4.1) jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.5.0) - jekyll-sitemap (= 1.2.0) - jekyll-swiss (= 0.4.0) + jekyll-seo-tag (= 2.6.1) + jekyll-sitemap (= 1.4.0) + jekyll-swiss (= 1.0.0) jekyll-theme-architect (= 0.1.1) jekyll-theme-cayman (= 0.1.1) jekyll-theme-dinky (= 0.1.1) @@ -61,19 +61,18 @@ GEM jekyll-theme-midnight (= 0.1.1) jekyll-theme-minimal (= 0.1.1) jekyll-theme-modernist (= 0.1.1) - jekyll-theme-primer (= 0.5.3) + jekyll-theme-primer (= 0.5.4) jekyll-theme-slate (= 0.1.1) jekyll-theme-tactile (= 0.1.1) jekyll-theme-time-machine (= 0.1.1) - jekyll-titles-from-headings (= 0.5.1) - jemoji (= 0.10.2) + jekyll-titles-from-headings (= 0.5.3) + jemoji (= 0.11.1) kramdown (= 1.17.0) - liquid (= 4.0.0) - listen (= 3.1.5) + liquid (= 4.0.3) mercenary (~> 0.3) - minima (= 2.5.0) + minima (= 2.5.1) nokogiri (>= 1.10.4, < 2.0) - rouge (= 2.2.1) + rouge (= 3.13.0) terminal-table (~> 1.4) github-pages-health-check (1.16.1) addressable (~> 2.3) @@ -81,7 +80,7 @@ GEM octokit (~> 4.0) public_suffix (~> 3.0) typhoeus (~> 1.3) - html-pipeline (2.12.0) + html-pipeline (2.12.3) activesupport (>= 2) nokogiri (>= 1.4) http_parser.rb (0.6.0) @@ -100,50 +99,50 @@ GEM pathutil (~> 0.9) rouge (>= 1.7, < 4) safe_yaml (~> 1.0) - jekyll-avatar (0.6.0) - jekyll (~> 3.0) + jekyll-avatar (0.7.0) + jekyll (>= 3.0, < 5.0) jekyll-coffeescript (1.1.1) coffee-script (~> 2.2) coffee-script-source (~> 1.11.1) jekyll-commonmark (1.3.1) commonmarker (~> 0.14) jekyll (>= 3.7, < 5.0) - jekyll-commonmark-ghpages (0.1.5) + jekyll-commonmark-ghpages (0.1.6) commonmarker (~> 0.17.6) - jekyll-commonmark (~> 1) - rouge (~> 2) + jekyll-commonmark (~> 1.2) + rouge (>= 2.0, < 4.0) jekyll-default-layout (0.1.4) jekyll (~> 3.0) - jekyll-feed (0.11.0) - jekyll (~> 3.3) + jekyll-feed (0.13.0) + jekyll (>= 3.7, < 5.0) jekyll-gist (1.5.0) octokit (~> 4.2) jekyll-github-metadata (2.12.1) jekyll (~> 3.4) octokit (~> 4.0, != 4.4.0) - jekyll-mentions (1.4.1) + jekyll-mentions (1.5.1) html-pipeline (~> 2.3) - jekyll (~> 3.0) - jekyll-optional-front-matter (0.3.0) - jekyll (~> 3.0) + jekyll (>= 3.7, < 5.0) + jekyll-optional-front-matter (0.3.2) + jekyll (>= 3.0, < 5.0) jekyll-paginate (1.1.0) - jekyll-readme-index (0.2.0) - jekyll (~> 3.0) - jekyll-redirect-from (0.14.0) - jekyll (~> 3.3) - jekyll-relative-links (0.6.0) - jekyll (~> 3.3) - jekyll-remote-theme (0.4.0) + jekyll-readme-index (0.3.0) + jekyll (>= 3.0, < 5.0) + jekyll-redirect-from (0.15.0) + jekyll (>= 3.3, < 5.0) + jekyll-relative-links (0.6.1) + jekyll (>= 3.3, < 5.0) + jekyll-remote-theme (0.4.1) addressable (~> 2.0) - jekyll (~> 3.5) - rubyzip (>= 1.2.1, < 3.0) + jekyll (>= 3.5, < 5.0) + rubyzip (>= 1.3.0) jekyll-sass-converter (1.5.2) sass (~> 3.4) - jekyll-seo-tag (2.5.0) - jekyll (~> 3.3) - jekyll-sitemap (1.2.0) - jekyll (~> 3.3) - jekyll-swiss (0.4.0) + jekyll-seo-tag (2.6.1) + jekyll (>= 3.3, < 5.0) + jekyll-sitemap (1.4.0) + jekyll (>= 3.7, < 5.0) + jekyll-swiss (1.0.0) jekyll-theme-architect (0.1.1) jekyll (~> 3.5) jekyll-seo-tag (~> 2.0) @@ -171,8 +170,8 @@ GEM jekyll-theme-modernist (0.1.1) jekyll (~> 3.5) jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.5.3) - jekyll (~> 3.5) + jekyll-theme-primer (0.5.4) + jekyll (> 3.5, < 5.0) jekyll-github-metadata (~> 2.9) jekyll-seo-tag (~> 2.0) jekyll-theme-slate (0.1.1) @@ -184,42 +183,41 @@ GEM jekyll-theme-time-machine (0.1.1) jekyll (~> 3.5) jekyll-seo-tag (~> 2.0) - jekyll-titles-from-headings (0.5.1) - jekyll (~> 3.3) + jekyll-titles-from-headings (0.5.3) + jekyll (>= 3.3, < 5.0) jekyll-watch (2.2.1) listen (~> 3.0) - jemoji (0.10.2) + jemoji (0.11.1) gemoji (~> 3.0) html-pipeline (~> 2.2) - jekyll (~> 3.0) + jekyll (>= 3.0, < 5.0) kramdown (1.17.0) - liquid (4.0.0) - listen (3.1.5) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - ruby_dep (~> 1.2) + liquid (4.0.3) + listen (3.2.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.3.6) mini_portile2 (2.4.0) - minima (2.5.0) - jekyll (~> 3.5) + minima (2.5.1) + jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) - minitest (5.12.2) + minitest (5.14.0) multipart-post (2.1.1) - nokogiri (1.10.4) + nokogiri (1.10.7) mini_portile2 (~> 2.4.0) - octokit (4.14.0) + octokit (4.15.0) + faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (3.1.1) rb-fsevent (0.10.3) - rb-inotify (0.10.0) + rb-inotify (0.10.1) ffi (~> 1.0) - rouge (2.2.1) + rouge (3.13.0) ruby-enum (0.7.2) i18n - ruby_dep (1.5.0) rubyzip (2.0.0) safe_yaml (1.0.5) sass (3.7.4) @@ -235,9 +233,10 @@ GEM thread_safe (0.3.6) typhoeus (1.3.1) ethon (>= 0.9.0) - tzinfo (1.2.5) + tzinfo (1.2.6) thread_safe (~> 0.1) - unicode-display_width (1.6.0) + unicode-display_width (1.6.1) + zeitwerk (2.2.2) PLATFORMS ruby @@ -247,4 +246,4 @@ DEPENDENCIES jekyll BUNDLED WITH - 1.17.3 + 2.1.4 diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index 78c9fdadd1..2d0b5032b4 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -67,13 +67,13 @@ entries: - title: Introduction to writing rules url: /pmd_userdocs_extending_writing_rules_intro.html output: web, pdf - - title: Using the Rule Designer - url: /pmd_userdocs_extending_designer_intro.html + - title: Your first rule + url: /pmd_userdocs_extending_your_first_rule.html output: web, pdf - - title: Writing XPath rules + - title: XPath rules url: /pmd_userdocs_extending_writing_xpath_rules.html output: web, pdf - - title: Writing Java rules + - title: Java rules url: /pmd_userdocs_extending_writing_java_rules.html output: web, pdf - title: Rule designer reference diff --git a/docs/pages/pmd/userdocs/extending/defining_properties.md b/docs/pages/pmd/userdocs/extending/defining_properties.md index 5a4039f79a..aa24312f13 100644 --- a/docs/pages/pmd/userdocs/extending/defining_properties.md +++ b/docs/pages/pmd/userdocs/extending/defining_properties.md @@ -29,33 +29,12 @@ The basic thing you need to do as a developer is to define a **property descript Don't worry, all of these attributes can be specified in a single Java statement (or xml element for XPath rules). -Without further ado, here is the list of available (single-value) property types: - -|Value type|Factory method| -|----------|--------------| -| int |{% jdoc :PF#intProperty(java.lang.String) %}| -| double |{% jdoc :PF#doubleProperty(java.lang.String) %}| -| long |{% jdoc :PF#longProperty(java.lang.String) %}| -| char |{% jdoc :PF#charProperty(java.lang.String) %}| -| boolean |{% jdoc :PF#booleanProperty(java.lang.String) %}| -| String |{% jdoc :PF#stringProperty(java.lang.String) %}| -| java.util.regex.Pattern |{% jdoc :PF#regexProperty(java.lang.String) %}| -| *anything* |{% jdoc :PF#enumProperty(java.lang.String,java.util.Map) %}| - -Each of these is complemented by a multivalued variant, whose value is a list, e.g. - -|Value type|Factory method| -|----------|--------------| -| List\ |{% jdoc :PF#intListProperty(java.lang.String) %}| -| List\<*E*\> |{% jdoc :PF#enumListProperty(java.lang.String,java.util.Map) %}| - -Note that no multivalue property is available for regex properties, since the -delimiters could be part of a specific value. ## For Java rules The procedure to define a property is quite straightforward: -* Create a property descriptor of the type you want, using its builder; +* Create a property descriptor of the type you want, by using a +builder from {% jdoc :PF %} * Call {% jdoc !a!props::PropertySource#definePropertyDescriptor(props::PropertyDescriptor) %}` in the rule's noarg constructor. You can then retrieve the value of the property at any time using {% jdoc !a!props::PropertySource#getProperty(props::PropertyDescriptor) %}. diff --git a/docs/pages/pmd/userdocs/extending/designer_usage.md b/docs/pages/pmd/userdocs/extending/designer_usage.md deleted file mode 100644 index 5ea442d373..0000000000 --- a/docs/pages/pmd/userdocs/extending/designer_usage.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Using the Rule Designer -short_title: Using the Rule Designer -tags: [userdocs, extending, designer] -summary: "Learn how to use the designer" -last_updated: July 2018 (6.6.0) -permalink: pmd_userdocs_extending_designer_usage.html -author: Clément Fournier ---- - -## Getting around - -We here explain the global organisation of the UI. - -{% include image.html file="userdocs/designer-overview-with-numbers.png" alt="Designer overview" %} - -### Examining the AST - -The code in zone (1) on the image will be parsed automatically, and its AST rendered -in zone (2). You can examine each node of the AST individually by clicking on it. -Node-specific information will be displayed in zone (3). In that panel, you can view -in different tabs: -* The XPath attributes of the node and their value. These are the attributes accessible -via XPath, but for some languages are also accessible as methods of the node for your Java rules. -* The scope hierarchy of the node, for languages that support it (e.g. Java). This will -be a tree of the scopes that enclose the node and their declarations. -* The value of metrics on the node, for languages that support it (Java and Apex). Note that -metrics can only be computed on a few node types, e.g. class or method declarations. - - -### XPath tools - -The bottom panel has a tab with tools to develop XPath rules. In zone (4), you can edit an -XPath expression that will be automatically evaluated on the current AST. The results will -be displayed in zone (5), and highlighted on the main code area (1). - - -#### Editing properties - -The table in zone (6) allows you to define properties for your XPath rule and change their -values. This is good practice if you want to develop a configurable rule. To add a property, -right-click on the table and select "Add property...". A pop-up will allow you to set the -name, type, and other attributes of the property. - -Properties can then be referenced in your XPath query by their name prefixed with a dollar symbol, -e.g. `$myProperty`. - -## FAQ - - -
- - {% include custom/faq_entry.html - question="How do I change the parser language?" - answer="The toolbar in the center of the UI allows you to select the language of the parser." %} - - {% include custom/faq_entry.html - question="What's in the Scopes tab?" - answer="For languages that support it (e.g. Java), this will - be a tree of the scopes that enclose the node, and their declarations." %} - - {% include custom/faq_entry.html - question="Why is the Metrics tab always disabled?" - answer="The Metrics tab is only enabled when the currently selected node - supports the computation of metrics. These are for instance class - declaration or method declaration nodes." %} - - {% include custom/faq_entry.html - question="Where are my preferences stored?" - answer="The Designer saves the current state of the application upon closing - into an XML file. This file is located inside your home directory, in - the subdirectory `.pmd`" %} - -
- - - diff --git a/docs/pages/pmd/userdocs/extending/writing_java_rules.md b/docs/pages/pmd/userdocs/extending/writing_java_rules.md index 3a32b5d080..7c69854899 100644 --- a/docs/pages/pmd/userdocs/extending/writing_java_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_java_rules.md @@ -13,7 +13,7 @@ author: Tom Copeland {% jdoc_nspace :jast java::lang.java.ast %} {% jdoc_nspace :jrule java::lang.java.rule %} -{% include note.html content="TODO All that should be written in the Javadocs, +{% include note.html content="TODO All that should be written in the Javadocs, not sure we even need a doc page. Would be simpler to maintain too" %} {% include warning.html content="WIP lots of stuff missing" %} @@ -24,20 +24,30 @@ process is very similar to the process for XPath rules, which is described in Basically, you open the designer, look at the structure of the AST, and refine your rule as you add test cases. -All rules ultimately implement the interface {% jdoc core::Rule %}. Each -language implementation provides a specific base rule class to ease your pain, -e.g. {% jdoc jrule::AbstractJavaRule %}. - In this page we'll talk about rules for the Java language, but the process is very similar for other languages. + +## Basics + +To write a rule in Java you'll have to: + 1. write a Java class that implements the interface {% jdoc core::Rule %}. Each +language implementation provides a base rule class to ease your pain, +e.g. {% jdoc jrule::AbstractJavaRule %}. + 2. compile this class, linking it to PMD APIs (eg using PMD as a maven dependency) + 3. bundle this into a JAR and add it to the execution classpath of PMD + 4. declare the rule in your ruleset XML + ## Rule execution +Most base rule classes use a [Visitor pattern](https://sourcemaking.com/design_patterns/visitor) +to explore the AST. + ### Tree traversal When a rule is applied to a file, it's handed the root of the AST and told to traverse all the tree to look for violations. Each rule defines a specific -`visit` method for each type of node that can be found in the Java AST, which +`visit` method for each type of node for of the language, which by default just visits the children. So the following rule would traverse the whole tree and do nothing: @@ -64,8 +74,15 @@ public class MyRule extends AbstractJavaRule { public Object visit(ASTVariableDeclaratorId node, Object data) { // This method is called on each node of type ASTVariableDeclaratorId // in the AST + + if (node.getType() == short.class) { + // reports a violation at the position of the node + // the "data" parameter is a context object handed to by your rule + // the message for the violation is the message defined in the rule declaration XML element + addViolation(data, node); + } - + // this calls back to the default implementation, which recurses further down the subtree return super.visit(node, data); } } @@ -135,33 +152,13 @@ If an overridden property is unknown, an error is reported. ### Execution -For each thread, a deep copy of the rule is created. -Then, for each thread, for each analysed file: +For each thread, a deep copy of the rule is created. Each thread is given +a different set of files to analyse. Then, for each such file, for each +rule copy: 3. {% jdoc core::Rule#start(core::RuleContext) %} is called once, before parsing -4. {% jdoc core::Rule#apply(java.util.List,core::RuleContext) %} is called with the root -of the AST. That method performs the AST traversal that ultimately calls visit methods. +4. {% jdoc core::Rule#apply(java.util.List,core::RuleContext) %} is called with the root +of the AST. That method performs the AST traversal that ultimately calls visit methods. It's not called for RuleChain rules. -5. {% jdoc core::Rule#end(core::RuleContext) %} is called when the rule is done processing +5. {% jdoc core::Rule#end(core::RuleContext) %} is called when the rule is done processing the file - -### FIXME - -without specific order: -* There's no hook for "after construction", or "after analysis" we only have "before file" -and "after file" -* What's the point of having `Rule#start` ? The globally accepted pattern is to override -the visit method for the root node. We have `visit()`, `apply`, and `start` -that are called at the same lifecycle point... -* Rule#apply is not called for RuleChain visits -* Why is Rule#apply overridable? Anyone can break it -* Sooo much code is duplicated everywhere in rulechain visitor implementations, which are -all the same modulo a cast... -* Converting a rule to the rulechain shouldn't force removing `super.visit` calls... We -could just provide a base class for rulechain rules that overrides eg `visit(JavaNode)` -to be a noop -* RuleSets is unnecessary, we should just rely on a good RuleSet implementation -* Initializer.initialize() is called for each file instead of once per language module loading -* For each file all the rules in all rulesets are checked to use typeres or other -analysis passes - diff --git a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md index 6c2177182b..24c753d217 100644 --- a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md +++ b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md @@ -21,13 +21,66 @@ in Java, method declarations belong to a class: in the AST, the nodes representi method declarations will be descendants of a node representing the declaration of their enclosing class. This representation is thus much richer than the original source code (which, for a program, is just a chain of characters), or the token -chain produced by a lexer (which is e.g. what Checkstyle works on). +chain produced by a lexer (which is e.g. what Checkstyle works on). For example: + + ++++ + + + + + + + + + + + + +
Sample code (Java)AST
+ +```java +class Foo extends Object { + +} +``` + + + +```java +└─ CompilationUnit + └─ TypeDeclaration + └─ ClassOrInterfaceDeclaration "Foo" + ├─ ExtendsList + │ └─ ClassOrInterfaceType "Object" + └─ ClassOrInterfaceBody +``` + +
Conceptually, PMD rules work by **matching a "pattern" against the AST** of a file. Rules explore the AST and find nodes that satisfy some conditions that are characteristic of the specific thing the rule is trying to flag. Rules then report a violation on these nodes. +### Discovering the AST + + +ASTs are represented by Java classes deriving from {% jdoc core::lang.ast.Node %}. +Each PMD language has its own set of such classes, and its own rules about how +these classes relate to one another, based on the grammar of the language. For +example, all Java AST nodes extend {% jdoc java::lang.java.ast.JavaNode %}. + +The structure of the AST can be discovered by using the [Rule Designer](pmd_userdocs_extending_designer_reference.html). + + + + + + ## Writing new rules PMD supports two ways to define rules: using an **XPath query**, or using a @@ -41,6 +94,32 @@ complicated processing, to which an XPath rule couldn't scale. In the end, choosing one strategy or the other depends on the difficulty of what your rule does. I'd advise to keep to XPath unless you have no other choice. + +## XML rule definition + +New rules must be declared in a ruleset before they're referenced. This is the +case for both XPath and Java rules. To do this, the `rule` element is used, but +instead of mentioning the `ref` attribute, it mentions the `class` attribute, +with the implementation class of your rule. + +* **For Java rules:** this is the class extending AbstractRule (transitively) +* **For XPath rules:** this is `net.sourceforge.pmd.lang.rule.XPathRule` + +Example: + +```xml + + + Description + + 3 + +``` + + ## Resource index To learn how to write a rule: diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index 0887b3d73b..fd1299854f 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -19,8 +19,6 @@ also [the tutorial about how to write an XPath rule](pmd_userdocs_extending_desi - - ## XPath version PMD supports three XPath versions for now: 1.0, 2.0, and 1.0 compatibility mode. @@ -32,16 +30,62 @@ The version can be specified with the `version` property in the rule definition, The default has always been version 1.0. -**As of PMD version 6.13.0, XPath versions 1.0 and the 1.0 compatibility mode are +**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. The -following section describes incompatibilities between 1.0 and 2.0 for PMD rules. +to be able to provide an automatic migration tool when releasing 7.0.0. +See [the migration guide](l#migrating-from-10-to-20) below. -### Migrating from 1.0 to 2.0 + +## DOM representation of ASTs + +XPath rules view the AST as an XML-like DOM, which is what the XPath language is +defined on. Concretely, this means: +* Every AST node is viewed as an XML element + * The element has for local name the value of {% jdoc core::lang.ast.Node#getXPathNodeName() %} + for the given node +* Some Java getters are exposed as XML attributes on those elements + * This means, that documentation for attributes can be found in our Javadocs. For + example, the attribute `@SimpleName` of the Java node `EnumDeclaration` is backed + by the Java getter {% jdoc java::lang.java.ast.ASTAnyTypeDeclaration#getSimpleName() %}. + +### 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. + +| Java type `T` | XSD type `conv(T)` +|-----------------|---------------------| +|`int` | `xs:integer` +|`long` | `xs:integer` +|`double` | `xs:decimal` +|`float` | `xs:decimal` +|`boolean` | `xs:boolean` +|`String` | `xs:string` +|`Character` | `xs:string` +|`List` | `conv(E)*` (a sequence type) + + +The same `conv` function is used to translate rule property values to XDM values. + + +## 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 @@ -74,6 +118,9 @@ represented by our 1.0 implementation as strings, meaning that `@BeginLine > "1" worked ---that's not the case in 2.0 mode. * @ArgumentCount > '1' → `@ArgumentCount > 1` +## Rule properties + +**See [Defining rule properties](pmd_userdocs_extending_defining_properties.html#for-xpath-rules)** ## PMD extension functions diff --git a/docs/pages/pmd/userdocs/extending/designer_intro.md b/docs/pages/pmd/userdocs/extending/your_first_rule.md similarity index 94% rename from docs/pages/pmd/userdocs/extending/designer_intro.md rename to docs/pages/pmd/userdocs/extending/your_first_rule.md index babe31139a..27dba388cf 100644 --- a/docs/pages/pmd/userdocs/extending/designer_intro.md +++ b/docs/pages/pmd/userdocs/extending/your_first_rule.md @@ -1,15 +1,15 @@ --- -title: Using the Rule Designer +title: Your first rule XPath tags: [extending, userdocs] -summary: "This page is a gentle introduction to the Rule Designer, a tool made -to help developers write new rules." +summary: "Introduction to rule writing through an example." last_updated: July 2018 (6.6.0) -permalink: pmd_userdocs_extending_designer_intro.html +permalink: pmd_userdocs_extending_your_first_rule.html author: Miguel Griffa --- -This page is a gentle introduction to the Rule Designer, a tool made to help -developers write new rules. Using the designer is useful both to write Java +This page is a gentle introduction to rule writing, and the Rule Designer. + +Using the designer is useful both to write Java rules and XPath rules, but it's more specifically geared towards XPath rules. This page uses a simple XPath rule to illustrate the common workflow. We assume here that you already know what XPath is and how to read basic XPath queries. W3C From 3318cc28081a151735c7f1c13790df48e273b827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 24 Jan 2020 18:34:33 +0100 Subject: [PATCH 045/235] Remove old page --- docs/_data/sidebars/pmd_sidebar.yml | 3 - .../userdocs/extending/writing_pmd_rules.md | 333 ------------------ 2 files changed, 336 deletions(-) delete mode 100644 docs/pages/pmd/userdocs/extending/writing_pmd_rules.md diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index 2d0b5032b4..6598a2cec8 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -61,9 +61,6 @@ entries: - title: Extending PMD output: web, pdf subfolderitems: - - title: Writing a rule - url: /pmd_userdocs_extending_writing_pmd_rules.html - output: web, pdf - title: Introduction to writing rules url: /pmd_userdocs_extending_writing_rules_intro.html output: web, pdf diff --git a/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md b/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md deleted file mode 100644 index 1919e1c039..0000000000 --- a/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md +++ /dev/null @@ -1,333 +0,0 @@ ---- -title: Writing a custom rule -tags: [extending, userdocs] -summary: "Learn how to write a custom rule for PMD" -last_updated: July 3, 2016 -permalink: pmd_userdocs_extending_writing_pmd_rules.html -author: Tom Copeland ---- - - -{% include warning.html content="This is going away" %} - -# How to write a PMD rule - -Writing PMD rules is cool because you don’t have to wait for us to get around to implementing feature requests. - -## Get a development environment set up first - [Here’s some initial information on compiling PMD] - -## Java or XPath? - -There are two way to write rules: - -* Write a rule using Java -* Write an XPath expression - -We’ll cover the Java way first and the XPath way second. Most of this documentation is applicable to both methods, too, so read on. - -## Figure out what you want to look for - -Lets’s figure out what problem we want to spot. We can use “While loops must use braces” as an example. In the source code below, it’s easy to get lost visually - it’s kind of hard to tell what the curly braces belong to. - -```java -class Example { - void bar() { - while (baz) - buz.doSomething(); - } -} -``` - -So we know what an example in source code looks like, which is half the battle. - -## Write a test-data example and look at the AST - -PMD doesn’t use the source code directly; it uses a `JavaCC` generated parser to parse the source code and produce an AST (Abstract Syntax Tree). The AST for the code above looks like this: - -``` -CompilationUnit - TypeDeclaration - ClassDeclaration:(package private) - UnmodifiedClassDeclaration(Example) - ClassBody - ClassBodyDeclaration - MethodDeclaration:(package private) - ResultType - MethodDeclarator(bar) - FormalParameters - Block - BlockStatement - Statement - WhileStatement - Expression - PrimaryExpression - PrimaryPrefix - Name:baz - Statement - StatementExpression:null - PrimaryExpression - PrimaryPrefix - Name:buz.doSomething - PrimarySuffix - Arguments -``` - -You can generate this yourself by: - -* Run the batch file `bin/designer.bat` -* Paste the code into the left text area and click the “Go” button -* Note that there’s another panel and a textfield to test out XPath expressions; more on that later. -* Here’s a screenshot: {% include image.html file="devdocs/designer_screenshot.png" alt="Designer Screenshot" %} - -So you can see in the example above that the AST for a `WhileStatement` looks kind of like this (excluding that expression gibberish for clarity): - -``` -WhileStatement - Expression - Statement - StatementExpression -``` - -If you were to add curly braces around the call to `buz.doSomething()` and click “Go” again, you’d see that the AST would change a bit. It’d look like this: - -``` -WhileStatement - Expression - Statement - Block - BlockStatement - Statement - StatementExpression -``` - -Ah ha! We see that the curly braces add a couple more AST nodes - a `Block` and a `BlockStatement`. So all we have to do is write a rule to detect a `WhileStatement` that has a `Statement` that’s not followed by a `Block`, and we’ve got a rule violation. - -By the way, all this structural information - i.e., the fact that a Statement may be followed a Block - is concisely defined in the [EBNF grammar](https://github.com/pmd/pmd/blob/master/pmd-java/etc/grammar/Java.jjt). So, for example, the Statement definition looks like this: - -``` -void Statement() : -{} -{ - LOOKAHEAD( { isNextTokenAnAssert() } ) AssertStatement() -| LOOKAHEAD(2) LabeledStatement() -| Block() -| EmptyStatement() -| StatementExpression() ";" -| SwitchStatement() -| IfStatement() -| WhileStatement() -| DoStatement() -| ForStatement() -| BreakStatement() -| ContinueStatement() -| ReturnStatement() -| ThrowStatement() -| SynchronizedStatement() -| TryStatement() -} -``` - -showing that a Statement may be followed by all sorts of stuff. - -## Write a rule class - -Create a new Java class that extends `net.sourceforge.pmd.lang.java.rule.AbstractJavaRule`: - -```java -import net.sourceforge.pmd.lang.java.rule.*; -public class WhileLoopsMustUseBracesRule extends AbstractJavaRule { -} -``` - -That was easy. PMD works by creating the AST and then traverses it recursively so a rule can get a callback for any type it’s interested in. So let’s make sure our rule gets called whenever the AST traversal finds a `WhileStatement`: - -```java -import net.sourceforge.pmd.lang.java.rule.*; -import net.sourceforge.pmd.lang.java.ast.*; -public class WhileLoopsMustUseBracesRule extends AbstractJavaRule { - public Object visit(ASTWhileStatement node, Object data) { - System.out.println("hello world"); - return data; - } -} -``` - -We stuck a `println()` in there for now so we can see when our rule gets hit. - -## Put the WhileLoopsMustUseBracesRule rule in a ruleset file - -Now our rule is written - at least, the shell of it is - and now we need to tell PMD about it. We need to add it to a ruleset XML file. Look at `pmd-java/src/main/resources/category/java/bestpractices.xml`; it’s got lots of rule definitions in it. Copy and paste one of these rules into a new ruleset - call it `mycustomrules.xml` or something. Then fill in the elements and attributes: - -* name - WhileLoopsMustUseBracesRule -* message - Use braces for while loops -* class - Wherever you put the rule. Note this doesn’t have to be in `net.sourceforge.pmd`; it can be in `com.yourcompany.util.pmd` or whereever you want -* description - Use braces for while loops -* example - A little code snippet in CDATA tags that shows a rule violation - -The whole ruleset file should look something like this: - -```xml - - - - - Avoid using 'while' statements without using curly braces - - 3 - - - - - - -``` - -## Run PMD using your new ruleset - -OK, let’s run the new rule so we can see something work. Like this: - -```DOS -pmd.bat c:\path\to\my\src xml c:\path\to\mycustomrules.xml -``` - - -This time your “hello world” will show up right after the AST gets printed out. If it doesn’t, post a message to [the forum](http://sourceforge.net/p/pmd/discussion/188192) so we can improve this document :-) - -## Write code to add rule violations where appropriate - -Now that we’ve identified our problem, recognized the AST pattern that illustrates the problem, written a new rule, and plugged it into a ruleset, we need to actually make our rule find the problem, create a `RuleViolation`, and put it in the `Report`, which is attached to the `RuleContext`. Like this: - -```java -import net.sourceforge.pmd.lang.ast.*; -import net.sourceforge.pmd.lang.java.ast.*; -import net.sourceforge.pmd.lang.java.rule.*; - -public class WhileLoopsMustUseBracesRule extends AbstractJavaRule { - public Object visit(ASTWhileStatement node, Object data) { - Node firstStmt = node.jjtGetChild(1); - if (!hasBlockAsFirstChild(firstStmt)) { - addViolation(data, node); - } - return super.visit(node,data); - } - private boolean hasBlockAsFirstChild(Node node) { - return (node.getNumChildren() != 0 && (node.jjtGetChild(0) instanceof ASTBlock)); - } -} -``` - -TODO - if you don’t understand the code for the rule, post a message to [the forum](http://sourceforge.net/p/pmd/discussion/188192) so we can improve this document :-) - -## Writing a rule as an XPath expression - -Daniel Sheppard integrated an XPath engine into PMD, so now you can write rules as XPath expressions. For example, the XPath expression for our WhileLoopsMustUseBracesRule looks like this: - -`//WhileStatement[not(Statement/Block)]` - -Concise, eh? - -Note that for XPath rules you’ll need to set the `class` attribute in the rule definition to `net.sourceforge.pmd.lang.rule.XPathRule.` Like this: - -```xml - - - etc., etc. -``` - -Note that access modifiers are held as attributes, so, for example, - -`//FieldDeclaration[@Private='true']` - -finds all private fields. You can see the code that determines all the attributes [here](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java) - -More information about writing XPath rules is [available here](pmd_userdocs_extending_writing_xpath_rules.html). - -## I need some kind of Type Resolution for my rule! - -### Inside an XPath query - -PMD's XPath extensions include two functions called `typeIs` and `typeIsExactly`, -which determine if a node is of a specific type (either any subtype or exactly, -respectively). - -Here a an example of use, inside an XPath query: - -```ruby -//ClassOrInterfaceDeclaration/ExtendsList/ClassOrInterfaceType[typeIs('junit.framework.TestCase')] -``` - -This query will for instance match the following class declaration: - -```java -import junit.framework.TestCase; - -public class Foo extends TestCase { } -``` - -It will also match against classes which extend a *subtype* of `junit.framework.TestCase`, -i.e. a base class itself extending `TestCase` transitively. If you don't want this behaviour, -then use `typeIsExactly` instead of `typeIs`. - -Checking against an array type is possible with the double bracket syntax. -An array type is denoted by just appending `[]` to the fully qualified class name -of the component type. These can be repeated for arrays of arrays -(e.g. `byte[][]` or `java.lang.String[]`). - - -### With Java code - -Below an other sample of use of type resolution inside a java code: - -```java -/** - * A simple to detect the use of the class 'com.forbidden.class'. - */ -@SuppressWarnings("unchecked") -public Object visit(ASTClassOrInterfaceType type, Object ruleCtx) { - Class clazz = type.getType(); - if ("com.forbidden.class".equals(clazz.getName())) { - addViolation(ruleCtx,type); - } - return super.visit(type, ruleCtx); -} -```` - ->Note, that this will only work, if the auxiliary classpath for PMD is setup correctly, so that PMD can actually find the (compiled) class “com.forbidden.class” and you get the actual Class instance by calling getType(). - -Otherwise, you’ll have to string-compare the image, e.g. `"com.forbidden.class".equals(node.getImage())` - -## Thread safety, concurrency issues and reuse of rule instances - -When executing the rule, PMD will instantiate a new instance of your rule. If PMD is executed in multiple threads, then each thread is using its own instance of the rule. This means, that the rule implementation **does not need to care about threading issues**, as PMD makes sure, that a single instance is not used concurrently by multiple threads. - -However, for performance reasons, the rule instances are used for multiple files. This means, that the constructor of the rule is only executed once (per thread) and the rule instance is reused. If you rely on a proper initialization of instance properties, you can do the initialization e.g. in the visit-method of the `ASTCompilationUnit` AST node - which is visited as first node and only once per file. However, this solution would only work for rules written for the Java language. A language independent way is to override the method `apply` of the rule (and call super). The apply method is called exactly once per file. - -If you want to share data across multiple files, see the above section “I want to implement a rule that analyze more than the class”. - -## Bundle it up - -To use your rules as part of a nightly build or whatever, it’s helpful to bundle up both the rule and the ruleset.xml file in a jar file. Then you can put that jar file on the CLASSPATH of your build. Setting up a script or an Ant task to do this can save you some tedious typing. - -## Repeat as necessary - -I’ve found that my rules usually don’t work the first time, and so I have to go back and tweak them a couple times. That’s OK, if we were perfect programmers PMD would be useless anyhow :-). - -As an acceptance test of sorts, I usually run a rule on the JDK 1.4 source code and make sure that a random sampling of the problems found are in fact legitimate rule violations. This also ensures that the rule doesn’t get confused by nested inner classes or any of the other oddities that appear at various points in the JDK source. - -You’re rolling now. If you think a rule would benefit the (Java) development community as a whole, -create a [issue on github](https://github.com/pmd/pmd/issues) so we can get the rule moved into one of the core rulesets. - -Or, if you can improve one of the existing rules, that’d be great too! Thanks! From 90849802031b6f42690f4b3dade771fee885c978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 24 Jan 2020 18:39:58 +0100 Subject: [PATCH 046/235] Update again --- docs/_data/xpath_funs.yml | 3 +++ docs/_includes/custom/faq_entry.html | 21 ------------------ docs/_plugins/render_block.rb | 3 +-- .../userdocs/designer-overview-with-nums.png | Bin 254594 -> 132019 bytes docs/images/userdocs/designer-overview.png | Bin 0 -> 103341 bytes .../userdocs/extending/defining_properties.md | 1 + .../userdocs/extending/writing_rules_intro.md | 15 +++++++------ .../pmd/userdocs/extending/your_first_rule.md | 21 ------------------ 8 files changed, 13 insertions(+), 51 deletions(-) delete mode 100644 docs/_includes/custom/faq_entry.html create mode 100644 docs/images/userdocs/designer-overview.png diff --git a/docs/_data/xpath_funs.yml b/docs/_data/xpath_funs.yml index 2b56bfb2bf..222f3b70f2 100644 --- a/docs/_data/xpath_funs.yml +++ b/docs/_data/xpath_funs.yml @@ -1,3 +1,6 @@ +# This file describes custom XPath functions per language +# This is rendered using _includes/custom/xpath_fun_doc.html + aliases: - &qname_param name: javaQualifiedName diff --git a/docs/_includes/custom/faq_entry.html b/docs/_includes/custom/faq_entry.html deleted file mode 100644 index 1cbb2560ec..0000000000 --- a/docs/_includes/custom/faq_entry.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - -{% assign panel_id = 8 | random_alphabetic %} - -
- -
-
- {{ include.answer | render_markdown }} -
-
-
\ No newline at end of file diff --git a/docs/_plugins/render_block.rb b/docs/_plugins/render_block.rb index 49f3fa8cfb..111f01ab76 100644 --- a/docs/_plugins/render_block.rb +++ b/docs/_plugins/render_block.rb @@ -1,6 +1,5 @@ -require 'pp' # -# Tags to create a complex object inline in JSON. +# Apply a second pass of rendering on a block # class RenderBlock < Liquid::Block diff --git a/docs/images/userdocs/designer-overview-with-nums.png b/docs/images/userdocs/designer-overview-with-nums.png index a6e2eb386fdc23c964a46ebf40f376e2f74353b6..2851fd8ae667028af3e55aefbb9e6f821ac53aac 100644 GIT binary patch literal 132019 zcmcG#W0Yjw(gs*Ycd5JVt}ffQyKLK5mu;)dwr$(CnPuCq$-eKs_nU9lteHPED_5S( zqrLZu*b)1Qc;bZ0N{hmO!TJIM0s=4gOGq9B1i}^s1Z)8Y3V5X08Lb2O1Ent^Dg^TR z_mkaG6bC#4Yx_&h9t7ko^4~8gNNPF;@F287?bnba}Dr zxUt}P{>2aFtFVw;3?APv0W2i>UzaK4lEw#{0DRwR0VRTy!+S2CXhY*k?!$5JeXoOc z`-J&;6sZL!^)<^Qc&N7ug(d6p%~TBD1nE zGjerhl@bzJu)RRh{QL#&S~S_TaEql$Qwzn;VgGw)I(S%a_8fU~1PK*A+R3T8nVDJ7 zj>+J(xy2A|w;wYdhK73^gw=ogfgzX#mzukBVdBa};LxNg=kFoo)3Er;(b2=_!wl25 zLDPf%-XOvyPW2YLAaHiE>R24VZ(%L&}r zV7LB9Tz9tLyZ`pre|;A!>3Jf&nf8J3h)Dm&c5{|6d_Og@HKz7CT5V}S4J zYhpc4G=HVQ69X4utUbk8#nt;HE4-Qjl>T*w$U>cBr#F6T;Wtd&@XhIzh@tZXJ~i?% zX;BBwx2e*fV~>}8GuD?6%z0IpQVpPRs zWlC=uFe>J*`wfd_kNy~i@6&Lhk4C#LZ8auym-9U=w9|l;-kc8x+`BEo%3F=UgNs)X z_*iU|Cb-=xjP7XKP_))vyDCplFQ8kNP4u7PQ??wqTvtbNyk%kO+@}UXaG0~_78;F~ z+dV@cWF~3Au^7^b3u1g;=`?%(!r(_^t6m8E(3?O3&CFZy%0gdViG4REmddLUcrSol6RF6#&OMu(-yVL73APHXu3 zV&u`N%T0W~3VX|Z(NomoX$nCA+UY`ReMapVk9wiI;Md~OngcfET3S{|F@-5l*;K86 zNR(?Jq1M?_8VqFvBFHdjjVty8!D&3TC#Vi#69Y!F<&PM$NDT9j&?i~waJ*0W&k6gi zJw`XbxuWZ%-6p#6)<|z@_ppJA;HWBHX`HDlFXqVbxt~`>k)wW69v_=+9;tI4J1Bfo`3Gnz6+iT(8f`cJx%`}eGHhV4kh<~Tcr1>7N zgmE1{`G{xA$4v0L$5;i(c=E@$krB_844tRCvSDOM8<5)C+C52Rfsm~41HViyx#W6+ zgXC~UBxv0bPlPY;Vj@DkW8FX6kg+)gdIjjovXAnTUB-yVT|MZTp{tVMJxT1x$RrNm z$2)qD3;cgKFrFV(zM9`*ybFfNd?nyH2P2VI@4JoW8B#&Lu)bZOXJq|Tx)<7wlI()}5=cmCP1K^TzP;_I8PB&0fDp@n@Mo z$?lSOmu~YBY3|YK5%)RPbqVl%8gJT;;6+vY>EiVo4RiO%Jv#1bJ%57g(RqzFOB<%& zi;CHv)bzX#{XGx~C>o!-P4L4R($D_R*zfZ4v45p0`FSK58~0l44B)|g-Oci9MCGs> zZO~+M0z;3==*}mf+k^WnRHlTm7DNW?w**bEK71EfE9%l6skekUOydh2W5HfOM1;mK z2jdngscyD5XaiX>OIl)nIk%-Mhxp>O29IVk$xft*?X3a1PFG>ge_rv^f5rdicupNo zXyO@MTbU>h3ye4=Wt;{{9=eGhkWjt7=UmUog+|FO?C8DOmr(sUQT!>B*f=@bU4nRZ z5^S&9YRGfT>k<`AO1fK>?xmGc&s8L;L-50jLgwSt6OBf@zxKKAX>Wp;fmjve_KqF&igSeF|d!sN}R-qPLdQFB*(*7=#1L!xQC(k5!tBCxK4@B*^ z2?&N?;=N@89r!^iMBX zh>*>iKK+xtor%@#e3RSZTwc{-qb2l)|L~|fX81;a^g+jbUkm@?O{fipPqj_1>9L0Y zysH!gJ?4P5zc@hmdv*X$3~tDrDVsI9TAg`SJ$fYRyEq`9&%tFmPQypb!f5P8i;Wqw z3)KG?3y4ch>lSJs`n3ZMLUkIJ&xtPI|2 zkmuCT9@k2E)+ps>$9Fs!7lvfuf@sqxFTC7jB`ebjBjX`ffS<7(?^Srs2p*FWK(R)h1lZUG`si&4ISjRhx zE&9!cmWti={#^6+=8~$KvqwvO_SY6iaT^cYYWGD0$&MZIN;fmgjf?KwhU&d3h336c zotw88W5ofX)nWn&N)uJIhV`H@+~ZdxPS={If3p@jCi0p+tJcwbNqas1NBWS6B&waeG*|kN_^2~ za|~a^F#9VEku0=SQCw9eS-5!chVR&MVPk3AuFLLj1qd!%dWKH!VzV#m+J*jdh-od9 z=v9t8jM_K1`5^f6Wn*3%Q+-(29#K%b?-=W@a|zC-KM9MtC4cjAeqOe~r%!YaN1fZ; z4g+x49XEvYhoE=M8mEuG{OHdWwX!N~Xxr!hlD?QqGZESc`{cH}OUNAz1cY|d;B1#2 zk2HTlfr@Vi`|Bj<+ruMbdK?%Io2=995-kqrcDk~u^@TKhSpd?G ziLjsoH`^K(8SUo43vm{MyDPmDNCu`iFRm$WeFICi&&%A%5PP zV0miX1c-{7>~#@8ynY3ANK}qV&d!s%?ngQJ1x06Pd4Xe3nbX(D%_?19?Ug!ngdb!L z^nJclB2!b`Lqck$+2Ffgur4rfEp~H~#p`mPDWSdz`d!QMS(viD4ciVt=OJc0ZaIio z{fz?B=Rl%LOHfeIu7{Dm&sJ{_K7#RgTe^7t3(a`j!qyYw#(e5OHaZ&_Nku1_fWApg zz9jh_q^Z5-6+*^|VfU~MMEcAL@q%0D`gyWsJ%}Azt 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 z³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≷gRU7)<4!r9y*50kUgUP34fJZ+(KL-} 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 Vc->qF!$YCe&TE~^IAebQe*vpTAZ`Ev diff --git a/docs/images/userdocs/designer-overview.png b/docs/images/userdocs/designer-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..8cbda3c4d5b2cb2f4b6a621beb321fd39d34339a GIT binary patch literal 103341 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 --- - -## Why write custom rules? - -TODO +PMD is a framework to perform code analysis. You can create your own rules to +check for patterns specific to your codebase, or the coding practices of your +team. ## How rules work: the AST Before running rules, PMD parses the source file into a data structure called an -*abstract syntax tree* (AST). This tree represents the syntactic structure of the +**abstract syntax tree (AST)**. This tree represents the syntactic structure of the code, and encodes syntactic relations between source code elements. For instance, in Java, method declarations belong to a class: in the AST, the nodes representing method declarations will be descendants of a node representing the declaration of @@ -74,7 +73,9 @@ Each PMD language has its own set of such classes, and its own rules about how these classes relate to one another, based on the grammar of the language. For example, all Java AST nodes extend {% jdoc java::lang.java.ast.JavaNode %}. -The structure of the AST can be discovered by using the [Rule Designer](pmd_userdocs_extending_designer_reference.html). +The structure of the AST can be discovered through + * the [Rule Designer](pmd_userdocs_extending_designer_reference.html#ast-inspection) + * the [AST dump feature](pmd_devdocs_experimental_ast_dump.html) diff --git a/docs/pages/pmd/userdocs/extending/your_first_rule.md b/docs/pages/pmd/userdocs/extending/your_first_rule.md index 27dba388cf..acec128716 100644 --- a/docs/pages/pmd/userdocs/extending/your_first_rule.md +++ b/docs/pages/pmd/userdocs/extending/your_first_rule.md @@ -140,24 +140,3 @@ TODO You can notice that your XPath expression ends up inside a [property](pmd_userdocs_configuring_rules.html#rule-properties) of a rule of type XPathRule, which is how XPath rules are implemented. - -### Defining rule properties - -Some time later, your boss' boss decides he doesn't want to be called short in Java -too, and would like you to add him to the rule. There are several ways to do that, -but you decide to use a rule property to make your rule extensible. Doing that -directly in the XML is [explained on that page](pmd_userdocs_extending_defining_properties.html#for-xpath-rules), - and we'll explain here how to do that in the designer. - -The table to the left of the zone (3) in the screenshot above is a list of -properties defined for your rule. -Right-clicking the table and selecting "Add property..", you may add a property of -type `List[String]` to represent your boss names. You can then use it in your XPath -query with a dollar prefix, i.e. - -```xpath -//VariableDeclaratorId[@Image = $bossNames and ../../Type[@TypeImage = "short"]] -``` - - -{% include note.html content="Using a property of type `List[String]` requires you to use XPath 2.0" %} From 54b8acea5bd028d56961d0dd9c1bdd7d50699d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 6 Feb 2020 16:19:01 +0100 Subject: [PATCH 047/235] Fix dead links --- .../pmd/userdocs/extending/defining_properties.md | 2 +- .../pmd/userdocs/extending/writing_java_rules.md | 12 ++++++------ .../pmd/userdocs/extending/writing_rules_intro.md | 4 ++-- .../pmd/userdocs/extending/writing_xpath_rules.md | 4 ++-- docs/pages/pmd/userdocs/suppressing_warnings.md | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/defining_properties.md b/docs/pages/pmd/userdocs/extending/defining_properties.md index 82892447ed..97a3151664 100644 --- a/docs/pages/pmd/userdocs/extending/defining_properties.md +++ b/docs/pages/pmd/userdocs/extending/defining_properties.md @@ -189,4 +189,4 @@ the sequence *contains* `@Image`. That is, the above rule will report all variab named `foo` or `bar`. All other XPath 2.0 [functions operating on sequences](https://www.w3.org/TR/xpath-functions/#sequence-functions) are supported. -{%include tip.html content="You can also [define properties directly in the designer](pmd-userdocs_designer_reference.html#rule-properties)" %} +{%include tip.html content="You can also [define properties directly in the designer](pmd_userdocs_extending_designer_reference.html#rule-properties)" %} diff --git a/docs/pages/pmd/userdocs/extending/writing_java_rules.md b/docs/pages/pmd/userdocs/extending/writing_java_rules.md index 7c69854899..4b03dd6626 100644 --- a/docs/pages/pmd/userdocs/extending/writing_java_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_java_rules.md @@ -19,7 +19,7 @@ not sure we even need a doc page. Would be simpler to maintain too" %} This page covers the specifics of writing a rule in Java. The basic development process is very similar to the process for XPath rules, which is described in -[Using the Designer](pmd_userdocs_extending_designer_intro.html#rule-development-process). +[Your First Rule](pmd_userdocs_extending_your_first_rule.html#rule-development-process). Basically, you open the designer, look at the structure of the AST, and refine your rule as you add test cases. @@ -59,7 +59,7 @@ public class MyRule extends AbstractJavaRule { ``` Generally, a rule wants to check for only some node types. In our XPath example -in [Using the Designer](pmd_userdocs_extending_designer_intro.html#a-simple-rule), +in [Your First Rule](pmd_userdocs_extending_your_first_rule.html), we wanted to check for some `VariableDeclaratorId` nodes. That's the XPath name, but in Java, you'll get access to the {% jdoc jast::ASTVariableDeclaratorId %} full API. @@ -74,12 +74,12 @@ public class MyRule extends AbstractJavaRule { public Object visit(ASTVariableDeclaratorId node, Object data) { // This method is called on each node of type ASTVariableDeclaratorId // in the AST - + if (node.getType() == short.class) { // reports a violation at the position of the node // the "data" parameter is a context object handed to by your rule - // the message for the violation is the message defined in the rule declaration XML element - addViolation(data, node); + // the message for the violation is the message defined in the rule declaration XML element + addViolation(data, node); } // this calls back to the default implementation, which recurses further down the subtree @@ -144,7 +144,7 @@ Exactly once: 1. The rule's no-arg constructor is called when loading the ruleset. The rule's constructor must define: * [Rulechain visits](#economic-traversal-the-rulechain) - * [Property descriptors](pmd_userdocs_extending_defining_properties#for-java-rules) + * [Property descriptors](pmd_userdocs_extending_defining_properties.html#for-java-rules) 2. If the rule was included in the ruleset as a rule reference, some properties [may be overridden](pmd_userdocs_configuring_rules.html#rule-properties). If an overridden property is unknown, an error is reported. diff --git a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md index 20f4147b20..7eb50eaf85 100644 --- a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md +++ b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md @@ -39,7 +39,7 @@ chain produced by a lexer (which is e.g. what Checkstyle works on). For example: ```java class Foo extends Object { - + } ``` @@ -125,7 +125,7 @@ Example: To learn how to write a rule: -* [Using the Rule Designer](pmd_userdocs_extending_designer_intro.html) +* [Your First Rule](pmd_userdocs_extending_your_first_rule.html) introduces the basic development process of a rule with a running example * [Writing XPath Rules](pmd_userdocs_extending_writing_xpath_rules.html) explains a bit more about XPath rules and our XPath API diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index fd1299854f..02668f79ef 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -15,7 +15,7 @@ author: Miguel Griffa , Clément Fournier @@ -37,7 +37,7 @@ but approachable review of the features of XPath 2.0 and above, see [the Saxon d 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](l#migrating-from-10-to-20) below. +See [the migration guide](#migrating-from-10-to-20) below. ## DOM representation of ASTs diff --git a/docs/pages/pmd/userdocs/suppressing_warnings.md b/docs/pages/pmd/userdocs/suppressing_warnings.md index 78860877d0..320fb9b5b7 100644 --- a/docs/pages/pmd/userdocs/suppressing_warnings.md +++ b/docs/pages/pmd/userdocs/suppressing_warnings.md @@ -32,7 +32,7 @@ for you: changing the Rule, but you do not need to submit a patch back to the PMD project. -If you need to modify the Rule, see [How to write a rule](pmd_userdocs_extending_writing_pmd_rules.html). +If you need to modify the Rule, see [How to write a rule](pmd_userdocs_extending_writing_rules_intro.html). Otherwise, the other suppression methods are explained in the following sections. ## Annotations From 6e4daadc434974294e71eb7cec7f54c919168fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 8 Feb 2020 20:22:59 +0100 Subject: [PATCH 048/235] Add java version 14 --- .../java/net/sourceforge/pmd/lang/BaseLanguageModule.java | 2 ++ .../net/sourceforge/pmd/lang/java/JavaLanguageModule.java | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/BaseLanguageModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/BaseLanguageModule.java index 696fcbe974..05cfba2c9f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/BaseLanguageModule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/BaseLanguageModule.java @@ -51,6 +51,8 @@ public abstract class BaseLanguageModule implements Language { } if (isDefault) { + assert defaultVersion == null + : "Default version already set to " + defaultVersion + ", cannot set it to " + languageVersion; defaultVersion = languageVersion; } } 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 a8052f8f32..c92acd6ea0 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,8 +28,10 @@ public class JavaLanguageModule extends BaseLanguageModule { addVersion("11", new JavaLanguageHandler(11), false); addVersion("12", new JavaLanguageHandler(12), false); addVersion("12-preview", new JavaLanguageHandler(12, true), false); - addVersion("13", new JavaLanguageHandler(13), true); + addVersion("13", new JavaLanguageHandler(13), false); addVersion("13-preview", new JavaLanguageHandler(13, true), false); + addVersion("14", new JavaLanguageHandler(14), true); + addVersion("14-preview", new JavaLanguageHandler(14, true), false); } } From ad023e8fa63392d814a9c91148b37275dbde83d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sat, 8 Feb 2020 20:35:47 +0100 Subject: [PATCH 049/235] Support type test patterns --- .../pmd/lang/BaseLanguageModule.java | 1 + pmd-java/etc/grammar/Java.jjt | 44 ++++++++++------- .../pmd/lang/java/JavaLanguageModule.java | 4 +- .../pmd/lang/java/ast/ASTPattern.java | 26 ++++++++++ .../pmd/lang/java/ast/ASTTypeTestPattern.java | 47 +++++++++++++++++++ .../java/ast/ASTVariableDeclaratorId.java | 10 ++++ .../java/ast/JavaParserDecoratedVisitor.java | 6 +++ .../java/ast/JavaParserVisitorAdapter.java | 5 ++ .../java/ast/JavaParserVisitorDecorator.java | 5 ++ .../pmd/lang/java/rule/AbstractJavaRule.java | 6 +++ .../pmd/lang/java/ast/ASTPatternTest.kt | 34 ++++++++++++++ .../pmd/lang/java/ast/KotlinTestingDsl.kt | 14 +++++- .../pmd/lang/ast/test/BaseParsingHelper.kt | 3 +- 13 files changed, 184 insertions(+), 21 deletions(-) create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java create mode 100644 pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/BaseLanguageModule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/BaseLanguageModule.java index 05cfba2c9f..93c64111c6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/BaseLanguageModule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/BaseLanguageModule.java @@ -111,6 +111,7 @@ public abstract class BaseLanguageModule implements Language { @Override public LanguageVersion getDefaultVersion() { + assert defaultVersion != null : "Null default version for language " + this; return defaultVersion; } diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 727a1d6f06..002b1009e3 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -205,7 +205,7 @@ options { STATIC = false; USER_CHAR_STREAM = true; JDK_VERSION = "1.5"; - + MULTI = true; VISITOR = true; NODE_USES_PARSER = true; @@ -294,25 +294,25 @@ public class JavaParser { throwParseException("Can't use hexadecimal floating point literals in pre-JDK 1.5 target"); } } - + private void checkForBadNumericalLiteralslUsage(Token token) { if (jdkVersion < 7) { if (token.image.contains("_")) { throwParseException("Can't use underscores in numerical literals when running in JDK inferior to 1.7 mode!"); } - + if (token.image.startsWith("0b") || token.image.startsWith("0B")) { - throwParseException("Can't use binary numerical literals when running in JDK inferior to 1.7 mode!"); + throwParseException("Can't use binary numerical literals when running in JDK inferior to 1.7 mode!"); } } } - + private void checkForBadDiamondUsage() { if (jdkVersion < 7) { throwParseException("Cannot use the diamond generic notation when running in JDK inferior to 1.7 mode!"); } } - + private void checkForBadTryWithResourcesUsage() { if (jdkVersion < 7) { throwParseException("Cannot use the try-with-resources notation when running in JDK inferior to 1.7 mode!"); @@ -355,6 +355,13 @@ public class JavaParser { throwParseException("Cannot use explicit receiver parameters when running in JDK inferior to 1.8 mode!"); } } + + private void checkforBadInstanceOfPattern() { + if (jdkVersion != 14 || !preview) { + throwParseException("Cannot use type test patterns in instanceof when running in JDK other than 14-preview"); + } + } + private void checkForBadAnonymousDiamondUsage() { if (jdkVersion < 9) { ASTAllocationExpression node = (ASTAllocationExpression)jjtree.peekNode(); @@ -397,7 +404,7 @@ public class JavaParser { } } private void checkForMultipleCaseLabels() { - if ((jdkVersion != 12 && jdkVersion != 13) || !preview) { + if (!switchExprAllowed()) { throwParseException("Multiple case labels in switch statements are only supported with Java 12 or 13 Preview"); } } @@ -410,14 +417,19 @@ public class JavaParser { * See also comment at #Expression(). */ private boolean inSwitchLabel = false; + + private boolean switchExprAllowed() { + return jdkVersion >= 14 || jdkVersion >= 12 && preview; + } + private void checkForSwitchRules() { - if ((jdkVersion != 12 && jdkVersion != 13) || !preview) { - throwParseException("Switch rules in switch statements are only supported with Java 12 or 13 Preview"); + if (!switchExprAllowed()) { + throwParseException("Switch rules in switch statements are only supported with Java 12 or 13 Preview, or Java >= 14"); } } private void checkForSwitchExpression() { - if ((jdkVersion != 12 && jdkVersion != 13) || !preview) { - throwParseException("Switch expressions are only supported with Java 12 or 13 Preview"); + if (!switchExprAllowed()) { + throwParseException("Switch expressions are only supported with Java 12 or 13 Preview, or Java >= 14"); } } @@ -447,7 +459,7 @@ public class JavaParser { if (jdkVersion <= 3) { return false; } - + return getToken(1).image.equals("assert"); } @@ -1429,7 +1441,7 @@ void EqualityExpression() #EqualityExpression(>1): void InstanceOfExpression() #InstanceOfExpression(>1): {} { - RelationalExpression() [ LOOKAHEAD(2) "instanceof" Type() ] + RelationalExpression() [ LOOKAHEAD(2) "instanceof" Type() [ {checkforBadInstanceOfPattern();} VariableDeclaratorId() #TypeTestPattern(2) ] ] } void RelationalExpression() #RelationalExpression(>1): @@ -1447,7 +1459,7 @@ void RelationalExpression() #RelationalExpression(>1): void ShiftExpression() #ShiftExpression(>1): {} { - AdditiveExpression() + AdditiveExpression() ( LOOKAHEAD(2) ( "<<" { jjtThis.setImage("<<");} | RSIGNEDSHIFT() { jjtThis.setImage(">>"); } @@ -1717,7 +1729,7 @@ void Block() : {Token t;} { "{" - + ( BlockStatement() )* t = "}" { if (isPrecededByComment(t)) { jjtThis.setContainsComment(); } } } @@ -1971,7 +1983,7 @@ void ResourceSpecification() : "(" Resources() (LOOKAHEAD(2) ";")? - ")" + ")" } void Resources() : 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 c92acd6ea0..4deafd44e9 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,9 @@ public class JavaLanguageModule extends BaseLanguageModule { addVersion("11", new JavaLanguageHandler(11), false); addVersion("12", new JavaLanguageHandler(12), false); addVersion("12-preview", new JavaLanguageHandler(12, true), false); - addVersion("13", new JavaLanguageHandler(13), false); + addVersion("13", new JavaLanguageHandler(13), true); // 13 is the default addVersion("13-preview", new JavaLanguageHandler(13, true), false); - addVersion("14", new JavaLanguageHandler(14), true); + addVersion("14", new JavaLanguageHandler(14), false); addVersion("14-preview", new JavaLanguageHandler(14, true), false); } 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 new file mode 100644 index 0000000000..ee1c507354 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java @@ -0,0 +1,26 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +/** + * A pattern (for pattern matching constructs like {@link ASTInstanceOfExpression InstanceOfExpression}). + * This is a JDK 14 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 + * patterns are in the works for JDK 15 preview. + * + *

See https://openjdk.java.net/jeps/305, https://openjdk.java.net/jeps/8235186 + * + *

+ *
+ * Pattern ::= {@link ASTTypeTestPattern TypeTestPattern}
+ *
+ * 
+ */ +public interface ASTPattern extends JavaNode { + + +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java new file mode 100644 index 0000000000..86b0546525 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java @@ -0,0 +1,47 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.ast; + +/** + * A type test pattern (JDK 14 preview feature). This can be found on + * the right-hand side of an {@link ASTInstanceOfExpression InstanceOfExpression}. + * + *
+ *
+ * TypeTestPattern ::= {@linkplain ASTType Type} {@link ASTVariableDeclaratorId VariableDeclaratorId}
+ *
+ * 
+ */ +public final class ASTTypeTestPattern extends AbstractJavaNode implements ASTPattern { + + + ASTTypeTestPattern(int id) { + super(id); + } + + ASTTypeTestPattern(JavaParser p, int id) { + super(p, id); + } + + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + + /** + * Gets the type against which the expression is tested. + */ + public ASTType getTypeNode() { + return (ASTType) getChild(0); + } + + /** Returns the declared variable. */ + public ASTVariableDeclaratorId getVarId() { + return (ASTVariableDeclaratorId) getChild(1); + } + +} 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 7ec951b2c3..70732e0c3b 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 @@ -239,6 +239,14 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim return isLambdaParamWithNoType() || isLocalVariableTypeInferred() || isLambdaTypeInferred(); } + /** + * Returns true if this is a binding variable in a + * {@linkplain ASTPattern pattern}. + */ + public boolean isPatternBinding() { + return getParent() instanceof ASTPattern; + } + private boolean isLocalVariableTypeInferred() { if (isResourceDeclaration()) { @@ -288,6 +296,8 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim } else if (isTypeInferred()) { // lambda expression with lax types. The type is inferred... return null; + } else if (getParent() instanceof ASTTypeTestPattern) { + return ((ASTTypeTestPattern) getParent()).getTypeNode(); } else { Node n = getParent().getParent(); if (n instanceof ASTLocalVariableDeclaration || n instanceof ASTFieldDeclaration) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java index e290b50ddc..fe79a473d0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java @@ -898,4 +898,10 @@ public class JavaParserDecoratedVisitor implements JavaParserVisitor { visitor.visit(node, data); return visit((JavaNode) node, data); } + + @Override + public Object visit(ASTTypeTestPattern node, Object data) { + visitor.visit(node, data); + return visit((JavaNode) node, data); + } } 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 4f8b181003..10a6c0c735 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 @@ -625,4 +625,9 @@ public class JavaParserVisitorAdapter implements JavaParserVisitor { public Object visit(ASTYieldStatement node, Object data) { return visit((JavaNode) node, data); } + + @Override + public Object visit(ASTTypeTestPattern node, Object data) { + return visit((JavaNode) node, data); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java index a94d67a3d9..aa8f4f46c9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java @@ -758,4 +758,9 @@ public class JavaParserVisitorDecorator implements JavaParserControllessVisitor public Object visit(ASTYieldStatement node, Object data) { return visitor.visit(node, data); } + + @Override + public Object visit(ASTTypeTestPattern node, Object data) { + return visitor.visit(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 219c6981b1..f21ab51b2f 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 @@ -123,6 +123,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTTypeBound; import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTTypeParameter; import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters; +import net.sourceforge.pmd.lang.java.ast.ASTTypeTestPattern; import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpressionNotPlusMinus; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; @@ -834,4 +835,9 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse public Object visit(ASTYieldStatement node, Object data) { return visit((JavaNode) node, data); } + + @Override + public Object visit(ASTTypeTestPattern node, Object data) { + return visit((JavaNode) node, data); + } } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt new file mode 100644 index 0000000000..64dc9dd6c1 --- /dev/null +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt @@ -0,0 +1,34 @@ +package net.sourceforge.pmd.lang.java.ast + +import net.sourceforge.pmd.lang.ast.test.shouldBe +import net.sourceforge.pmd.lang.java.ast.JavaVersion.J14__PREVIEW +import java.io.IOException + +class ASTPatternTest : ParserTestSpec({ + + parserTest("Test patterns only available on JDK 14 (preview)", javaVersions = !J14__PREVIEW) { + + expectParseException("Cannot use type test patterns in instanceof when running in JDK other than 14-preview") { + parseAstExpression("obj instanceof Class c") + } + + } + + parserTest("Test simple patterns", javaVersion = J14__PREVIEW) { + + importedTypes += IOException::class.java + + "obj instanceof Class c" should matchExpr { + unspecifiedChild() + child { + it::getTypeNode shouldBe child(ignoreChildren = true) {} + + it::getVarId shouldBe child { + it::getVariableName shouldBe "c" + } + } + } + } + + +}) diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt index 71756d18f8..cbc9ed4da2 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt @@ -3,18 +3,28 @@ package net.sourceforge.pmd.lang.java.ast import io.kotlintest.matchers.string.shouldContain import io.kotlintest.shouldThrow import net.sourceforge.pmd.lang.ast.Node -import net.sourceforge.pmd.lang.ast.test.* +import net.sourceforge.pmd.lang.ast.test.Assertions +import net.sourceforge.pmd.lang.ast.test.NodeSpec +import net.sourceforge.pmd.lang.ast.test.matchNode +import net.sourceforge.pmd.lang.ast.test.shouldMatchNode import net.sourceforge.pmd.lang.java.JavaParsingHelper /** * Represents the different Java language versions. */ enum class JavaVersion : Comparable { - J1_3, J1_4, J1_5, J1_6, J1_7, J1_8, J9, J10, J11, J12, J12__PREVIEW, J13, J13__PREVIEW; + J1_3, J1_4, J1_5, J1_6, J1_7, J1_8, J9, J10, J11, + J12, J12__PREVIEW, + J13, J13__PREVIEW, + J14, J14__PREVIEW; /** Name suitable for use with e.g. [JavaParsingHelper.parse] */ val pmdName: String = name.removePrefix("J").replaceFirst("__", "-").replace('_', '.').toLowerCase() + val parser: JavaParsingHelper = JavaParsingHelper.WITH_PROCESSING.withDefaultVersion(pmdName) + + operator fun not(): List = values().toList() - this + /** * Overloads the range operator, e.g. (`J9..J11`). * If both operands are the same, a singleton list is returned. diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt index c9e21e4a19..4a486a397c 100644 --- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt +++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt @@ -49,7 +49,8 @@ abstract class BaseParsingHelper, T : RootNode */ fun getVersion(version: String?): LanguageVersion { val language = LanguageRegistry.getLanguage(langName) - return if (version == null) language.defaultVersion else language.getVersion(version) + return if (version == null) language.defaultVersion + else language.getVersion(version) ?: throw AssertionError("Unsupported version $version for language $language") } val defaultVersion: LanguageVersion From 5a6d332579a975d3d2e19078a3b31303fa75045b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 9 Feb 2020 00:11:06 +0100 Subject: [PATCH 050/235] Make sure symbol table doesn't cry on duplicate name --- .../pmd/lang/java/symboltable/AbstractJavaScope.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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..39dc26a5d7 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 @@ -24,9 +24,13 @@ public abstract class AbstractJavaScope extends AbstractScope { } protected void checkForDuplicatedNameDeclaration(NameDeclaration declaration) { - if (declaration instanceof VariableNameDeclaration && getDeclarations().keySet().contains(declaration)) { - throw new RuntimeException(declaration + " is already in the symbol table"); - } + // Don't throw an exception, type tests patterns are tricky to implement + // and given it's a preview feature, and the sym table will be replaced + // for 7.0, it's not useful to support them. + + // if (declaration instanceof VariableNameDeclaration && getDeclarations().keySet().contains(declaration)) { + // throw new RuntimeException(declaration + " is already in the symbol table"); + // } } @Override From 97a43945531457d933057706f4c3b5e00d5ebe71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 9 Feb 2020 00:48:01 +0100 Subject: [PATCH 051/235] Mark new API as experimental --- .../pmd/lang/java/ast/ASTInstanceOfExpression.java | 6 ++++-- .../java/net/sourceforge/pmd/lang/java/ast/ASTPattern.java | 3 +++ .../sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java | 3 +++ .../pmd/lang/java/ast/ASTVariableDeclaratorId.java | 2 ++ .../pmd/lang/java/ast/JavaParserDecoratedVisitor.java | 3 +++ .../sourceforge/pmd/lang/java/rule/AbstractJavaRule.java | 2 ++ .../pmd/lang/java/symboltable/AbstractJavaScope.java | 1 + 7 files changed, 18 insertions(+), 2 deletions(-) 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 9cfb458436..091810cbd2 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 @@ -16,7 +16,7 @@ import net.sourceforge.pmd.annotation.InternalApi; * *
  *
- * InstanceOfExpression ::=  {@linkplain ASTShiftExpression ShiftExpression} "instanceof" {@linkplain ASTType Type}
+ * InstanceOfExpression ::= {@linkplain ASTShiftExpression ShiftExpression} "instanceof" ({@linkplain ASTType Type} | {@link ASTPattern Pattern})
  *
  * 
*/ @@ -46,7 +46,9 @@ public class ASTInstanceOfExpression extends AbstractJavaTypeNode { * Gets the type against which the expression is tested. */ public ASTType getTypeNode() { - return (ASTType) getChild(1); + JavaNode child = getChild(1); + return child instanceof ASTType ? (ASTType) child + : ((ASTTypeTestPattern) child).getTypeNode(); } } 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 ee1c507354..db9f2b0e8c 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 @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.java.ast; +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. @@ -20,6 +22,7 @@ package net.sourceforge.pmd.lang.java.ast; * * */ +@Experimental public interface ASTPattern extends JavaNode { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java index 86b0546525..c126b89198 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.Experimental; + /** * A type test pattern (JDK 14 preview feature). This can be found on * the right-hand side of an {@link ASTInstanceOfExpression InstanceOfExpression}. @@ -14,6 +16,7 @@ package net.sourceforge.pmd.lang.java.ast; * * */ +@Experimental public final class ASTTypeTestPattern extends AbstractJavaNode implements ASTPattern { 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 70732e0c3b..c5383b7c19 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 @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.List; +import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; @@ -243,6 +244,7 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim * Returns true if this is a binding variable in a * {@linkplain ASTPattern pattern}. */ + @Experimental public boolean isPatternBinding() { return getParent() instanceof ASTPattern; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java index fe79a473d0..1512a3084c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.Experimental; + /** * External wrapper for a visitor decorator. This one drives the AST visit, delegating to the base controlless visitor * given in the constructor. Add decorators using the {@link #decorateWith(JavaParserVisitorDecorator)}. @@ -900,6 +902,7 @@ public class JavaParserDecoratedVisitor implements JavaParserVisitor { } @Override + @Experimental public Object visit(ASTTypeTestPattern node, Object data) { visitor.visit(node, data); return visit((JavaNode) 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 f21ab51b2f..80c9c6fd52 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 @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.rule; import java.util.List; import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.JavaLanguageModule; @@ -837,6 +838,7 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse } @Override + @Experimental public Object visit(ASTTypeTestPattern node, Object data) { return visit((JavaNode) node, data); } 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 39dc26a5d7..3e7eb4fa51 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 @@ -27,6 +27,7 @@ public abstract class AbstractJavaScope extends AbstractScope { // Don't throw an exception, type tests patterns are tricky to implement // and given it's a preview feature, and the sym table will be replaced // for 7.0, it's not useful to support them. + // See https://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html#scoping-of-pattern-variables // if (declaration instanceof VariableNameDeclaration && getDeclarations().keySet().contains(declaration)) { // throw new RuntimeException(declaration + " is already in the symbol table"); From 63fbfbd8c7f38b0f9cae20a02fb0a7041f11d221 Mon Sep 17 00:00:00 2001 From: kris-scheibe Date: Mon, 10 Feb 2020 23:20:08 +0100 Subject: [PATCH 052/235] UnusedImports rule now matches regular static imports first and on-demand static imports after that --- .../rule/bestpractices/UnusedImportsRule.java | 15 ++++++++++- .../rule/bestpractices/xml/UnusedImports.xml | 26 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedImportsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedImportsRule.java index da54a66ce0..ce0966823e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedImportsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedImportsRule.java @@ -152,14 +152,27 @@ public class UnusedImportsRule extends AbstractJavaRule { return; } ImportWrapper candidate = getImportWrapper(node); + + // check exact imports Iterator it = imports.iterator(); while (it.hasNext()) { ImportWrapper i = it.next(); - if (i.matches(candidate)) { + if (!i.isStaticOnDemand() && i.matches(candidate)) { it.remove(); return; } } + + // check static on-demand imports + it = imports.iterator(); + while (it.hasNext()) { + ImportWrapper i = it.next(); + if (i.isStaticOnDemand() && i.matches(candidate)) { + it.remove(); + return; + } + } + if (TypeNode.class.isAssignableFrom(node.getClass()) && ((TypeNode) node).getType() != null) { Class c = ((TypeNode) node).getType(); if (c.getPackage() != null) { diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedImports.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedImports.xml index 13438e73cd..5fe5e64653 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedImports.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedImports.xml @@ -552,4 +552,30 @@ public class Issue2016 { } ]]> + + + 0 + + java 1.5 + From 2922694cdd8c371cc935bc6ea57919f0b7a681ca Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 11 Feb 2020 17:32:22 +0000 Subject: [PATCH 053/235] Copy paste the apex doc detector to calculate the suppress map We can generate the suppress map from the individual tokens that get passed from the lexer. --- .../pmd/lang/apex/ast/ApexParser.java | 2 +- .../pmd/lang/apex/ast/ApexTreeBuilder.java | 29 +++++++++++++++++++ .../pmd/lang/apex/SuppressWarningsTest.java | 10 +++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java index 3cbd386de2..d48f49452a 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java @@ -48,7 +48,7 @@ public class ApexParser { final String sourceCode = IOUtils.toString(reader); final Compilation astRoot = parseApex(sourceCode); final ApexTreeBuilder treeBuilder = new ApexTreeBuilder(sourceCode); - suppressMap = new HashMap<>(); + suppressMap = treeBuilder.getSuppressMap(); if (astRoot == null) { throw new ParseException("Couldn't parse the source - there is not root node - Syntax Error??"); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index 084186cbfa..4301f9a725 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -228,11 +228,13 @@ public final class ApexTreeBuilder extends AstVisitor { private final SourceCodePositioner sourceCodePositioner; private final String sourceCode; private List apexDocTokenLocations; + private Map suppressMap; public ApexTreeBuilder(String sourceCode) { this.sourceCode = sourceCode; sourceCodePositioner = new SourceCodePositioner(sourceCode); apexDocTokenLocations = buildApexDocTokenLocations(sourceCode); + suppressMap = buildSuppressMap(sourceCode); } static AbstractApexNode createNodeAdapter(T node) { @@ -366,6 +368,29 @@ public final class ApexTreeBuilder extends AstVisitor { return tokenLocations; } + private static Map buildSuppressMap(String source) { + ANTLRStringStream stream = new ANTLRStringStream(source); + ApexLexer lexer = new ApexLexer(stream); + + Map suppressMap = new HashMap<>(); + Token token = lexer.nextToken(); + + while (token.getType() != Token.EOF) { + if (token.getType() == ApexLexer.EOL_COMMENT) { + // check if it starts with NOPMD + String trimmedCommentText = token.getText().substring(2).trim(); + + if (trimmedCommentText.startsWith("NOPMD")) { + suppressMap.put(token.getLine(), trimmedCommentText.substring(5)); + } + } + + token = lexer.nextToken(); + } + + return suppressMap; + } + private static class ApexDocTokenLocation { int index; Token token; @@ -387,6 +412,10 @@ public final class ApexTreeBuilder extends AstVisitor { } } + public Map getSuppressMap() { + return suppressMap; + } + @Override public boolean visit(UserEnum node, AdditionalPassScope scope) { return visit(node); diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java index 79c4e5ed86..f45167d4cf 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java @@ -139,6 +139,14 @@ public class SuppressWarningsTest extends RuleTst { assertEquals(0, rpt.size()); } + @Test + public void testCommentSuppression() { + Report rpt = new Report(); + runTestFromString(TEST14, new FooRule(), rpt, + LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getDefaultVersion()); + assertEquals(0, rpt.size()); + } + private static final String TEST1 = "@SuppressWarnings('PMD')" + PMD.EOL + "public class Foo {}"; private static final String TEST2 = "@SuppressWarnings('PMD')" + PMD.EOL + "public class Foo {" + PMD.EOL @@ -181,4 +189,6 @@ public class SuppressWarningsTest extends RuleTst { private static final String TEST13 = "@SuppressWarnings('PMD.NoBar')" + PMD.EOL + "public class Bar {" + PMD.EOL + "}"; + + private static final String TEST14 = "public class Bar {" + PMD.EOL + "Integer foo; // NOPMD" + PMD.EOL + "}"; } From c0ec1f67c974453d055b20d7ef99c936bd1b06c5 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 11 Feb 2020 17:41:55 +0000 Subject: [PATCH 054/235] Only parse source code once for doc comments and suppressions --- .../pmd/lang/apex/ast/ApexTreeBuilder.java | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index 4301f9a725..e77e25d7bf 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -233,8 +233,10 @@ public final class ApexTreeBuilder extends AstVisitor { public ApexTreeBuilder(String sourceCode) { this.sourceCode = sourceCode; sourceCodePositioner = new SourceCodePositioner(sourceCode); - apexDocTokenLocations = buildApexDocTokenLocations(sourceCode); - suppressMap = buildSuppressMap(sourceCode); + + CommentInformation commentInformation = extractInformationFromComments(sourceCode); + apexDocTokenLocations = commentInformation.docTokenLocations; + suppressMap = commentInformation.suppressMap; } static AbstractApexNode createNodeAdapter(T node) { @@ -343,11 +345,13 @@ public final class ApexTreeBuilder extends AstVisitor { } } - private static List buildApexDocTokenLocations(String source) { + private static CommentInformation extractInformationFromComments(String source) { ANTLRStringStream stream = new ANTLRStringStream(source); ApexLexer lexer = new ApexLexer(stream); List tokenLocations = new LinkedList<>(); + Map suppressMap = new HashMap<>(); + int startIndex = 0; Token token = lexer.nextToken(); int endIndex = lexer.getCharIndex(); @@ -358,25 +362,7 @@ public final class ApexTreeBuilder extends AstVisitor { if (token.getText().startsWith("/**")) { tokenLocations.add(new ApexDocTokenLocation(startIndex, token)); } - } - // TODO : Check other non-doc comments and tokens of type ApexLexer.EOL_COMMENT for "NOPMD" suppressions - startIndex = endIndex; - token = lexer.nextToken(); - endIndex = lexer.getCharIndex(); - } - - return tokenLocations; - } - - private static Map buildSuppressMap(String source) { - ANTLRStringStream stream = new ANTLRStringStream(source); - ApexLexer lexer = new ApexLexer(stream); - - Map suppressMap = new HashMap<>(); - Token token = lexer.nextToken(); - - while (token.getType() != Token.EOF) { - if (token.getType() == ApexLexer.EOL_COMMENT) { + } else if (token.getType() == ApexLexer.EOL_COMMENT) { // check if it starts with NOPMD String trimmedCommentText = token.getText().substring(2).trim(); @@ -385,10 +371,22 @@ public final class ApexTreeBuilder extends AstVisitor { } } + startIndex = endIndex; token = lexer.nextToken(); + endIndex = lexer.getCharIndex(); } - return suppressMap; + return new CommentInformation(suppressMap, tokenLocations); + } + + private static class CommentInformation { + Map suppressMap; + List docTokenLocations; + + CommentInformation(Map suppressMap, List docTokenLocations) { + this.suppressMap = suppressMap; + this.docTokenLocations = docTokenLocations; + } } private static class ApexDocTokenLocation { From 15cd1a2d592f591b8eb9e4c4a209c5bdbf27f9a2 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 11 Feb 2020 17:42:44 +0000 Subject: [PATCH 055/235] Use the PMD.SUPPRESS_MARKER rather than duplicating the string --- .../net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index e77e25d7bf..4bea97c467 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import java.util.Stack; +import net.sourceforge.pmd.PMD; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.Token; @@ -366,8 +367,8 @@ public final class ApexTreeBuilder extends AstVisitor { // check if it starts with NOPMD String trimmedCommentText = token.getText().substring(2).trim(); - if (trimmedCommentText.startsWith("NOPMD")) { - suppressMap.put(token.getLine(), trimmedCommentText.substring(5)); + if (trimmedCommentText.startsWith(PMD.SUPPRESS_MARKER)) { + suppressMap.put(token.getLine(), trimmedCommentText.substring(PMD.SUPPRESS_MARKER.length())); } } From 4916316e42b160729961853b85ab67e841cc6777 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 11 Feb 2020 17:48:07 +0000 Subject: [PATCH 056/235] Use the suppress marker from parser options --- .../sourceforge/pmd/lang/apex/ast/ApexParser.java | 2 +- .../pmd/lang/apex/ast/ApexTreeBuilder.java | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java index d48f49452a..486983b432 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java @@ -47,7 +47,7 @@ public class ApexParser { try { final String sourceCode = IOUtils.toString(reader); final Compilation astRoot = parseApex(sourceCode); - final ApexTreeBuilder treeBuilder = new ApexTreeBuilder(sourceCode); + final ApexTreeBuilder treeBuilder = new ApexTreeBuilder(sourceCode, parserOptions); suppressMap = treeBuilder.getSuppressMap(); if (astRoot == null) { diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index 4bea97c467..b5f4606573 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -12,7 +12,7 @@ import java.util.List; import java.util.Map; import java.util.Stack; -import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.lang.apex.ApexParserOptions; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.Token; @@ -231,11 +231,11 @@ public final class ApexTreeBuilder extends AstVisitor { private List apexDocTokenLocations; private Map suppressMap; - public ApexTreeBuilder(String sourceCode) { + public ApexTreeBuilder(String sourceCode, ApexParserOptions parserOptions) { this.sourceCode = sourceCode; sourceCodePositioner = new SourceCodePositioner(sourceCode); - CommentInformation commentInformation = extractInformationFromComments(sourceCode); + CommentInformation commentInformation = extractInformationFromComments(sourceCode, parserOptions.getSuppressMarker()); apexDocTokenLocations = commentInformation.docTokenLocations; suppressMap = commentInformation.suppressMap; } @@ -346,7 +346,7 @@ public final class ApexTreeBuilder extends AstVisitor { } } - private static CommentInformation extractInformationFromComments(String source) { + private static CommentInformation extractInformationFromComments(String source, String suppressMarker) { ANTLRStringStream stream = new ANTLRStringStream(source); ApexLexer lexer = new ApexLexer(stream); @@ -364,11 +364,11 @@ public final class ApexTreeBuilder extends AstVisitor { tokenLocations.add(new ApexDocTokenLocation(startIndex, token)); } } else if (token.getType() == ApexLexer.EOL_COMMENT) { - // check if it starts with NOPMD + // check if it starts with the suppress marker String trimmedCommentText = token.getText().substring(2).trim(); - if (trimmedCommentText.startsWith(PMD.SUPPRESS_MARKER)) { - suppressMap.put(token.getLine(), trimmedCommentText.substring(PMD.SUPPRESS_MARKER.length())); + if (trimmedCommentText.startsWith(suppressMarker)) { + suppressMap.put(token.getLine(), trimmedCommentText.substring(suppressMarker.length())); } } From 28ce8f6486583b144810b70666ec0b5c742543a4 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Wed, 12 Feb 2020 08:38:31 +0000 Subject: [PATCH 057/235] Properly extract user message --- .../pmd/lang/apex/ast/ApexTreeBuilder.java | 3 ++- .../pmd/lang/apex/SuppressWarningsTest.java | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index b5f4606573..230e8dfa9f 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -368,7 +368,8 @@ public final class ApexTreeBuilder extends AstVisitor { String trimmedCommentText = token.getText().substring(2).trim(); if (trimmedCommentText.startsWith(suppressMarker)) { - suppressMap.put(token.getLine(), trimmedCommentText.substring(suppressMarker.length())); + String userMessage = trimmedCommentText.substring(suppressMarker.length()).trim(); + suppressMap.put(token.getLine(), userMessage); } } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java index f45167d4cf..4622565145 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.apex; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -15,6 +16,8 @@ import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; import net.sourceforge.pmd.testframework.RuleTst; +import java.util.List; + public class SuppressWarningsTest extends RuleTst { private static class BarRule extends AbstractApexRule { @@ -145,6 +148,24 @@ public class SuppressWarningsTest extends RuleTst { runTestFromString(TEST14, new FooRule(), rpt, LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getDefaultVersion()); assertEquals(0, rpt.size()); + + List suppressions = rpt.getSuppressedRuleViolations(); + assertEquals(1, suppressions.size()); + } + + @Test + public void testMessageWithCommentSuppression() { + Report rpt = new Report(); + runTestFromString(TEST15, new FooRule(), rpt, + LanguageRegistry.getLanguage(ApexLanguageModule.NAME).getDefaultVersion()); + assertEquals(0, rpt.size()); + + List suppressions = rpt.getSuppressedRuleViolations(); + assertEquals(1, suppressions.size()); + Report.SuppressedViolation suppression = suppressions.get(0); + + assertTrue(suppression.suppressedByNOPMD()); + assertEquals("We allow foo here", suppression.getUserMessage()); } private static final String TEST1 = "@SuppressWarnings('PMD')" + PMD.EOL + "public class Foo {}"; @@ -191,4 +212,6 @@ public class SuppressWarningsTest extends RuleTst { + "}"; private static final String TEST14 = "public class Bar {" + PMD.EOL + "Integer foo; // NOPMD" + PMD.EOL + "}"; + + private static final String TEST15 = "public class Bar {" + PMD.EOL + "Integer foo; //NOPMD We allow foo here" + PMD.EOL + "}"; } From bcf1c88cc249223b22a290b000988cb185fbb894 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Wed, 12 Feb 2020 09:34:04 +0000 Subject: [PATCH 058/235] If suppress marker is null, don't check for suppressions --- .../net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index 230e8dfa9f..42ae4c6308 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -357,13 +357,15 @@ public final class ApexTreeBuilder extends AstVisitor { Token token = lexer.nextToken(); int endIndex = lexer.getCharIndex(); + boolean checkForCommentSuppression = suppressMarker != null; + while (token.getType() != Token.EOF) { if (token.getType() == ApexLexer.BLOCK_COMMENT) { // Filter only block comments starting with "/**" if (token.getText().startsWith("/**")) { tokenLocations.add(new ApexDocTokenLocation(startIndex, token)); } - } else if (token.getType() == ApexLexer.EOL_COMMENT) { + } else if (checkForCommentSuppression && token.getType() == ApexLexer.EOL_COMMENT) { // check if it starts with the suppress marker String trimmedCommentText = token.getText().substring(2).trim(); From 202da60d2ded03139653bc2720a1ef4f75a1ff0c Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Wed, 12 Feb 2020 09:49:12 +0000 Subject: [PATCH 059/235] Fix checkstyle errors --- .../java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java | 1 - .../net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java | 2 +- .../net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java index 486983b432..71a4b1d446 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.apex.ast; import java.io.IOException; import java.io.Reader; -import java.util.HashMap; import java.util.Map; import org.apache.commons.io.IOUtils; diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index 42ae4c6308..53ba9d6f7a 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -12,10 +12,10 @@ import java.util.List; import java.util.Map; import java.util.Stack; -import net.sourceforge.pmd.lang.apex.ApexParserOptions; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.Token; +import net.sourceforge.pmd.lang.apex.ApexParserOptions; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.SourceCodePositioner; diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java index 4622565145..f98c1af402 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java @@ -7,6 +7,8 @@ package net.sourceforge.pmd.lang.apex; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.util.List; + import org.junit.Test; import net.sourceforge.pmd.PMD; @@ -16,8 +18,6 @@ import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; import net.sourceforge.pmd.testframework.RuleTst; -import java.util.List; - public class SuppressWarningsTest extends RuleTst { private static class BarRule extends AbstractApexRule { From 659e709f7988a5cda6338d8820bde289a22d5f62 Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Wed, 12 Feb 2020 11:12:14 +0100 Subject: [PATCH 060/235] Adjusted BaseTokenFilter to allow filtering on more than one token. When filtering tokens, the analyzeToken method can be overriden to access the current token. This can then be used to implement isLanguageSpecificDiscarding. However, it may be desirable to "look ahead" and base the decision of whether to filter or not on multiple tokens. In order to support this new use case, a new extension point analyzeTokens is provided, which not only has access to the current token, but can also iterate over the upcoming tokens. The functionality of iterating over remaining tokens uses Guava for its implementation. Since pmd-core targets Java 7, the Android flavour of Guava is used. In order to stay consistent with pmd-apex-jorje, this has also been adjusted to the Android flavour. For PMD 7.0, the jre flavour can be used instead. --- pmd-apex-jorje/pom.xml | 2 +- pmd-core/pom.xml | 6 ++ .../cpd/token/internal/BaseTokenFilter.java | 69 ++++++++++++++++++- 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/pmd-apex-jorje/pom.xml b/pmd-apex-jorje/pom.xml index ab7238f975..52c7b7c313 100644 --- a/pmd-apex-jorje/pom.xml +++ b/pmd-apex-jorje/pom.xml @@ -81,7 +81,7 @@ com.google.guava guava - 26.0-jre + 26.0-android com.google.j2objc diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index 80aab40792..80d980a398 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -186,6 +186,12 @@ system-rules test + + com.google.guava + guava + 26.0-android + compile + diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java index 747619b5f3..67cb75937c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java @@ -4,10 +4,16 @@ package net.sourceforge.pmd.cpd.token.internal; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.LinkedList; + import net.sourceforge.pmd.cpd.token.TokenFilter; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.GenericToken; +import com.google.common.collect.AbstractIterator; + /** * A generic filter for PMD token managers that allows to use comments * to enable / disable analysis of parts of the stream @@ -15,7 +21,10 @@ import net.sourceforge.pmd.lang.ast.GenericToken; public abstract class BaseTokenFilter implements TokenFilter { private final TokenManager tokenManager; + private final LinkedList unprocessedTokens; // NOPMD - used both as Queue and List + private final Iterable remainingTokens; private boolean discardingSuppressing; + private T currentToken; /** * Creates a new BaseTokenFilter @@ -23,13 +32,21 @@ public abstract class BaseTokenFilter implements TokenFi */ public BaseTokenFilter(final TokenManager tokenManager) { this.tokenManager = tokenManager; + this.unprocessedTokens = new LinkedList<>(); + this.remainingTokens = new RemainingTokens(); } @Override public final T getNextToken() { - T currentToken = (T) tokenManager.getNextToken(); + currentToken = null; + if (!unprocessedTokens.isEmpty()) { + currentToken = unprocessedTokens.poll(); + return currentToken; + } + currentToken = (T) tokenManager.getNextToken(); while (!shouldStopProcessing(currentToken)) { analyzeToken(currentToken); + analyzeTokens(currentToken, remainingTokens); processCPDSuppression(currentToken); if (!isDiscarding()) { @@ -73,6 +90,18 @@ public abstract class BaseTokenFilter implements TokenFi // noop } + /** + * Extension point for subclasses to analyze all tokens (before filtering) + * and update internal status to decide on custom discard rules. + * + * @param currentToken The token to be analyzed + * @param remainingTokens All upcoming tokens + * @see #isLanguageSpecificDiscarding() + */ + protected void analyzeTokens(final T currentToken, final Iterable remainingTokens) { + // noop + } + /** * Extension point for subclasses to indicate tokens are to be filtered. * @@ -90,4 +119,42 @@ public abstract class BaseTokenFilter implements TokenFi */ protected abstract boolean shouldStopProcessing(T currentToken); + private class RemainingTokens implements Iterable { + + @Override + public Iterator iterator() { + return new RemainingTokensIterator(currentToken); + } + + private class RemainingTokensIterator extends AbstractIterator implements Iterator { + + int index = 0; // index of next element + T startToken; + + RemainingTokensIterator(final T startToken) { + this.startToken = startToken; + } + + @Override + protected T computeNext() { + assert index >= 0; + if (startToken != currentToken) { // NOPMD - intentional check for reference equality + throw new ConcurrentModificationException("Using iterator after next token has been requested."); + } + if (index < unprocessedTokens.size()) { + return unprocessedTokens.get(index++); + } else { + final T nextToken = (T) tokenManager.getNextToken(); + if (shouldStopProcessing(nextToken)) { + return endOfData(); + } + index++; + unprocessedTokens.add(nextToken); + return nextToken; + } + } + + } + } + } From bdfbfae231ce437f6c9a6a67e7a313b6295a9632 Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Wed, 12 Feb 2020 11:19:20 +0100 Subject: [PATCH 061/235] C# tokenizer is now Antlr-based. This is based on the Antlr grammar from https://github.com/antlr/grammars-v4/tree/master/csharp. This adds column information for C# and fixes #2139. --- .../token/internal/BaseTokenFilterTest.java | 190 +++ pmd-cs/pom.xml | 10 +- .../pmd/lang/cs/antlr4/CSharpLexer.g4 | 1105 +++++++++++++++++ .../net/sourceforge/pmd/cpd/CsTokenizer.java | 387 ++---- .../sourceforge/pmd/cpd/CsTokenizerTest.java | 23 +- 5 files changed, 1433 insertions(+), 282 deletions(-) create mode 100644 pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java create mode 100644 pmd-cs/src/main/antlr4/net/sourceforge/pmd/lang/cs/antlr4/CSharpLexer.g4 diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java new file mode 100644 index 0000000000..21da8ccc19 --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java @@ -0,0 +1,190 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.cpd.token.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.junit.Test; + +import net.sourceforge.pmd.lang.TokenManager; +import net.sourceforge.pmd.lang.ast.GenericToken; + +import com.google.common.collect.ImmutableList; + +public class BaseTokenFilterTest { + + class StringToken implements GenericToken { + + private final String text; + + StringToken(final String text) { + this.text = text; + } + + @Override + public GenericToken getNext() { + return null; + } + + @Override + public GenericToken getPreviousComment() { + return null; + } + + @Override + public String getImage() { + return text; + } + + @Override + public int getBeginLine() { + return 0; + } + + @Override + public int getEndLine() { + return 0; + } + + @Override + public int getBeginColumn() { + return 0; + } + + @Override + public int getEndColumn() { + return 0; + } + } + + class StringTokenManager implements TokenManager { + + Iterator iterator = ImmutableList.of("a", "b", "c").iterator(); + + @Override + public Object getNextToken() { + if (iterator.hasNext()) { + return new StringToken(iterator.next()); + } else { + return null; + } + } + + @Override + public void setFileName(final String fileName) { + } + } + + class DummyTokenFilter extends BaseTokenFilter { + + Iterable remainingTokens; + + DummyTokenFilter(final TokenManager tokenManager) { + super(tokenManager); + } + + @Override + protected boolean shouldStopProcessing(final T currentToken) { + return currentToken == null; + } + + @Override + protected void analyzeTokens(final T currentToken, final Iterable remainingTokens) { + this.remainingTokens = remainingTokens; + } + + public Iterable getRemainingTokens() { + return remainingTokens; + } + } + + @Test + public void testRemainingTokensFunctionality1() { + final TokenManager tokenManager = new StringTokenManager(); + final DummyTokenFilter tokenFilter = new DummyTokenFilter(tokenManager); + final GenericToken firstToken = tokenFilter.getNextToken(); + assertEquals("a", firstToken.getImage()); + final Iterable iterable = tokenFilter.getRemainingTokens(); + final Iterator it1 = iterable.iterator(); + final Iterator it2 = iterable.iterator(); + assertTrue(it1.hasNext()); + assertTrue(it2.hasNext()); + final StringToken firstValFirstIt = (StringToken) it1.next(); + final StringToken firstValSecondIt = (StringToken) it2.next(); + assertTrue(it1.hasNext()); + assertTrue(it2.hasNext()); + final StringToken secondValFirstIt = (StringToken) it1.next(); + assertFalse(it1.hasNext()); + assertTrue(it2.hasNext()); + final StringToken secondValSecondIt = (StringToken) it2.next(); + assertFalse(it2.hasNext()); + assertEquals("b", firstValFirstIt.getImage()); + assertEquals("b", firstValSecondIt.getImage()); + assertEquals("c", secondValFirstIt.getImage()); + assertEquals("c", secondValSecondIt.getImage()); + } + + @Test + public void testRemainingTokensFunctionality2() { + final TokenManager tokenManager = new StringTokenManager(); + final DummyTokenFilter tokenFilter = new DummyTokenFilter(tokenManager); + final GenericToken firstToken = tokenFilter.getNextToken(); + assertEquals("a", firstToken.getImage()); + final Iterable iterable = tokenFilter.getRemainingTokens(); + final Iterator it1 = iterable.iterator(); + final Iterator it2 = iterable.iterator(); + assertTrue(it1.hasNext()); + assertTrue(it2.hasNext()); + final StringToken firstValFirstIt = (StringToken) it1.next(); + assertTrue(it1.hasNext()); + final StringToken secondValFirstIt = (StringToken) it1.next(); + assertFalse(it1.hasNext()); + assertTrue(it2.hasNext()); + final StringToken firstValSecondIt = (StringToken) it2.next(); + assertTrue(it2.hasNext()); + final StringToken secondValSecondIt = (StringToken) it2.next(); + assertFalse(it2.hasNext()); + assertEquals("b", firstValFirstIt.getImage()); + assertEquals("b", firstValSecondIt.getImage()); + assertEquals("c", secondValFirstIt.getImage()); + assertEquals("c", secondValSecondIt.getImage()); + } + + @Test(expected = NoSuchElementException.class) + public void testRemainingTokensFunctionality3() { + final TokenManager tokenManager = new StringTokenManager(); + final DummyTokenFilter tokenFilter = new DummyTokenFilter(tokenManager); + final GenericToken firstToken = tokenFilter.getNextToken(); + assertEquals("a", firstToken.getImage()); + final Iterable iterable = tokenFilter.getRemainingTokens(); + final Iterator it1 = iterable.iterator(); + final Iterator it2 = iterable.iterator(); + it1.next(); + it1.next(); + it2.next(); + it2.next(); + it1.next(); + } + + @Test(expected = ConcurrentModificationException.class) + public void testRemainingTokensFunctionality4() { + final TokenManager tokenManager = new StringTokenManager(); + final DummyTokenFilter tokenFilter = new DummyTokenFilter(tokenManager); + final GenericToken firstToken = tokenFilter.getNextToken(); + assertEquals("a", firstToken.getImage()); + final Iterable iterable = tokenFilter.getRemainingTokens(); + final Iterator it1 = iterable.iterator(); + final GenericToken secondToken = tokenFilter.getNextToken(); + assertEquals("b", secondToken.getImage()); + it1.next(); + } + +} diff --git a/pmd-cs/pom.xml b/pmd-cs/pom.xml index 551f9fd4b3..39679d6150 100644 --- a/pmd-cs/pom.xml +++ b/pmd-cs/pom.xml @@ -12,6 +12,11 @@ + + org.antlr + antlr4-maven-plugin + + maven-resources-plugin @@ -23,6 +28,7 @@ + net.sourceforge.pmd @@ -32,10 +38,6 @@ commons-io commons-io - - org.apache.commons - commons-lang3 - junit diff --git a/pmd-cs/src/main/antlr4/net/sourceforge/pmd/lang/cs/antlr4/CSharpLexer.g4 b/pmd-cs/src/main/antlr4/net/sourceforge/pmd/lang/cs/antlr4/CSharpLexer.g4 new file mode 100644 index 0000000000..37428cbc72 --- /dev/null +++ b/pmd-cs/src/main/antlr4/net/sourceforge/pmd/lang/cs/antlr4/CSharpLexer.g4 @@ -0,0 +1,1105 @@ +// Eclipse Public License - v 1.0, http://www.eclipse.org/legal/epl-v10.html +// Copyright (c) 2013, Christian Wulf (chwchw@gmx.de) +// Copyright (c) 2016-2017, Ivan Kochurkin (kvanttt@gmail.com), Positive Technologies. + +lexer grammar CSharpLexer; + +@lexer::header +{import java.util.Stack;} + +channels { COMMENTS_CHANNEL, DIRECTIVE } + +@lexer::members +{private int interpolatedStringLevel; +private Stack interpolatedVerbatiums = new Stack(); +private Stack curlyLevels = new Stack(); +private boolean verbatium; +} + +BYTE_ORDER_MARK: '\u00EF\u00BB\u00BF'; + +SINGLE_LINE_DOC_COMMENT: '///' InputCharacter* -> channel(COMMENTS_CHANNEL); +DELIMITED_DOC_COMMENT: '/**' .*? '*/' -> channel(COMMENTS_CHANNEL); +SINGLE_LINE_COMMENT: '//' InputCharacter* -> channel(COMMENTS_CHANNEL); +DELIMITED_COMMENT: '/*' .*? '*/' -> channel(COMMENTS_CHANNEL); + +WHITESPACES: (Whitespace | NewLine)+ -> channel(HIDDEN); +SHARP: '#' -> mode(DIRECTIVE_MODE); + +ABSTRACT: 'abstract'; +ADD: 'add'; +ALIAS: 'alias'; +ARGLIST: '__arglist'; +AS: 'as'; +ASCENDING: 'ascending'; +ASYNC: 'async'; +AWAIT: 'await'; +BASE: 'base'; +BOOL: 'bool'; +BREAK: 'break'; +BY: 'by'; +BYTE: 'byte'; +CASE: 'case'; +CATCH: 'catch'; +CHAR: 'char'; +CHECKED: 'checked'; +CLASS: 'class'; +CONST: 'const'; +CONTINUE: 'continue'; +DECIMAL: 'decimal'; +DEFAULT: 'default'; +DELEGATE: 'delegate'; +DESCENDING: 'descending'; +DO: 'do'; +DOUBLE: 'double'; +DYNAMIC: 'dynamic'; +ELSE: 'else'; +ENUM: 'enum'; +EQUALS: 'equals'; +EVENT: 'event'; +EXPLICIT: 'explicit'; +EXTERN: 'extern'; +FALSE: 'false'; +FINALLY: 'finally'; +FIXED: 'fixed'; +FLOAT: 'float'; +FOR: 'for'; +FOREACH: 'foreach'; +FROM: 'from'; +GET: 'get'; +GOTO: 'goto'; +GROUP: 'group'; +IF: 'if'; +IMPLICIT: 'implicit'; +IN: 'in'; +INT: 'int'; +INTERFACE: 'interface'; +INTERNAL: 'internal'; +INTO: 'into'; +IS: 'is'; +JOIN: 'join'; +LET: 'let'; +LOCK: 'lock'; +LONG: 'long'; +NAMEOF: 'nameof'; +NAMESPACE: 'namespace'; +NEW: 'new'; +NULL: 'null'; +OBJECT: 'object'; +ON: 'on'; +OPERATOR: 'operator'; +ORDERBY: 'orderby'; +OUT: 'out'; +OVERRIDE: 'override'; +PARAMS: 'params'; +PARTIAL: 'partial'; +PRIVATE: 'private'; +PROTECTED: 'protected'; +PUBLIC: 'public'; +READONLY: 'readonly'; +REF: 'ref'; +REMOVE: 'remove'; +RETURN: 'return'; +SBYTE: 'sbyte'; +SEALED: 'sealed'; +SELECT: 'select'; +SET: 'set'; +SHORT: 'short'; +SIZEOF: 'sizeof'; +STACKALLOC: 'stackalloc'; +STATIC: 'static'; +STRING: 'string'; +STRUCT: 'struct'; +SWITCH: 'switch'; +THIS: 'this'; +THROW: 'throw'; +TRUE: 'true'; +TRY: 'try'; +TYPEOF: 'typeof'; +UINT: 'uint'; +ULONG: 'ulong'; +UNCHECKED: 'unchecked'; +UNSAFE: 'unsafe'; +USHORT: 'ushort'; +USING: 'using'; +VAR: 'var'; +VIRTUAL: 'virtual'; +VOID: 'void'; +VOLATILE: 'volatile'; +WHEN: 'when'; +WHERE: 'where'; +WHILE: 'while'; +YIELD: 'yield'; + +//B.1.6 Identifiers +// must be defined after all keywords so the first branch (Available_identifier) does not match keywords +// https://msdn.microsoft.com/en-us/library/aa664670(v=vs.71).aspx +IDENTIFIER: '@'? IdentifierOrKeyword; + +//B.1.8 Literals +// 0.Equals() would be parsed as an invalid real (1. branch) causing a lexer error +LITERAL_ACCESS: [0-9]+ IntegerTypeSuffix? '.' '@'? IdentifierOrKeyword; +INTEGER_LITERAL: [0-9]+ IntegerTypeSuffix?; +HEX_INTEGER_LITERAL: '0' [xX] HexDigit+ IntegerTypeSuffix?; +REAL_LITERAL: [0-9]* '.' [0-9]+ ExponentPart? [FfDdMm]? | [0-9]+ ([FfDdMm] | ExponentPart [FfDdMm]?); + +CHARACTER_LITERAL: '\'' (~['\\\r\n\u0085\u2028\u2029] | CommonCharacter) '\''; +REGULAR_STRING: '"' (~["\\\r\n\u0085\u2028\u2029] | CommonCharacter)* '"'; +VERBATIUM_STRING: '@"' (~'"' | '""')* '"'; +INTERPOLATED_REGULAR_STRING_START: '$"' + { interpolatedStringLevel++; interpolatedVerbatiums.push(false); verbatium = false; } -> pushMode(INTERPOLATION_STRING); +INTERPOLATED_VERBATIUM_STRING_START: '$@"' + { interpolatedStringLevel++; interpolatedVerbatiums.push(true); verbatium = true; } -> pushMode(INTERPOLATION_STRING); + +//B.1.9 Operators And Punctuators +OPEN_BRACE: '{' +{ +if (interpolatedStringLevel > 0) +{ + curlyLevels.push(curlyLevels.pop() + 1); +}}; +CLOSE_BRACE: '}' +{ +if (interpolatedStringLevel > 0) +{ + curlyLevels.push(curlyLevels.pop() - 1); + if (curlyLevels.peek() == 0) + { + curlyLevels.pop(); + skip(); + popMode(); + } +} +}; +OPEN_BRACKET: '['; +CLOSE_BRACKET: ']'; +OPEN_PARENS: '('; +CLOSE_PARENS: ')'; +DOT: '.'; +COMMA: ','; +COLON: ':' +{ +if (interpolatedStringLevel > 0) +{ + int ind = 1; + boolean switchToFormatString = true; + while ((char)_input.LA(ind) != '}') + { + if (_input.LA(ind) == ':' || _input.LA(ind) == ')') + { + switchToFormatString = false; + break; + } + ind++; + } + if (switchToFormatString) + { + mode(INTERPOLATION_FORMAT); + } +} +}; +SEMICOLON: ';'; +PLUS: '+'; +MINUS: '-'; +STAR: '*'; +DIV: '/'; +PERCENT: '%'; +AMP: '&'; +BITWISE_OR: '|'; +CARET: '^'; +BANG: '!'; +TILDE: '~'; +ASSIGNMENT: '='; +LT: '<'; +GT: '>'; +INTERR: '?'; +DOUBLE_COLON: '::'; +OP_COALESCING: '??'; +OP_INC: '++'; +OP_DEC: '--'; +OP_AND: '&&'; +OP_OR: '||'; +OP_PTR: '->'; +OP_EQ: '=='; +OP_NE: '!='; +OP_LE: '<='; +OP_GE: '>='; +OP_ADD_ASSIGNMENT: '+='; +OP_SUB_ASSIGNMENT: '-='; +OP_MULT_ASSIGNMENT: '*='; +OP_DIV_ASSIGNMENT: '/='; +OP_MOD_ASSIGNMENT: '%='; +OP_AND_ASSIGNMENT: '&='; +OP_OR_ASSIGNMENT: '|='; +OP_XOR_ASSIGNMENT: '^='; +OP_LEFT_SHIFT: '<<'; +OP_LEFT_SHIFT_ASSIGNMENT: '<<='; + +// https://msdn.microsoft.com/en-us/library/dn961160.aspx +mode INTERPOLATION_STRING; + +DOUBLE_CURLY_INSIDE: '{{'; +OPEN_BRACE_INSIDE: '{' { curlyLevels.push(1); } -> skip, pushMode(DEFAULT_MODE); +REGULAR_CHAR_INSIDE: { !verbatium }? SimpleEscapeSequence; +VERBATIUM_DOUBLE_QUOTE_INSIDE: { verbatium }? '""'; +DOUBLE_QUOTE_INSIDE: '"' { interpolatedStringLevel--; interpolatedVerbatiums.pop(); + verbatium = (interpolatedVerbatiums.size() > 0 ? interpolatedVerbatiums.peek() : false); } -> popMode; +REGULAR_STRING_INSIDE: { !verbatium }? ~('{' | '\\' | '"')+; +VERBATIUM_INSIDE_STRING: { verbatium }? ~('{' | '"')+; + +mode INTERPOLATION_FORMAT; + +DOUBLE_CURLY_CLOSE_INSIDE: '}}' -> type(FORMAT_STRING); +CLOSE_BRACE_INSIDE: '}' { curlyLevels.pop(); } -> skip, popMode; +FORMAT_STRING: ~'}'+; + +mode DIRECTIVE_MODE; + +DIRECTIVE_WHITESPACES: Whitespace+ -> channel(HIDDEN); +DIGITS: [0-9]+ -> channel(DIRECTIVE); +DIRECTIVE_TRUE: 'true' -> channel(DIRECTIVE), type(TRUE); +DIRECTIVE_FALSE: 'false' -> channel(DIRECTIVE), type(FALSE); +DEFINE: 'define' -> channel(DIRECTIVE); +UNDEF: 'undef' -> channel(DIRECTIVE); +DIRECTIVE_IF: 'if' -> channel(DIRECTIVE), type(IF); +ELIF: 'elif' -> channel(DIRECTIVE); +DIRECTIVE_ELSE: 'else' -> channel(DIRECTIVE), type(ELSE); +ENDIF: 'endif' -> channel(DIRECTIVE); +LINE: 'line' -> channel(DIRECTIVE); +ERROR: 'error' Whitespace+ -> channel(DIRECTIVE), mode(DIRECTIVE_TEXT); +WARNING: 'warning' Whitespace+ -> channel(DIRECTIVE), mode(DIRECTIVE_TEXT); +REGION: 'region' Whitespace* -> channel(DIRECTIVE), mode(DIRECTIVE_TEXT); +ENDREGION: 'endregion' Whitespace* -> channel(DIRECTIVE), mode(DIRECTIVE_TEXT); +PRAGMA: 'pragma' Whitespace+ -> channel(DIRECTIVE), mode(DIRECTIVE_TEXT); +DIRECTIVE_DEFAULT: 'default' -> channel(DIRECTIVE), type(DEFAULT); +DIRECTIVE_HIDDEN: 'hidden' -> channel(DIRECTIVE); +DIRECTIVE_OPEN_PARENS: '(' -> channel(DIRECTIVE), type(OPEN_PARENS); +DIRECTIVE_CLOSE_PARENS: ')' -> channel(DIRECTIVE), type(CLOSE_PARENS); +DIRECTIVE_BANG: '!' -> channel(DIRECTIVE), type(BANG); +DIRECTIVE_OP_EQ: '==' -> channel(DIRECTIVE), type(OP_EQ); +DIRECTIVE_OP_NE: '!=' -> channel(DIRECTIVE), type(OP_NE); +DIRECTIVE_OP_AND: '&&' -> channel(DIRECTIVE), type(OP_AND); +DIRECTIVE_OP_OR: '||' -> channel(DIRECTIVE), type(OP_OR); +DIRECTIVE_STRING: '"' ~('"' | [\r\n\u0085\u2028\u2029])* '"' -> channel(DIRECTIVE), type(STRING); +CONDITIONAL_SYMBOL: IdentifierOrKeyword -> channel(DIRECTIVE); +DIRECTIVE_SINGLE_LINE_COMMENT: '//' ~[\r\n\u0085\u2028\u2029]* -> channel(COMMENTS_CHANNEL), type(SINGLE_LINE_COMMENT); +DIRECTIVE_NEW_LINE: NewLine -> channel(DIRECTIVE), mode(DEFAULT_MODE); + +mode DIRECTIVE_TEXT; + +TEXT: ~[\r\n\u0085\u2028\u2029]+ -> channel(DIRECTIVE); +TEXT_NEW_LINE: NewLine -> channel(DIRECTIVE), type(DIRECTIVE_NEW_LINE), mode(DEFAULT_MODE); + +// Fragments + +fragment InputCharacter: ~[\r\n\u0085\u2028\u2029]; + +fragment NewLineCharacter + : '\u000D' //'' + | '\u000A' //'' + | '\u0085' //'' + | '\u2028' //'' + | '\u2029' //'' + ; + +fragment IntegerTypeSuffix: [lL]? [uU] | [uU]? [lL]; +fragment ExponentPart: [eE] ('+' | '-')? [0-9]+; + +fragment CommonCharacter + : SimpleEscapeSequence + | HexEscapeSequence + | UnicodeEscapeSequence + ; + +fragment SimpleEscapeSequence + : '\\\'' + | '\\"' + | '\\\\' + | '\\0' + | '\\a' + | '\\b' + | '\\f' + | '\\n' + | '\\r' + | '\\t' + | '\\v' + ; + +fragment HexEscapeSequence + : '\\x' HexDigit + | '\\x' HexDigit HexDigit + | '\\x' HexDigit HexDigit HexDigit + | '\\x' HexDigit HexDigit HexDigit HexDigit + ; + +fragment NewLine + : NL + ; + +NL + : '\r\n' | '\r' | '\n' + | '\u0085' // ' + | '\u2028' //'' + | '\u2029' //'' + ; + +fragment Whitespace + : UnicodeClassZS //'' + | '\u0009' //'' + | '\u000B' //'' + | '\u000C' //'
' + ; + +fragment UnicodeClassZS + : '\u0020' // SPACE + | '\u00A0' // NO_BREAK SPACE + | '\u1680' // OGHAM SPACE MARK + | '\u180E' // MONGOLIAN VOWEL SEPARATOR + | '\u2000' // EN QUAD + | '\u2001' // EM QUAD + | '\u2002' // EN SPACE + | '\u2003' // EM SPACE + | '\u2004' // THREE_PER_EM SPACE + | '\u2005' // FOUR_PER_EM SPACE + | '\u2006' // SIX_PER_EM SPACE + | '\u2008' // PUNCTUATION SPACE + | '\u2009' // THIN SPACE + | '\u200A' // HAIR SPACE + | '\u202F' // NARROW NO_BREAK SPACE + | '\u3000' // IDEOGRAPHIC SPACE + | '\u205F' // MEDIUM MATHEMATICAL SPACE + ; + +fragment IdentifierOrKeyword + : IdentifierStartCharacter IdentifierPartCharacter* + ; + +fragment IdentifierStartCharacter + : LetterCharacter + | '_' + ; + +fragment IdentifierPartCharacter + : LetterCharacter + | DecimalDigitCharacter + | ConnectingCharacter + | CombiningCharacter + | FormattingCharacter + ; + +//'' +// WARNING: ignores UnicodeEscapeSequence +fragment LetterCharacter + : UnicodeClassLU + | UnicodeClassLL + | UnicodeClassLT + | UnicodeClassLM + | UnicodeClassLO + | UnicodeClassNL + | UnicodeEscapeSequence + ; + +//'' +// WARNING: ignores UnicodeEscapeSequence +fragment DecimalDigitCharacter + : UnicodeClassND + | UnicodeEscapeSequence + ; + +//'' +// WARNING: ignores UnicodeEscapeSequence +fragment ConnectingCharacter + : UnicodeClassPC + | UnicodeEscapeSequence + ; + +//'' +// WARNING: ignores UnicodeEscapeSequence +fragment CombiningCharacter + : UnicodeClassMN + | UnicodeClassMC + | UnicodeEscapeSequence + ; + +//'' +// WARNING: ignores UnicodeEscapeSequence +fragment FormattingCharacter + : UnicodeClassCF + | UnicodeEscapeSequence + ; + +//B.1.5 Unicode Character Escape Sequences +fragment UnicodeEscapeSequence + : '\\u' HexDigit HexDigit HexDigit HexDigit + | '\\U' HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit + ; + +fragment HexDigit : [0-9] | [A-F] | [a-f]; + +// Unicode character classes +fragment UnicodeClassLU + : '\u0041'..'\u005a' + | '\u00c0'..'\u00d6' + | '\u00d8'..'\u00de' + | '\u0100'..'\u0136' + | '\u0139'..'\u0147' + | '\u014a'..'\u0178' + | '\u0179'..'\u017d' + | '\u0181'..'\u0182' + | '\u0184'..'\u0186' + | '\u0187'..'\u0189' + | '\u018a'..'\u018b' + | '\u018e'..'\u0191' + | '\u0193'..'\u0194' + | '\u0196'..'\u0198' + | '\u019c'..'\u019d' + | '\u019f'..'\u01a0' + | '\u01a2'..'\u01a6' + | '\u01a7'..'\u01a9' + | '\u01ac'..'\u01ae' + | '\u01af'..'\u01b1' + | '\u01b2'..'\u01b3' + | '\u01b5'..'\u01b7' + | '\u01b8'..'\u01bc' + | '\u01c4'..'\u01cd' + | '\u01cf'..'\u01db' + | '\u01de'..'\u01ee' + | '\u01f1'..'\u01f4' + | '\u01f6'..'\u01f8' + | '\u01fa'..'\u0232' + | '\u023a'..'\u023b' + | '\u023d'..'\u023e' + | '\u0241'..'\u0243' + | '\u0244'..'\u0246' + | '\u0248'..'\u024e' + | '\u0370'..'\u0372' + | '\u0376'..'\u037f' + | '\u0386'..'\u0388' + | '\u0389'..'\u038a' + | '\u038c'..'\u038e' + | '\u038f'..'\u0391' + | '\u0392'..'\u03a1' + | '\u03a3'..'\u03ab' + | '\u03cf'..'\u03d2' + | '\u03d3'..'\u03d4' + | '\u03d8'..'\u03ee' + | '\u03f4'..'\u03f7' + | '\u03f9'..'\u03fa' + | '\u03fd'..'\u042f' + | '\u0460'..'\u0480' + | '\u048a'..'\u04c0' + | '\u04c1'..'\u04cd' + | '\u04d0'..'\u052e' + | '\u0531'..'\u0556' + | '\u10a0'..'\u10c5' + | '\u10c7'..'\u10cd' + | '\u1e00'..'\u1e94' + | '\u1e9e'..'\u1efe' + | '\u1f08'..'\u1f0f' + | '\u1f18'..'\u1f1d' + | '\u1f28'..'\u1f2f' + | '\u1f38'..'\u1f3f' + | '\u1f48'..'\u1f4d' + | '\u1f59'..'\u1f5f' + | '\u1f68'..'\u1f6f' + | '\u1fb8'..'\u1fbb' + | '\u1fc8'..'\u1fcb' + | '\u1fd8'..'\u1fdb' + | '\u1fe8'..'\u1fec' + | '\u1ff8'..'\u1ffb' + | '\u2102'..'\u2107' + | '\u210b'..'\u210d' + | '\u2110'..'\u2112' + | '\u2115'..'\u2119' + | '\u211a'..'\u211d' + | '\u2124'..'\u212a' + | '\u212b'..'\u212d' + | '\u2130'..'\u2133' + | '\u213e'..'\u213f' + | '\u2145'..'\u2183' + | '\u2c00'..'\u2c2e' + | '\u2c60'..'\u2c62' + | '\u2c63'..'\u2c64' + | '\u2c67'..'\u2c6d' + | '\u2c6e'..'\u2c70' + | '\u2c72'..'\u2c75' + | '\u2c7e'..'\u2c80' + | '\u2c82'..'\u2ce2' + | '\u2ceb'..'\u2ced' + | '\u2cf2'..'\ua640' + | '\ua642'..'\ua66c' + | '\ua680'..'\ua69a' + | '\ua722'..'\ua72e' + | '\ua732'..'\ua76e' + | '\ua779'..'\ua77d' + | '\ua77e'..'\ua786' + | '\ua78b'..'\ua78d' + | '\ua790'..'\ua792' + | '\ua796'..'\ua7aa' + | '\ua7ab'..'\ua7ad' + | '\ua7b0'..'\ua7b1' + | '\uff21'..'\uff3a' + ; + +fragment UnicodeClassLL + : '\u0061'..'\u007A' + | '\u00b5'..'\u00df' + | '\u00e0'..'\u00f6' + | '\u00f8'..'\u00ff' + | '\u0101'..'\u0137' + | '\u0138'..'\u0148' + | '\u0149'..'\u0177' + | '\u017a'..'\u017e' + | '\u017f'..'\u0180' + | '\u0183'..'\u0185' + | '\u0188'..'\u018c' + | '\u018d'..'\u0192' + | '\u0195'..'\u0199' + | '\u019a'..'\u019b' + | '\u019e'..'\u01a1' + | '\u01a3'..'\u01a5' + | '\u01a8'..'\u01aa' + | '\u01ab'..'\u01ad' + | '\u01b0'..'\u01b4' + | '\u01b6'..'\u01b9' + | '\u01ba'..'\u01bd' + | '\u01be'..'\u01bf' + | '\u01c6'..'\u01cc' + | '\u01ce'..'\u01dc' + | '\u01dd'..'\u01ef' + | '\u01f0'..'\u01f3' + | '\u01f5'..'\u01f9' + | '\u01fb'..'\u0233' + | '\u0234'..'\u0239' + | '\u023c'..'\u023f' + | '\u0240'..'\u0242' + | '\u0247'..'\u024f' + | '\u0250'..'\u0293' + | '\u0295'..'\u02af' + | '\u0371'..'\u0373' + | '\u0377'..'\u037b' + | '\u037c'..'\u037d' + | '\u0390'..'\u03ac' + | '\u03ad'..'\u03ce' + | '\u03d0'..'\u03d1' + | '\u03d5'..'\u03d7' + | '\u03d9'..'\u03ef' + | '\u03f0'..'\u03f3' + | '\u03f5'..'\u03fb' + | '\u03fc'..'\u0430' + | '\u0431'..'\u045f' + | '\u0461'..'\u0481' + | '\u048b'..'\u04bf' + | '\u04c2'..'\u04ce' + | '\u04cf'..'\u052f' + | '\u0561'..'\u0587' + | '\u1d00'..'\u1d2b' + | '\u1d6b'..'\u1d77' + | '\u1d79'..'\u1d9a' + | '\u1e01'..'\u1e95' + | '\u1e96'..'\u1e9d' + | '\u1e9f'..'\u1eff' + | '\u1f00'..'\u1f07' + | '\u1f10'..'\u1f15' + | '\u1f20'..'\u1f27' + | '\u1f30'..'\u1f37' + | '\u1f40'..'\u1f45' + | '\u1f50'..'\u1f57' + | '\u1f60'..'\u1f67' + | '\u1f70'..'\u1f7d' + | '\u1f80'..'\u1f87' + | '\u1f90'..'\u1f97' + | '\u1fa0'..'\u1fa7' + | '\u1fb0'..'\u1fb4' + | '\u1fb6'..'\u1fb7' + | '\u1fbe'..'\u1fc2' + | '\u1fc3'..'\u1fc4' + | '\u1fc6'..'\u1fc7' + | '\u1fd0'..'\u1fd3' + | '\u1fd6'..'\u1fd7' + | '\u1fe0'..'\u1fe7' + | '\u1ff2'..'\u1ff4' + | '\u1ff6'..'\u1ff7' + | '\u210a'..'\u210e' + | '\u210f'..'\u2113' + | '\u212f'..'\u2139' + | '\u213c'..'\u213d' + | '\u2146'..'\u2149' + | '\u214e'..'\u2184' + | '\u2c30'..'\u2c5e' + | '\u2c61'..'\u2c65' + | '\u2c66'..'\u2c6c' + | '\u2c71'..'\u2c73' + | '\u2c74'..'\u2c76' + | '\u2c77'..'\u2c7b' + | '\u2c81'..'\u2ce3' + | '\u2ce4'..'\u2cec' + | '\u2cee'..'\u2cf3' + | '\u2d00'..'\u2d25' + | '\u2d27'..'\u2d2d' + | '\ua641'..'\ua66d' + | '\ua681'..'\ua69b' + | '\ua723'..'\ua72f' + | '\ua730'..'\ua731' + | '\ua733'..'\ua771' + | '\ua772'..'\ua778' + | '\ua77a'..'\ua77c' + | '\ua77f'..'\ua787' + | '\ua78c'..'\ua78e' + | '\ua791'..'\ua793' + | '\ua794'..'\ua795' + | '\ua797'..'\ua7a9' + | '\ua7fa'..'\uab30' + | '\uab31'..'\uab5a' + | '\uab64'..'\uab65' + | '\ufb00'..'\ufb06' + | '\ufb13'..'\ufb17' + | '\uff41'..'\uff5a' + ; + +fragment UnicodeClassLT + : '\u01c5'..'\u01cb' + | '\u01f2'..'\u1f88' + | '\u1f89'..'\u1f8f' + | '\u1f98'..'\u1f9f' + | '\u1fa8'..'\u1faf' + | '\u1fbc'..'\u1fcc' + | '\u1ffc'..'\u1ffc' + ; + +fragment UnicodeClassLM + : '\u02b0'..'\u02c1' + | '\u02c6'..'\u02d1' + | '\u02e0'..'\u02e4' + | '\u02ec'..'\u02ee' + | '\u0374'..'\u037a' + | '\u0559'..'\u0640' + | '\u06e5'..'\u06e6' + | '\u07f4'..'\u07f5' + | '\u07fa'..'\u081a' + | '\u0824'..'\u0828' + | '\u0971'..'\u0e46' + | '\u0ec6'..'\u10fc' + | '\u17d7'..'\u1843' + | '\u1aa7'..'\u1c78' + | '\u1c79'..'\u1c7d' + | '\u1d2c'..'\u1d6a' + | '\u1d78'..'\u1d9b' + | '\u1d9c'..'\u1dbf' + | '\u2071'..'\u207f' + | '\u2090'..'\u209c' + | '\u2c7c'..'\u2c7d' + | '\u2d6f'..'\u2e2f' + | '\u3005'..'\u3031' + | '\u3032'..'\u3035' + | '\u303b'..'\u309d' + | '\u309e'..'\u30fc' + | '\u30fd'..'\u30fe' + | '\ua015'..'\ua4f8' + | '\ua4f9'..'\ua4fd' + | '\ua60c'..'\ua67f' + | '\ua69c'..'\ua69d' + | '\ua717'..'\ua71f' + | '\ua770'..'\ua788' + | '\ua7f8'..'\ua7f9' + | '\ua9cf'..'\ua9e6' + | '\uaa70'..'\uaadd' + | '\uaaf3'..'\uaaf4' + | '\uab5c'..'\uab5f' + | '\uff70'..'\uff9e' + | '\uff9f'..'\uff9f' + ; + +fragment UnicodeClassLO + : '\u00aa'..'\u00ba' + | '\u01bb'..'\u01c0' + | '\u01c1'..'\u01c3' + | '\u0294'..'\u05d0' + | '\u05d1'..'\u05ea' + | '\u05f0'..'\u05f2' + | '\u0620'..'\u063f' + | '\u0641'..'\u064a' + | '\u066e'..'\u066f' + | '\u0671'..'\u06d3' + | '\u06d5'..'\u06ee' + | '\u06ef'..'\u06fa' + | '\u06fb'..'\u06fc' + | '\u06ff'..'\u0710' + | '\u0712'..'\u072f' + | '\u074d'..'\u07a5' + | '\u07b1'..'\u07ca' + | '\u07cb'..'\u07ea' + | '\u0800'..'\u0815' + | '\u0840'..'\u0858' + | '\u08a0'..'\u08b2' + | '\u0904'..'\u0939' + | '\u093d'..'\u0950' + | '\u0958'..'\u0961' + | '\u0972'..'\u0980' + | '\u0985'..'\u098c' + | '\u098f'..'\u0990' + | '\u0993'..'\u09a8' + | '\u09aa'..'\u09b0' + | '\u09b2'..'\u09b6' + | '\u09b7'..'\u09b9' + | '\u09bd'..'\u09ce' + | '\u09dc'..'\u09dd' + | '\u09df'..'\u09e1' + | '\u09f0'..'\u09f1' + | '\u0a05'..'\u0a0a' + | '\u0a0f'..'\u0a10' + | '\u0a13'..'\u0a28' + | '\u0a2a'..'\u0a30' + | '\u0a32'..'\u0a33' + | '\u0a35'..'\u0a36' + | '\u0a38'..'\u0a39' + | '\u0a59'..'\u0a5c' + | '\u0a5e'..'\u0a72' + | '\u0a73'..'\u0a74' + | '\u0a85'..'\u0a8d' + | '\u0a8f'..'\u0a91' + | '\u0a93'..'\u0aa8' + | '\u0aaa'..'\u0ab0' + | '\u0ab2'..'\u0ab3' + | '\u0ab5'..'\u0ab9' + | '\u0abd'..'\u0ad0' + | '\u0ae0'..'\u0ae1' + | '\u0b05'..'\u0b0c' + | '\u0b0f'..'\u0b10' + | '\u0b13'..'\u0b28' + | '\u0b2a'..'\u0b30' + | '\u0b32'..'\u0b33' + | '\u0b35'..'\u0b39' + | '\u0b3d'..'\u0b5c' + | '\u0b5d'..'\u0b5f' + | '\u0b60'..'\u0b61' + | '\u0b71'..'\u0b83' + | '\u0b85'..'\u0b8a' + | '\u0b8e'..'\u0b90' + | '\u0b92'..'\u0b95' + | '\u0b99'..'\u0b9a' + | '\u0b9c'..'\u0b9e' + | '\u0b9f'..'\u0ba3' + | '\u0ba4'..'\u0ba8' + | '\u0ba9'..'\u0baa' + | '\u0bae'..'\u0bb9' + | '\u0bd0'..'\u0c05' + | '\u0c06'..'\u0c0c' + | '\u0c0e'..'\u0c10' + | '\u0c12'..'\u0c28' + | '\u0c2a'..'\u0c39' + | '\u0c3d'..'\u0c58' + | '\u0c59'..'\u0c60' + | '\u0c61'..'\u0c85' + | '\u0c86'..'\u0c8c' + | '\u0c8e'..'\u0c90' + | '\u0c92'..'\u0ca8' + | '\u0caa'..'\u0cb3' + | '\u0cb5'..'\u0cb9' + | '\u0cbd'..'\u0cde' + | '\u0ce0'..'\u0ce1' + | '\u0cf1'..'\u0cf2' + | '\u0d05'..'\u0d0c' + | '\u0d0e'..'\u0d10' + | '\u0d12'..'\u0d3a' + | '\u0d3d'..'\u0d4e' + | '\u0d60'..'\u0d61' + | '\u0d7a'..'\u0d7f' + | '\u0d85'..'\u0d96' + | '\u0d9a'..'\u0db1' + | '\u0db3'..'\u0dbb' + | '\u0dbd'..'\u0dc0' + | '\u0dc1'..'\u0dc6' + | '\u0e01'..'\u0e30' + | '\u0e32'..'\u0e33' + | '\u0e40'..'\u0e45' + | '\u0e81'..'\u0e82' + | '\u0e84'..'\u0e87' + | '\u0e88'..'\u0e8a' + | '\u0e8d'..'\u0e94' + | '\u0e95'..'\u0e97' + | '\u0e99'..'\u0e9f' + | '\u0ea1'..'\u0ea3' + | '\u0ea5'..'\u0ea7' + | '\u0eaa'..'\u0eab' + | '\u0ead'..'\u0eb0' + | '\u0eb2'..'\u0eb3' + | '\u0ebd'..'\u0ec0' + | '\u0ec1'..'\u0ec4' + | '\u0edc'..'\u0edf' + | '\u0f00'..'\u0f40' + | '\u0f41'..'\u0f47' + | '\u0f49'..'\u0f6c' + | '\u0f88'..'\u0f8c' + | '\u1000'..'\u102a' + | '\u103f'..'\u1050' + | '\u1051'..'\u1055' + | '\u105a'..'\u105d' + | '\u1061'..'\u1065' + | '\u1066'..'\u106e' + | '\u106f'..'\u1070' + | '\u1075'..'\u1081' + | '\u108e'..'\u10d0' + | '\u10d1'..'\u10fa' + | '\u10fd'..'\u1248' + | '\u124a'..'\u124d' + | '\u1250'..'\u1256' + | '\u1258'..'\u125a' + | '\u125b'..'\u125d' + | '\u1260'..'\u1288' + | '\u128a'..'\u128d' + | '\u1290'..'\u12b0' + | '\u12b2'..'\u12b5' + | '\u12b8'..'\u12be' + | '\u12c0'..'\u12c2' + | '\u12c3'..'\u12c5' + | '\u12c8'..'\u12d6' + | '\u12d8'..'\u1310' + | '\u1312'..'\u1315' + | '\u1318'..'\u135a' + | '\u1380'..'\u138f' + | '\u13a0'..'\u13f4' + | '\u1401'..'\u166c' + | '\u166f'..'\u167f' + | '\u1681'..'\u169a' + | '\u16a0'..'\u16ea' + | '\u16f1'..'\u16f8' + | '\u1700'..'\u170c' + | '\u170e'..'\u1711' + | '\u1720'..'\u1731' + | '\u1740'..'\u1751' + | '\u1760'..'\u176c' + | '\u176e'..'\u1770' + | '\u1780'..'\u17b3' + | '\u17dc'..'\u1820' + | '\u1821'..'\u1842' + | '\u1844'..'\u1877' + | '\u1880'..'\u18a8' + | '\u18aa'..'\u18b0' + | '\u18b1'..'\u18f5' + | '\u1900'..'\u191e' + | '\u1950'..'\u196d' + | '\u1970'..'\u1974' + | '\u1980'..'\u19ab' + | '\u19c1'..'\u19c7' + | '\u1a00'..'\u1a16' + | '\u1a20'..'\u1a54' + | '\u1b05'..'\u1b33' + | '\u1b45'..'\u1b4b' + | '\u1b83'..'\u1ba0' + | '\u1bae'..'\u1baf' + | '\u1bba'..'\u1be5' + | '\u1c00'..'\u1c23' + | '\u1c4d'..'\u1c4f' + | '\u1c5a'..'\u1c77' + | '\u1ce9'..'\u1cec' + | '\u1cee'..'\u1cf1' + | '\u1cf5'..'\u1cf6' + | '\u2135'..'\u2138' + | '\u2d30'..'\u2d67' + | '\u2d80'..'\u2d96' + | '\u2da0'..'\u2da6' + | '\u2da8'..'\u2dae' + | '\u2db0'..'\u2db6' + | '\u2db8'..'\u2dbe' + | '\u2dc0'..'\u2dc6' + | '\u2dc8'..'\u2dce' + | '\u2dd0'..'\u2dd6' + | '\u2dd8'..'\u2dde' + | '\u3006'..'\u303c' + | '\u3041'..'\u3096' + | '\u309f'..'\u30a1' + | '\u30a2'..'\u30fa' + | '\u30ff'..'\u3105' + | '\u3106'..'\u312d' + | '\u3131'..'\u318e' + | '\u31a0'..'\u31ba' + | '\u31f0'..'\u31ff' + | '\u3400'..'\u4db5' + | '\u4e00'..'\u9fcc' + | '\ua000'..'\ua014' + | '\ua016'..'\ua48c' + | '\ua4d0'..'\ua4f7' + | '\ua500'..'\ua60b' + | '\ua610'..'\ua61f' + | '\ua62a'..'\ua62b' + | '\ua66e'..'\ua6a0' + | '\ua6a1'..'\ua6e5' + | '\ua7f7'..'\ua7fb' + | '\ua7fc'..'\ua801' + | '\ua803'..'\ua805' + | '\ua807'..'\ua80a' + | '\ua80c'..'\ua822' + | '\ua840'..'\ua873' + | '\ua882'..'\ua8b3' + | '\ua8f2'..'\ua8f7' + | '\ua8fb'..'\ua90a' + | '\ua90b'..'\ua925' + | '\ua930'..'\ua946' + | '\ua960'..'\ua97c' + | '\ua984'..'\ua9b2' + | '\ua9e0'..'\ua9e4' + | '\ua9e7'..'\ua9ef' + | '\ua9fa'..'\ua9fe' + | '\uaa00'..'\uaa28' + | '\uaa40'..'\uaa42' + | '\uaa44'..'\uaa4b' + | '\uaa60'..'\uaa6f' + | '\uaa71'..'\uaa76' + | '\uaa7a'..'\uaa7e' + | '\uaa7f'..'\uaaaf' + | '\uaab1'..'\uaab5' + | '\uaab6'..'\uaab9' + | '\uaaba'..'\uaabd' + | '\uaac0'..'\uaac2' + | '\uaadb'..'\uaadc' + | '\uaae0'..'\uaaea' + | '\uaaf2'..'\uab01' + | '\uab02'..'\uab06' + | '\uab09'..'\uab0e' + | '\uab11'..'\uab16' + | '\uab20'..'\uab26' + | '\uab28'..'\uab2e' + | '\uabc0'..'\uabe2' + | '\uac00'..'\ud7a3' + | '\ud7b0'..'\ud7c6' + | '\ud7cb'..'\ud7fb' + | '\uf900'..'\ufa6d' + | '\ufa70'..'\ufad9' + | '\ufb1d'..'\ufb1f' + | '\ufb20'..'\ufb28' + | '\ufb2a'..'\ufb36' + | '\ufb38'..'\ufb3c' + | '\ufb3e'..'\ufb40' + | '\ufb41'..'\ufb43' + | '\ufb44'..'\ufb46' + | '\ufb47'..'\ufbb1' + | '\ufbd3'..'\ufd3d' + | '\ufd50'..'\ufd8f' + | '\ufd92'..'\ufdc7' + | '\ufdf0'..'\ufdfb' + | '\ufe70'..'\ufe74' + | '\ufe76'..'\ufefc' + | '\uff66'..'\uff6f' + | '\uff71'..'\uff9d' + | '\uffa0'..'\uffbe' + | '\uffc2'..'\uffc7' + | '\uffca'..'\uffcf' + | '\uffd2'..'\uffd7' + | '\uffda'..'\uffdc' + ; + +fragment UnicodeClassNL + : '\u16EE' // RUNIC ARLAUG SYMBOL + | '\u16EF' // RUNIC TVIMADUR SYMBOL + | '\u16F0' // RUNIC BELGTHOR SYMBOL + | '\u2160' // ROMAN NUMERAL ONE + | '\u2161' // ROMAN NUMERAL TWO + | '\u2162' // ROMAN NUMERAL THREE + | '\u2163' // ROMAN NUMERAL FOUR + | '\u2164' // ROMAN NUMERAL FIVE + | '\u2165' // ROMAN NUMERAL SIX + | '\u2166' // ROMAN NUMERAL SEVEN + | '\u2167' // ROMAN NUMERAL EIGHT + | '\u2168' // ROMAN NUMERAL NINE + | '\u2169' // ROMAN NUMERAL TEN + | '\u216A' // ROMAN NUMERAL ELEVEN + | '\u216B' // ROMAN NUMERAL TWELVE + | '\u216C' // ROMAN NUMERAL FIFTY + | '\u216D' // ROMAN NUMERAL ONE HUNDRED + | '\u216E' // ROMAN NUMERAL FIVE HUNDRED + | '\u216F' // ROMAN NUMERAL ONE THOUSAND + ; + +fragment UnicodeClassMN + : '\u0300' // COMBINING GRAVE ACCENT + | '\u0301' // COMBINING ACUTE ACCENT + | '\u0302' // COMBINING CIRCUMFLEX ACCENT + | '\u0303' // COMBINING TILDE + | '\u0304' // COMBINING MACRON + | '\u0305' // COMBINING OVERLINE + | '\u0306' // COMBINING BREVE + | '\u0307' // COMBINING DOT ABOVE + | '\u0308' // COMBINING DIAERESIS + | '\u0309' // COMBINING HOOK ABOVE + | '\u030A' // COMBINING RING ABOVE + | '\u030B' // COMBINING DOUBLE ACUTE ACCENT + | '\u030C' // COMBINING CARON + | '\u030D' // COMBINING VERTICAL LINE ABOVE + | '\u030E' // COMBINING DOUBLE VERTICAL LINE ABOVE + | '\u030F' // COMBINING DOUBLE GRAVE ACCENT + | '\u0310' // COMBINING CANDRABINDU + ; + +fragment UnicodeClassMC + : '\u0903' // DEVANAGARI SIGN VISARGA + | '\u093E' // DEVANAGARI VOWEL SIGN AA + | '\u093F' // DEVANAGARI VOWEL SIGN I + | '\u0940' // DEVANAGARI VOWEL SIGN II + | '\u0949' // DEVANAGARI VOWEL SIGN CANDRA O + | '\u094A' // DEVANAGARI VOWEL SIGN SHORT O + | '\u094B' // DEVANAGARI VOWEL SIGN O + | '\u094C' // DEVANAGARI VOWEL SIGN AU + ; + +fragment UnicodeClassCF + : '\u00AD' // SOFT HYPHEN + | '\u0600' // ARABIC NUMBER SIGN + | '\u0601' // ARABIC SIGN SANAH + | '\u0602' // ARABIC FOOTNOTE MARKER + | '\u0603' // ARABIC SIGN SAFHA + | '\u06DD' // ARABIC END OF AYAH + ; + +fragment UnicodeClassPC + : '\u005F' // LOW LINE + | '\u203F' // UNDERTIE + | '\u2040' // CHARACTER TIE + | '\u2054' // INVERTED UNDERTIE + | '\uFE33' // PRESENTATION FORM FOR VERTICAL LOW LINE + | '\uFE34' // PRESENTATION FORM FOR VERTICAL WAVY LOW LINE + | '\uFE4D' // DASHED LOW LINE + | '\uFE4E' // CENTRELINE LOW LINE + | '\uFE4F' // WAVY LOW LINE + | '\uFF3F' // FULLWIDTH LOW LINE + ; + +fragment UnicodeClassND + : '\u0030'..'\u0039' + | '\u0660'..'\u0669' + | '\u06f0'..'\u06f9' + | '\u07c0'..'\u07c9' + | '\u0966'..'\u096f' + | '\u09e6'..'\u09ef' + | '\u0a66'..'\u0a6f' + | '\u0ae6'..'\u0aef' + | '\u0b66'..'\u0b6f' + | '\u0be6'..'\u0bef' + | '\u0c66'..'\u0c6f' + | '\u0ce6'..'\u0cef' + | '\u0d66'..'\u0d6f' + | '\u0de6'..'\u0def' + | '\u0e50'..'\u0e59' + | '\u0ed0'..'\u0ed9' + | '\u0f20'..'\u0f29' + | '\u1040'..'\u1049' + | '\u1090'..'\u1099' + | '\u17e0'..'\u17e9' + | '\u1810'..'\u1819' + | '\u1946'..'\u194f' + | '\u19d0'..'\u19d9' + | '\u1a80'..'\u1a89' + | '\u1a90'..'\u1a99' + | '\u1b50'..'\u1b59' + | '\u1bb0'..'\u1bb9' + | '\u1c40'..'\u1c49' + | '\u1c50'..'\u1c59' + | '\ua620'..'\ua629' + | '\ua8d0'..'\ua8d9' + | '\ua900'..'\ua909' + | '\ua9d0'..'\ua9d9' + | '\ua9f0'..'\ua9f9' + | '\uaa50'..'\uaa59' + | '\uabf0'..'\uabf9' + | '\uff10'..'\uff19' + ; \ No newline at end of file diff --git a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java index c3e4f6e622..49229f3170 100644 --- a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java +++ b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java @@ -4,21 +4,19 @@ package net.sourceforge.pmd.cpd; -import java.io.BufferedReader; -import java.io.CharArrayReader; -import java.io.Closeable; -import java.io.IOException; -import java.io.PushbackReader; import java.util.Properties; -import org.apache.commons.lang3.RandomStringUtils; +import org.antlr.v4.runtime.CharStream; + +import net.sourceforge.pmd.cpd.token.AntlrToken; +import net.sourceforge.pmd.cpd.token.AntlrTokenFilter; +import net.sourceforge.pmd.lang.antlr.AntlrTokenManager; +import net.sourceforge.pmd.lang.cs.antlr4.CSharpLexer; /** - * This class does a best-guess try-anything tokenization. - * - * @author jheintz + * The C# tokenizer. */ -public class CsTokenizer implements Tokenizer { +public class CsTokenizer extends AntlrTokenizer { private boolean ignoreUsings = false; @@ -28,283 +26,128 @@ public class CsTokenizer implements Tokenizer { } } - @Override - public void tokenize(SourceCode sourceCode, Tokens tokenEntries) { - try (Tokenizer tokenizer = new Tokenizer(sourceCode.getCodeBuffer().toString())) { - Token token = tokenizer.getNextToken(); - - while (!token.equals(Token.EOF)) { - Token lookAhead = tokenizer.getNextToken(); - - // Ignore using directives - // Only using directives should be ignored, because these are used - // to import namespaces - // - // Using directive: 'using System.Math;' - // Using statement: 'using (Font font1 = new Font(..)) { .. }' - if (ignoreUsings && "using".equals(token.image) && !"(".equals(lookAhead.image)) { - // We replace the 'using' token by a random token, because it - // should not be part of - // any duplication block. When we omit it from the token stream, - // there is a change that - // we get a duplication block that starts before the 'using' - // directives and ends afterwards. - String randomTokenText = RandomStringUtils.randomAlphanumeric(20); - - token = new Token(randomTokenText, token.lineNumber); - // Skip all other tokens of the using directive to prevent a - // partial matching - while (!";".equals(lookAhead.image) && !lookAhead.equals(Token.EOF)) { - lookAhead = tokenizer.getNextToken(); - } - } - if (!";".equals(token.image)) { - tokenEntries.add(new TokenEntry(token.image, sourceCode.getFileName(), token.lineNumber)); - } - token = lookAhead; - } - tokenEntries.add(TokenEntry.getEOF()); - } catch (IOException e) { - e.printStackTrace(); - } - } - public void setIgnoreUsings(boolean ignoreUsings) { this.ignoreUsings = ignoreUsings; } - private static class Tokenizer implements Closeable { - private boolean endOfFile; - private int line; - private final PushbackReader reader; + @Override + protected AntlrTokenManager getLexerForSource(final SourceCode sourceCode) { + final CharStream charStream = AntlrTokenizer.getCharStreamFromSourceCode(sourceCode); + return new AntlrTokenManager(new CSharpLexer(charStream), sourceCode.getFileName()); + } - Tokenizer(String sourceCode) { - endOfFile = false; - line = 1; - reader = new PushbackReader(new BufferedReader(new CharArrayReader(sourceCode.toCharArray()))); + @Override + protected AntlrTokenFilter getTokenFilter(final AntlrTokenManager tokenManager) { + return new CsTokenFilter(tokenManager, ignoreUsings); + } + + /** + * The {@link CsTokenFilter} extends the {@link AntlrTokenFilter} to discard + * C#-specific tokens. + *

+ * By default, it enables annotation-based CPD suppression. + * If the --ignoreUsings flag is provided, using directives are filtered out. + *

+ */ + private static class CsTokenFilter extends AntlrTokenFilter { + private enum UsingState { + KEYWORD, // just encountered the using keyword + IDENTIFIER, // just encountered an identifier or var keyword } - public Token getNextToken() { - if (endOfFile) { - return Token.EOF; - } + private final boolean ignoreUsings; + private boolean discardingUsings = false; + private boolean discardingNL = false; - try { - int ic = reader.read(); - char c; - StringBuilder b; - while (ic != -1) { - c = (char) ic; - switch (c) { - // new line - case '\n': - line++; - ic = reader.read(); - break; - - // white space - case ' ': - case '\t': - case '\r': - ic = reader.read(); - break; - - case ';': - return new Token(";", line); - - // < << <= <<= > >> >= >>= - case '<': - case '>': - ic = reader.read(); - if (ic == '=') { - return new Token(c + "=", line); - } else if (ic == c) { - ic = reader.read(); - if (ic == '=') { - return new Token(c + c + "=", line); - } else { - reader.unread(ic); - return new Token(String.valueOf(c) + c, line); - } - } else { - reader.unread(ic); - return new Token(String.valueOf(c), line); - } - - // = == & &= && | |= || + += ++ - -= -- - case '=': - case '&': - case '|': - case '+': - case '-': - ic = reader.read(); - if (ic == '=' || ic == c) { - return new Token(c + String.valueOf((char) ic), line); - } else { - reader.unread(ic); - return new Token(String.valueOf(c), line); - } - - // ! != * *= % %= ^ ^= ~ ~= - case '!': - case '*': - case '%': - case '^': - case '~': - ic = reader.read(); - if (ic == '=') { - return new Token(c + "=", line); - } else { - reader.unread(ic); - return new Token(String.valueOf(c), line); - } - - // strings & chars - case '"': - case '\'': - int beginLine = line; - b = new StringBuilder(); - b.append(c); - while ((ic = reader.read()) != c) { - if (ic == -1) { - break; - } - b.append((char) ic); - if (ic == '\\') { - int next = reader.read(); - if (next != -1) { - b.append((char) next); - - if (next == '\n') { - line++; - } - } - } else if (ic == '\n') { - line++; - } - } - if (ic != -1) { - b.append((char) ic); - } - return new Token(b.toString(), beginLine); - - // / /= /*...*/ //... - case '/': - ic = reader.read(); - c = (char) ic; - switch (c) { - case '*': - // int beginLine = line; - int state = 1; - b = new StringBuilder(); - b.append("/*"); - - while ((ic = reader.read()) != -1) { - c = (char) ic; - b.append(c); - - if (c == '\n') { - line++; - } - - if (state == 1) { - if (c == '*') { - state = 2; - } - } else { - if (c == '/') { - ic = reader.read(); - break; - } else if (c != '*') { - state = 1; - } - } - } - // ignore the /* comment - // tokenEntries.add(new TokenEntry(b.toString(), - // sourceCode.getFileName(), beginLine)); - break; - - case '/': - b = new StringBuilder(); - b.append("//"); - while ((ic = reader.read()) != '\n') { - if (ic == -1) { - break; - } - b.append((char) ic); - } - // ignore the // comment - // tokenEntries.add(new TokenEntry(b.toString(), - // sourceCode.getFileName(), line)); - break; - - case '=': - return new Token("/=", line); - - default: - reader.unread(ic); - return new Token("/", line); - } - break; - - default: - // [a-zA-Z_][a-zA-Z_0-9]* - if (Character.isJavaIdentifierStart(c)) { - b = new StringBuilder(); - do { - b.append(c); - ic = reader.read(); - c = (char) ic; - } while (Character.isJavaIdentifierPart(c)); - reader.unread(ic); - return new Token(b.toString(), line); - } else if (Character.isDigit(c) || c == '.') { - // numbers - b = new StringBuilder(); - do { - b.append(c); - if (c == 'e' || c == 'E') { - ic = reader.read(); - c = (char) ic; - if ("1234567890-".indexOf(c) == -1) { - break; - } - b.append(c); - } - ic = reader.read(); - c = (char) ic; - } while ("1234567890.iIlLfFdDsSuUeExX".indexOf(c) != -1); - reader.unread(ic); - return new Token(b.toString(), line); - } else { - // anything else - return new Token(String.valueOf(c), line); - } - } - } - } catch (IOException e) { - e.printStackTrace(); - } - endOfFile = true; - return Token.EOF; + CsTokenFilter(final AntlrTokenManager tokenManager, boolean ignoreUsings) { + super(tokenManager); + this.ignoreUsings = ignoreUsings; } @Override - public void close() throws IOException { - reader.close(); + protected void analyzeToken(final AntlrToken currentToken) { + skipNewLines(currentToken); } - } - private static class Token { - public static final Token EOF = new Token("EOF", -1); + @Override + protected void analyzeTokens(final AntlrToken currentToken, final Iterable remainingTokens) { + skipUsingDirectives(currentToken, remainingTokens); + } - public final String image; - public final int lineNumber; + private void skipUsingDirectives(final AntlrToken currentToken, final Iterable remainingTokens) { + final int type = currentToken.getType(); + if (type == CSharpLexer.USING && isUsingDirective(remainingTokens)) { + discardingUsings = true; + } else if (type == CSharpLexer.SEMICOLON) { + discardingUsings = false; + } + } - Token(String image, int lineNumber) { - this.image = image; - this.lineNumber = lineNumber; + private boolean isUsingDirective(final Iterable remainingTokens) { + UsingState usingState = UsingState.KEYWORD; + for (final AntlrToken token : remainingTokens) { + final int type = token.getType(); + if (usingState == UsingState.KEYWORD) { + // The previous token was a using keyword. + switch (type) { + case CSharpLexer.STATIC: + // Definitely a using directive. + // Example: using static System.Math; + return true; + case CSharpLexer.VAR: + // Definitely a using statement. + // Example: using var font1 = new Font("Arial", 10.0f); + return false; + case CSharpLexer.OPEN_PARENS: + // Definitely a using statement. + // Example: using (var font1 = new Font("Arial", 10.0f); + return false; + case CSharpLexer.IDENTIFIER: + // This is either a type for a using statement or an alias for a using directive. + // Example (directive): using Project = PC.MyCompany.Project; + // Example (statement): using Font font1 = new Font("Arial", 10.0f); + usingState = UsingState.IDENTIFIER; + break; + default: + // Some unknown construct? + return false; + } + } else if (usingState == UsingState.IDENTIFIER) { + // The previous token was an identifier. + switch (type) { + case CSharpLexer.ASSIGNMENT: + // Definitely a using directive. + // Example: using Project = PC.MyCompany.Project; + return true; + case CSharpLexer.IDENTIFIER: + // Definitely a using statement. + // Example: using Font font1 = new Font("Arial", 10.0f); + return false; + case CSharpLexer.DOT: + // This should be considered part of the same type; revert to previous state. + // Example (directive): using System.Text; + // Example (statement): using System.Drawing.Font font1 = new Font("Arial", 10.0f); + usingState = UsingState.KEYWORD; + break; + case CSharpLexer.SEMICOLON: + // End of using directive. + return true; + default: + // Some unknown construct? + return false; + } + } + } + return false; + } + + private void skipNewLines(final AntlrToken currentToken) { + discardingNL = currentToken.getType() == CSharpLexer.NL; + } + + @Override + protected boolean isLanguageSpecificDiscarding() { + return discardingUsings || discardingNL; } } } diff --git a/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java b/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java index 20aefc8194..ed87562537 100644 --- a/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java +++ b/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java @@ -12,6 +12,8 @@ import java.util.List; import org.junit.Before; import org.junit.Test; +import net.sourceforge.pmd.lang.ast.TokenMgrError; + public class CsTokenizerTest { private CsTokenizer tokenizer; @@ -46,7 +48,7 @@ public class CsTokenizerTest { public void testSimpleClassMethodMultipleLines() { tokenizer.tokenize(toSourceCode("class Foo {\n" + " public String foo(int a) {\n" + " int i = a;\n" + " return \"x\" + a;\n" + " }\n" + "}"), tokens); - assertEquals(22, tokens.size()); + assertEquals(24, tokens.size()); List tokenList = tokens.getTokens(); assertEquals(1, tokenList.get(0).getBeginLine()); assertEquals(2, tokenList.get(4).getBeginLine()); @@ -56,13 +58,12 @@ public class CsTokenizerTest { @Test public void testStrings() { tokenizer.tokenize(toSourceCode("String s =\"aaa \\\"b\\n\";"), tokens); - assertEquals(5, tokens.size()); + assertEquals(6, tokens.size()); } - @Test + @Test(expected = TokenMgrError.class) public void testOpenString() { tokenizer.tokenize(toSourceCode("String s =\"aaa \\\"b\\"), tokens); - assertEquals(5, tokens.size()); } @Test @@ -91,7 +92,7 @@ public class CsTokenizerTest { + " a++; \n" + " a /= 3e2; \n" + " float f = -3.1; \n" + " f *= 2; \n" + " bool b = ! (f == 2.0 || f >= 1.0 && f <= 2.0) \n" + " }\n" + "}"), tokens); - assertEquals(50, tokens.size()); + assertEquals(57, tokens.size()); } @Test @@ -119,8 +120,9 @@ public class CsTokenizerTest { public void testIgnoreUsingDirectives() { tokenizer.setIgnoreUsings(true); tokenizer.tokenize(toSourceCode("using System.Text;\n"), tokens); + assertEquals(1, tokens.size()); assertNotEquals("using", tokens.getTokens().get(0).toString()); - assertEquals(2, tokens.size()); + assertEquals(TokenEntry.EOF, tokens.getTokens().get(0)); } @Test @@ -132,6 +134,15 @@ public class CsTokenizerTest { assertEquals("using", tokens.getTokens().get(0).toString()); } + @Test + public void testUsingVarStatementsAreNotIgnored() { + tokenizer.setIgnoreUsings(true); + tokenizer.tokenize(toSourceCode( + "using var font1 = new Font(\"Arial\", 10.0f);\n" + " byte charset = font1.GdiCharSet;\n"), + tokens); + assertEquals("using", tokens.getTokens().get(0).toString()); + } + private SourceCode toSourceCode(String source) { return new SourceCode(new SourceCode.StringCodeLoader(source)); } From fce8f766a27a8a32c2c75aab203d5823970b4dd7 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 13 Feb 2020 10:53:25 +0100 Subject: [PATCH 062/235] [doc] Add simple gradle documentation --- docs/_data/sidebars/pmd_sidebar.yml | 5 +- docs/pages/pmd/userdocs/tools/gradle.md | 64 +++++++++++++++++++++++++ docs/pages/pmd/userdocs/tools/maven.md | 2 +- 3 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 docs/pages/pmd/userdocs/tools/gradle.md diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index 1725effaac..6d7a37115f 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -91,9 +91,12 @@ entries: - title: Tools / Integrations output: web, pdf subfolderitems: - - title: Maven PMD plugin + - title: Maven PMD Plugin output: web, pdf url: /pmd_userdocs_tools_maven.html + - title: Gradle + output: web, pdf + url: /pmd_userdocs_tools_gradle.html - title: Ant output: web, pdf url: /pmd_userdocs_tools_ant.html diff --git a/docs/pages/pmd/userdocs/tools/gradle.md b/docs/pages/pmd/userdocs/tools/gradle.md new file mode 100644 index 0000000000..b1fa09f443 --- /dev/null +++ b/docs/pages/pmd/userdocs/tools/gradle.md @@ -0,0 +1,64 @@ +--- +title: Gradle +tags: [userdocs, tools] +permalink: pmd_userdocs_tools_gradle.html +--- + +The [Gradle Build Tool](https://gradle.org/) provides a [PMD Plugin](https://docs.gradle.org/current/userguide/pmd_plugin.html) +that can be added to your build configuration. Technically it is based on the [Ant Task](pmd_userdocs_tools_ant.html). + +## Example + +In your `build.gradle` add the following: + +``` +plugins { + id 'pmd' +} +``` + +### Custom ruleset + +Configuration of a custom ruleset looks like this: + +``` +pmd { + ruleSetFiles = files("custom-pmd-ruleset.xml") + ruleSets = [] +} +``` + +Note: The `ruleSets` array is explicitly set to empty to avoid using the default configuration. + +### Fail the build + +If you want to fail the build for pmd violations, you need to set `ignoreFailures`: + +``` +pmd { + ignoreFailures = false +} +``` + +More configuration options are documented on [PMD Extension](https://docs.gradle.org/current/dsl/org.gradle.api.plugins.quality.PmdExtension.html). + +### Upgrade PMD version + +If you want to use a newer PMD version than the default one provided with gradle, you can do so +with the property `toolVersion`: + +``` +pmd { + toolVersion = "6.21.0" +} +``` + +## References + +Source code for Gradles PMD Plugin is available here: + +* [gradle/gradle code-quality](https://github.com/gradle/gradle/tree/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality) + * [Pmd.java](https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/Pmd.java) + * [PmdExtension.java](https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdExtension.java) + * [PmdPlugin.java](https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdPlugin.java) +* The default PMD version used by gradle: [DEFAULT_PMD_VERSION](https://github.com/gradle/gradle/blob/62297596035d0ed59304bf458eb89bb9859bb3e3/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdPlugin.java#L51) diff --git a/docs/pages/pmd/userdocs/tools/maven.md b/docs/pages/pmd/userdocs/tools/maven.md index a592d04df3..2d07e1a07c 100644 --- a/docs/pages/pmd/userdocs/tools/maven.md +++ b/docs/pages/pmd/userdocs/tools/maven.md @@ -1,7 +1,7 @@ --- title: Maven PMD Plugin tags: [userdocs, tools] -permalink: /pmd_userdocs_tools_maven.html +permalink: pmd_userdocs_tools_maven.html last_updated: August 2017 author: > Miguel Griffa , From 2e6ada82ce648eeb2c5eed9fd32139629ea4e987 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 13 Feb 2020 10:54:08 +0100 Subject: [PATCH 063/235] [doc] Add PMD java api documentation Refs #2274 --- docs/_data/sidebars/pmd_sidebar.yml | 3 + docs/pages/pmd/userdocs/tools/java-api.md | 283 ++++++++++++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 docs/pages/pmd/userdocs/tools/java-api.md diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index 6d7a37115f..20991dfd04 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -100,6 +100,9 @@ entries: - title: Ant output: web, pdf url: /pmd_userdocs_tools_ant.html + - title: PMD Java API + output: web, pdf + url: /pmd_userdocs_tools_java_api.html - title: CI integrations output: web, pdf url: /pmd_userdocs_tools_ci.html diff --git a/docs/pages/pmd/userdocs/tools/java-api.md b/docs/pages/pmd/userdocs/tools/java-api.md new file mode 100644 index 0000000000..32cdc1d88c --- /dev/null +++ b/docs/pages/pmd/userdocs/tools/java-api.md @@ -0,0 +1,283 @@ +--- +title: PMD Java API +tags: [userdocs, tools] +permalink: pmd_userdocs_tools_java_api.html +--- + +The easiest way to run PMD is to just use a build plugin in your favorite build tool +like [Apache Ant](pmd_userdocs_tools_ant.html), [Apache Maven](pmd_userdocs_tools_maven.html) or +[Gradle](pmd_userdocs_tools_gradle.html). + +There are also many integrations for IDEs available, see [Tools](pmd_userdocs_tools.html). + +If you have your own build tool or want to integrate PMD in a different way, you can call PMD programmatically, +as described here. + +## Dependencies + +You'll need to add the dependency to the language, you want to analyze. For Java, it will be +`net.sourceforge.pmd:pmd-java`. If you use Maven, you can add a new (compile time) dependency like this: + +``` xml + + net.sourceforge.pmd + pmd-java + ${pmdVersion} + +``` + +Note: You'll need to select a specific version. This is done in the example via the property `pmdVersion`. + +This will transitively pull in the artifact `pmd-core` which contains the API. + +## Command line interface + +The easiest way is to call PMD with the same interface as from command line. The main class is +`net.sourceforge.pmd.PMD`: + +``` java +import net.sourceforge.pmd.PMD; + +public class Example { + public static void main(String[] args) { + String[] pmdArgs = { + "-d", "/home/workspace/src/main/java/code", + "-R", "rulesets/java/quickstart.xml", + "-f", "xml", + "-r", "/home/workspace/pmd-report.xml" + }; + PMD.main(pmdArgs); + } +} +``` + +It uses the same options as described in [PMD CLI reference](pmd_userdocs_cli_reference.html). + +## Programmatically, variant 1 + +This is very similar: + +``` java +import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.PMDConfiguration; + +public class PmdExample { + + public static void main(String[] args) { + PMDConfiguration configuration = new PMDConfiguration(); + configuration.setInputPaths("/home/workspace/src/main/java/code"); + configuration.setRuleSets("rulesets/java/quickstart.xml"); + configuration.setReportFormat("xml"); + configuration.setReportFile("/home/workspace/pmd-report.xml"); + + PMD.doPMD(configuration); + } +} +``` + +## Programmatically, variant 2 + +This gives you more control over which files are processed, but is also more complicated. +You can also provide your own listeners and renderers. + +1. First we create a `PMDConfiguration`. This is currently the only way to specify a ruleset: + + ```java + PMDConfiguration configuration = new PMDConfiguration(); + configuration.setMinimumPriority(RulePriority.MEDIUM); + configuration.setRuleSets("rulesets/java/quickstart.xml"); + ``` + +2. In order to support type resolution, PMD needs to have access to the compiled classes and dependencies + as well. This is called "auxclasspath" and is also configured here. + Note: you can specify multiple class paths separated by `:` on Unix-systems or `;` under Windows. + + ```java + configuration.prependClasspath("/home/workspace/target/classes:/home/.m2/repository/my/dependency.jar"); + ``` + +3. Then we need a ruleset factory. This is created using the configuration, taking the minimum priority into + account: + + ```java + RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.createFactory(configuration); + ``` + +4. PMD operates on a list of `DataSource`. You can assemble a own list of `FileDataSource`, e.g. + + ```java + List files = Arrays.asList(new FileDataSource(new File("/path/to/src/MyClass.java"))); + ``` + +5. For reporting, you can use a built-in renderer, e.g. `XMLRenderer`. Note, that you must manually initialize + the renderer by setting a suitable `Writer` and calling `start()`. After the PMD run, you need to call + `end()` and `flush()`. Then your writer should have received all output. + + ```java + StringWriter rendererOutput = new StringWriter(); + Renderer xmlRenderer = new XMLRenderer("UTF-8"); + xmlRenderer.setWriter(rendererOutput); + xmlRenderer.start(); + ``` + +6. Create a `RuleContext`. This is the context instance, that is available then in the rule implementations. + Note: when running in multi-threaded mode (which is the default), the rule context instance is cloned for + each thread. + + ```java + RuleContext ctx = new RuleContext(); + ``` + +7. Optionally register a report listener. This allows you to react immediately on found violations. You could also + use such a listener to implement your own renderer. The listener must implement the interface + `ThreadSafeReportListener` and can be registered via `ctx.getReport().addListener(...)`. + + ```java + ctx.getReport().addListener(new ThreadSafeReportListener() { + public void ruleViolationAdded(RuleViolation ruleViolation) { + } + public void metricAdded(Metric metric) { + } + ``` + +8. Now, all the preparations are done, and PMD can be executed. This is done by calling + `PMD.processFiles(...)`. This method call takes the configuration, the ruleset factory, the files + to process, the rule context and the list of renderers. Provide an empty list, if you don't want to use + any renderer. Note: The auxclasspath needs to be closed explicitly. Otherwise the class or jar files may + remain open and file resources are leaked. + + ```java + try { + PMD.processFiles(configuration, ruleSetFactory, files, ctx, + Collections.singletonList(renderer)); + } finally { + ClassLoader auxiliaryClassLoader = configuration.getClassLoader(); + if (auxiliaryClassLoader instanceof ClasspathClassLoader) { + ((ClasspathClassLoader) auxiliaryClassLoader).close(); + } + } + ``` + +9. After the call, you need to finish the renderer via `end()` and `flush()`. + Then you can check the rendered output. + + ``` java + renderer.end(); + renderer.flush(); + System.out.println("Rendered Report:"); + System.out.println(rendererOutput.toString()); + ``` + +Here is a complete example: + +``` java +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.PMDConfiguration; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RulePriority; +import net.sourceforge.pmd.RuleSetFactory; +import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.RulesetsFactoryUtils; +import net.sourceforge.pmd.ThreadSafeReportListener; +import net.sourceforge.pmd.renderers.Renderer; +import net.sourceforge.pmd.renderers.XMLRenderer; +import net.sourceforge.pmd.stat.Metric; +import net.sourceforge.pmd.util.ClasspathClassLoader; +import net.sourceforge.pmd.util.datasource.DataSource; +import net.sourceforge.pmd.util.datasource.FileDataSource; + +public class PmdExample2 { + + public static void main(String[] args) throws IOException { + PMDConfiguration configuration = new PMDConfiguration(); + configuration.setMinimumPriority(RulePriority.MEDIUM); + configuration.setRuleSets("rulesets/java/quickstart.xml"); + configuration.prependClasspath("/home/workspace/target/classes"); + RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.createFactory(configuration); + + List files = determineFiles("/home/workspace/src/main/java/code"); + + Writer rendererOutput = new StringWriter(); + Renderer renderer = createRenderer(rendererOutput); + renderer.start(); + + RuleContext ctx = new RuleContext(); + + ctx.getReport().addListener(createReportListener()); // alternative way to collect violations + + try { + PMD.processFiles(configuration, ruleSetFactory, files, ctx, + Collections.singletonList(renderer)); + } finally { + ClassLoader auxiliaryClassLoader = configuration.getClassLoader(); + if (auxiliaryClassLoader instanceof ClasspathClassLoader) { + ((ClasspathClassLoader) auxiliaryClassLoader).close(); + } + } + + renderer.end(); + renderer.flush(); + System.out.println("Rendered Report:"); + System.out.println(rendererOutput.toString()); + } + + private static ThreadSafeReportListener createReportListener() { + return new ThreadSafeReportListener() { + @Override + public void ruleViolationAdded(RuleViolation ruleViolation) { + System.out.printf("%-20s:%d %s%n", ruleViolation.getFilename(), + ruleViolation.getBeginLine(), ruleViolation.getDescription()); + } + + @Override + public void metricAdded(Metric metric) { + // ignored + } + }; + } + + private static Renderer createRenderer(Writer writer) { + XMLRenderer xml = new XMLRenderer("UTF-8"); + xml.setWriter(writer); + return xml; + } + + private static List determineFiles(String basePath) throws IOException { + Path dirPath = FileSystems.getDefault().getPath(basePath); + PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:*.java"); + + List files = new ArrayList<>(); + + Files.walkFileTree(dirPath, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { + if (matcher.matches(path.getFileName())) { + System.out.printf("Using %s%n", path); + files.add(new FileDataSource(path.toFile())); + } else { + System.out.printf("Ignoring %s%n", path); + } + return super.visitFile(path, attrs); + } + }); + System.out.printf("Analyzing %d files in %s%n", files.size(), basePath); + return files; + } +} +``` + + From 1bba78cc6578424e455e3f846837f6fbd8ee7f94 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 13 Feb 2020 11:12:44 +0100 Subject: [PATCH 064/235] [java] Remove unnecessary CDATA for UnusedImports tests --- .../rule/bestpractices/xml/UnusedImports.xml | 116 ++++++++---------- 1 file changed, 50 insertions(+), 66 deletions(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedImports.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedImports.xml index 5fe5e64653..321098f929 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedImports.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedImports.xml @@ -3,20 +3,18 @@ xmlns="http://pmd.sourceforge.net/rule-tests" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + - + simple unused single type import 1 + - + one used single type import 0 + - + 2 unused single-type imports 2 + - + 1 used single type import 0 + - + 1 import stmt, used only in throws clause 0 + - + for loop 0 java 1.5 + - + Generics 0 java 1.5 + - + Generics 2 0 java 1.5 + - + Annotations 0 java 1.5 + - + Annotations 2 0 java 1.5 + - + import from default package 0 + - + import from default package 1 + - + Used static import 0 java 1.5 + - + Unused static import 1 java 1.5 + - + On demand import 0 + - + imports used in javadoc comment, see also bug #254 0 + #1280 False Positive in UnusedImports when import used in javadoc 0 @@ -258,9 +243,7 @@ public class Foo { - + Bug 2606609 : False "UnusedImports" positive in package-info.java 0 + #1181 unused import false positive if used as parameter in javadoc only. 0 @@ -308,6 +292,7 @@ public class Foo { } ]]> + #1280 False Positive in UnusedImports when import used in javadoc 0 @@ -323,6 +308,7 @@ public class Foo { } ]]> + #914 False +ve from UnusedImports with wildcard static imports 0 @@ -386,10 +372,10 @@ import foo.bar.Fixed_Values; */ public interface Interface { - /** - * @throws Under_Score_Exception - */ - void doSomething(); + /** + * @throws Under_Score_Exception + */ + void doSomething(); } ]]> @@ -405,7 +391,7 @@ public class Foo { /** * {@link Bar#doSomething(GroupLayout.Group)} - */ + */ void doSomething(); } ]]> @@ -517,7 +503,7 @@ public class VendingV2PaymentRequest { } ]]> - + #2025 False Positive in UnusedImports for params when using @link with FQCN 0 @@ -528,7 +514,7 @@ import spark.Request; // flaged, should not * {@link foo.bar.MyController#startTransaction(Request)} */ public class VendingV2PaymentRequest { -} +} ]]> @@ -552,10 +538,9 @@ public class Issue2016 { } ]]> + - + resolve ambiguous static on-demand imports (#2277) 0 - java 1.5 From 1f75eb551fafdd24cc9163fbd2731819ee5b0099 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 13 Feb 2020 11:15:26 +0100 Subject: [PATCH 065/235] [doc] Update release notes, fixes #2277, refs #2278 --- docs/pages/release_notes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 4ea9b3b8b4..34a8b6ff80 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -23,6 +23,8 @@ For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designe * java * [#2268](https://github.com/pmd/pmd/issues/2268): \[java] Improve TypeHelper resilience +* java-bestpractices + * [#2277](https://github.com/pmd/pmd/issues/2277): \[java] FP in UnusedImports for ambiguous static on-demand imports * java-errorprone * [#2250](https://github.com/pmd/pmd/issues/2250): \[java] InvalidLogMessageFormat flags logging calls using a slf4j-Marker * java-performance @@ -36,6 +38,7 @@ For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designe * [#2253](https://github.com/pmd/pmd/pull/2253): \[modelica] Remove duplicated dependencies - [Piotrek Żygieło](https://github.com/pzygielo) * [#2256](https://github.com/pmd/pmd/pull/2256): \[doc] Corrected XML attributes in release notes - [Maikel Steneker](https://github.com/maikelsteneker) * [#2276](https://github.com/pmd/pmd/pull/2276): \[java] AppendCharacterWithCharRule ignore literals in expressions - [Kris Scheibe](https://github.com/kris-scheibe) +* [#2278](https://github.com/pmd/pmd/pull/2278): \[java] fix UnusedImports rule for ambiguous static on-demand imports - [Kris Scheibe](https://github.com/kris-scheibe) {% endtocmaker %} From ca6720d55c33684f7c905092fd1280cede2b6fcf Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 13 Feb 2020 11:32:40 +0100 Subject: [PATCH 066/235] [doc] Fix invalid link to JJTJavaParserState jdoc generated link to net.sourceforge.pmd.lang.ast.JJTJavaParserState, but the source file couldn't be found in the source tree of pmd-java --- docs/pages/next_major_development.md | 2 +- docs/pages/release_notes_old.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/next_major_development.md b/docs/pages/next_major_development.md index d4b449aa9a..4c7704ef6c 100644 --- a/docs/pages/next_major_development.md +++ b/docs/pages/next_major_development.md @@ -106,7 +106,7 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati {% jdoc core::lang.ast.SimpleCharStream %}: these are APIs used by our JavaCC implementations and that will be moved/refactored for PMD 7.0.0. They should not be used, extended or implemented directly. -* All classes generated by JavaCC, eg {% jdoc java::lang.ast.JJTJavaParserState %}. +* All classes generated by JavaCC, eg {% jdoc java::lang.java.ast.JJTJavaParserState %}. This includes token classes, which will be replaced with a single implementation, and subclasses of {% jdoc core::lang.ast.ParseException %}, whose usages will be replaced by just that superclass. diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index 51b9e8416e..8fc42da0fd 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -147,7 +147,7 @@ methods on [`ApexParserVisitor`](https://javadoc.io/page/net.sourceforge.pmd/pmd [`SimpleCharStream`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.21.0/net/sourceforge/pmd/lang/ast/SimpleCharStream.html#): these are APIs used by our JavaCC implementations and that will be moved/refactored for PMD 7.0.0. They should not be used, extended or implemented directly. -* All classes generated by JavaCC, eg [`JJTJavaParserState`](https://javadoc.io/page/net.sourceforge.pmd/pmd-java/6.21.0/net/sourceforge/pmd/lang/ast/JJTJavaParserState.html#). +* All classes generated by JavaCC, eg [`JJTJavaParserState`](https://javadoc.io/page/net.sourceforge.pmd/pmd-java/6.21.0/net/sourceforge/pmd/lang/java/ast/JJTJavaParserState.html#). This includes token classes, which will be replaced with a single implementation, and subclasses of [`ParseException`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.21.0/net/sourceforge/pmd/lang/ast/ParseException.html#), whose usages will be replaced by just that superclass. From 0358dfdb977950d37cd14a679403194663bb26a5 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 13 Feb 2020 11:39:04 +0100 Subject: [PATCH 067/235] [doc] Update release notes, fixes #1078, refs #2279 --- docs/pages/release_notes.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 4ea9b3b8b4..f6984c5552 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -19,8 +19,15 @@ This is a {{ site.pmd.release_type }} release. This PMD release ships a new version of the pmd-designer. For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/6.21.0). +### Apex Suppressions + +In addition to suppressing violation with the `@SuppressWarnings` annotation, Apex now also supports +the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs_suppressing_warnings.html). + ### Fixed Issues +* apex + * [#1087](https://github.com/pmd/pmd/issues/1087): \[apex] Support suppression via //NOPMD * java * [#2268](https://github.com/pmd/pmd/issues/2268): \[java] Improve TypeHelper resilience * java-errorprone @@ -36,6 +43,7 @@ For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designe * [#2253](https://github.com/pmd/pmd/pull/2253): \[modelica] Remove duplicated dependencies - [Piotrek Żygieło](https://github.com/pzygielo) * [#2256](https://github.com/pmd/pmd/pull/2256): \[doc] Corrected XML attributes in release notes - [Maikel Steneker](https://github.com/maikelsteneker) * [#2276](https://github.com/pmd/pmd/pull/2276): \[java] AppendCharacterWithCharRule ignore literals in expressions - [Kris Scheibe](https://github.com/kris-scheibe) +* [#2279](https://github.com/pmd/pmd/pull/2279): \[apex] Add support for suppressing violations using the // NOPMD comment - [Gwilym Kuiper](https://github.com/gwilymatgearset) {% endtocmaker %} From 86ef30f26ab14d259aefccba78311dc59cc1d493 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 13 Feb 2020 13:51:39 +0100 Subject: [PATCH 068/235] [java] Remove unnecessary CDATAs in tests for MisplacedNullCheck --- .../errorprone/xml/MisplacedNullCheck.xml | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml index 3194f0b654..bc226c8ef5 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml @@ -3,11 +3,11 @@ xmlns="http://pmd.sourceforge.net/rule-tests" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + - + null check after method invocation with conditional AND and != 1 + 3 + - + null check after nested method invocation 1 + 3 + - + null check before nested method invocation 0 + - + 1610730: null check after method invocation with conditional OR and == 1 + 3 + - + 3372128: False positive: ArrayIsStoredDirectly 0 + #977 MisplacedNullCheck makes false positives 0 @@ -85,6 +84,7 @@ public class Test { } ]]> + #2242 False-positive MisplacedNullCheck reported (1) 0 @@ -102,6 +102,7 @@ public class Test { } ]]> + #2242 False-positive MisplacedNullCheck reported (2) 0 From 00c0d3a7130366852ed2733865b569a95be2d6a5 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 13 Feb 2020 15:04:27 +0100 Subject: [PATCH 069/235] [java] MisplacedNullCheck - fix false positive * Upgrade to XPath 2.0 * Extend test cases * Report on variable that is being null check and improve violation message Fixes #2242 --- .../resources/category/java/errorprone.xml | 59 ++++++++++++------- .../errorprone/xml/MisplacedNullCheck.xml | 51 ++++++++++++---- 2 files changed, 79 insertions(+), 31 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml index 35d5c71a3e..54ca2b51b2 100644 --- a/pmd-java/src/main/resources/category/java/errorprone.xml +++ b/pmd-java/src/main/resources/category/java/errorprone.xml @@ -2288,7 +2288,7 @@ public class MyClass { @@ -2297,26 +2297,39 @@ Either the check is useless (the variable will never be "null") or it is incorre 3 + @@ -2325,8 +2338,10 @@ Either the check is useless (the variable will never be "null") or it is incorre @@ -2334,7 +2349,9 @@ public class Foo { diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml index bc226c8ef5..ef0c904a12 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml @@ -6,26 +6,52 @@ null check after method invocation with conditional AND and != - 1 - 3 + 4 + 3,4,6,7 + + The null check here is misplaced; if the variable 'a' is null there will be a NullPointerException + The null check here is misplaced; if the variable 'a' is null there will be a NullPointerException + The null check here is misplaced; if the variable 'a' is null there will be a NullPointerException + The null check here is misplaced; if the variable 'a' is null there will be a NullPointerException + null check after nested method invocation - 1 - 3 + 4 + 3,4,6,7 + + The null check here is misplaced; if the variable 'baz' is null there will be a NullPointerException + The null check here is misplaced; if the variable 'baz' is null there will be a NullPointerException + The null check here is misplaced; if the variable 'baz' is null there will be a NullPointerException + The null check here is misplaced; if the variable 'baz' is null there will be a NullPointerException + @@ -46,6 +72,9 @@ public class Foo { 1610730: null check after method invocation with conditional OR and == 1 3 + + The null check here is misplaced; if the variable 'a' is null there will be a NullPointerException + From 0444509545b8c3438d00b875d6f1e744daeef361 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 13 Feb 2020 15:11:20 +0100 Subject: [PATCH 070/235] [doc] Update release notes, fixes #2242 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 930ff2987c..a92b8b2e83 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -34,6 +34,7 @@ the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs * [#2277](https://github.com/pmd/pmd/issues/2277): \[java] FP in UnusedImports for ambiguous static on-demand imports * java-errorprone * [#2250](https://github.com/pmd/pmd/issues/2250): \[java] InvalidLogMessageFormat flags logging calls using a slf4j-Marker + * [#2242](https://github.com/pmd/pmd/issues/2242): \[java] False-positive MisplacedNullCheck reported * java-performance * [#2275](https://github.com/pmd/pmd/issues/2275): \[java] AppendCharacterWithChar flags literals in an expression From 3dbbb8a935e116fb2f769e82ac0a8e2e04b438ee Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 13 Feb 2020 16:16:08 +0100 Subject: [PATCH 071/235] [java] MisplacedNullCheck - fix new false positives Also simplify the xpath expression. --- .../resources/category/java/errorprone.xml | 22 +++++++------------ .../errorprone/xml/MisplacedNullCheck.xml | 21 ++++++++++++++++++ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml index 54ca2b51b2..dae3e8c109 100644 --- a/pmd-java/src/main/resources/category/java/errorprone.xml +++ b/pmd-java/src/main/resources/category/java/errorprone.xml @@ -2302,34 +2302,28 @@ Either the check is useless (the variable will never be "null") or it is incorre diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml index ef0c904a12..1d23d6f199 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MisplacedNullCheck.xml @@ -152,4 +152,25 @@ public class Test { ]]> + + False-positive/negative with multiple conditions + 2 + 7,8 + + The null check here is misplaced; if the variable 'attributes' is null there will be a NullPointerException + The null check here is misplaced; if the variable 'attributes' is null there will be a NullPointerException + + attributes) { + boolean isStereotype = annotationType.equals("javax.inject.Named"); + if (isStereotype && attributes != null && attributes.containsKey("value")) {} + if (isStereotype || attributes == null || attributes.containsKey("value")) {} + + if (isStereotype && attributes.containsKey("value") && attributes != null) {} + if (isStereotype || attributes.containsKey("value") || attributes == null) {} + } +} + ]]> + From de622bcbaec93fe8e3a1fbee1cbba77002698dd8 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 15 Feb 2020 18:19:01 +0100 Subject: [PATCH 072/235] [doc] Update release notes, refs #2274 --- 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 930ff2987c..85f639a6db 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -28,6 +28,8 @@ the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs * apex * [#1087](https://github.com/pmd/pmd/issues/1087): \[apex] Support suppression via //NOPMD +* doc + * [#2274](https://github.com/pmd/pmd/issues/2274): \[doc] Java API documentation for PMD * java * [#2268](https://github.com/pmd/pmd/issues/2268): \[java] Improve TypeHelper resilience * java-bestpractices From ba19a3d6ff20b29cfe0af63e3ea99c18b5d68184 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 15 Feb 2020 19:07:20 +0100 Subject: [PATCH 073/235] Update support channels Refs #2249 --- CONTRIBUTING.md | 19 ++++++++----------- README.md | 15 ++++++++++++--- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 594aa8b29e..f86d7d2287 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,10 +18,7 @@ First off, thanks for taking the time to contribute! ## Bug reports -We used to use Sourceforge for bug tracking, but we are in the process of moving to github issues. - -* Old bugs are still available at . -* Please report new bugs at . +We use the issue tracker on Github. Please report new bugs at . When filing a bug report, please provide as much information as possible, so that we can reproduce the issue: @@ -32,7 +29,7 @@ When filing a bug report, please provide as much information as possible, so tha ## Documentation -There is some documentation available under . Feel free to create a bug report if +There is some documentation available under . Feel free to create a bug report if documentation is missing, incomplete or outdated. See [Bug reports](#bug-reports). The documentation is generated as a Jekyll site, the source is available at: . You can find build instructions there. @@ -42,18 +39,18 @@ For more on contributing documentation check - * On [StackOverflow](https://stackoverflow.com/questions/tagged/pmd): Make sure, to tag your question with "pmd". +* Create a issue for your question at . + +* Ask your question on Gitter . + ## Code Style PMD uses [checkstyle](http://checkstyle.sourceforge.net/) to enforce a common code style. -See [pmd-checkstyle-config.xml](https://github.com/pmd/build-tools/blob/master/config/src/main/resources/net/sourceforge/pmd/pmd-checkstyle-config.xml) for the configuration and -[the eclipse configuration files](https://github.com/pmd/build-tools/tree/master/config/eclipse) that can +See [pmd-checkstyle-config.xml](https://github.com/pmd/build-tools/blob/master/src/main/resources/net/sourceforge/pmd/pmd-checkstyle-config.xml) for the configuration and +[the eclipse configuration files](https://github.com/pmd/build-tools/tree/master/eclipse) that can be imported into a fresh workspace. diff --git a/README.md b/README.md index e89fa6db57..dbfbd7d9ca 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,16 @@ Additionally it includes **CPD**, the copy-paste-detector. CPD finds duplicated C/C++, C#, Dart, Fortran, Go, Groovy, Java, JavaScript, JSP, Kotlin, Lua, Matlab, Modelica, Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex, Scala, Swift and Visualforce. -## Source and Documentation +## Support + +* How do I? -- Ask a question on [StackOverflow](https://stackoverflow.com/questions/tagged/pmd). +* I got this error, why? -- Ask a question on [StackOverflow](https://stackoverflow.com/questions/tagged/pmd). +* I got this error and I'm sure it's a bug -- file an [issue](https://github.com/pmd/pmd/issues). +* I have an idea/request/question -- file an [issue](https://github.com/pmd/pmd/issues). +* I have a quick question -- ask on our [Gitter chat](https://gitter.im/pmd/pmd). +* Where's your documentation? -- + +## Source Our latest source of PMD can be found on [GitHub](https://github.com/pmd/pmd). Fork us! @@ -26,6 +35,6 @@ The rule designer is developed over at [pmd/pmd-designer](https://github.com/pmd Please see [its README](https://github.com/pmd/pmd-designer#contributing) for developer documentation. -## News and Website +## Website -More information can be found on our [Website](https://pmd.github.io) and on [SourceForge](https://sourceforge.net/projects/pmd/). +More information can be found on our [Website](https://pmd.github.io). From 4566567e5e662d264dbf86e2ca693eaed3c22cdd Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 10:42:20 +0100 Subject: [PATCH 074/235] [doc] Update last changed date --- .../devdocs/major_contributions/adding_new_metrics_framework.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/pmd/devdocs/major_contributions/adding_new_metrics_framework.md b/docs/pages/pmd/devdocs/major_contributions/adding_new_metrics_framework.md index c545c7815e..cc4f085329 100644 --- a/docs/pages/pmd/devdocs/major_contributions/adding_new_metrics_framework.md +++ b/docs/pages/pmd/devdocs/major_contributions/adding_new_metrics_framework.md @@ -5,7 +5,7 @@ tags: [devdocs, extending, metrics] summary: "PMD's Java module has an extensive framework for the calculation of metrics, which allows rule developers to implement and use new code metrics very simply. Most of the functionality of this framework is abstracted in such a way that any PMD supported language can implement such a framework without too much trouble. Here's how." -last_updated: December 2017 +last_updated: February 2020 permalink: pmd_devdocs_major_adding_new_metrics_framework.html author: Clément Fournier --- From dfb1315ff5f188ca1d896f1b084099487ceb178f Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 10:43:35 +0100 Subject: [PATCH 075/235] [core] Use concurrent hash map in ParameterizedMetricKey --- .../pmd/lang/metrics/ParameterizedMetricKey.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKey.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKey.java index 474852c8ec..fd863681d9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKey.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKey.java @@ -4,8 +4,8 @@ package net.sourceforge.pmd.lang.metrics; -import java.util.HashMap; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; @@ -24,7 +24,7 @@ import net.sourceforge.pmd.util.DataMap.DataKey; @Deprecated public final class ParameterizedMetricKey implements DataKey, Double> { - private static final Map, ParameterizedMetricKey> POOL = new HashMap<>(); + private static final ConcurrentMap, ParameterizedMetricKey> POOL = new ConcurrentHashMap<>(); /** The metric key. */ public final MetricKey key; @@ -72,9 +72,7 @@ public final class ParameterizedMetricKey implements DataKey ParameterizedMetricKey getInstance(MetricKey key, MetricOptions options) { // sharing instances allows using DataMap, which uses reference identity ParameterizedMetricKey tmp = new ParameterizedMetricKey<>(key, options); - if (!POOL.containsKey(tmp)) { - POOL.put(tmp, tmp); - } + POOL.putIfAbsent(tmp, tmp); @SuppressWarnings("unchecked") ParameterizedMetricKey result = (ParameterizedMetricKey) POOL.get(tmp); From d06b01785a712e61d33f366520f37c2473f5bd1a Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 11:20:02 +0100 Subject: [PATCH 076/235] [java] Code formatting for properties in SingularFieldRule --- .../pmd/lang/java/rule/design/SingularFieldRule.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) 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 a8bd4da90b..fd3dedb405 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 @@ -40,8 +40,16 @@ public class SingularFieldRule extends AbstractLombokAwareRule { * Restore old behavior by setting both properties to true, which will * result in many false positives */ - private static final PropertyDescriptor CHECK_INNER_CLASSES = booleanProperty("checkInnerClasses").defaultValue(false).desc("Check inner classes").build(); - private static final PropertyDescriptor DISALLOW_NOT_ASSIGNMENT = booleanProperty("disallowNotAssignment").defaultValue(false).desc("Disallow violations where the first usage is not an assignment").build(); + private static final PropertyDescriptor CHECK_INNER_CLASSES = + booleanProperty("checkInnerClasses") + .defaultValue(false) + .desc("Check inner classes") + .build(); + private static final PropertyDescriptor DISALLOW_NOT_ASSIGNMENT = + booleanProperty("disallowNotAssignment") + .defaultValue(false) + .desc("Disallow violations where the first usage is not an assignment") + .build(); public SingularFieldRule() { From 5e5070f3ec6816a7758242a0f92a7a3ad191d3f0 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 11:53:24 +0100 Subject: [PATCH 077/235] [doc] Update link to SingularFieldRule --- docs/pages/pmd/userdocs/extending/defining_properties.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/pmd/userdocs/extending/defining_properties.md b/docs/pages/pmd/userdocs/extending/defining_properties.md index 97a3151664..f3a13610d6 100644 --- a/docs/pages/pmd/userdocs/extending/defining_properties.md +++ b/docs/pages/pmd/userdocs/extending/defining_properties.md @@ -97,7 +97,7 @@ static PropertyDescriptor modeProperty ### Example -You can see an example of properties used in a PMD rule [here](https://github.com/pmd/pmd/blob/5d86217871f086f8223da327099d1d67a6e45dab/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java#L41-L42). +You can see an example of properties used in a PMD rule [here](https://github.com/pmd/pmd/blob/d06b01785a712e61d33f366520f37c2473f5bd1a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java#L43-L52). There are several things to notice here: * The property descriptors are declared `static final`, which should generally be the case, as descriptors are immutable and can be shared between instances of the same rule; From 587500e0c24947b54d9dca94fecad0359c7d7d65 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 11:54:48 +0100 Subject: [PATCH 078/235] [doc] Update last_updated timestamp for writing rule docs --- docs/pages/pmd/userdocs/extending/defining_properties.md | 2 +- docs/pages/pmd/userdocs/extending/rule_guidelines.md | 2 +- docs/pages/pmd/userdocs/extending/writing_java_rules.md | 2 +- docs/pages/pmd/userdocs/extending/writing_rules_intro.md | 4 ++-- docs/pages/pmd/userdocs/extending/writing_xpath_rules.md | 2 +- docs/pages/pmd/userdocs/extending/your_first_rule.md | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/defining_properties.md b/docs/pages/pmd/userdocs/extending/defining_properties.md index f3a13610d6..31360fbdad 100644 --- a/docs/pages/pmd/userdocs/extending/defining_properties.md +++ b/docs/pages/pmd/userdocs/extending/defining_properties.md @@ -3,7 +3,7 @@ title: Defining rule properties short_title: Defining rule properties tags: [extending, userdocs] summary: "Learn how to define your own properties both for Java and XPath rules." -last_updated: December 2017 (6.0.0) +last_updated: February 2020 (6.22.0) permalink: pmd_userdocs_extending_defining_properties.html author: Hooper Bloob , Romain Pelisse , Clément Fournier --- diff --git a/docs/pages/pmd/userdocs/extending/rule_guidelines.md b/docs/pages/pmd/userdocs/extending/rule_guidelines.md index c01e8ca4f1..bf21cd041e 100644 --- a/docs/pages/pmd/userdocs/extending/rule_guidelines.md +++ b/docs/pages/pmd/userdocs/extending/rule_guidelines.md @@ -2,7 +2,7 @@ title: Rule guidelines tags: [extending, userdocs] summary: "Rule Guidelines, or the last touches to a rule" -last_updated: July 3, 2016 +last_updated: February 2020 (6.22.0) permalink: pmd_userdocs_extending_rule_guidelines.html author: Xavier Le Vourch, Ryan Gustafson, Romain Pelisse --- diff --git a/docs/pages/pmd/userdocs/extending/writing_java_rules.md b/docs/pages/pmd/userdocs/extending/writing_java_rules.md index 4b03dd6626..7ad4e33036 100644 --- a/docs/pages/pmd/userdocs/extending/writing_java_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_java_rules.md @@ -2,7 +2,7 @@ title: Writing a custom rule tags: [extending, userdocs] summary: "Learn how to write a custom rule for PMD" -last_updated: July 3, 2016 +last_updated: February 2020 (6.22.0) permalink: pmd_userdocs_extending_writing_java_rules.html author: Tom Copeland --- diff --git a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md index 7eb50eaf85..e98398684f 100644 --- a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md +++ b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md @@ -1,8 +1,8 @@ --- title: Introduction to writing PMD rules tags: [extending, userdocs, getting_started] -summary: "Writing your own PMD rules TODO" -last_updated: July 2018 (6.6.0) +summary: "Writing your own PMD rules" +last_updated: February 2020 (6.22.0) permalink: pmd_userdocs_extending_writing_rules_intro.html author: Clément Fournier --- diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index 02668f79ef..1a4c1b5fe9 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -2,7 +2,7 @@ title: Writing XPath rules tags: [extending, userdocs] summary: "This page describes XPath rule support in more details" -last_updated: July 2018 (6.6.0) +last_updated: February 2020 (6.22.0) permalink: pmd_userdocs_extending_writing_xpath_rules.html author: Miguel Griffa , Clément Fournier --- diff --git a/docs/pages/pmd/userdocs/extending/your_first_rule.md b/docs/pages/pmd/userdocs/extending/your_first_rule.md index acec128716..d559fcd6ad 100644 --- a/docs/pages/pmd/userdocs/extending/your_first_rule.md +++ b/docs/pages/pmd/userdocs/extending/your_first_rule.md @@ -2,9 +2,9 @@ title: Your first rule XPath tags: [extending, userdocs] summary: "Introduction to rule writing through an example." -last_updated: July 2018 (6.6.0) +last_updated: February 2020 (6.22.0) permalink: pmd_userdocs_extending_your_first_rule.html -author: Miguel Griffa +author: Miguel Griffa , Clément Fournier --- This page is a gentle introduction to rule writing, and the Rule Designer. From 5685013e35eecf12ecbb838e9dcc665e31d8b670 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 11:55:29 +0100 Subject: [PATCH 079/235] [doc] Re-add pmd_userdocs_extending_writing_pmd_rules.html Links to the other pages now. --- .../userdocs/extending/writing_pmd_rules.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 docs/pages/pmd/userdocs/extending/writing_pmd_rules.md diff --git a/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md b/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md new file mode 100644 index 0000000000..e44eab3046 --- /dev/null +++ b/docs/pages/pmd/userdocs/extending/writing_pmd_rules.md @@ -0,0 +1,23 @@ +--- +title: Writing a custom rule +tags: [extending, userdocs] +last_updated: February 2020 (6.22.0) +permalink: pmd_userdocs_extending_writing_pmd_rules.html +--- + +The information on this page has been split into several separate pages. Please update your bookmarks: + +* [Introduction to writing rules](pmd_userdocs_extending_writing_rules_intro.html) + * [Your First Rule](pmd_userdocs_extending_your_first_rule.html) + introduces the basic development process of a rule with a running example + * [Writing XPath Rules](pmd_userdocs_extending_writing_xpath_rules.html) + explains a bit more about XPath rules and our XPath API + * [Writing Java Rules](pmd_userdocs_extending_writing_java_rules.html) + describes how to write a rule in Java + +To go further: +* [Defining Properties](pmd_userdocs_extending_defining_properties.html) + describes how to make your rules more configurable with rule properties +* [Testing your Rules](pmd_userdocs_extending_testing.html) introduces + our testing framework and how you can use it to safeguard the quality of + your rule From e7b72c2b6b7710a2e8d7863ccd46c79243260b30 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 11:56:05 +0100 Subject: [PATCH 080/235] [doc] Override Rule.start(RuleContext) instead of apply --- docs/pages/pmd/userdocs/extending/writing_java_rules.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/pmd/userdocs/extending/writing_java_rules.md b/docs/pages/pmd/userdocs/extending/writing_java_rules.md index 7ad4e33036..82b9a4941b 100644 --- a/docs/pages/pmd/userdocs/extending/writing_java_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_java_rules.md @@ -128,8 +128,8 @@ and the rule instance is reused. If you rely on a proper initialization of insta properties, you can do the initialization e.g. in the visit-method of the {% jdoc jast::ASTCompilationUnit %} node - which is visited first and only once per file. However, this solution would only work for rules written for the Java language. A language -independent way is to override the method `apply` of the rule (and call super). -The apply method is called exactly once per file. +independent way is to override the method `start` of the rule. +The start method is called exactly once per file. From 75d901068af51204cce060081d10b207f6a20192 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 11:56:26 +0100 Subject: [PATCH 081/235] [doc] Update gems --- docs/Gemfile.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index b8dfb746e2..f87471028b 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -16,7 +16,7 @@ GEM colorator (1.1.0) commonmarker (0.17.13) ruby-enum (~> 0.5) - concurrent-ruby (1.1.5) + concurrent-ruby (1.1.6) dnsruby (1.61.3) addressable (~> 2.5) em-websocket (0.5.1) @@ -28,10 +28,10 @@ GEM execjs (2.7.0) faraday (1.0.0) multipart-post (>= 1.2, < 3) - ffi (1.12.1) + ffi (1.12.2) forwardable-extended (2.6.0) gemoji (3.0.1) - github-pages (203) + github-pages (204) github-pages-health-check (= 1.16.1) jekyll (= 3.8.5) jekyll-avatar (= 0.7.0) @@ -40,7 +40,7 @@ GEM jekyll-default-layout (= 0.1.4) jekyll-feed (= 0.13.0) jekyll-gist (= 1.5.0) - jekyll-github-metadata (= 2.12.1) + jekyll-github-metadata (= 2.13.0) jekyll-mentions (= 1.5.1) jekyll-optional-front-matter (= 0.3.2) jekyll-paginate (= 1.1.0) @@ -117,8 +117,8 @@ GEM jekyll (>= 3.7, < 5.0) jekyll-gist (1.5.0) octokit (~> 4.2) - jekyll-github-metadata (2.12.1) - jekyll (~> 3.4) + jekyll-github-metadata (2.13.0) + jekyll (>= 3.4, < 5.0) octokit (~> 4.0, != 4.4.0) jekyll-mentions (1.5.1) html-pipeline (~> 2.3) @@ -204,9 +204,9 @@ GEM jekyll-seo-tag (~> 2.1) minitest (5.14.0) multipart-post (2.1.1) - nokogiri (1.10.7) + nokogiri (1.10.8) mini_portile2 (~> 2.4.0) - octokit (4.15.0) + octokit (4.16.0) faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) pathutil (0.16.2) @@ -218,7 +218,7 @@ GEM rouge (3.13.0) ruby-enum (0.7.2) i18n - rubyzip (2.0.0) + rubyzip (2.2.0) safe_yaml (1.0.5) sass (3.7.4) sass-listen (~> 4.0.0) From 80cba026c2ecda9fc7c770cd78df134ca0803e79 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 13:12:28 +0100 Subject: [PATCH 082/235] [java] Deprecate getArgumentCount()/getParameterCount() * ASTArguments#getArgumentCount() * ASTFormalParameters#getParameterCount() Refs #2271 --- docs/pages/release_notes.md | 6 ++++-- .../pmd/lang/java/ast/ASTArgumentList.java | 9 +++++++++ .../pmd/lang/java/ast/ASTArguments.java | 16 ++++++++++++++-- .../lang/java/ast/ASTConstructorDeclaration.java | 2 +- .../ast/ASTExplicitConstructorInvocation.java | 4 ++-- .../pmd/lang/java/ast/ASTFormalParameters.java | 10 +++++++++- .../pmd/lang/java/ast/ASTMethodDeclaration.java | 2 +- .../pmd/lang/java/ast/ASTMethodDeclarator.java | 2 +- .../pmd/lang/java/ast/ASTPrimarySuffix.java | 2 +- .../pmd/lang/java/ast/DumpFacade.java | 4 ++-- .../signature/JavaOperationSignature.java | 4 ++-- .../AccessorClassGenerationRule.java | 2 +- .../JUnitAssertionsShouldIncludeMessageRule.java | 2 +- .../rule/bestpractices/MissingOverrideRule.java | 4 ++-- .../codestyle/ClassNamingConventionsRule.java | 2 +- .../ConstructorCallsOverridableMethodRule.java | 4 ++-- .../performance/BigIntegerInstantiationRule.java | 2 +- .../performance/StringInstantiationRule.java | 2 +- .../rule/security/HardCodedCryptoKeyRule.java | 2 +- .../java/rule/security/InsecureCryptoIvRule.java | 2 +- .../java/symboltable/MethodNameDeclaration.java | 4 ++-- .../pmd/lang/java/symboltable/NameFinder.java | 2 +- 22 files changed, 60 insertions(+), 29 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index b6e947ad79..834c546dfa 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -42,8 +42,6 @@ the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs ### API Changes -#### Deprecated API - #### Deprecated APIs ##### Internal API @@ -111,6 +109,10 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * {% jdoc java::lang.java.ast.ASTYieldStatement %} will not implement {% jdoc java::lang.java.ast.TypeNode %} anymore come 7.0.0. Test the type of the expression nested within it. * {% jdoc java::lang.java.metrics.JavaMetrics %}, {% jdoc java::lang.java.metrics.JavaMetricsComputer %} + * {% jdoc !!java::lang.java.ast.ASTArguments#getArgumentCount() %}. + Use {% jdoc java::lang.java.ast.ASTArguments#size() %} instead. + * {% jdoc !!java::lang.java.ast.ASTFormalParameters#getParameterCount() %}. + Use {% jdoc java::lang.java.ast.ASTFormalParameters#size() %} instead. * pmd-apex * {% jdoc java::lang.apex.metrics.ApexMetrics %}, {% jdoc java::lang.java.metrics.JavaMetricsComputer %} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArgumentList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArgumentList.java index 08c57dd9a7..a1db7aebd0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArgumentList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArgumentList.java @@ -24,4 +24,13 @@ public class ASTArgumentList extends AbstractJavaNode { public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + /** + * Gets the number of arguments. + * + * @return the number of arguments. + */ + public int size() { + return this.getNumChildren(); + } } 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 009f645899..fd9fb5dbad 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 @@ -20,11 +20,23 @@ public class ASTArguments extends AbstractJavaNode { super(p, id); } - public int getArgumentCount() { + /** + * Gets the number of arguments. + * @return + */ + public int size() { if (this.getNumChildren() == 0) { return 0; } - return this.getChild(0).getNumChildren(); + return ((ASTArgumentList) this.getChild(0)).size(); + } + + /** + * @deprecated for removal. Use {@link #size()} or {@link ASTArgumentList#size()} instead. + */ + @Deprecated + public int getArgumentCount() { + return size(); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclaration.java index ed57be5330..3e3f473bd3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclaration.java @@ -65,7 +65,7 @@ public class ASTConstructorDeclaration extends AbstractMethodOrConstructorDeclar * (excluding any receiver parameter). A varargs parameter counts as one. */ public int getArity() { - return getFormalParameters().getParameterCount(); + return getFormalParameters().size(); } //@Override // enable this with PMD 7.0.0 - see interface ASTMethodOrConstructorDeclaration diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java index 622ab94228..badbf6c685 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java @@ -29,9 +29,9 @@ public class ASTExplicitConstructorInvocation extends AbstractJavaNode { public int getArgumentCount() { if (this.getNumChildren() == 1) { - return ((ASTArguments) this.getChild(0)).getArgumentCount(); + return ((ASTArguments) this.getChild(0)).size(); } else { - return ((ASTArguments) this.getChild(1)).getArgumentCount(); + return ((ASTArguments) this.getChild(1)).size(); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameters.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameters.java index 40adda2a39..b492f7f2c1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameters.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameters.java @@ -24,12 +24,20 @@ public class ASTFormalParameters extends AbstractJavaNode implements Iterable parameters = findChildrenOfType(ASTFormalParameter.class); return !parameters.isEmpty() && parameters.get(0).isExplicitReceiverParameter() ? parameters.size() - 1 : parameters.size(); } + /** + * @deprecated for removal. Use {@link #size()} instead. + */ + @Deprecated + public int getParameterCount() { + return size(); + } + @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); 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 45631c1361..fe39f9db94 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 @@ -151,7 +151,7 @@ public class ASTMethodDeclaration extends AbstractMethodOrConstructorDeclaration * (excluding any receiver parameter). A varargs parameter counts as one. */ public int getArity() { - return getFormalParameters().getParameterCount(); + return getFormalParameters().size(); } 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 c91b57bda8..c8f17b95ab 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 @@ -31,7 +31,7 @@ public class ASTMethodDeclarator extends AbstractJavaNode { */ @Deprecated public int getParameterCount() { - return getFirstChildOfType(ASTFormalParameters.class).getParameterCount(); + return getFirstChildOfType(ASTFormalParameters.class).size(); } /** 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 67e0d79e27..2ec9b2e923 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 @@ -55,7 +55,7 @@ public class ASTPrimarySuffix extends AbstractJavaTypeNode { if (!this.isArguments()) { return -1; } - return ((ASTArguments) getChild(getNumChildren() - 1)).getArgumentCount(); + return ((ASTArguments) getChild(getNumChildren() - 1)).size(); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DumpFacade.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DumpFacade.java index eb5b46e7f0..29d713e630 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DumpFacade.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DumpFacade.java @@ -107,7 +107,7 @@ public class DumpFacade extends JavaParserVisitorAdapter { // Other extras if (node instanceof ASTArguments) { - extras.add(String.valueOf(((ASTArguments) node).getArgumentCount())); + extras.add(String.valueOf(((ASTArguments) node).size())); } else if (node instanceof ASTAssignmentOperator) { extras.add(((ASTAssignmentOperator) node).isCompound() ? "compound" : "simple"); } else if (node instanceof ASTClassOrInterfaceBodyDeclaration) { @@ -146,7 +146,7 @@ public class DumpFacade extends JavaParserVisitorAdapter { extras.add("varargs"); } } else if (node instanceof ASTFormalParameters) { - extras.add(String.valueOf(((ASTFormalParameters) node).getParameterCount())); + extras.add(String.valueOf(((ASTFormalParameters) node).size())); } else if (node instanceof ASTIfStatement) { if (((ASTIfStatement) node).hasElse()) { extras.add("has else"); 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 45afbc061e..2c20589f93 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 @@ -139,7 +139,7 @@ public final class JavaOperationSignature extends JavaSignature fieldNames) { - if (node.getFirstDescendantOfType(ASTFormalParameters.class).getParameterCount() != 0 + if (node.getFirstDescendantOfType(ASTFormalParameters.class).size() != 0 || node.getFirstDescendantOfType(ASTResultType.class).isVoid()) { return false; } @@ -158,7 +158,7 @@ public final class JavaOperationSignature extends JavaSignature fieldNames) { - if (node.getFirstDescendantOfType(ASTFormalParameters.class).getParameterCount() != 1 + if (node.getFirstDescendantOfType(ASTFormalParameters.class).size() != 1 || !node.getFirstDescendantOfType(ASTResultType.class).isVoid()) { return false; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AccessorClassGenerationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AccessorClassGenerationRule.java index a44e32fed9..79a348e7a2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AccessorClassGenerationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AccessorClassGenerationRule.java @@ -83,7 +83,7 @@ public class AccessorClassGenerationRule extends AbstractJavaRule { break; } - if (cd.getArity() == callArguments.getArgumentCount()) { + if (cd.getArity() == callArguments.size()) { // TODO : Check types addViolation(data, node); break; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitAssertionsShouldIncludeMessageRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitAssertionsShouldIncludeMessageRule.java index 585100ab6b..6ae4943d11 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitAssertionsShouldIncludeMessageRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnitAssertionsShouldIncludeMessageRule.java @@ -27,7 +27,7 @@ public class JUnitAssertionsShouldIncludeMessageRule extends AbstractJUnitRule { } public void check(Object ctx, ASTArguments node) { - if (node.getArgumentCount() == argumentsCount + if (node.size() == argumentsCount && node.getNthParent(2) instanceof ASTPrimaryExpression) { ASTPrimaryPrefix primaryPrefix = node.getNthParent(2).getFirstChildOfType(ASTPrimaryPrefix.class); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java index bf0762a71d..9076e635de 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java @@ -337,7 +337,7 @@ public class MissingOverrideRule extends AbstractJavaRule { * @throws NoSuchMethodException if no method is registered with this name and paramcount, which is a bug */ boolean isOverridden(String name, ASTFormalParameters params) throws NoSuchMethodException { - List methods = getMethods(name, params.getParameterCount()); + List methods = getMethods(name, params.size()); if (methods.size() == 1) { // only one method with this name and parameter count, we can conclude return overridden.contains(methods.get(0)); @@ -358,7 +358,7 @@ public class MissingOverrideRule extends AbstractJavaRule { private static Class[] getParameterTypes(ASTFormalParameters params) { - Class[] paramTypes = new Class[params.getParameterCount()]; + Class[] paramTypes = new Class[params.size()]; int i = 0; for (ASTFormalParameter p : params) { Class pType = p.getType(); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/ClassNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/ClassNamingConventionsRule.java index 14767ca038..b90c1804aa 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/ClassNamingConventionsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/ClassNamingConventionsRule.java @@ -104,7 +104,7 @@ public class ClassNamingConventionsRule extends AbstractNamingConventionRule packagesAndClasses = new ArrayList<>(); String methodName = null; ASTArguments args = (ASTArguments) lastNode.getChild(0); - int numOfArguments = args.getArgumentCount(); + int numOfArguments = args.size(); List argumentTypes = ConstructorCallsOverridableMethodRule.getArgumentTypes(args); boolean superFirst = false; int thisIndex = -1; @@ -455,7 +455,7 @@ public final class ConstructorCallsOverridableMethodRule extends AbstractJavaRul List l = eci.findChildrenOfType(ASTArguments.class); if (!l.isEmpty()) { ASTArguments aa = l.get(0); - count = aa.getArgumentCount(); + count = aa.size(); argumentTypes = ConstructorCallsOverridableMethodRule.getArgumentTypes(aa); } name = eci.getImage(); 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 065ea786fe..f0a4d7ddda 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 @@ -40,7 +40,7 @@ public class BigIntegerInstantiationRule extends AbstractJavaRule { || jdk15 && TypeHelper.isA((ASTClassOrInterfaceType) type, BigDecimal.class)) && !node.hasDescendantOfType(ASTArrayDimsAndInits.class)) { ASTArguments args = node.getFirstChildOfType(ASTArguments.class); - if (args.getArgumentCount() == 1) { + if (args.size() == 1) { ASTLiteral literal = node.getFirstDescendantOfType(ASTLiteral.class); if (literal == null || literal.getParent().getParent().getParent().getParent().getParent() != args) { 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 ad5e7c9a6d..adf195b25d 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 @@ -72,7 +72,7 @@ public class StringInstantiationRule extends AbstractJavaRule { private boolean isArrayAccess(ASTAllocationExpression node) { ASTArguments arguments = node.getFirstChildOfType(ASTArguments.class); - if (arguments == null || arguments.getArgumentCount() != 1) { + if (arguments == null || arguments.size() != 1) { return false; } 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 71afea81a8..d1b001af89 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 @@ -40,7 +40,7 @@ public class HardCodedCryptoKeyRule extends AbstractJavaRule { Node firstArgument = null; ASTArguments arguments = node.getFirstChildOfType(ASTArguments.class); - if (arguments.getArgumentCount() > 0) { + if (arguments.size() > 0) { firstArgument = arguments.getFirstChildOfType(ASTArgumentList.class).getChild(0); } 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 6c5e10698a..0bffb60dec 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 @@ -47,7 +47,7 @@ public class InsecureCryptoIvRule extends AbstractJavaRule { Node firstArgument = null; ASTArguments arguments = node.getFirstChildOfType(ASTArguments.class); - if (arguments.getArgumentCount() > 0) { + if (arguments.size() > 0) { firstArgument = arguments.getFirstChildOfType(ASTArgumentList.class).getChild(0); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java index 0473f78c76..024e1f0728 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java @@ -23,12 +23,12 @@ public class MethodNameDeclaration extends AbstractNameDeclaration { public boolean isVarargs() { ASTFormalParameters params = (ASTFormalParameters) node.getChild(0); - if (params.getParameterCount() == 0) { + if (params.size() == 0) { return false; } // If it's a varargs, it HAS to be the last parameter - ASTFormalParameter p = (ASTFormalParameter) params.getChild(params.getParameterCount() - 1); + ASTFormalParameter p = (ASTFormalParameter) params.getChild(params.size() - 1); return p.isVarargs(); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/NameFinder.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/NameFinder.java index b602f7ec06..0372c81ff8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/NameFinder.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/NameFinder.java @@ -59,7 +59,7 @@ public class NameFinder { JavaNameOccurrence occurrence = names.get(names.size() - 1); occurrence.setIsMethodOrConstructorInvocation(); ASTArguments args = (ASTArguments) ((ASTPrimarySuffix) node).getChild(0); - occurrence.setArgumentCount(args.getArgumentCount()); + occurrence.setArgumentCount(args.size()); } else if (suffix.getNumChildren() == 1 && suffix.getChild(0) instanceof ASTMemberSelector) { ASTMemberSelector member = (ASTMemberSelector) suffix.getChild(0); if (member.getNumChildren() == 1 && member.getChild(0) instanceof ASTMethodReference) { From da7596a0272c89195a930877384ba5f9e0bed8eb Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 14:16:27 +0100 Subject: [PATCH 083/235] [core] Add missing @Deprecated annotations for Node --- .../main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java | 2 ++ pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java | 2 ++ 2 files changed, 4 insertions(+) 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 b00a38a6b8..e7f7b0fdef 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 @@ -526,11 +526,13 @@ public abstract class AbstractNode implements Node { } @Override + @Deprecated public Object getUserData() { return userData.get(LEGACY_USER_DATA); } @Override + @Deprecated public void setUserData(final Object userData) { this.userData.set(LEGACY_USER_DATA, userData); } 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 4f3ac8f9b2..1b8172ec54 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 @@ -391,6 +391,7 @@ public interface Node { * @return The user data set on this node. * @deprecated Use {@link #getUserMap()} */ + @Deprecated Object getUserData(); /** @@ -408,6 +409,7 @@ public interface Node { * The data to set on this node. * @deprecated Use {@link #getUserMap()} */ + @Deprecated void setUserData(Object userData); /** From 4ce85c4656f6e34c72eb69803777c210e41949fc Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 16 Feb 2020 14:28:01 +0100 Subject: [PATCH 084/235] [java] Fix deprecated usage of ArgumentCount/ParameterCount in rules --- .../pmd/lang/ast/xpath/AttributeAxisIterator.java | 3 +++ .../src/main/resources/category/java/errorprone.xml | 10 +++++----- .../main/resources/category/java/multithreading.xml | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java index a1e5edeb2d..5a1e554a7e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/xpath/AttributeAxisIterator.java @@ -174,6 +174,9 @@ public class AttributeAxisIterator implements Iterator { if (n.startsWith("uses")) { return n.substring("uses".length()); } + if ("size".equals(n)) { + return "Size"; + } return n; } diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml index 35d5c71a3e..e9a7f6ce78 100644 --- a/pmd-java/src/main/resources/category/java/errorprone.xml +++ b/pmd-java/src/main/resources/category/java/errorprone.xml @@ -1195,7 +1195,7 @@ should be annotated with @Test and @Ignore. [not(Annotation)] [MethodDeclaration[(@Public = true() or @PackagePrivate = true()) and @Static = false() and ResultType[@Void = true()] and - MethodDeclarator/FormalParameters[@ParameterCount = 0] + MethodDeclarator/FormalParameters[@Size = 0] ] ] ]]> @@ -2854,7 +2854,7 @@ formatting is used. @@ -3366,7 +3366,7 @@ To make sure the full stacktrace is printed out, use the logging statement with concat(ancestor::ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/FieldDeclaration [Type//ClassOrInterfaceType[@Image='Log']] /VariableDeclarator/VariableDeclaratorId/@Image, '.'))]] -[PrimarySuffix/Arguments[@ArgumentCount='1']] +[PrimarySuffix/Arguments[@Size='1']] [PrimarySuffix/Arguments//Name/@Image = ancestor::CatchStatement/FormalParameter/VariableDeclaratorId/@Image] ]]> @@ -3482,13 +3482,13 @@ class Test { [ PrimaryPrefix [Name[ends-with(@Image, 'toLowerCase') or ends-with(@Image, 'toUpperCase')]] -[following-sibling::PrimarySuffix[position() = 1]/Arguments[@ArgumentCount=0]] +[following-sibling::PrimarySuffix[position() = 1]/Arguments[@Size=0]] or PrimarySuffix [ends-with(@Image, 'toLowerCase') or ends-with(@Image, 'toUpperCase')] -[following-sibling::PrimarySuffix[position() = 1]/Arguments[@ArgumentCount=0]] +[following-sibling::PrimarySuffix[position() = 1]/Arguments[@Size=0]] ] [not(PrimaryPrefix/Name[ends-with(@Image, 'toHexString')])] ]]> diff --git a/pmd-java/src/main/resources/category/java/multithreading.xml b/pmd-java/src/main/resources/category/java/multithreading.xml index d251dee839..c1ca1d5c2f 100644 --- a/pmd-java/src/main/resources/category/java/multithreading.xml +++ b/pmd-java/src/main/resources/category/java/multithreading.xml @@ -379,7 +379,7 @@ one is chosen. The thread chosen is arbitrary; thus its usually safer to call n Date: Thu, 6 Feb 2020 17:06:46 +0100 Subject: [PATCH 085/235] Document enum conversion --- docs/pages/pmd/userdocs/extending/writing_xpath_rules.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index 1a4c1b5fe9..78910e95cb 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -79,6 +79,7 @@ function from Java types to XDM types. |`boolean` | `xs:boolean` |`String` | `xs:string` |`Character` | `xs:string` +|`Enum` | `xs:string` (uses `Object::toString`) |`List` | `conv(E)*` (a sequence type) From 653c02c263b76bb4168b1b8af8e683714d9c8a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 16 Feb 2020 18:46:23 +0100 Subject: [PATCH 086/235] Adapt Antlr nodes to DataMap --- .../sourceforge/pmd/lang/ast/AbstractNode.java | 3 ++- .../pmd/lang/ast/impl/antlr4/AntlrBaseNode.java | 17 +++++++++++++---- .../ast/impl/antlr4/PmdAntlrTerminalNode.java | 16 ++++++++++++---- 3 files changed, 27 insertions(+), 9 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 49e5421a0b..a9a4f9e84f 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 @@ -28,7 +28,8 @@ public abstract class AbstractNode implements Node { private static final Node[] EMPTY_ARRAY = new Node[0]; - private static final SimpleDataKey LEGACY_USER_DATA = DataMap.simpleDataKey("legacy user data"); + @Deprecated + public static final SimpleDataKey LEGACY_USER_DATA = DataMap.simpleDataKey("legacy user data"); private final DataMap> userData = DataMap.newDataMap(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseNode.java index c35c30e6d2..1dcaf06ab3 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseNode.java @@ -6,9 +6,13 @@ package net.sourceforge.pmd.lang.ast.impl.antlr4; import org.antlr.v4.runtime.ParserRuleContext; +import net.sourceforge.pmd.lang.ast.AbstractNode; +import net.sourceforge.pmd.util.DataMap; +import net.sourceforge.pmd.util.DataMap.DataKey; + public abstract class AntlrBaseNode extends ParserRuleContext implements AntlrNode { - private Object userData; + private final DataMap> userData = DataMap.newDataMap(); /** * Constructor required by {@link ParserRuleContext} @@ -63,12 +67,17 @@ public abstract class AntlrBaseNode extends ParserRuleContext implements AntlrNo @Override public Object getUserData() { - return userData; + return userData.get(AbstractNode.LEGACY_USER_DATA); } @Override - public void setUserData(final Object userData) { - this.userData = userData; + public void setUserData(Object userData) { + this.userData.set(AbstractNode.LEGACY_USER_DATA, userData); + } + + @Override + public DataMap> getUserMap() { + return userData; } @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/PmdAntlrTerminalNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/PmdAntlrTerminalNode.java index 51aae8dba0..c7a8dc5d25 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/PmdAntlrTerminalNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/PmdAntlrTerminalNode.java @@ -8,12 +8,16 @@ import org.antlr.v4.runtime.RuleContext; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.TerminalNodeImpl; +import net.sourceforge.pmd.lang.ast.AbstractNode; +import net.sourceforge.pmd.util.DataMap; +import net.sourceforge.pmd.util.DataMap.DataKey; + /** * @author Clément Fournier */ public class PmdAntlrTerminalNode extends TerminalNodeImpl implements AntlrNode { - private Object userData; + private final DataMap> userData = DataMap.newDataMap(); public PmdAntlrTerminalNode(Token t) { super(t); @@ -72,12 +76,16 @@ public class PmdAntlrTerminalNode extends TerminalNodeImpl implements AntlrNode @Override public Object getUserData() { - return userData; + return userData.get(AbstractNode.LEGACY_USER_DATA); } @Override - public void setUserData(Object userData) { - this.userData = userData; + public void setUserData(Object data) { + this.userData.set(AbstractNode.LEGACY_USER_DATA, data); } + @Override + public DataMap> getUserMap() { + return userData; + } } From 31ee5c384591d0bde0d834a7e9e2ab26df982766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 16 Feb 2020 18:54:31 +0100 Subject: [PATCH 087/235] Simplify metrics result options --- .../pmd/lang/metrics/MetricsUtil.java | 51 +++++-------------- 1 file changed, 13 insertions(+), 38 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java index 39c108721a..d151855803 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/metrics/MetricsUtil.java @@ -4,9 +4,10 @@ package net.sourceforge.pmd.lang.metrics; -import java.util.ArrayList; -import java.util.List; +import java.util.DoubleSummaryStatistics; import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import net.sourceforge.pmd.lang.ast.Node; @@ -55,22 +56,21 @@ public final class MetricsUtil { Objects.requireNonNull(resultOption, "The result option must not be null"); - List values = new ArrayList<>(); - for (O op : ops) { - if (key.supports(op)) { - double val = computeMetric(key, op, options); - values.add(val); - } - } + DoubleSummaryStatistics stats = + StreamSupport.stream(ops.spliterator(), false) + .filter(key::supports) + .collect(Collectors.summarizingDouble(op -> computeMetric(key, op, options))); - // FUTURE use streams to do that when we upgrade the compiler to 1.8 + // note these operations coalesce Double.NaN + // (if any value is NaN, the result is NaN) switch (resultOption) { case SUM: - return sum(values); + return stats.getSum(); case HIGHEST: - return highest(values); + double max = stats.getMax(); + return max == Double.NEGATIVE_INFINITY ? 0 : max; case AVERAGE: - return average(values); + return stats.getAverage(); default: throw new IllegalArgumentException("Unknown result option " + resultOption); } @@ -166,29 +166,4 @@ public final class MetricsUtil { return val; } - private static double sum(List values) { - double sum = 0; - for (double val : values) { - sum += val; - } - return sum; - } - - - private static double highest(List values) { - double highest = Double.NEGATIVE_INFINITY; - for (double val : values) { - if (val > highest) { - highest = val; - } - } - return highest == Double.NEGATIVE_INFINITY ? 0 : highest; - } - - - private static double average(List values) { - return sum(values) / values.size(); - } - - } From d227038df27cc42e0e94903c121cc0c01d26f3ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 16 Feb 2020 19:01:27 +0100 Subject: [PATCH 088/235] Port Apex NOPMD comment implementation to 7.0 version --- .../sourceforge/pmd/lang/apex/ast/ApexParser.java | 12 +++--------- .../pmd/lang/apex/SuppressWarningsTest.java | 4 ++-- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java index 71a4b1d446..008fbb01e9 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexParser.java @@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.apex.ast; import java.io.IOException; import java.io.Reader; -import java.util.Map; import org.apache.commons.io.IOUtils; @@ -26,8 +25,6 @@ import apex.jorje.semantic.ast.visitor.AstVisitor; public class ApexParser { protected final ApexParserOptions parserOptions; - private Map suppressMap; - public ApexParser(ApexParserOptions parserOptions) { ApexJorjeLogging.disableLogging(); this.parserOptions = parserOptions; @@ -47,22 +44,19 @@ public class ApexParser { final String sourceCode = IOUtils.toString(reader); final Compilation astRoot = parseApex(sourceCode); final ApexTreeBuilder treeBuilder = new ApexTreeBuilder(sourceCode, parserOptions); - suppressMap = treeBuilder.getSuppressMap(); if (astRoot == null) { throw new ParseException("Couldn't parse the source - there is not root node - Syntax Error??"); } - return treeBuilder.build(astRoot); + ApexRootNode treeRoot = (ApexRootNode) treeBuilder.build(astRoot); + treeRoot.setNoPmdComments(treeBuilder.getSuppressMap()); + return treeRoot; } catch (IOException e) { throw new ParseException(e); } } - public Map getSuppressMap() { - return suppressMap; - } - private class TopLevelVisitor extends AstVisitor { Compilation topLevel; diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java index f98c1af402..bf8991bb1b 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/SuppressWarningsTest.java @@ -5,7 +5,6 @@ package net.sourceforge.pmd.lang.apex; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import java.util.List; @@ -13,6 +12,7 @@ import org.junit.Test; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.Report; +import net.sourceforge.pmd.ViolationSuppressor; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; @@ -164,7 +164,7 @@ public class SuppressWarningsTest extends RuleTst { assertEquals(1, suppressions.size()); Report.SuppressedViolation suppression = suppressions.get(0); - assertTrue(suppression.suppressedByNOPMD()); + assertEquals(ViolationSuppressor.NOPMD_COMMENT_SUPPRESSOR, suppression.getSuppressor()); assertEquals("We allow foo here", suppression.getUserMessage()); } From 8ab362c0ad98dc65741b7e62193cb26659c52700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Sun, 16 Feb 2020 19:09:23 +0100 Subject: [PATCH 089/235] Fix java metrics handler --- .../java/internal/JavaLanguageHandler.java | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) 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 5879872d60..f9953d7191 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 @@ -4,6 +4,9 @@ package net.sourceforge.pmd.lang.java.internal; +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; @@ -16,7 +19,9 @@ import net.sourceforge.pmd.lang.java.ast.JavaParser; import net.sourceforge.pmd.lang.java.ast.MethodLikeNode; import net.sourceforge.pmd.lang.java.ast.internal.LanguageLevelChecker; import net.sourceforge.pmd.lang.java.ast.internal.ReportingStrategy; -import net.sourceforge.pmd.lang.java.metrics.JavaMetricsProvider; +import net.sourceforge.pmd.lang.java.metrics.JavaMetrics; +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; @@ -25,6 +30,8 @@ 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.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.sf.saxon.sxpath.IndependentContext; @@ -79,4 +86,28 @@ public class JavaLanguageHandler extends AbstractPmdLanguageVersionHandler { public LanguageMetricsProvider getLanguageMetricsProvider() { return myMetricsProvider; } + + + private static class JavaMetricsProvider extends AbstractLanguageMetricsProvider { + + JavaMetricsProvider() { + super(ASTAnyTypeDeclaration.class, MethodLikeNode.class); + } + + @Override + protected List findOps(ASTAnyTypeDeclaration astAnyTypeDeclaration) { + return JavaMetrics.findOps(astAnyTypeDeclaration); + } + + @Override + public List> getAvailableTypeMetrics() { + return Arrays.asList(JavaClassMetricKey.values()); + } + + + @Override + public List> getAvailableOperationMetrics() { + return Arrays.asList(JavaOperationMetricKey.values()); + } + } } From ed0dd0a6aeb25d1a49b3aa13f3369ef42074a20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 17 Feb 2020 00:28:25 +0100 Subject: [PATCH 090/235] Fix merge --- .../sourceforge/pmd/lang/apex/ast/ApexCompilerTest.java | 8 ++------ .../sourceforge/pmd/lang/apex/ast/ApexParserTestBase.java | 4 ++-- .../sourceforge/pmd/lang/apex/ast/ApexParsingHelper.java | 7 ++++--- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCompilerTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCompilerTest.java index e7f91d271a..320e82b234 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCompilerTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCompilerTest.java @@ -4,18 +4,14 @@ package net.sourceforge.pmd.lang.apex.ast; -import static net.sourceforge.pmd.lang.apex.ast.ApexParserTestHelpers.parse; - import org.junit.Test; import net.sourceforge.pmd.lang.ast.ParseException; -import apex.jorje.semantic.ast.compilation.Compilation; - -public class ApexCompilerTest { +public class ApexCompilerTest extends ApexParserTestBase { @Test(expected = ParseException.class) public void compileShouldFail() { - ApexNode node = parse("public class Foo { private String myField = \"a\"; }"); + apex.parse("public class Foo { private String myField = \"a\"; }"); } } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTestBase.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTestBase.java index 74f8e59c43..82966d4c34 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTestBase.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTestBase.java @@ -12,10 +12,10 @@ public class ApexParserTestBase { protected ApexNode parse(String code) { - return (ApexNode) apex.parse(code); + return apex.parse(code); } protected ApexNode parseResource(String code) { - return (ApexNode) apex.parseResource(code); + return apex.parseResource(code); } } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParsingHelper.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParsingHelper.java index 6b2dfecf23..025d2a1d02 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParsingHelper.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParsingHelper.java @@ -5,16 +5,17 @@ package net.sourceforge.pmd.lang.apex.ast; import net.sourceforge.pmd.lang.apex.ApexLanguageModule; -import net.sourceforge.pmd.lang.ast.RootNode; import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper; -public class ApexParsingHelper extends BaseParsingHelper { +import apex.jorje.semantic.ast.compilation.Compilation; + +public class ApexParsingHelper extends BaseParsingHelper> { public static final ApexParsingHelper DEFAULT = new ApexParsingHelper(Params.getDefaultProcess()); private ApexParsingHelper(Params p) { - super(ApexLanguageModule.NAME, RootNode.class, p); + super(ApexLanguageModule.NAME, (Class>) (Class) ApexRootNode.class, p); } @Override From 35ce86823567078a2c8d11e8f78151992f385dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 17 Feb 2020 00:28:51 +0100 Subject: [PATCH 091/235] Only throw parse exceptions (not semantic ones, like unresolved type) --- .../pmd/lang/apex/ast/CompilerService.java | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java index 1655c57f2e..f9bbb5c5d1 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java @@ -24,6 +24,8 @@ import apex.jorje.semantic.compiler.sfdc.AccessEvaluator; import apex.jorje.semantic.compiler.sfdc.NoopCompilerProgressCallback; import apex.jorje.semantic.compiler.sfdc.QueryValidator; import apex.jorje.semantic.compiler.sfdc.SymbolProvider; +import apex.jorje.services.exception.CompilationException; +import apex.jorje.services.exception.ParseException; import com.google.common.collect.ImmutableList; /** @@ -42,14 +44,6 @@ public class CompilerService { /** * Configure a compiler with the default configurations: - * - * @param symbolProvider - * EmptySymbolProvider, doesn't provide any symbols that are not - * part of source. - * @param accessEvaluator - * TestAccessEvaluator, doesn't provide any validation. - * @param queryValidator - * TestQueryValidators.Noop, no validation of queries. */ CompilerService() { this(EmptySymbolProvider.get(), new TestAccessEvaluator(), new TestQueryValidators.Noop()); @@ -92,14 +86,32 @@ public class CompilerService { ApexCompiler compiler = ApexCompiler.builder().setInput(compilationInput).build(); compiler.compile(compilerStage); callAdditionalPassVisitor(compiler); - compiler.throwErrorsIfAny(); + throwParseErrorIfAny(compiler); return compiler; } + private void throwParseErrorIfAny(ApexCompiler compiler) { + // this ignores semantic errors + + ParseException parseError = null; + for (CompilationException error : compiler.getErrors()) { + if (error instanceof ParseException) { + if (parseError == null) { + parseError = (ParseException) error; + } else { + parseError.addSuppressed(error); + } + } + } + if (parseError != null) { + throw parseError; + } + } + private CompilationInput createCompilationInput(List sourceFiles, - AstVisitor visitor) { + AstVisitor visitor) { return new CompilationInput(sourceFiles, symbolProvider, accessEvaluator, queryValidator, visitor, - NoopCompilerProgressCallback.get()); + NoopCompilerProgressCallback.get()); } /** From e11371272a2dacae22c49f7cbe45a8eb28f05f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 17 Feb 2020 00:46:15 +0100 Subject: [PATCH 092/235] Fix tests --- .../pmd/lang/apex/ast/CompilerService.java | 4 + .../AbstractNamingConventionsRule.java | 7 +- .../lang/apex/ast/ASTSoqlExpressionTest.java | 4 +- .../pmd/lang/apex/ast/ApexParserTest.java | 2 +- .../pmd/lang/apex/ast/StackOverflowClass.cls | 4 +- .../lang/apex/metrics/impl/xml/CycloTest.xml | 6 +- .../bestpractices/xml/AvoidGlobalModifier.xml | 4 +- .../xml/DebugsShouldUseLoggingLevel.xml | 4 +- .../codestyle/xml/ClassNamingConventions.xml | 4 +- .../codestyle/xml/MethodNamingConventions.xml | 20 ++--- .../xml/VariableNamingConventions.xml | 12 +-- .../rule/design/xml/CyclomaticComplexity.xml | 6 +- .../rule/design/xml/ExcessiveClassLength.xml | 4 +- .../design/xml/ExcessiveParameterList.xml | 2 +- .../rule/design/xml/ExcessivePublicCount.xml | 2 +- .../rule/design/xml/NcssConstructorCount.xml | 2 +- .../apex/rule/design/xml/NcssMethodCount.xml | 2 +- .../apex/rule/design/xml/NcssTypeCount.xml | 2 +- .../design/xml/StdCyclomaticComplexity.xml | 2 +- .../apex/rule/design/xml/TooManyFields.xml | 77 ++++++------------- .../xml/AvoidDirectAccessTriggerMap.xml | 6 +- .../rule/security/xml/ApexCRUDViolation.xml | 5 +- .../rule/security/xml/ApexSOQLInjection.xml | 12 +-- 23 files changed, 70 insertions(+), 123 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java index f9bbb5c5d1..5b62b786b4 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/CompilerService.java @@ -66,14 +66,18 @@ public class CompilerService { this.queryValidator = queryValidator; } + + /** @throws ParseException If the code is unparsable */ public ApexCompiler visitAstFromString(String source, AstVisitor visitor) { return visitAstsFromStrings(ImmutableList.of(source), visitor, CompilerStage.POST_TYPE_RESOLVE); } + /** @throws ParseException If the code is unparsable */ public ApexCompiler visitAstsFromStrings(List sources, AstVisitor visitor) { return visitAstsFromStrings(sources, visitor, CompilerStage.POST_TYPE_RESOLVE); } + /** @throws ParseException If the code is unparsable */ public ApexCompiler visitAstsFromStrings(List sources, AstVisitor visitor, CompilerStage compilerStage) { List sourceFiles = sources.stream().map(s -> SourceFile.builder().setBody(s).build()) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/AbstractNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/AbstractNamingConventionsRule.java index 53e6fa6894..fb21041ef7 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/AbstractNamingConventionsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/AbstractNamingConventionsRule.java @@ -23,12 +23,7 @@ abstract class AbstractNamingConventionsRule extends AbstractApexRule { abstract String displayName(String name); protected void checkMatches(PropertyDescriptor propertyDescriptor, ApexNode node, Object data) { - Pattern regex = getProperty(propertyDescriptor); - String name = node.getImage(); - if (!regex.matcher(name).matches()) { - String displayName = displayName(propertyDescriptor.name()); - addViolation(data, node, new Object[] { displayName, name, regex.toString() }); - } + checkMatches(propertyDescriptor, getProperty(propertyDescriptor), node, data); } protected void checkMatches(PropertyDescriptor propertyDescriptor, Pattern overridePattern, ApexNode node, Object data) { diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSoqlExpressionTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSoqlExpressionTest.java index aa421fc83e..4bf940aaa2 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSoqlExpressionTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSoqlExpressionTest.java @@ -13,8 +13,8 @@ public class ASTSoqlExpressionTest extends ApexParserTestBase { @Test public void testQuery() { - ApexNode node = parse("class Foo { void test1() { Account acc = [SELECT 1 FROM Account]; } }"); + ApexNode node = parse("class Foo { void test1() { Account acc = [SELECT col FROM Account]; } }"); ASTSoqlExpression soqlExpression = node.getFirstDescendantOfType(ASTSoqlExpression.class); - Assert.assertEquals("SELECT 1 FROM Account", soqlExpression.getQuery()); + Assert.assertEquals("SELECT col FROM Account", soqlExpression.getQuery()); } } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java index 3f051e0a09..79ecc234c6 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java @@ -44,7 +44,7 @@ public class ApexParserTest extends ApexParserTestBase { private String testCodeForLineNumbers = "public class SimpleClass {\n" // line 1 + " public void method1() {\n" // line 2 - + " System.out.println(\"abc\");\n" // line 3 + + " System.out.println('abc');\n" // line 3 + " // this is a comment\n" // line 4 + " }\n" // line 5 + "}\n"; // line 6 diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/StackOverflowClass.cls b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/StackOverflowClass.cls index 2896906ffe..44ba1f8643 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/StackOverflowClass.cls +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/StackOverflowClass.cls @@ -85,7 +85,7 @@ public class SomeClass { if(object1Map.get(object1.Id).Id != null && object1.Text != null){ Item post = new Item(); post.ParentId = object1Map.get(object1.Id).Id; - post.Body = "Something"; + post.Body = 'Something'; itemList.add(post); } @@ -99,7 +99,7 @@ public class SomeClass { if(object1.Text != null && object1.Id != null){ Item post = new Item(); post.ParentId = object1.Id; - post.Body = "Something"; + post.Body = 'Something'; itemList.add(post); } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CycloTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CycloTest.xml index 522f07545b..ca8ccfdca1 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CycloTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CycloTest.xml @@ -13,7 +13,7 @@ k++; } catch (IOException ioe) { ioe.printStackTrace(); - throw new Exception("surprise", ioe); + throw new Exception('surprise', ioe); } catch (Exception e) { // do nothing } @@ -22,7 +22,7 @@ int x = 0, y = 1, z = 2, t = 2; boolean a = false, b = true, c = false, d = true; - for (String s : list) { + for (String s : lst) { // list is a kw x++; } @@ -86,7 +86,7 @@ public Test() { if (a == 1) { if (b == 2) { - System.out.println("b"); + System.out.println('b'); } else if (b == 1) { } } else { diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/bestpractices/xml/AvoidGlobalModifier.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/bestpractices/xml/AvoidGlobalModifier.xml index 28f5acf78c..470fbdee69 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/bestpractices/xml/AvoidGlobalModifier.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/bestpractices/xml/AvoidGlobalModifier.xml @@ -42,8 +42,8 @@ global class Foo { 1 diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/bestpractices/xml/DebugsShouldUseLoggingLevel.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/bestpractices/xml/DebugsShouldUseLoggingLevel.xml index 431c9c2e47..1b79209ec3 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/bestpractices/xml/DebugsShouldUseLoggingLevel.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/bestpractices/xml/DebugsShouldUseLoggingLevel.xml @@ -14,7 +14,7 @@ public class Foo { @isTest static void methodATest() { System.debug('I am a bad debug!'); // not good - System.debug(LoggingLevel.WARN, 'I am a good warning.') // good + System.debug(LoggingLevel.WARN, 'I am a good warning.'); // good } } ]]> @@ -44,7 +44,7 @@ public class Foo { public class Foo { @isTest static void methodATest() { - System.debug(LoggingLevel.DEBUG, 'I am a good debug.') // good + System.debug(LoggingLevel.DEBUG, 'I am a good debug.'); // good } } ]]> diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/ClassNamingConventions.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/ClassNamingConventions.xml index 8817e4f30b..b649a57ab2 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/ClassNamingConventions.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/ClassNamingConventions.xml @@ -9,7 +9,7 @@ class names should not start with lowercase character 1 @@ -17,7 +17,7 @@ public class foo {}; all is well 0 diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml index ea9db4a8d0..42d1088243 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml @@ -34,18 +34,7 @@ public class Foo { } ]]> - - - #1343 MethodNamingConventions for overrided methods - 0 - - - + #25 Method rules should ignore Property Getter/Setter 0 @@ -81,10 +70,11 @@ public class Foo { #1573 method names should not contain underscores, but skip test methods 2 true - 0 + 1 @@ -107,7 +97,7 @@ public class Foo { - - variables in inner classes should not trigger problems in parent declaration - 0 - - - Rule property control 5 @@ -268,7 +258,7 @@ public class Foo { 1 diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/CyclomaticComplexity.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/CyclomaticComplexity.xml index c1c8ec239d..a93ac95a7f 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/CyclomaticComplexity.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/CyclomaticComplexity.xml @@ -111,7 +111,7 @@ public Test() { if (a == 1) { if (b == 2) { - System.out.println("b"); + System.out.println('b'); } else if (b == 1) { } } else { @@ -222,7 +222,7 @@ k++; } catch (IOException ioe) { ioe.printStackTrace(); - throw new Exception("surprise", ioe); + throw new Exception('surprise', ioe); } catch (Exception e) { // do nothing } @@ -233,7 +233,7 @@ k++; } catch (IOException ioe) { ioe.printStackTrace(); - throw new Exception("surprise", ioe); + throw new Exception('surprise', ioe); } catch (Exception e) { // do nothing } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessiveClassLength.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessiveClassLength.xml index ffb61e51f5..5bc6b83218 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessiveClassLength.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessiveClassLength.xml @@ -84,7 +84,7 @@ public class SomeClass { * Comment */ public void doSomething() { - System.debug("hello world"); + System.debug('hello world'); } /** Field comment */ @@ -92,4 +92,4 @@ public class SomeClass { } ]]> - \ No newline at end of file + diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessiveParameterList.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessiveParameterList.xml index 7b3b14d252..2c3b6e3b48 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessiveParameterList.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessiveParameterList.xml @@ -41,7 +41,7 @@ public class SomeClass { * Comment */ public void doSomething() { - System.debug("hello world"); + System.debug('hello world'); } /** Field comment */ diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml index 91c1856bca..87fa58fd6d 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml @@ -106,7 +106,7 @@ public class SomeClass { * Comment */ public void doSomething() { - System.debug("hello world"); + System.debug('hello world'); } /** Field comment */ diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssConstructorCount.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssConstructorCount.xml index e0a4320647..a6c831fdf4 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssConstructorCount.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssConstructorCount.xml @@ -129,7 +129,7 @@ public class SomeClass { * Comment */ public void doSomething() { - System.debug("hello world"); + System.debug('hello world'); } /** Field comment */ diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssMethodCount.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssMethodCount.xml index 58e523add4..70ae35a88e 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssMethodCount.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssMethodCount.xml @@ -143,7 +143,7 @@ public class SomeClass { * Comment */ public void doSomething() { - System.debug("hello world"); + System.debug('hello world'); } /** Field comment */ diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssTypeCount.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssTypeCount.xml index 55692690aa..c2f2562084 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssTypeCount.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/NcssTypeCount.xml @@ -119,7 +119,7 @@ public class SomeClass { * Comment */ public void doSomething() { - System.debug("hello world"); + System.debug('hello world'); } /** Field comment */ diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/StdCyclomaticComplexity.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/StdCyclomaticComplexity.xml index ddaed915e2..fe56df1285 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/StdCyclomaticComplexity.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/StdCyclomaticComplexity.xml @@ -150,7 +150,7 @@ public class Test { public Test() { if (a == 1) { if (b == 2) { - System.out.println("b"); + System.out.println('b'); } else if (b == 1) { } } else { diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/TooManyFields.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/TooManyFields.xml index a830a6f1d1..d26b4d8ff0 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/TooManyFields.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/TooManyFields.xml @@ -63,33 +63,12 @@ public class Foo { Integer a5; Integer a6; public class Bar { - Integer a7; - Integer a8; - Integer a9; - Integer a10; - Integer a11; - Integer a12; - } -} - ]]> - - - - outer class, inner interface, both OK - 0 - @@ -119,34 +98,22 @@ public class Foo { Integer b16; } public class Bar2 { - Integer b1; - Integer b2; - Integer b3; - Integer b4; - Integer b5; - Integer b6; - Integer b7; - Integer b8; - Integer b9; - Integer b10; - Integer b11; - Integer b12; - Integer b13; - Integer b14; - Integer b15; - Integer b16; - } -} - ]]> - - - - anonymous class with a field - 0 - diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/AvoidDirectAccessTriggerMap.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/AvoidDirectAccessTriggerMap.xml index 49d7898859..99568b713f 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/AvoidDirectAccessTriggerMap.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/AvoidDirectAccessTriggerMap.xml @@ -20,9 +20,9 @@ trigger AccountTrigger on Account (before insert, before update) { 0 @@ -40,5 +40,5 @@ class NotATrigger { ]]> - + diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexCRUDViolation.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexCRUDViolation.xml index 2c7a4768b6..d6e9bf8b4d 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexCRUDViolation.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexCRUDViolation.xml @@ -607,7 +607,8 @@ public class Foo { } public void doChecks() { - if (!Contact.sObjectType.getDescribe().isCreateable() && !Contact.sObjectType.getDescribe().isUpdateable()) { + if (!Contact.sObjectType.getDescribe().isCreateable() + && !Contact.sObjectType.getDescribe().isUpdateable()) { throw new NoAccessException(); } } @@ -626,7 +627,7 @@ public class Foo { } public void doChecks() { - anotherLevelHere("yolo"); + anotherLevelHere('yolo'); } private void anotherLevelHere(String s) { diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSOQLInjection.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSOQLInjection.xml index 920ef3e1ba..b6a00c7a4f 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSOQLInjection.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSOQLInjection.xml @@ -274,11 +274,11 @@ public class Foo { Integer is safe in query 0 - res = Database.query('Select Id, Name From ' + String.escapeSingleQuotes(objName) + ' LIMIT ' + nLimit); + public void test1(String objName, String lim) { // "limit" is a kw + Integer nLimit = Integer.valueOf(lim); + List res = Database.query('Select Id, Name From ' + String.escapeSingleQuotes(objName) + ' LIMIT ' + nLimit); } } ]]> @@ -316,10 +316,10 @@ public class Foo { isn't 1 - res = Database.query('Select Id,Name From ' + (name == 'Account' ? name : 'Cases'); + List res = Database.query('Select Id,Name From ' + (name == 'Account' ? name : 'Cases')); } } ]]> From 5b630a906269a806207e497fe38a3c6d3a9211a4 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 17 Feb 2020 20:06:33 +0100 Subject: [PATCH 093/235] [apex] Re-add fixed test cases, fix code sample Test cases for MethodNamingConventions Code sample for AvoidDirectAccessTriggerMap --- .../main/resources/category/apex/errorprone.xml | 2 +- .../codestyle/xml/MethodNamingConventions.xml | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/pmd-apex/src/main/resources/category/apex/errorprone.xml b/pmd-apex/src/main/resources/category/apex/errorprone.xml index cd458821a1..884c0f31f0 100644 --- a/pmd-apex/src/main/resources/category/apex/errorprone.xml +++ b/pmd-apex/src/main/resources/category/apex/errorprone.xml @@ -72,7 +72,7 @@ Avoid directly accessing Trigger.old and Trigger.new as it can lead to a bug. Tr trigger AccountTrigger on Account (before insert, before update) { Account a = Trigger.new[0]; //Bad: Accessing the trigger array directly is not recommended. - foreach ( Account a : Trigger.new ){ + for ( Account a : Trigger.new ){ //Good: Iterate through the trigger.new array instead. } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml index 42d1088243..c8c901f389 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml @@ -35,6 +35,17 @@ public class Foo { ]]> + + #1343 MethodNamingConventions for overriden methods + 0 + + + + #25 Method rules should ignore Property Getter/Setter 0 @@ -70,11 +81,10 @@ public class Foo { #1573 method names should not contain underscores, but skip test methods 2 true - 1 + 0 From 9c09303d753cbd46cbd8f05218b1f99eba891096 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 10:46:56 +0000 Subject: [PATCH 094/235] Skeleton implementation of CognativeComplexityVisitor --- .../impl/CognitiveComplexityMetric.java | 20 +++++++++++++++++++ .../visitors/CognitiveComplexityVisitor.java | 14 +++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityMetric.java create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/visitors/CognitiveComplexityVisitor.java 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 new file mode 100644 index 0000000000..90eeadf8ed --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityMetric.java @@ -0,0 +1,20 @@ +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.metrics.MetricOptions; + +/** + * Measures the cognitive complexity of a Class / Method in Apex. + * + * See https://www.sonarsource.com/docs/CognitiveComplexity.pdf for information about the metric + * + * @author Gwilym Kuiper + */ +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(); + } +} 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 new file mode 100644 index 0000000000..76ffa404b1 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/visitors/CognitiveComplexityVisitor.java @@ -0,0 +1,14 @@ +package net.sourceforge.pmd.lang.apex.metrics.impl.visitors; + +import net.sourceforge.pmd.lang.apex.ast.*; + +/** + * @author Gwilym Kuiper + */ +public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { + public static class State { + public double getComplexity() { + return 0.0; + } + } +} From 69c239e5a37366f613c7330d8015e70c9a14e07c Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 11:02:06 +0000 Subject: [PATCH 095/235] Register the cognitive complexity measure --- .../pmd/lang/apex/metrics/api/ApexOperationMetricKey.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/api/ApexOperationMetricKey.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/api/ApexOperationMetricKey.java index 502dbbd069..e5816c5e6c 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/api/ApexOperationMetricKey.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/api/ApexOperationMetricKey.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.apex.metrics.api; import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.metrics.impl.CognitiveComplexityMetric; import net.sourceforge.pmd.lang.apex.metrics.impl.CycloMetric; import net.sourceforge.pmd.lang.metrics.MetricKey; @@ -12,7 +13,8 @@ import net.sourceforge.pmd.lang.metrics.MetricKey; * @author Clément Fournier */ public enum ApexOperationMetricKey implements MetricKey { - CYCLO(new CycloMetric()); + CYCLO(new CycloMetric()), + COGNITIVE(new CognitiveComplexityMetric()); private final ApexOperationMetric calculator; From 0967e437671f53aab2aa6a7bfb830698109eb411 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 11:02:31 +0000 Subject: [PATCH 096/235] Add class level cognitive complexity measures --- .../apex/metrics/api/ApexClassMetricKey.java | 2 ++ .../impl/ClassCognitiveComplexityMetric.java | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/ClassCognitiveComplexityMetric.java diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/api/ApexClassMetricKey.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/api/ApexClassMetricKey.java index 2ffae23a42..73a08d5f2c 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/api/ApexClassMetricKey.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/api/ApexClassMetricKey.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.apex.metrics.api; import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface; +import net.sourceforge.pmd.lang.apex.metrics.impl.ClassCognitiveComplexityMetric; import net.sourceforge.pmd.lang.apex.metrics.impl.WmcMetric; import net.sourceforge.pmd.lang.metrics.MetricKey; @@ -12,6 +13,7 @@ import net.sourceforge.pmd.lang.metrics.MetricKey; * @author Clément Fournier */ public enum ApexClassMetricKey implements MetricKey> { + COGNITIVE(new ClassCognitiveComplexityMetric()), WMC(new WmcMetric()); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/ClassCognitiveComplexityMetric.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/ClassCognitiveComplexityMetric.java new file mode 100644 index 0000000000..6adfdc7538 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/ClassCognitiveComplexityMetric.java @@ -0,0 +1,19 @@ +package net.sourceforge.pmd.lang.apex.metrics.impl; + +import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface; +import net.sourceforge.pmd.lang.apex.metrics.ApexMetrics; +import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey; +import net.sourceforge.pmd.lang.metrics.MetricOptions; +import net.sourceforge.pmd.lang.metrics.ResultOption; + +/** + * The sum of the cognitive complexities of all the methods within a class. + * + * @author Gwilym Kuiper + */ +public class ClassCognitiveComplexityMetric extends AbstractApexClassMetric { + @Override + public double computeFor(ASTUserClassOrInterface node, MetricOptions options) { + return ApexMetrics.get(ApexOperationMetricKey.COGNITIVE, node, ResultOption.SUM); + } +} From a8234af9a6aaeb950999c234ab3b93669467d35c Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 11:02:56 +0000 Subject: [PATCH 097/235] Create design rule for cognitive complexity --- .../rule/design/CognitiveComplexityRule.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java new file mode 100644 index 0000000000..dfc8ddee79 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java @@ -0,0 +1,99 @@ +package net.sourceforge.pmd.lang.apex.rule.design; + +import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.apex.ast.ASTUserTrigger; +import net.sourceforge.pmd.lang.apex.metrics.ApexMetrics; +import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey; +import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey; +import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; +import net.sourceforge.pmd.lang.metrics.MetricsUtil; +import net.sourceforge.pmd.lang.metrics.ResultOption; +import net.sourceforge.pmd.properties.PropertyDescriptor; +import net.sourceforge.pmd.properties.PropertyFactory; + +import java.util.Stack; + +import static net.sourceforge.pmd.properties.constraints.NumericConstraints.positive; + +public class CognitiveComplexityRule extends AbstractApexRule { + + private static final PropertyDescriptor CLASS_LEVEL_DESCRIPTOR + = PropertyFactory.intProperty("classReportLevel") + .desc("Total class cognitive complexity reporting threshold") + .require(positive()) + .defaultValue(40) + .build(); + + private static final PropertyDescriptor METHOD_LEVEL_DESCRIPTOR + = PropertyFactory.intProperty("methodReportLevel") + .desc("Cognitive complexity reporting threshold") + .require(positive()) + .defaultValue(10) + .build(); + + private Stack classNames = new Stack<>(); + private boolean inTrigger; + + + public CognitiveComplexityRule() { + definePropertyDescriptor(CLASS_LEVEL_DESCRIPTOR); + definePropertyDescriptor(METHOD_LEVEL_DESCRIPTOR); + } + + + @Override + public Object visit(ASTUserTrigger node, Object data) { + inTrigger = true; + super.visit(node, data); + inTrigger = false; + return data; + } + + + @Override + public Object visit(ASTUserClass node, Object data) { + + classNames.push(node.getImage()); + super.visit(node, data); + classNames.pop(); + + if (ApexClassMetricKey.COGNITIVE.supports(node)) { + int classCognitive = (int) MetricsUtil.computeMetric(ApexClassMetricKey.COGNITIVE, node); + + if (classCognitive >= getProperty(CLASS_LEVEL_DESCRIPTOR)) { + int classHighest = (int) ApexMetrics.get(ApexOperationMetricKey.COGNITIVE, node, ResultOption.HIGHEST); + + String[] messageParams = {"class", + node.getImage(), + " total", + classCognitive + " (highest " + classHighest + ")", }; + + addViolation(data, node, messageParams); + } + } + return data; + } + + + @Override + public final Object visit(ASTMethod node, Object data) { + + if (ApexOperationMetricKey.COGNITIVE.supports(node)) { + int cognitive = (int) MetricsUtil.computeMetric(ApexOperationMetricKey.COGNITIVE, node); + if (cognitive >= getProperty(METHOD_LEVEL_DESCRIPTOR)) { + String opType = inTrigger ? "trigger" + : node.getImage().equals(classNames.peek()) ? "constructor" + : "method"; + + addViolation(data, node, new String[] {opType, + node.getQualifiedName().getOperation(), + "", + "" + cognitive, }); + } + } + + return data; + } + +} From 01da573f5fcda19dcce70241fac88e5d97b3f553 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 11:24:39 +0000 Subject: [PATCH 098/235] Add design rule for CognitiveComplexity --- .../main/resources/category/apex/design.xml | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/pmd-apex/src/main/resources/category/apex/design.xml b/pmd-apex/src/main/resources/category/apex/design.xml index 790c5cd416..cbd40a4866 100644 --- a/pmd-apex/src/main/resources/category/apex/design.xml +++ b/pmd-apex/src/main/resources/category/apex/design.xml @@ -86,6 +86,63 @@ public class Complicated { + + + TODO + + 3 + + + + + Date: Tue, 18 Feb 2020 11:40:30 +0000 Subject: [PATCH 099/235] Add tests for CognitiveComplexity --- .../apex/metrics/impl/AllMetricsTest.java | 1 + .../impl/CognitiveComplexityTestRule.java | 19 ++++++++++++++ .../impl/xml/CognitiveComplexityTest.xml | 26 +++++++++++++++++++ .../resources/rulesets/apex/metrics_test.xml | 5 ++++ 4 files changed, 51 insertions(+) create mode 100644 pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityTestRule.java create mode 100644 pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AllMetricsTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AllMetricsTest.java index 4f60d06fa6..f829c0ee65 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AllMetricsTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/AllMetricsTest.java @@ -20,6 +20,7 @@ public class AllMetricsTest extends SimpleAggregatorTst { public void setUp() { addRule(RULESET, "CycloTest"); addRule(RULESET, "WmcTest"); + addRule(RULESET, "CognitiveComplexityTest"); } } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityTestRule.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityTestRule.java new file mode 100644 index 0000000000..c7e9194967 --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityTestRule.java @@ -0,0 +1,19 @@ +package net.sourceforge.pmd.lang.apex.metrics.impl; + +import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey; +import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey; + +/** + * @author Gwilym Kuiper + */ +public class CognitiveComplexityTestRule extends AbstractApexMetricTestRule { + @Override + protected ApexClassMetricKey getClassKey() { + return null; + } + + @Override + protected ApexOperationMetricKey getOpKey() { + return ApexOperationMetricKey.COGNITIVE; + } +} diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml new file mode 100644 index 0000000000..b5a09067e0 --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -0,0 +1,26 @@ + + + + If statements have complexity 1 + 1 + + 'c__Foo#foo(Integer)' has value 1. + + + + + + \ No newline at end of file diff --git a/pmd-apex/src/test/resources/rulesets/apex/metrics_test.xml b/pmd-apex/src/test/resources/rulesets/apex/metrics_test.xml index b9980f7571..cbb1c7324f 100644 --- a/pmd-apex/src/test/resources/rulesets/apex/metrics_test.xml +++ b/pmd-apex/src/test/resources/rulesets/apex/metrics_test.xml @@ -19,4 +19,9 @@ class="net.sourceforge.pmd.lang.apex.metrics.impl.WmcTestRule"> + + + From 38ea3d1be92066783ce139c7ceaa12d0e7b99eb5 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 11:47:40 +0000 Subject: [PATCH 100/235] Implement complexity for `if` --- .../visitors/CognitiveComplexityVisitor.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) 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 76ffa404b1..8787f01187 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 @@ -7,8 +7,22 @@ import net.sourceforge.pmd.lang.apex.ast.*; */ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { public static class State { + private int complexity = 0; + public double getComplexity() { - return 0.0; + return complexity; + } + + void increaseComplexity() { + complexity += 1; } } + + @Override + public Object visit(ASTIfBlockStatement node, Object data) { + State state = (State) data; + state.increaseComplexity(); + super.visit(node, data); + return data; + } } From cea2081628dee5c1cfb9222596efbc30539c48c5 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 11:51:46 +0000 Subject: [PATCH 101/235] Cognitive complexity for nested if statements --- .../visitors/CognitiveComplexityVisitor.java | 22 ++++++++++++++-- .../impl/xml/CognitiveComplexityTest.xml | 25 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) 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 8787f01187..36e59f0668 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 @@ -8,21 +8,39 @@ import net.sourceforge.pmd.lang.apex.ast.*; public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { public static class State { private int complexity = 0; + private int nestingLevel = 0; public double getComplexity() { return complexity; } - void increaseComplexity() { + void structureComplexity() { complexity += 1; } + + void nestingComplexity() { + complexity += nestingLevel; + } + + void increaseNestingLevel() { + nestingLevel++; + } + + void decreaseNestingLevel() { + nestingLevel--; + } } @Override public Object visit(ASTIfBlockStatement node, Object data) { State state = (State) data; - state.increaseComplexity(); + state.structureComplexity(); + state.nestingComplexity(); + + state.increaseNestingLevel(); super.visit(node, data); + state.decreaseNestingLevel(); + return data; } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index b5a09067e0..f1123e76dc 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -23,4 +23,29 @@ ]]> + + + Nested if statements bump complexity level + 1 + + 'c__Foo#foo(Integer)' has value 3. + + + 0) { // +1 + if (n == 1) { // +2 + return "one"; + } + + return "positive"; + } + + return "negative or 0"; + } + } + ]]> + + \ No newline at end of file From 9492ca02c171e52a11814712f4951b1aa404eba9 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 11:53:00 +0000 Subject: [PATCH 102/235] Add test for non-nested if statements --- .../impl/xml/CognitiveComplexityTest.xml | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index f1123e76dc..ae79cff889 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -48,4 +48,31 @@ ]]> + + + Non nested if statements don't incur a penalty + 1 + + 'c__Foo#foo(Integer)' has value 3. + + + 0) { // +1 + return "positive"; + } + + if (n == 0) { // +1 + return "zero"; + } + + if (n < 0) { // +1 + return "negative"; + } + } + } + ]]> + + \ No newline at end of file From 1b93be5f600ac262aae26a79750977eaa8be7a86 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 14:02:56 +0000 Subject: [PATCH 103/235] Handle if-else correctly --- .../visitors/CognitiveComplexityVisitor.java | 20 +++++++++++----- .../impl/xml/CognitiveComplexityTest.xml | 23 +++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) 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 36e59f0668..94a5f8f791 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 @@ -32,14 +32,22 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { } @Override - public Object visit(ASTIfBlockStatement node, Object data) { + public Object visit(ASTIfElseBlockStatement node, Object data) { State state = (State) data; - state.structureComplexity(); - state.nestingComplexity(); - state.increaseNestingLevel(); - super.visit(node, data); - state.decreaseNestingLevel(); + boolean hasElseStatement = node.getNode().hasElseStatement(); + for (ApexNode child : node.children()) { + // If we don't have an else statement, we get an empty block statement which we shouldn't count + if (!hasElseStatement && child instanceof ASTBlockStatement) { + break; + } + + state.structureComplexity(); + state.nestingComplexity(); + state.increaseNestingLevel(); + super.visit(child, data); + state.decreaseNestingLevel(); + } return data; } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index ae79cff889..92cd68dac7 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -75,4 +75,27 @@ ]]> + + + Else-if blocks count as non-nested + 1 + + 'c__Foo#foo(Integer)' has value 3. + + + 0) { // +1 + return "positive"; + } else if (n < 0) { // +1 + return "negative"; + } else { // +1 + return "zero"; + } + } + } + ]]> + + \ No newline at end of file From 50d2bcb7f1ea0df1d8611680e1d419e9fd69194d Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 14:08:05 +0000 Subject: [PATCH 104/235] Cognitive complexity for for loops --- .../visitors/CognitiveComplexityVisitor.java | 13 +++++++++++ .../impl/xml/CognitiveComplexityTest.xml | 23 +++++++++++++++++++ 2 files changed, 36 insertions(+) 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 94a5f8f791..93cc0a06cc 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 @@ -51,4 +51,17 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { return data; } + + @Override + public Object visit(ASTForLoopStatement node, Object data) { + State state = (State) data; + + state.structureComplexity(); + state.nestingComplexity(); + state.increaseNestingLevel(); + super.visit(node, data); + state.decreaseNestingLevel(); + + return data; + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index 92cd68dac7..6f5b8f9bb4 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -98,4 +98,27 @@ ]]> + + + For loops increment nesting + 1 + + 'c__Foo#foo()' has value 3. + + + + + \ No newline at end of file From 7d3a5ef7f4e222e35ed015aad34f6fb22a0e6e2d Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 14:08:44 +0000 Subject: [PATCH 105/235] When increasing nesting level we always get structure and nesting complexity --- .../metrics/impl/visitors/CognitiveComplexityVisitor.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 93cc0a06cc..153b5642e5 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 @@ -23,6 +23,8 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { } void increaseNestingLevel() { + structureComplexity(); + nestingComplexity(); nestingLevel++; } @@ -42,8 +44,6 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { break; } - state.structureComplexity(); - state.nestingComplexity(); state.increaseNestingLevel(); super.visit(child, data); state.decreaseNestingLevel(); @@ -56,8 +56,6 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { public Object visit(ASTForLoopStatement node, Object data) { State state = (State) data; - state.structureComplexity(); - state.nestingComplexity(); state.increaseNestingLevel(); super.visit(node, data); state.decreaseNestingLevel(); From d9e7928d75b7ec00bb3a09adbd2473372b86154b Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 14:10:32 +0000 Subject: [PATCH 106/235] For each statements incur cognitive complexity --- .../visitors/CognitiveComplexityVisitor.java | 11 +++++++++ .../impl/xml/CognitiveComplexityTest.xml | 24 +++++++++++++++++++ 2 files changed, 35 insertions(+) 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 153b5642e5..a0196e678e 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 @@ -62,4 +62,15 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { return data; } + + @Override + public Object visit(ASTForEachStatement node, Object data) { + State state = (State) data; + + state.increaseNestingLevel(); + super.visit(node, data); + state.decreaseNestingLevel(); + + return data; + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index 6f5b8f9bb4..5647e9fd69 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -121,4 +121,28 @@ ]]> + + + Foreach loops increment nesting + 1 + + 'c__Foo#foo()' has value 3. + + + + + \ No newline at end of file From 7d3bb60d8381d7889112bc5e600aacb56e969167 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 14:12:07 +0000 Subject: [PATCH 107/235] Continue statements incur complexity --- .../visitors/CognitiveComplexityVisitor.java | 8 +++++++ .../impl/xml/CognitiveComplexityTest.xml | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+) 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 a0196e678e..efbf832376 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 @@ -73,4 +73,12 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { return data; } + + @Override + public Object visit(ASTContinueStatement node, Object data) { + State state = (State) data; + + state.structureComplexity(); + return super.visit(node, data); + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index 5647e9fd69..740e471273 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -145,4 +145,28 @@ ]]> + + + Continue statements increase complexity + 1 + + 'c__Foo#foo()' has value 4. + + + + + \ No newline at end of file From b2a42bf8ccc9c7c883c666a48b34cef7ae26f3a4 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 14:12:49 +0000 Subject: [PATCH 108/235] Break statements incur complexity --- .../visitors/CognitiveComplexityVisitor.java | 8 +++++++ .../impl/xml/CognitiveComplexityTest.xml | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+) 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 efbf832376..98b8c3701e 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 @@ -81,4 +81,12 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { state.structureComplexity(); return super.visit(node, data); } + + @Override + public Object visit(ASTBreakStatement node, Object data) { + State state = (State) data; + + state.structureComplexity(); + return super.visit(node, data); + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index 740e471273..c4ee8b2c85 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -169,4 +169,28 @@ ]]> + + + Break statements increase complexity + 1 + + 'c__Foo#foo()' has value 4. + + + + + \ No newline at end of file From ec870225f2ecb9797f9f7b726bed6a3c9d761723 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 14:16:19 +0000 Subject: [PATCH 109/235] While statements incur nesting complexity --- .../visitors/CognitiveComplexityVisitor.java | 11 ++++++++ .../impl/xml/CognitiveComplexityTest.xml | 26 +++++++++++++++++++ 2 files changed, 37 insertions(+) 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 98b8c3701e..4e863a16c2 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 @@ -89,4 +89,15 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { state.structureComplexity(); return super.visit(node, data); } + + @Override + public Object visit(ASTWhileLoopStatement node, Object data) { + State state = (State) data; + + state.increaseNestingLevel(); + super.visit(node, data); + state.decreaseNestingLevel(); + + return data; + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index c4ee8b2c85..fc066baef2 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -193,4 +193,30 @@ ]]> + + + While statements increase nesting + 1 + + 'c__Foo#foo()' has value 3. + + + 1000) { // +2 + return "big"; + } + } + + return "small"; + } + } + ]]> + + \ No newline at end of file From 559c1d9c397eafe87e6d54a070db4e6666043397 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 15:19:39 +0000 Subject: [PATCH 110/235] Catch blocks incur nesting complexity --- .../visitors/CognitiveComplexityVisitor.java | 11 ++++++++ .../impl/xml/CognitiveComplexityTest.xml | 27 +++++++++++++++++++ 2 files changed, 38 insertions(+) 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 4e863a16c2..b9b438e820 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 @@ -100,4 +100,15 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { return data; } + + @Override + public Object visit(ASTCatchBlockStatement node, Object data) { + State state = (State) data; + + state.increaseNestingLevel(); + super.visit(node, data); + state.decreaseNestingLevel(); + + return data; + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index fc066baef2..0429260d76 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -219,4 +219,31 @@ ]]> + + + Only the catch statement increases nesting + 1 + + 'c__Foo#foo()' has value 4. + + + + + \ No newline at end of file From 5ea69530d7a65dae5a6173368c01ff9e3e639d74 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 15:40:46 +0000 Subject: [PATCH 111/235] Add do-while loop nesting complexity --- .../visitors/CognitiveComplexityVisitor.java | 11 ++++++++ .../impl/xml/CognitiveComplexityTest.xml | 25 +++++++++++++++++++ 2 files changed, 36 insertions(+) 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 b9b438e820..3ae4d16a94 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 @@ -111,4 +111,15 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { return data; } + + @Override + public Object visit(ASTDoLoopStatement node, Object data) { + State state = (State) data; + + state.increaseNestingLevel(); + super.visit(node, data); + state.decreaseNestingLevel(); + + return data; + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index 0429260d76..2f2410aede 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -246,4 +246,29 @@ ]]> + + + Do-while loops cause nesting + 1 + + 'c__Foo#foo()' has value 5. + + + + + \ No newline at end of file From 4b26d22c73c42a77d53871a217163197a4e80472 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 15:56:08 +0000 Subject: [PATCH 112/235] Ternary operators increase nesting complexity --- .../visitors/CognitiveComplexityVisitor.java | 11 +++++++++++ .../impl/xml/CognitiveComplexityTest.xml | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) 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 3ae4d16a94..03b1b5bb4c 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 @@ -122,4 +122,15 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { return data; } + + @Override + public Object visit(ASTTernaryExpression node, Object data) { + State state = (State) data; + + state.increaseNestingLevel(); + super.visit(node, data); + state.decreaseNestingLevel(); + + return data; + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index 2f2410aede..300c7d1450 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -271,4 +271,23 @@ ]]> + + + Ternary operators cause nesting + 1 + + 'c__Foo#foo(Integer)' has value 3. + + + 0 ? // +2 + 1 : 0; + } + } + ]]> + + \ No newline at end of file From a4db0ea069f513fd5671aa6897e31025397400ea Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 16:32:28 +0000 Subject: [PATCH 113/235] Any boolean expression causes increases in cognative complexity --- .../visitors/CognitiveComplexityVisitor.java | 37 ++++++++++++++++ .../impl/xml/CognitiveComplexityTest.xml | 42 +++++++++++++++++++ 2 files changed, 79 insertions(+) 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 03b1b5bb4c..de14a62040 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 @@ -1,5 +1,7 @@ package net.sourceforge.pmd.lang.apex.metrics.impl.visitors; +import apex.jorje.data.ast.BooleanOp; +import apex.jorje.data.ast.PrefixOp; import net.sourceforge.pmd.lang.apex.ast.*; /** @@ -9,6 +11,7 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { public static class State { private int complexity = 0; private int nestingLevel = 0; + private BooleanOp currentBooleanOperation = null; public double getComplexity() { return complexity; @@ -22,6 +25,16 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { complexity += nestingLevel; } + void booleanOperation(BooleanOp op) { + if (currentBooleanOperation != op) { + if (op != null) { + structureComplexity(); + } + + currentBooleanOperation = op; + } + } + void increaseNestingLevel() { structureComplexity(); nestingComplexity(); @@ -133,4 +146,28 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { return data; } + + @Override + public Object visit(ASTBooleanExpression node, Object data) { + State state = (State) data; + + BooleanOp op = node.getNode().getOp(); + if (op == BooleanOp.AND || op == BooleanOp.OR) { + state.booleanOperation(op); + } + + return super.visit(node, data); + } + + @Override + public Object visit(ASTPrefixExpression node, Object data) { + State state = (State) data; + + PrefixOp op = node.getNode().getOp(); + if (op == PrefixOp.NOT) { + state.booleanOperation(null); + } + + return super.visit(node, data); + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index 300c7d1450..5784716ff1 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -290,4 +290,46 @@ ]]> + + + Boolean operators + 5 + + 'c__Foo#a(Integer)' has value 1. + 'c__Foo#b(Integer)' has value 1. + 'c__Foo#c(Integer)' has value 1. + 'c__Foo#d(Boolean,Boolean,Boolean,Boolean,Boolean,Boolean)' has value 3. + 'c__Foo#e(Boolean,Boolean,Boolean)' has value 2. + + + 0 && n > 1; // +1 + } + + Boolean b(Integer n) { + return n > 0 && n > 1 && n > 2; // +1 + } + + Boolean c(Integer n) { + return n > 0 || n < 0; // +1 + } + + Boolean d(Boolean a, Boolean b, Boolean c, Boolean d, Boolean e, Boolean f) { + return (a + && b && c) // +1 + || (d || e) // +1 + && f; // +1 + } + + Boolean e(Boolean a, Boolean b, Boolean c) { + return a + && // +1 + !(b && c); // +1 + } + } + ]]> + + \ No newline at end of file From 0231350dea7b8235a9309b24d15088ab59eea09f Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 16:59:12 +0000 Subject: [PATCH 114/235] Handle boolean expressions on different statements --- .../impl/visitors/CognitiveComplexityVisitor.java | 15 +++++++++++++++ .../metrics/impl/xml/CognitiveComplexityTest.xml | 8 +++++++- 2 files changed, 22 insertions(+), 1 deletion(-) 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 de14a62040..00dbf63f62 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 @@ -170,4 +170,19 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { return super.visit(node, data); } + + @Override + public Object visit(ASTBlockStatement node, Object data) { + State state = (State) data; + + for (ApexNode child : node.children()) { + child.jjtAccept(this, data); + + // This needs to happen because the current 'run' of boolean operations is terminated + // once we finish a statement. + state.booleanOperation(null); + } + + return data; + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index 5784716ff1..ef225a7c0f 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -293,13 +293,14 @@ Boolean operators - 5 + 6 'c__Foo#a(Integer)' has value 1. 'c__Foo#b(Integer)' has value 1. 'c__Foo#c(Integer)' has value 1. 'c__Foo#d(Boolean,Boolean,Boolean,Boolean,Boolean,Boolean)' has value 3. 'c__Foo#e(Boolean,Boolean,Boolean)' has value 2. + 'c__Foo#f()' has value 2. From 9d0fb82d6f5f66cec01b6c3537fe9e78da3cc678 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 17:06:18 +0000 Subject: [PATCH 115/235] Increase cognitive complexity on recursion --- .../visitors/CognitiveComplexityVisitor.java | 26 +++++++++++++++++++ .../impl/xml/CognitiveComplexityTest.xml | 21 +++++++++++++++ 2 files changed, 47 insertions(+) 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 00dbf63f62..afb412874e 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 @@ -11,7 +11,9 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { public static class State { private int complexity = 0; private int nestingLevel = 0; + private BooleanOp currentBooleanOperation = null; + private String methodName = null; public double getComplexity() { return complexity; @@ -44,6 +46,16 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { void decreaseNestingLevel() { nestingLevel--; } + + void methodCall(String methodCalledName) { + if (methodCalledName.equals(methodName)) { + structureComplexity(); + } + } + + void setMethodName(String name) { + methodName = name; + } } @Override @@ -185,4 +197,18 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { return data; } + + @Override + public Object visit(ASTMethod node, Object data) { + State state = (State) data; + state.setMethodName(node.getNode().getMethodInfo().getCanonicalName()); + return super.visit(node, data); + } + + @Override + public Object visit(ASTMethodCallExpression node, Object data) { + State state = (State) data; + state.methodCall(node.getNode().getMethodName()); + return super.visit(node, data); + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index ef225a7c0f..6b0df4594c 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -338,4 +338,25 @@ ]]> + + + Recursion bumps complexity value + 1 + + 'c__Foo#foo(Integer)' has value 3. + + + + + \ No newline at end of file From acfbb132d199fef8e40cdbaedd1ea4e00dd857b4 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 17:07:22 +0000 Subject: [PATCH 116/235] We don't actually support switch statements yet --- .../main/resources/category/apex/design.xml | 43 +------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/pmd-apex/src/main/resources/category/apex/design.xml b/pmd-apex/src/main/resources/category/apex/design.xml index cbd40a4866..5ae4b0fb32 100644 --- a/pmd-apex/src/main/resources/category/apex/design.xml +++ b/pmd-apex/src/main/resources/category/apex/design.xml @@ -97,48 +97,7 @@ public class Complicated { 3 From 5d55b84f96e93f92e139827cb4db4b7def581cb5 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 17:24:40 +0000 Subject: [PATCH 117/235] Fix checkstyle errors --- .../impl/ClassCognitiveComplexityMetric.java | 4 +++ .../impl/CognitiveComplexityMetric.java | 4 +++ .../visitors/CognitiveComplexityVisitor.java | 22 ++++++++++++- .../rule/design/CognitiveComplexityRule.java | 32 ++++++++++++------- .../impl/CognitiveComplexityTestRule.java | 4 +++ 5 files changed, 53 insertions(+), 13 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/ClassCognitiveComplexityMetric.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/ClassCognitiveComplexityMetric.java index 6adfdc7538..90e0527c14 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/ClassCognitiveComplexityMetric.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/impl/ClassCognitiveComplexityMetric.java @@ -1,3 +1,7 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + package net.sourceforge.pmd.lang.apex.metrics.impl; import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface; 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 90eeadf8ed..740bfd29bb 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 @@ -1,3 +1,7 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + package net.sourceforge.pmd.lang.apex.metrics.impl; import net.sourceforge.pmd.lang.apex.ast.ASTMethod; 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 afb412874e..8cdcddcb55 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 @@ -1,8 +1,28 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + package net.sourceforge.pmd.lang.apex.metrics.impl.visitors; +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.ASTCatchBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTContinueStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTDoLoopStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTForEachStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTForLoopStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTIfElseBlockStatement; +import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.ast.ASTMethodCallExpression; +import net.sourceforge.pmd.lang.apex.ast.ASTPrefixExpression; +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 apex.jorje.data.ast.BooleanOp; import apex.jorje.data.ast.PrefixOp; -import net.sourceforge.pmd.lang.apex.ast.*; /** * @author Gwilym Kuiper diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java index dfc8ddee79..96c392aa2a 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java @@ -1,5 +1,13 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + package net.sourceforge.pmd.lang.apex.rule.design; +import static net.sourceforge.pmd.properties.constraints.NumericConstraints.positive; + +import java.util.Stack; + import net.sourceforge.pmd.lang.apex.ast.ASTMethod; import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; import net.sourceforge.pmd.lang.apex.ast.ASTUserTrigger; @@ -12,10 +20,6 @@ import net.sourceforge.pmd.lang.metrics.ResultOption; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; -import java.util.Stack; - -import static net.sourceforge.pmd.properties.constraints.NumericConstraints.positive; - public class CognitiveComplexityRule extends AbstractApexRule { private static final PropertyDescriptor CLASS_LEVEL_DESCRIPTOR @@ -64,10 +68,12 @@ public class CognitiveComplexityRule extends AbstractApexRule { if (classCognitive >= getProperty(CLASS_LEVEL_DESCRIPTOR)) { int classHighest = (int) ApexMetrics.get(ApexOperationMetricKey.COGNITIVE, node, ResultOption.HIGHEST); - String[] messageParams = {"class", - node.getImage(), - " total", - classCognitive + " (highest " + classHighest + ")", }; + String[] messageParams = { + "class", + node.getImage(), + " total", + classCognitive + " (highest " + classHighest + ")", + }; addViolation(data, node, messageParams); } @@ -86,10 +92,12 @@ public class CognitiveComplexityRule extends AbstractApexRule { : node.getImage().equals(classNames.peek()) ? "constructor" : "method"; - addViolation(data, node, new String[] {opType, - node.getQualifiedName().getOperation(), - "", - "" + cognitive, }); + addViolation(data, node, new String[] { + opType, + node.getQualifiedName().getOperation(), + "", + "" + cognitive, + }); } } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityTestRule.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityTestRule.java index c7e9194967..5bb127e5e7 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityTestRule.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/metrics/impl/CognitiveComplexityTestRule.java @@ -1,3 +1,7 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + package net.sourceforge.pmd.lang.apex.metrics.impl; import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey; From de878175c8bc42d98872883e84c2598fd80b05c7 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 18 Feb 2020 17:29:37 +0000 Subject: [PATCH 118/235] Use correct message for cognitive complexity rule --- pmd-apex/src/main/resources/category/apex/design.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-apex/src/main/resources/category/apex/design.xml b/pmd-apex/src/main/resources/category/apex/design.xml index 5ae4b0fb32..6adf25f389 100644 --- a/pmd-apex/src/main/resources/category/apex/design.xml +++ b/pmd-apex/src/main/resources/category/apex/design.xml @@ -87,7 +87,7 @@ public class Complicated { From b06772b95322202f33b3e7e64b58078fdff989c3 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Tue, 18 Feb 2020 18:54:47 +0100 Subject: [PATCH 119/235] Update rulesets * add comment for removed rules in the releases rulesets * remove rules completely in normal rulesets (instead of commenting) --- pmd-apex/src/main/resources/rulesets/apex/style.xml | 1 - pmd-core/src/main/resources/rulesets/releases/34.xml | 2 +- pmd-core/src/main/resources/rulesets/releases/36.xml | 2 +- pmd-core/src/main/resources/rulesets/releases/41.xml | 2 +- pmd-core/src/main/resources/rulesets/releases/50.xml | 2 +- pmd-core/src/main/resources/rulesets/releases/512.xml | 4 ++-- pmd-core/src/main/resources/rulesets/releases/550.xml | 2 +- pmd-java/src/main/resources/rulesets/java/design.xml | 1 - 8 files changed, 7 insertions(+), 9 deletions(-) diff --git a/pmd-apex/src/main/resources/rulesets/apex/style.xml b/pmd-apex/src/main/resources/rulesets/apex/style.xml index 0e20621929..7064578fca 100644 --- a/pmd-apex/src/main/resources/rulesets/apex/style.xml +++ b/pmd-apex/src/main/resources/rulesets/apex/style.xml @@ -10,7 +10,6 @@ The Style Ruleset contains rules regarding preferred usage of names and identifi - diff --git a/pmd-core/src/main/resources/rulesets/releases/34.xml b/pmd-core/src/main/resources/rulesets/releases/34.xml index 6bd6183f19..a3328515ae 100644 --- a/pmd-core/src/main/resources/rulesets/releases/34.xml +++ b/pmd-core/src/main/resources/rulesets/releases/34.xml @@ -17,7 +17,7 @@ This ruleset contains links to rules that are new in PMD v3.4 - + diff --git a/pmd-core/src/main/resources/rulesets/releases/36.xml b/pmd-core/src/main/resources/rulesets/releases/36.xml index f83d3c8791..16a32f41f4 100644 --- a/pmd-core/src/main/resources/rulesets/releases/36.xml +++ b/pmd-core/src/main/resources/rulesets/releases/36.xml @@ -9,7 +9,7 @@ This ruleset contains links to rules that are new in PMD v3.6 - + diff --git a/pmd-core/src/main/resources/rulesets/releases/41.xml b/pmd-core/src/main/resources/rulesets/releases/41.xml index b6819f114c..50a9b1277b 100644 --- a/pmd-core/src/main/resources/rulesets/releases/41.xml +++ b/pmd-core/src/main/resources/rulesets/releases/41.xml @@ -11,7 +11,7 @@ This ruleset contains links to rules that are new in PMD v4.1 - + diff --git a/pmd-core/src/main/resources/rulesets/releases/50.xml b/pmd-core/src/main/resources/rulesets/releases/50.xml index e98718a9a2..d612ceac00 100644 --- a/pmd-core/src/main/resources/rulesets/releases/50.xml +++ b/pmd-core/src/main/resources/rulesets/releases/50.xml @@ -25,7 +25,7 @@ This ruleset contains links to rules that are new in PMD v5.0 - + diff --git a/pmd-core/src/main/resources/rulesets/releases/512.xml b/pmd-core/src/main/resources/rulesets/releases/512.xml index ca15347b4b..234204bbf4 100644 --- a/pmd-core/src/main/resources/rulesets/releases/512.xml +++ b/pmd-core/src/main/resources/rulesets/releases/512.xml @@ -8,8 +8,8 @@ This ruleset contains links to rules that are new in PMD v5.1.2 - - + + diff --git a/pmd-core/src/main/resources/rulesets/releases/550.xml b/pmd-core/src/main/resources/rulesets/releases/550.xml index a3df927ec1..5fb17c056b 100644 --- a/pmd-core/src/main/resources/rulesets/releases/550.xml +++ b/pmd-core/src/main/resources/rulesets/releases/550.xml @@ -22,7 +22,7 @@ This ruleset contains links to rules that are new in PMD v5.5.0 - + diff --git a/pmd-java/src/main/resources/rulesets/java/design.xml b/pmd-java/src/main/resources/rulesets/java/design.xml index 8e1b2de0f9..bef304b2e6 100644 --- a/pmd-java/src/main/resources/rulesets/java/design.xml +++ b/pmd-java/src/main/resources/rulesets/java/design.xml @@ -54,7 +54,6 @@ are suggested. - From 3ad6b06d21527a7cea5b67cca9a8c6db39ed2d99 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Tue, 18 Feb 2020 20:09:28 +0100 Subject: [PATCH 120/235] [doc] List the removed rules in 7.0.0 release notes --- docs/pages/7_0_0_release_notes.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/pages/7_0_0_release_notes.md b/docs/pages/7_0_0_release_notes.md index b044ecaa4d..65b93c1696 100644 --- a/docs/pages/7_0_0_release_notes.md +++ b/docs/pages/7_0_0_release_notes.md @@ -40,6 +40,26 @@ 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. +#### Removed Rules + +The following previously deprecated rules have been finally removed: + +* AbstractNaming (java-codestyle) +* AvoidFinalLocalVariable (java-codestyle) +* AvoidPrefixingMethodParameters (java-codestyle) +* ForLoopsMustUseBraces (java-codestyle) +* IfElseStmtsMustUseBraces (java-codestyle) +* IfStmtsMustUseBraces (java-codestyle) +* LoggerIsNotStaticFinal (java-errorprone) +* MIsLeadingVariableName (java-codestyle) +* ModifiedCyclomaticComplexity (java-design) +* StdCyclomaticComplexity (java-design) +* SuspiciousConstantFieldName (java-codestyle) +* UnsynchronizedStaticDateFormatter (java-multithreading) +* VariableNamingConventions (apex-codestyle) +* VariableNamingConventions (java-codestyle) +* WhileLoopsMustUseBraces (java-codestyle) + ### Fixed Issues ### API Changes From a22d6f62b470d64eb0448db653e99053ff5e818e Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Wed, 19 Feb 2020 10:24:40 +0000 Subject: [PATCH 121/235] Optimistically say that cognitive complexity is in the next release --- pmd-apex/src/main/resources/category/apex/design.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-apex/src/main/resources/category/apex/design.xml b/pmd-apex/src/main/resources/category/apex/design.xml index 6adf25f389..14178cbab1 100644 --- a/pmd-apex/src/main/resources/category/apex/design.xml +++ b/pmd-apex/src/main/resources/category/apex/design.xml @@ -88,7 +88,7 @@ public class Complicated { From 413d64ff39a5e074b6bca7e1af57527c87a45b0f Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Wed, 19 Feb 2020 14:22:30 +0000 Subject: [PATCH 122/235] Increase default values for cognitive complexity based on authors opinions --- .../pmd/lang/apex/rule/design/CognitiveComplexityRule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java index 96c392aa2a..319afdd529 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/design/CognitiveComplexityRule.java @@ -26,14 +26,14 @@ public class CognitiveComplexityRule extends AbstractApexRule { = PropertyFactory.intProperty("classReportLevel") .desc("Total class cognitive complexity reporting threshold") .require(positive()) - .defaultValue(40) + .defaultValue(50) .build(); private static final PropertyDescriptor METHOD_LEVEL_DESCRIPTOR = PropertyFactory.intProperty("methodReportLevel") .desc("Cognitive complexity reporting threshold") .require(positive()) - .defaultValue(10) + .defaultValue(15) .build(); private Stack classNames = new Stack<>(); From 68e4f52da1f6330881e2d860bbb400f96e7fe9e6 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Wed, 19 Feb 2020 16:28:02 +0000 Subject: [PATCH 123/235] Fill in TODO in documentation for coginitive complexity --- .../main/resources/category/apex/design.xml | 47 ++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/pmd-apex/src/main/resources/category/apex/design.xml b/pmd-apex/src/main/resources/category/apex/design.xml index 14178cbab1..ffac0783e4 100644 --- a/pmd-apex/src/main/resources/category/apex/design.xml +++ b/pmd-apex/src/main/resources/category/apex/design.xml @@ -92,12 +92,55 @@ public class Complicated { class="net.sourceforge.pmd.lang.apex.rule.design.CognitiveComplexityRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_design.html#cognitivecomplexity"> - TODO +Methods that are highly complex are difficult to read and more costly to maintain. If you include too much decisional +logic within a single method, you make its behavior hard to understand and more difficult to modify. + +Cognitive complexity is a measure of how difficult it is for humans to read and understand a method. Code that contains +a break in the control flow is more complex, whereas the use of language shorthands doesn't increase the level of +complexity. Nested control flows can make a method more difficult to understand, with each additional nesting of the +control flow leading to an increase in cognitive complexity. + +Information about Cognitive complexity can be found in the original paper here: +https://www.sonarsource.com/docs/CognitiveComplexity.pdf + +By default, this rule reports methods with a complexity of 15 or more. Reported methods should be broken down into less +complex components. 3 contacts) { + List contactsToUpdate = new List(); + + for (Contact contact : contacts) { // +1 + if (contact.Department == 'Finance') { // +2 + contact.Title = 'Finance Specialist'; + contactsToUpdate.add(contact); + } else if (contact.Department == 'Sales') { // +2 + contact.Title = 'Sales Specialist'; + contactsToUpdate.add(contact); + } + } + + update contactsToUpdate; + } +} ]]> From 59e4be3648c77892ad08c186df40eca37ee27a5f Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 20 Feb 2020 11:29:10 +0100 Subject: [PATCH 124/235] Update gitignore files generated by eclipse m2e plugin and pmd plugin --- .gitignore | 1 + pmd-core/.gitignore | 1 + pmd-java/.gitignore | 1 + pmd-test/.gitignore | 1 + pmd-vm/.gitignore | 1 + pmd-xml/.gitignore | 1 + 6 files changed, 6 insertions(+) create mode 100644 pmd-core/.gitignore create mode 100644 pmd-java/.gitignore create mode 100644 pmd-test/.gitignore create mode 100644 pmd-vm/.gitignore create mode 100644 pmd-xml/.gitignore diff --git a/.gitignore b/.gitignore index 5bf49d2cb2..3c33657fab 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ bin/ .classpath .checkstyle .pmd +.pmdruleset.xml .ruleset .settings/ *.iml diff --git a/pmd-core/.gitignore b/pmd-core/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/pmd-core/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/pmd-java/.gitignore b/pmd-java/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/pmd-java/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/pmd-test/.gitignore b/pmd-test/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/pmd-test/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/pmd-vm/.gitignore b/pmd-vm/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/pmd-vm/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/pmd-xml/.gitignore b/pmd-xml/.gitignore new file mode 100644 index 0000000000..b83d22266a --- /dev/null +++ b/pmd-xml/.gitignore @@ -0,0 +1 @@ +/target/ From 174bdd6b0db4ddd5a6b1e9de915e092657b0141d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 20 Feb 2020 12:17:07 +0100 Subject: [PATCH 125/235] [java] UselessOverridingMethod - remove unnecessary CDATA in tests --- .../design/xml/UselessOverridingMethod.xml | 216 ++++++++---------- 1 file changed, 90 insertions(+), 126 deletions(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml index b242777cda..9ff99b3289 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml @@ -3,10 +3,9 @@ xmlns="http://pmd.sourceforge.net/rule-tests" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + - + call super 1 + - + call super with same argument 1 + - + call super with different argument 0 + - + call super with different argument 2 0 + - + call super with different argument 3 0 + - + call super with inverted arguments 0 + - + return value of super 1 + - + return value of super with argument 1 + - + return value of super after adding a string 0 + - + do not crash on abstract methods 0 + - + do not crash on interfaces 0 + - + do not crash on empty returns 0 + - + do not crash on super 0 + - + call super with different argument 4 0 + - + adding final is OK 0 + - + adding synchronized is OK 0 + - + Constructors are OK 0 + - + Should ignore clone implementation ( see bug 1522517) 0 + - + clone method with arguments should not be ignored 1 + - - - + False +: Overriding method merely calls super (see bug 1415525) 0 - - + - - - + [ 1977230 ] false positive: UselessOverridingMethod 0 - - - - - + + + [ 2142986 ] UselessOverridingMethod doesn't consider annotations, ignoreAnnotations property set to true true 1 - - - - - + + + [ 2142986 ] UselessOverridingMethod doesn't consider annotations 0 - - - - - + + + [ 2142986 ] UselessOverridingMethod doesn't consider annotations, @Override only 1 - + - + ClassCastException in statement cast 0 comparator = new Comparator() { + public void method() { + @SuppressWarnings("unused") + final Comparator comparator = new Comparator() { - @Override - public int compare(@Nonnull Long o1, @Nonnull Long o2) { - return 0; - } - }; - } + @Override + public int compare(@Nonnull Long o1, @Nonnull Long o2) { + return 0; + } + }; + } } ]]> From 1a50010dfae8db32559f425ae0b3633f713a4592 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 20 Feb 2020 15:15:10 +0100 Subject: [PATCH 126/235] [java] UselessOverridingMethod false positive when elevating access modifier Fixes #911 --- docs/pages/release_notes.md | 2 + .../design/UselessOverridingMethodRule.java | 53 +++++++- .../uselessoverridingmethod/BaseClass.java | 16 +++ .../DirectSubclass.java | 20 +++ .../DirectSubclass2.java | 12 ++ .../ExposingSerializer.java | 31 +++++ .../OtherSubclass.java | 8 ++ .../uselessoverridingmethod/Serializer.java | 20 +++ .../TransitiveSubclass.java | 13 ++ .../design/xml/UselessOverridingMethod.xml | 117 ++++++++++++++---- 10 files changed, 260 insertions(+), 32 deletions(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/BaseClass.java create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass.java create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass2.java create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/ExposingSerializer.java create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/OtherSubclass.java create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/Serializer.java create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 834c546dfa..792ea4fe1c 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -34,6 +34,8 @@ the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs * [#2268](https://github.com/pmd/pmd/issues/2268): \[java] Improve TypeHelper resilience * java-bestpractices * [#2277](https://github.com/pmd/pmd/issues/2277): \[java] FP in UnusedImports for ambiguous static on-demand imports +* java-design + * [#911](https://github.com/pmd/pmd/issues/911): \[java] UselessOverridingMethod false positive when elevating access modifier * java-errorprone * [#2250](https://github.com/pmd/pmd/issues/2250): \[java] InvalidLogMessageFormat flags logging calls using a slf4j-Marker * [#2255](https://github.com/pmd/pmd/issues/2255): \[java] InvalidLogMessageFormat false-positive for a lambda argument diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java index fd5b262987..f07afb226b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.java.rule.design; import static net.sourceforge.pmd.properties.PropertyFactory.booleanProperty; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @@ -191,9 +192,7 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { } } - if (arguments.getNumChildren() == 0) { - addViolation(data, node, getMessage()); - } else { + if (arguments.size() > 0) { ASTArgumentList argumentList = (ASTArgumentList) arguments.getChild(0); for (int i = 0; i < argumentList.getNumChildren(); i++) { Node expressionChild = argumentList.getChild(i).getChild(0); @@ -226,14 +225,56 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { // The arguments are not simply passed through return super.visit(node, data); } - } - // All arguments are passed through directly - addViolation(data, node, getMessage()); } + + if (modifiersChanged(node)) { + return super.visit(node, data); + } + + // All arguments are passed through directly or there were no arguments + addViolation(data, node, getMessage()); + return super.visit(node, data); } + private boolean modifiersChanged(ASTMethodDeclaration node) { + Class type = node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class).getType(); + if (type == null) { + return false; + } + + String overriddenMethodName = node.getName(); + int overriddenModifiers = node.getModifiers(); + + List> typeArguments = new ArrayList<>(); + for (ASTFormalParameter parameter : node.getFormalParameters()) { + Class parameterType = parameter.getType(); + if (parameterType != null) { + typeArguments.add(parameterType); + } + } + + // did we have for each parameter the type? + if (typeArguments.size() != node.getFormalParameters().size()) { + return false; + } + + // search method with same name up the hierarchy + Class[] typeArgumentArray = typeArguments.toArray(new Class[0]); + Class superType = type.getSuperclass(); + Method declaredMethod = null; + while (superType != null && declaredMethod == null) { + try { + declaredMethod = superType.getDeclaredMethod(overriddenMethodName, typeArgumentArray); + } catch (NoSuchMethodException | SecurityException e) { + declaredMethod = null; + } + superType = superType.getSuperclass(); + } + return declaredMethod != null && overriddenModifiers != declaredMethod.getModifiers(); + } + public List findFirstDegreeChildrenOfType(Node n, Class targetType) { List l = new ArrayList<>(); lclFindChildrenOfType(n, targetType, l); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/BaseClass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/BaseClass.java new file mode 100644 index 0000000000..61c3799caa --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/BaseClass.java @@ -0,0 +1,16 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod; + +public class BaseClass { + + + protected void doBase() { + } + + + protected void doBaseWithArg(String foo) { + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass.java new file mode 100644 index 0000000000..ed73905e7b --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass.java @@ -0,0 +1,20 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod; + +public class DirectSubclass extends BaseClass { + + + @Override + public void doBase() { + super.doBase(); + } + + + @Override + public void doBaseWithArg(String foo) { + super.doBaseWithArg(foo); + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass2.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass2.java new file mode 100644 index 0000000000..4a282aeba7 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSubclass2.java @@ -0,0 +1,12 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod; + +public class DirectSubclass2 extends DirectSubclass { + @Override + public void doBase() { + super.doBase(); + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/ExposingSerializer.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/ExposingSerializer.java new file mode 100644 index 0000000000..6d7de02b26 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/ExposingSerializer.java @@ -0,0 +1,31 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import org.w3c.dom.Node; + +class ExposingSerializer extends Serializer { + + + ExposingSerializer(OutputStream out, String encoding) throws UnsupportedEncodingException { + super(out, encoding); + } + + + /** + * Overriding in order to change the access modifier from protected to public - so: not only merely calling super. + * + *

Method signature in super class: protected void writeChild(nu.xom.Node arg0) throws java.io.IOException; + * + *

See: https://sourceforge.net/tracker/?func=detail&aid=1415525&group_id=56262&atid=479921 + */ + public void writeChild(Node node) throws IOException { + super.writeChild(node); + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/OtherSubclass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/OtherSubclass.java new file mode 100644 index 0000000000..4f8c9d23c6 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/OtherSubclass.java @@ -0,0 +1,8 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod; + +public class OtherSubclass extends BaseClass { +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/Serializer.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/Serializer.java new file mode 100644 index 0000000000..614b8940d9 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/Serializer.java @@ -0,0 +1,20 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod; + +import java.io.IOException; +import java.io.OutputStream; + +import org.w3c.dom.Node; + +public class Serializer { + + public Serializer(OutputStream out, String encoding) { + } + + protected void writeChild(Node node) throws IOException { + } + +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java new file mode 100644 index 0000000000..d9c8465c4e --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java @@ -0,0 +1,13 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod; + +public class TransitiveSubclass extends OtherSubclass { + + @Override + protected void doBase() { + super.doBase(); + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml index 9ff99b3289..f5dac830bc 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml @@ -229,43 +229,36 @@ public class Foo extends Bar { ]]> - + False +: Overriding method merely calls super (see bug 1415525) 0 Method signature in super class: protected void writeChild(nu.xom.Node arg0) throws java.io.IOException; + * + *

See: https://sourceforge.net/tracker/?func=detail&aid=1415525&group_id=56262&atid=479921 + */ public void writeChild(Node node) throws IOException { super.writeChild(node); } - - public void exposedWriteRaw(String text) throws IOException { - writeRaw(text); - } - - public void exposedWriteEscaped(String text) throws IOException { - writeEscaped(text); - } - - public void exposedWriteAttributeValue(String text) throws IOException { - writeAttributeValue(text); - } } ]]> @@ -364,4 +357,76 @@ public class AnonymousClassConstructor { } ]]> + + + [java] UselessOverridingMethod false positive when elevating access modifier #911 - direct + 0 + + + + + [java] UselessOverridingMethod false positive when elevating access modifier #911 - direct but changing arguments + 0 + + + + + [java] UselessOverridingMethod false positive when elevating access modifier #911 - transitive + 0 + + + + + [java] UselessOverridingMethod false positive when elevating access modifier #911 - direct2 + 1 + 5 + + \ No newline at end of file From f0f06b8d840de9e59506aef6b1ffe0ddcb7ca5a1 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 20 Feb 2020 15:47:53 +0100 Subject: [PATCH 127/235] [java] Refactor/simplify UselessOverridingMethod --- .../design/UselessOverridingMethodRule.java | 130 +++++++----------- 1 file changed, 47 insertions(+), 83 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java index f07afb226b..b9f5f4de80 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java @@ -17,12 +17,10 @@ import net.sourceforge.pmd.lang.java.ast.ASTArguments; import net.sourceforge.pmd.lang.java.ast.ASTBlock; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTNameList; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; @@ -30,6 +28,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.ast.ASTResultType; import net.sourceforge.pmd.lang.java.ast.ASTStatement; +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.properties.PropertyDescriptor; @@ -40,31 +39,19 @@ import net.sourceforge.pmd.properties.PropertyDescriptor; * UselessOverridingMethod */ public class UselessOverridingMethodRule extends AbstractJavaRule { - private final List exceptions; - private boolean ignoreAnnotations; - private static final String CLONE = "clone"; - private static final String OBJECT = "Object"; + private static final String CLONE_METHOD_NAME = "clone"; - // TODO extend AbstractIgnoredAnnotationsRule node + // TODO extend AbstractIgnoredAnnotationRule node // TODO ignore if there is javadoc - private static final PropertyDescriptor IGNORE_ANNOTATIONS_DESCRIPTOR = booleanProperty("ignoreAnnotations").defaultValue(false).desc("Ignore annotations").build(); + private static final PropertyDescriptor IGNORE_ANNOTATIONS_DESCRIPTOR = + booleanProperty("ignoreAnnotations") + .defaultValue(false) + .desc("Ignore annotations") + .build(); public UselessOverridingMethodRule() { definePropertyDescriptor(IGNORE_ANNOTATIONS_DESCRIPTOR); - - exceptions = new ArrayList<>(1); - exceptions.add("CloneNotSupportedException"); - } - - @Override - public Object visit(ASTCompilationUnit node, Object data) { - init(); - return super.visit(node, data); - } - - private void init() { - ignoreAnnotations = getProperty(IGNORE_ANNOTATIONS_DESCRIPTOR); } @Override @@ -76,35 +63,27 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { } // TODO: this method should be externalize into an utility class, shouldn't it ? - private boolean isMethodType(ASTMethodDeclaration node, String methodType) { - boolean result = false; + private boolean isMethodResultType(ASTMethodDeclaration node, Class resultType) { ASTResultType type = node.getResultType(); - if (type != null) { - result = type.hasDescendantMatchingXPath( - "./Type/ReferenceType/ClassOrInterfaceType[@Image = '" + methodType + "']"); + if (type != null && type.getChild(0) instanceof ASTType) { + Class resolvedResultType = ((ASTType) type.getChild(0)).getType(); + return resultType.equals(resolvedResultType); } - return result; + return false; } // TODO: this method should be externalize into an utility class, shouldn't it ? - private boolean isMethodThrowingType(ASTMethodDeclaration node, List exceptedExceptions) { - boolean result = false; - ASTNameList thrownsExceptions = node.getFirstChildOfType(ASTNameList.class); + private boolean isMethodThrowingType(ASTMethodDeclaration node, Class exceptionType) { + ASTNameList thrownsExceptions = node.getThrows(); if (thrownsExceptions != null) { List names = thrownsExceptions.findChildrenOfType(ASTName.class); for (ASTName name : names) { - for (String exceptedException : exceptedExceptions) { - if (exceptedException.equals(name.getImage())) { - result = true; - } + if (name.getType() != null && name.getType() == exceptionType) { + return true; } } } - return result; - } - - private boolean hasArguments(ASTMethodDeclaration node) { - return node.hasDescendantMatchingXPath("./MethodDeclarator/FormalParameters/*"); + return false; } @Override @@ -118,8 +97,7 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { // We can also skip the 'clone' method as they are generally // 'useless' but as it is considered a 'good practice' to // implement them anyway ( see bug 1522517) - if (CLONE.equals(node.getName()) && node.isPublic() && !this.hasArguments(node) - && this.isMethodType(node, OBJECT) && this.isMethodThrowingType(node, exceptions)) { + if (isCloneMethod(node)) { return super.visit(node, data); } @@ -142,41 +120,38 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { if (statementGrandChild instanceof ASTPrimaryExpression) { primaryExpression = (ASTPrimaryExpression) statementGrandChild; } else { - List primaryExpressions = findFirstDegreeChildrenOfType(statementGrandChild, - ASTPrimaryExpression.class); + List primaryExpressions = statementGrandChild + .findChildrenOfType(ASTPrimaryExpression.class); if (primaryExpressions.size() != 1) { return super.visit(node, data); } primaryExpression = primaryExpressions.get(0); } - ASTPrimaryPrefix primaryPrefix = findFirstDegreeChildrenOfType(primaryExpression, ASTPrimaryPrefix.class) - .get(0); + ASTPrimaryPrefix primaryPrefix = primaryExpression.getFirstChildOfType(ASTPrimaryPrefix.class); if (!primaryPrefix.usesSuperModifier()) { return super.visit(node, data); } - List primarySuffixList = findFirstDegreeChildrenOfType(primaryExpression, - ASTPrimarySuffix.class); + List primarySuffixList = primaryExpression.findChildrenOfType(ASTPrimarySuffix.class); if (primarySuffixList.size() != 2) { // extra method call on result of super method return super.visit(node, data); } - ASTMethodDeclarator methodDeclarator = findFirstDegreeChildrenOfType(node, ASTMethodDeclarator.class).get(0); ASTPrimarySuffix primarySuffix = primarySuffixList.get(0); - if (!primarySuffix.hasImageEqualTo(methodDeclarator.getImage())) { + if (!primarySuffix.hasImageEqualTo(node.getName())) { return super.visit(node, data); } // Process arguments primarySuffix = primarySuffixList.get(1); ASTArguments arguments = (ASTArguments) primarySuffix.getChild(0); - ASTFormalParameters formalParameters = (ASTFormalParameters) methodDeclarator.getChild(0); + ASTFormalParameters formalParameters = node.getFormalParameters(); if (formalParameters.getNumChildren() != arguments.getNumChildren()) { return super.visit(node, data); } - if (!ignoreAnnotations) { + if (!getProperty(IGNORE_ANNOTATIONS_DESCRIPTOR)) { ASTClassOrInterfaceBodyDeclaration parent = (ASTClassOrInterfaceBodyDeclaration) node.getParent(); for (int i = 0; i < parent.getNumChildren(); i++) { Node n = parent.getChild(i); @@ -192,6 +167,11 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { } } + // different number of args + if (arguments.size() != node.getArity()) { + return super.visit(node, data); + } + if (arguments.size() > 0) { ASTArgumentList argumentList = (ASTArgumentList) arguments.getChild(0); for (int i = 0; i < argumentList.getNumChildren(); i++) { @@ -213,14 +193,9 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { return super.visit(node, data); } - if (formalParameters.getNumChildren() < i + 1) { - return super.visit(node, data); // different number of args - } - ASTName argumentName = (ASTName) argumentPrimaryPrefixChild; ASTFormalParameter formalParameter = (ASTFormalParameter) formalParameters.getChild(i); - ASTVariableDeclaratorId variableId = findFirstDegreeChildrenOfType(formalParameter, - ASTVariableDeclaratorId.class).get(0); + ASTVariableDeclaratorId variableId = formalParameter.getFirstChildOfType(ASTVariableDeclaratorId.class); if (!argumentName.hasImageEqualTo(variableId.getImage())) { // The arguments are not simply passed through return super.visit(node, data); @@ -238,6 +213,15 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { return super.visit(node, data); } + private boolean isCloneMethod(ASTMethodDeclaration node) { + boolean isCloneAndPublic = CLONE_METHOD_NAME.equals(node.getName()) && node.isPublic(); + boolean hasNoParameters = node.getArity() == 0; + return isCloneAndPublic + && hasNoParameters + && this.isMethodResultType(node, Object.class) + && this.isMethodThrowingType(node, CloneNotSupportedException.class); + } + private boolean modifiersChanged(ASTMethodDeclaration node) { Class type = node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class).getType(); if (type == null) { @@ -275,31 +259,11 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { return declaredMethod != null && overriddenModifiers != declaredMethod.getModifiers(); } - public List findFirstDegreeChildrenOfType(Node n, Class targetType) { - List l = new ArrayList<>(); - lclFindChildrenOfType(n, targetType, l); - return l; - } - - private void lclFindChildrenOfType(Node node, Class targetType, List results) { - if (node.getClass().equals(targetType)) { - results.add((T) node); - } - - if (node instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) node).isNested()) { - return; - } - - if (node instanceof ASTClassOrInterfaceBodyDeclaration - && ((ASTClassOrInterfaceBodyDeclaration) node).isAnonymousInnerClass()) { - return; - } - - for (int i = 0; i < node.getNumChildren(); i++) { - Node child = node.getChild(i); - if (child.getClass().equals(targetType)) { - results.add((T) child); - } - } + /** + * @deprecated this method will be removed. Just use {@link Node#findChildrenOfType(Class)} directly. + */ + @Deprecated + public List findFirstDegreeChaildrenOfType(Node n, Class targetType) { + return n.findChildrenOfType(targetType); } } From c6825d6dbfcfd153ad2dc071d342c83663147b59 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 20 Feb 2020 16:44:24 +0100 Subject: [PATCH 128/235] [java] UselessOverridingMethod: consider package-level elevation as well --- .../design/UselessOverridingMethodRule.java | 37 ++++++++++++++++++- .../TransitiveSubclass.java | 2 +- .../other/DirectSubclassInOtherPackage.java | 15 ++++++++ .../other/OtherClassInOtherPackage.java | 16 ++++++++ .../design/xml/UselessOverridingMethod.xml | 21 ++++++++++- 5 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/DirectSubclassInOtherPackage.java create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/OtherClassInOtherPackage.java diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java index b9f5f4de80..f73a34ebad 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java @@ -7,9 +7,11 @@ package net.sourceforge.pmd.lang.java.rule.design; import static net.sourceforge.pmd.properties.PropertyFactory.booleanProperty; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; +import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; @@ -23,6 +25,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTNameList; +import net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; @@ -49,11 +52,17 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { .desc("Ignore annotations") .build(); + private String packageName; public UselessOverridingMethodRule() { definePropertyDescriptor(IGNORE_ANNOTATIONS_DESCRIPTOR); } + @Override + public void start(RuleContext ctx) { + packageName = ""; + } + @Override public Object visit(ASTClassOrInterfaceDeclaration clz, Object data) { if (clz.isInterface()) { @@ -86,6 +95,12 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { return false; } + @Override + public Object visit(ASTPackageDeclaration node, Object data) { + packageName = node.getPackageNameImage(); + return super.visit(node, data); + } + @Override public Object visit(ASTMethodDeclaration node, Object data) { // Can skip abstract methods and methods whose only purpose is to @@ -229,7 +244,6 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { } String overriddenMethodName = node.getName(); - int overriddenModifiers = node.getModifiers(); List> typeArguments = new ArrayList<>(); for (ASTFormalParameter parameter : node.getFormalParameters()) { @@ -256,7 +270,26 @@ public class UselessOverridingMethodRule extends AbstractJavaRule { } superType = superType.getSuperclass(); } - return declaredMethod != null && overriddenModifiers != declaredMethod.getModifiers(); + + return declaredMethod != null && isElevatingAccessModifier(node, declaredMethod); + } + + private boolean isElevatingAccessModifier(ASTMethodDeclaration overridingMethod, Method superMethod) { + String superPackageName = null; + Package p = superMethod.getDeclaringClass().getPackage(); + if (p != null) { + superPackageName = p.getName(); + } + // Note: can't simply compare superMethod.getModifiers() with overridingMethod.getModifiers() + // since AccessNode#PROTECTED != Modifier#PROTECTED. + boolean elevatingFromProtected = Modifier.isProtected(superMethod.getModifiers()) + && !overridingMethod.isProtected(); + boolean elevatingFromPackagePrivate = superMethod.getModifiers() == 0 && overridingMethod.getModifiers() != 0; + boolean elevatingIntoDifferentPackage = !packageName.equals(superPackageName); + + return elevatingFromProtected + || elevatingFromPackagePrivate + || elevatingIntoDifferentPackage; } /** diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java index d9c8465c4e..050665ec8e 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/TransitiveSubclass.java @@ -7,7 +7,7 @@ package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod; public class TransitiveSubclass extends OtherSubclass { @Override - protected void doBase() { + public void doBase() { super.doBase(); } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/DirectSubclassInOtherPackage.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/DirectSubclassInOtherPackage.java new file mode 100644 index 0000000000..0585d7e4dd --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/DirectSubclassInOtherPackage.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.design.uselessoverridingmethod.other; + +import net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod.BaseClass; + +public class DirectSubclassInOtherPackage extends BaseClass { + + @Override + protected void doBase() { + super.doBase(); + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/OtherClassInOtherPackage.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/OtherClassInOtherPackage.java new file mode 100644 index 0000000000..80ec2a66d9 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/other/OtherClassInOtherPackage.java @@ -0,0 +1,16 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod.other; + +public class OtherClassInOtherPackage { + + + public void foo() { + DirectSubclassInOtherPackage instance = new DirectSubclassInOtherPackage(); + // this call is only possible, because DirectSubclassInOtherPackage makes this + // method available in this package as well. + instance.doBase(); + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml index f5dac830bc..e53b33f547 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml @@ -398,6 +398,25 @@ public class DirectSubclass extends BaseClass { ]]> + + [java] UselessOverridingMethod false positive when elevating access modifier #911 - direct different package, same visibility + 0 + + + [java] UselessOverridingMethod false positive when elevating access modifier #911 - transitive 0 @@ -407,7 +426,7 @@ package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod; public class TransitiveSubclass extends OtherSubclass { @Override - protected void doBase() { + public void doBase() { super.doBase(); } } From 9a7bf4df04d413bbd3049349c2bc8075678cf47d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 20 Feb 2020 21:25:25 +0100 Subject: [PATCH 129/235] [vm] Deprecate AST constructors / setters --- docs/pages/release_notes.md | 23 +++++++++++++++++++ .../pmd/lang/vm/ast/ASTAddNode.java | 15 ++++++------ .../pmd/lang/vm/ast/ASTDirective.java | 17 +++++++------- .../pmd/lang/vm/ast/ASTDivNode.java | 15 ++++++------ .../pmd/lang/vm/ast/ASTEscape.java | 15 ++++++------ .../pmd/lang/vm/ast/ASTMathNode.java | 6 +++++ .../pmd/lang/vm/ast/ASTMethod.java | 15 ++++++------ .../pmd/lang/vm/ast/ASTModNode.java | 15 ++++++------ .../pmd/lang/vm/ast/ASTMulNode.java | 15 ++++++------ .../pmd/lang/vm/ast/ASTReference.java | 21 +++++++++++------ .../pmd/lang/vm/ast/ASTStringLiteral.java | 19 +++++++++------ .../pmd/lang/vm/ast/ASTSubtractNode.java | 14 +++++------ .../pmd/lang/vm/ast/AbstractVmNode.java | 4 ++++ .../pmd/lang/vm/ast/MacroParseException.java | 2 ++ .../lang/vm/ast/TemplateParseException.java | 1 + .../pmd/lang/vm/ast/TokenMgrError.java | 4 ++++ .../sourceforge/pmd/lang/vm/ast/VmNode.java | 4 ++-- 17 files changed, 126 insertions(+), 79 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 834c546dfa..c37e536179 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -116,6 +116,29 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * pmd-apex * {% jdoc java::lang.apex.metrics.ApexMetrics %}, {% jdoc java::lang.java.metrics.JavaMetricsComputer %} +##### In ASTs (Velocity) + +As part of the changes we'd like to do to AST classes for 7.0.0, we would like to +hide some methods and constructors that rule writers should not have access to. +The following usages are now deprecated **in the VM AST** (with other languages to come): + +* Manual instantiation of nodes. **Constructors of node classes are deprecated** and + marked {% jdoc core::annotation.InternalApi %}. Nodes should only be obtained from the parser, + which for rules, means that they never need to instantiate node themselves. + Those constructors will be made package private with 7.0.0. +* **Subclassing of abstract node classes, or usage of their type**. Version 7.0.0 the base classes are and will + stay internal. You should not couple your code to them. + * In the meantime you should use interfaces like {% jdoc vm::lang.vm.ast.VmNode %} or + {% jdoc core::ast.Node %}, or the other published interfaces in this package, + to refer to nodes generically. + * Concrete node classes will **be made final** with 7.0.0. +* Setters found in any node class or interface. **Rules should consider the AST immutable**. + We will make those setters package private with 7.0.0. + +Please look at {% jdoc_package vm::lang.vm.ast %} to find out the full list of deprecations. + + + ### External Contributions diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTAddNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTAddNode.java index ac8136b9f2..4438076ee8 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTAddNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTAddNode.java @@ -1,6 +1,8 @@ package net.sourceforge.pmd.lang.vm.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -34,22 +36,19 @@ package net.sourceforge.pmd.lang.vm.ast; * @version $Id: ASTAddNode.java 712887 2008-11-11 00:27:50Z nbubna $ */ public class ASTAddNode extends ASTMathNode { - /** - * @param id - */ + + @InternalApi + @Deprecated public ASTAddNode(final int id) { super(id); } - /** - * @param p - * @param id - */ + @InternalApi + @Deprecated public ASTAddNode(final VmParser p, final int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(VmParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTDirective.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTDirective.java index 9068449cce..22243fe934 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTDirective.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTDirective.java @@ -3,6 +3,8 @@ package net.sourceforge.pmd.lang.vm.ast; import org.apache.commons.lang3.builder.ToStringBuilder; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -38,17 +40,14 @@ import org.apache.commons.lang3.builder.ToStringBuilder; public class ASTDirective extends AbstractVmNode { private String directiveName = ""; - /** - * @param id - */ + @InternalApi + @Deprecated public ASTDirective(final int id) { super(id); } - /** - * @param p - * @param id - */ + @InternalApi + @Deprecated public ASTDirective(final VmParser p, final int id) { super(p, id); } @@ -62,9 +61,9 @@ public class ASTDirective extends AbstractVmNode { * Sets the directive name. Used by the parser. This keeps us from having to * dig it out of the token stream and gives the parse the change to * override. - * - * @param str */ + @InternalApi + @Deprecated public void setDirectiveName(final String str) { directiveName = str; } diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTDivNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTDivNode.java index ba8cc16168..44ca67ab02 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTDivNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTDivNode.java @@ -1,6 +1,8 @@ package net.sourceforge.pmd.lang.vm.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -34,22 +36,19 @@ package net.sourceforge.pmd.lang.vm.ast; * @version $Id: ASTDivNode.java 691048 2008-09-01 20:26:11Z nbubna $ */ public class ASTDivNode extends ASTMathNode { - /** - * @param id - */ + + @InternalApi + @Deprecated public ASTDivNode(final int id) { super(id); } - /** - * @param p - * @param id - */ + @InternalApi + @Deprecated public ASTDivNode(final VmParser p, final int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(VmParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTEscape.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTEscape.java index 8c8197ac55..54d5ed43ca 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTEscape.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTEscape.java @@ -1,6 +1,8 @@ package net.sourceforge.pmd.lang.vm.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -31,19 +33,18 @@ package net.sourceforge.pmd.lang.vm.ast; */ public class ASTEscape extends AbstractVmNode { /** Used by the parser */ + @InternalApi + @Deprecated public String val; - /** - * @param id - */ + @InternalApi + @Deprecated public ASTEscape(final int id) { super(id); } - /** - * @param p - * @param id - */ + @InternalApi + @Deprecated public ASTEscape(final VmParser p, final int id) { super(p, id); } diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMathNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMathNode.java index 34733b9be1..c642288b73 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMathNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMathNode.java @@ -1,6 +1,8 @@ package net.sourceforge.pmd.lang.vm.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -37,10 +39,14 @@ package net.sourceforge.pmd.lang.vm.ast; public abstract class ASTMathNode extends AbstractVmNode { protected boolean strictMode = false; + @InternalApi + @Deprecated public ASTMathNode(final int id) { super(id); } + @InternalApi + @Deprecated public ASTMathNode(final VmParser p, final int id) { super(p, id); } diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMethod.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMethod.java index 5dc1e3d563..63dd3d1902 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMethod.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMethod.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.vm.ast; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -40,17 +42,14 @@ import org.apache.commons.lang3.StringUtils; * @version $Id: ASTMethod.java 720228 2008-11-24 16:58:33Z nbubna $ */ public class ASTMethod extends AbstractVmNode { - /** - * @param id - */ + @InternalApi + @Deprecated public ASTMethod(final int id) { super(id); } - /** - * @param p - * @param id - */ + @InternalApi + @Deprecated public ASTMethod(final VmParser p, final int id) { super(p, id); } @@ -66,7 +65,9 @@ public class ASTMethod extends AbstractVmNode { * constructor) for unit test purposes. * * @since 1.5 + * @deprecated for removal in PMD 7.0.0 - it's not used anywhere */ + @Deprecated public static class MethodCacheKey { private final String methodName; diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTModNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTModNode.java index 9bd588007b..dd177a4de7 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTModNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTModNode.java @@ -1,6 +1,8 @@ package net.sourceforge.pmd.lang.vm.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -33,22 +35,19 @@ package net.sourceforge.pmd.lang.vm.ast; * @version $Id: ASTModNode.java 691048 2008-09-01 20:26:11Z nbubna $ */ public class ASTModNode extends ASTMathNode { - /** - * @param id - */ + + @InternalApi + @Deprecated public ASTModNode(final int id) { super(id); } - /** - * @param p - * @param id - */ + @InternalApi + @Deprecated public ASTModNode(final VmParser p, final int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(VmParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMulNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMulNode.java index da565930a5..aba41e0beb 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMulNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMulNode.java @@ -1,6 +1,8 @@ package net.sourceforge.pmd.lang.vm.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -34,22 +36,19 @@ package net.sourceforge.pmd.lang.vm.ast; * @version $Id: ASTMulNode.java 691048 2008-09-01 20:26:11Z nbubna $ */ public class ASTMulNode extends ASTMathNode { - /** - * @param id - */ + + @InternalApi + @Deprecated public ASTMulNode(final int id) { super(id); } - /** - * @param p - * @param id - */ + @InternalApi + @Deprecated public ASTMulNode(final VmParser p, final int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(VmParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTReference.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTReference.java index d17e6b5a40..a4dd514966 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTReference.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTReference.java @@ -1,6 +1,8 @@ package net.sourceforge.pmd.lang.vm.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -39,7 +41,10 @@ public class ASTReference extends AbstractVmNode { /** * Indicates if we are running in strict reference mode. + * + * @deprecated for removal with PMD 7.0.0 */ + @Deprecated public boolean strictRef = false; /** @@ -48,20 +53,20 @@ public class ASTReference extends AbstractVmNode { * implementations are known to have non-null return values. Disabling the * check will give a performance improval since toString() may be a complex * operation on large objects. + * + * @deprecated for removal with PMD 7.0.0 */ + @Deprecated public boolean toStringNullCheck = true; - /** - * @param id - */ + @InternalApi + @Deprecated public ASTReference(final int id) { super(id); } - /** - * @param p - * @param id - */ + @InternalApi + @Deprecated public ASTReference(final VmParser p, final int id) { super(p, id); } @@ -91,6 +96,8 @@ public class ASTReference extends AbstractVmNode { * @param literal * String to render to when null */ + @InternalApi + @Deprecated public void setLiteral(final String literal) { /* * do only once diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTStringLiteral.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTStringLiteral.java index 16aea343dc..57b527fff2 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTStringLiteral.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTStringLiteral.java @@ -3,6 +3,8 @@ package net.sourceforge.pmd.lang.vm.ast; import org.apache.commons.lang3.text.StrBuilder; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with this @@ -28,17 +30,14 @@ import org.apache.commons.lang3.text.StrBuilder; * @version $Id: ASTStringLiteral.java 705297 2008-10-16 17:59:24Z nbubna $ */ public class ASTStringLiteral extends AbstractVmNode { - /** - * @param id - */ + @InternalApi + @Deprecated public ASTStringLiteral(final int id) { super(id); } - /** - * @param p - * @param id - */ + @InternalApi + @Deprecated public ASTStringLiteral(final VmParser p, final int id) { super(p, id); } @@ -50,7 +49,10 @@ public class ASTStringLiteral extends AbstractVmNode { * that the line and column position reported reflects the error position * within the template and not just relative to the error position within * the string literal. + * + * @deprecated for removal with PMD 7.0.0 */ + @Deprecated public void adjTokenLineNums(final AbstractVmNode node) { Token tok = node.getFirstToken(); // Test against null is probably not neccessary, but just being safe @@ -74,7 +76,10 @@ public class ASTStringLiteral extends AbstractVmNode { /** * @since 1.6 + * @deprecated for removal with PMD 7.0.0 */ + @InternalApi + @Deprecated public static String unescape(final String string) { int u = string.indexOf("\\u"); if (u < 0) { diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTSubtractNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTSubtractNode.java index 88e694669d..052fb7dbcf 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTSubtractNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTSubtractNode.java @@ -1,6 +1,8 @@ package net.sourceforge.pmd.lang.vm.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -34,22 +36,18 @@ package net.sourceforge.pmd.lang.vm.ast; * @version $Id: ASTSubtractNode.java 691048 2008-09-01 20:26:11Z nbubna $ */ public class ASTSubtractNode extends ASTMathNode { - /** - * @param id - */ + @InternalApi + @Deprecated public ASTSubtractNode(final int id) { super(id); } - /** - * @param p - * @param id - */ + @InternalApi + @Deprecated public ASTSubtractNode(final VmParser p, final int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(VmParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java index 2b17c462ba..cf7cc7d629 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java @@ -31,6 +31,8 @@ import net.sourceforge.pmd.lang.ast.impl.javacc.AbstractJjtreeNode; /** * */ +@InternalApi +@Deprecated public class AbstractVmNode extends AbstractJjtreeNode implements VmNode { /** */ @@ -139,7 +141,9 @@ public class AbstractVmNode extends AbstractJjtreeNode implements VmNode /** * @param prefix * @return String representation of this node. + * @deprecated will be removed with PMD 7. Was only needed for {@link #dump(String, boolean, Writer)}. */ + @Deprecated public String toString(final String prefix) { return prefix + toString(); } diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/MacroParseException.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/MacroParseException.java index 16237c1aba..e6b19accfa 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/MacroParseException.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/MacroParseException.java @@ -30,7 +30,9 @@ import net.sourceforge.pmd.lang.vm.util.LogUtil; * @author Geir Magnusson Jr. * @author Henning P. Schmiedehausen * @version $Id: MacroParseException.java 735709 2009-01-19 14:30:03Z byron $ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class MacroParseException extends ParseException { private final String templateName; diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/TemplateParseException.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/TemplateParseException.java index e41a76a3be..1913c84cee 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/TemplateParseException.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/TemplateParseException.java @@ -31,6 +31,7 @@ import net.sourceforge.pmd.lang.vm.util.LogUtil; * @version $Id: TemplateParseException.java 703544 2008-10-10 18:15:53Z nbubna * $ * @since 1.5 + * @deprecated for removal in PMD 7.0.0 */ @Deprecated public class TemplateParseException extends ParseException { diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/TokenMgrError.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/TokenMgrError.java index 546b054b60..898ad8dfec 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/TokenMgrError.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/TokenMgrError.java @@ -3,6 +3,10 @@ package net.sourceforge.pmd.lang.vm.ast; /* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ +/** + * @deprecated for removal in PMD 7.0.0 + */ +@Deprecated public class TokenMgrError extends RuntimeException { /* * Ordinals for various reasons why an Error of this type can be thrown. diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmNode.java index f549cdb3a3..28f142c86a 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/VmNode.java @@ -8,13 +8,13 @@ import net.sourceforge.pmd.lang.ast.Node; public interface VmNode extends Node { /** - * Accept the visitor. * + * Accept the visitor. */ Object jjtAccept(VmParserVisitor visitor, Object data); /** - * Accept the visitor. * + * Accept the visitor. * * @deprecated This method is not useful, the logic for combining * children values should be present on the visitor, not the node From f3b98d7140910e2371d55a4b1d477308b5302f46 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 20 Feb 2020 21:35:50 +0100 Subject: [PATCH 130/235] [vm] Mark generated AST node constructor InternalApi --- pmd-vm/src/main/ant/alljavacc.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pmd-vm/src/main/ant/alljavacc.xml b/pmd-vm/src/main/ant/alljavacc.xml index 358f1dee9b..9d5483e1bc 100644 --- a/pmd-vm/src/main/ant/alljavacc.xml +++ b/pmd-vm/src/main/ant/alljavacc.xml @@ -140,5 +140,21 @@ public class Token implements GenericToken, java.io.Serializable]]> + + + + + + + + + + + + + + + + From ddd338dc788c8d65a571f2f353fecc255925d281 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 22 Feb 2020 12:07:43 +0100 Subject: [PATCH 131/235] [doc] Update release notes, refs #2297, fixes #2162 --- docs/pages/release_notes.md | 12 +++++++++++- .../src/main/resources/rulesets/releases/6220.xml | 13 +++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 pmd-core/src/main/resources/rulesets/releases/6220.xml diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 834c546dfa..1bdd8ea2d5 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -19,15 +19,24 @@ This is a {{ site.pmd.release_type }} release. This PMD release ships a new version of the pmd-designer. For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/6.21.0). -### Apex Suppressions +#### Apex Suppressions In addition to suppressing violation with the `@SuppressWarnings` annotation, Apex now also supports the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs_suppressing_warnings.html). +#### New Rules + +* The Rule {% rule "apex/design/CognitiveComplexity" %} (`apex-design`) finds methods and classes + that are highly complex and therefore difficult to read and more costly to maintain. In contrast + to cyclomatic complexity, this rule uses "Cognitive Complexity", which is a measure of how + difficult it is for humans to read and understand a method. + ### Fixed Issues * apex * [#1087](https://github.com/pmd/pmd/issues/1087): \[apex] Support suppression via //NOPMD +* apex-design + * [#2162](https://github.com/pmd/pmd/issues/2162): \[apex] Cognitive Complexity rule * doc * [#2274](https://github.com/pmd/pmd/issues/2274): \[doc] Java API documentation for PMD * java @@ -125,6 +134,7 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * [#2276](https://github.com/pmd/pmd/pull/2276): \[java] AppendCharacterWithCharRule ignore literals in expressions - [Kris Scheibe](https://github.com/kris-scheibe) * [#2278](https://github.com/pmd/pmd/pull/2278): \[java] fix UnusedImports rule for ambiguous static on-demand imports - [Kris Scheibe](https://github.com/kris-scheibe) * [#2279](https://github.com/pmd/pmd/pull/2279): \[apex] Add support for suppressing violations using the // NOPMD comment - [Gwilym Kuiper](https://github.com/gwilymatgearset) +* [#2297](https://github.com/pmd/pmd/pull/2297): \[apex] Cognitive complexity metrics - [Gwilym Kuiper](https://github.com/gwilymatgearset) {% endtocmaker %} diff --git a/pmd-core/src/main/resources/rulesets/releases/6220.xml b/pmd-core/src/main/resources/rulesets/releases/6220.xml new file mode 100644 index 0000000000..e810572d8e --- /dev/null +++ b/pmd-core/src/main/resources/rulesets/releases/6220.xml @@ -0,0 +1,13 @@ + + + + +This ruleset contains links to rules that are new in PMD v6.22.0 + + + + + From 96f9efcb8ef71a3e000329e96bf96c5ba28741ab Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 22 Feb 2020 12:10:24 +0100 Subject: [PATCH 132/235] [apex] Update quickstart ruleset - add commented cognitive complexity rule --- pmd-apex/src/main/resources/rulesets/apex/quickstart.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml b/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml index d6ab81cc12..4d318d6f4f 100644 --- a/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml +++ b/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml @@ -105,6 +105,7 @@ + From 827cdfd053deb7ef34ae5e14eddad4d42a35d090 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 22 Feb 2020 12:23:24 +0100 Subject: [PATCH 133/235] [apex] Fix test code using apex strings --- .../impl/xml/CognitiveComplexityTest.xml | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index 6b0df4594c..2abee77abb 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -14,10 +14,10 @@ class Foo { string foo(integer n) { if (n == 1) { - return "one"; + return 'one'; } - return "not one"; + return 'not one'; } } ]]> @@ -36,13 +36,13 @@ string foo(integer n) { if (n > 0) { // +1 if (n == 1) { // +2 - return "one"; + return 'one'; } - return "positive"; + return 'positive'; } - return "negative or 0"; + return 'negative or 0'; } } ]]> @@ -60,15 +60,15 @@ class Foo { string foo(integer n) { if (n > 0) { // +1 - return "positive"; + return 'positive'; } if (n == 0) { // +1 - return "zero"; + return 'zero'; } if (n < 0) { // +1 - return "negative"; + return 'negative'; } } } @@ -87,11 +87,11 @@ class Foo { string foo(integer n) { if (n > 0) { // +1 - return "positive"; + return 'positive'; } else if (n < 0) { // +1 - return "negative"; + return 'negative'; } else { // +1 - return "zero"; + return 'zero'; } } } @@ -111,11 +111,11 @@ string foo() { for (integer i = 0; i < 10; i++) { // +1 if (i == 3) { // +2 - return "three"; + return 'three'; } } - return "done"; + return 'done'; } } ]]> @@ -135,11 +135,11 @@ Integer[] myInts = new Integer[] {1, 2, 3}; for (Integer i : myInts) { // +1 if (i == 3) { // +2 - return "three"; + return 'three'; } } - return "done"; + return 'done'; } } ]]> @@ -163,7 +163,7 @@ } } - return "done"; + return 'done'; } } ]]> @@ -187,7 +187,7 @@ } } - return "done"; + return 'done'; } } ]]> @@ -209,11 +209,11 @@ while (n < 100) { // +1 i = i * n; if (i > 1000) { // +2 - return "big"; + return 'big'; } } - return "small"; + return 'small'; } } ]]> @@ -260,9 +260,9 @@ Integer n = 0; do { // +1 if (n == 3) { // +2 - System.debug("n is 3"); + System.debug('n is 3'); } else { // +2 - System.debug("n is not 3"); + System.debug('n is not 3'); } n++; } while (n < 100); From d21e2565ae2aa89cabde1f1c92509b63d6d92149 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 22 Feb 2020 12:27:46 +0100 Subject: [PATCH 134/235] [doc] Fix jdoc links in release notes --- docs/pages/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 1bdd8ea2d5..a6b5973f9e 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -123,7 +123,7 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * {% jdoc !!java::lang.java.ast.ASTFormalParameters#getParameterCount() %}. Use {% jdoc java::lang.java.ast.ASTFormalParameters#size() %} instead. * pmd-apex - * {% jdoc java::lang.apex.metrics.ApexMetrics %}, {% jdoc java::lang.java.metrics.JavaMetricsComputer %} + * {% jdoc apex::lang.apex.metrics.ApexMetrics %}, {% jdoc apex::lang.apex.metrics.ApexMetricsComputer %} ### External Contributions From 00c2d5cc6bf099a379d4ad056a838cac97612506 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 22 Feb 2020 14:54:28 +0100 Subject: [PATCH 135/235] [apex] Add parser support for Switch Statements Fixes #2306 --- docs/pages/release_notes.md | 1 + .../pmd/lang/apex/ast/ASTElseWhenBlock.java | 21 ++++++ .../pmd/lang/apex/ast/ASTIdentifierCase.java | 21 ++++++ .../pmd/lang/apex/ast/ASTLiteralCase.java | 21 ++++++ .../pmd/lang/apex/ast/ASTSwitchStatement.java | 21 ++++++ .../pmd/lang/apex/ast/ASTTypeWhenBlock.java | 21 ++++++ .../pmd/lang/apex/ast/ASTValueWhenBlock.java | 21 ++++++ .../pmd/lang/apex/ast/ApexParserVisitor.java | 12 +++ .../apex/ast/ApexParserVisitorAdapter.java | 30 ++++++++ .../pmd/lang/apex/ast/ApexTreeBuilder.java | 50 ++++++++++++- .../pmd/lang/apex/rule/AbstractApexRule.java | 36 +++++++++ .../lang/apex/ast/ASTSwitchStatementTest.java | 42 +++++++++++ .../pmd/lang/apex/ast/SwitchStatements.cls | 74 +++++++++++++++++++ 13 files changed, 368 insertions(+), 3 deletions(-) create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTElseWhenBlock.java create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIdentifierCase.java create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralCase.java create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatement.java create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTypeWhenBlock.java create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTValueWhenBlock.java create mode 100644 pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatementTest.java create mode 100644 pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/SwitchStatements.cls diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index a6b5973f9e..acc48d4fe9 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -35,6 +35,7 @@ the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs * apex * [#1087](https://github.com/pmd/pmd/issues/1087): \[apex] Support suppression via //NOPMD + * [#2306](https://github.com/pmd/pmd/issues/2306): \[apex] Switch statements are not parsed/supported * apex-design * [#2162](https://github.com/pmd/pmd/issues/2162): \[apex] Cognitive Complexity rule * doc 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 new file mode 100644 index 0000000000..ce5c94b366 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTElseWhenBlock.java @@ -0,0 +1,21 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import apex.jorje.semantic.ast.statement.ElseWhenBlock; + +public class ASTElseWhenBlock extends AbstractApexNode { + + + ASTElseWhenBlock(ElseWhenBlock node) { + super(node); + } + + + @Override + public Object jjtAccept(ApexParserVisitor visitor, Object 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 new file mode 100644 index 0000000000..127fe3855a --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTIdentifierCase.java @@ -0,0 +1,21 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import apex.jorje.semantic.ast.statement.WhenCases.IdentifierCase; + +public class ASTIdentifierCase extends AbstractApexNode { + + + ASTIdentifierCase(IdentifierCase node) { + super(node); + } + + + @Override + public Object jjtAccept(ApexParserVisitor visitor, Object 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 new file mode 100644 index 0000000000..b866efd5d2 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralCase.java @@ -0,0 +1,21 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import apex.jorje.semantic.ast.statement.WhenCases.LiteralCase; + +public class ASTLiteralCase extends AbstractApexNode { + + + ASTLiteralCase(LiteralCase node) { + super(node); + } + + + @Override + public Object jjtAccept(ApexParserVisitor visitor, Object 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 new file mode 100644 index 0000000000..10cc291e8c --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatement.java @@ -0,0 +1,21 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import apex.jorje.semantic.ast.statement.SwitchStatement; + +public final class ASTSwitchStatement extends AbstractApexNode { + + + ASTSwitchStatement(SwitchStatement node) { + super(node); + } + + + @Override + public Object jjtAccept(ApexParserVisitor visitor, Object 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 new file mode 100644 index 0000000000..7a63c32105 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTTypeWhenBlock.java @@ -0,0 +1,21 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import apex.jorje.semantic.ast.statement.TypeWhenBlock; + +public class ASTTypeWhenBlock extends AbstractApexNode { + + + ASTTypeWhenBlock(TypeWhenBlock node) { + super(node); + } + + + @Override + public Object jjtAccept(ApexParserVisitor visitor, Object 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 new file mode 100644 index 0000000000..12a6a85bd9 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTValueWhenBlock.java @@ -0,0 +1,21 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import apex.jorje.semantic.ast.statement.ValueWhenBlock; + +public class ASTValueWhenBlock extends AbstractApexNode { + + + ASTValueWhenBlock(ValueWhenBlock node) { + super(node); + } + + + @Override + public Object jjtAccept(ApexParserVisitor visitor, Object data) { + return visitor.visit(this, 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 2edcc668b7..fe6d70edb1 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 @@ -191,4 +191,16 @@ public interface ApexParserVisitor { 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); } 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 eb58942e54..b50a29c296 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 @@ -468,4 +468,34 @@ public class ApexParserVisitorAdapter implements ApexParserVisitor { 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); + } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index 53ba9d6f7a..368e863eaf 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -93,6 +93,7 @@ import apex.jorje.semantic.ast.statement.DmlUndeleteStatement; import apex.jorje.semantic.ast.statement.DmlUpdateStatement; import apex.jorje.semantic.ast.statement.DmlUpsertStatement; import apex.jorje.semantic.ast.statement.DoLoopStatement; +import apex.jorje.semantic.ast.statement.ElseWhenBlock; import apex.jorje.semantic.ast.statement.ExpressionStatement; import apex.jorje.semantic.ast.statement.FieldDeclaration; import apex.jorje.semantic.ast.statement.FieldDeclarationStatements; @@ -106,10 +107,15 @@ import apex.jorje.semantic.ast.statement.ReturnStatement; import apex.jorje.semantic.ast.statement.RunAsBlockStatement; import apex.jorje.semantic.ast.statement.Statement; import apex.jorje.semantic.ast.statement.StatementExecuted; +import apex.jorje.semantic.ast.statement.SwitchStatement; import apex.jorje.semantic.ast.statement.ThrowStatement; import apex.jorje.semantic.ast.statement.TryCatchFinallyBlockStatement; +import apex.jorje.semantic.ast.statement.TypeWhenBlock; +import apex.jorje.semantic.ast.statement.ValueWhenBlock; import apex.jorje.semantic.ast.statement.VariableDeclaration; import apex.jorje.semantic.ast.statement.VariableDeclarationStatements; +import apex.jorje.semantic.ast.statement.WhenCases.IdentifierCase; +import apex.jorje.semantic.ast.statement.WhenCases.LiteralCase; import apex.jorje.semantic.ast.statement.WhileLoopStatement; import apex.jorje.semantic.ast.visitor.AdditionalPassScope; import apex.jorje.semantic.ast.visitor.AstVisitor; @@ -117,7 +123,8 @@ import apex.jorje.semantic.exception.Errors; public final class ApexTreeBuilder extends AstVisitor { - private static final Map, Constructor>> NODE_TYPE_TO_NODE_ADAPTER_TYPE = new HashMap<>(); + private static final Map, Constructor>> + NODE_TYPE_TO_NODE_ADAPTER_TYPE = new HashMap<>(); static { register(Annotation.class, ASTAnnotation.class); @@ -208,11 +215,18 @@ public final class ApexTreeBuilder extends AstVisitor { register(VariableDeclarationStatements.class, ASTVariableDeclarationStatements.class); register(VariableExpression.class, ASTVariableExpression.class); register(WhileLoopStatement.class, ASTWhileLoopStatement.class); + register(SwitchStatement.class, ASTSwitchStatement.class); + register(ElseWhenBlock.class, ASTElseWhenBlock.class); + register(TypeWhenBlock.class, ASTTypeWhenBlock.class); + register(ValueWhenBlock.class, ASTValueWhenBlock.class); + register(LiteralCase.class, ASTLiteralCase.class); + register(IdentifierCase.class, ASTIdentifierCase.class); } - private static void register(Class nodeType, Class> nodeAdapterType) { + private static void register(Class nodeType, + Class> nodeAdapterType) { try { - NODE_TYPE_TO_NODE_ADAPTER_TYPE.put(nodeType, nodeAdapterType.getConstructor(nodeType)); + NODE_TYPE_TO_NODE_ADAPTER_TYPE.put(nodeType, nodeAdapterType.getDeclaredConstructor(nodeType)); } catch (SecurityException | NoSuchMethodException e) { throw new RuntimeException(e); } @@ -805,4 +819,34 @@ public final class ApexTreeBuilder extends AstVisitor { public boolean visit(NewKeyValueObjectExpression node, AdditionalPassScope scope) { return visit(node); } + + @Override + public boolean visit(SwitchStatement node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ElseWhenBlock node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(TypeWhenBlock node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(ValueWhenBlock node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(LiteralCase node, AdditionalPassScope scope) { + return visit(node); + } + + @Override + public boolean visit(IdentifierCase node, AdditionalPassScope scope) { + return visit(node); + } } 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 d032c514b7..ef3482bdc7 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 @@ -36,6 +36,7 @@ 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.ASTExpression; import net.sourceforge.pmd.lang.apex.ast.ASTExpressionStatement; import net.sourceforge.pmd.lang.apex.ast.ASTField; @@ -44,12 +45,14 @@ 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; @@ -84,18 +87,21 @@ 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; @@ -604,4 +610,34 @@ public abstract class AbstractApexRule extends AbstractRule 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); + } } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatementTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatementTest.java new file mode 100644 index 0000000000..03ef4a0513 --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatementTest.java @@ -0,0 +1,42 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import apex.jorje.semantic.ast.compilation.Compilation; + +public class ASTSwitchStatementTest extends ApexParserTestBase { + + @Test + public void testExamples() { + ApexNode node = parseResource("SwitchStatements.cls"); + List switchStatements = node.findDescendantsOfType(ASTSwitchStatement.class); + Assert.assertEquals(4, switchStatements.size()); + + Assert.assertTrue(switchStatements.get(0).getChild(0) instanceof ASTVariableExpression); + Assert.assertEquals(5, switchStatements.get(0).findChildrenOfType(ASTValueWhenBlock.class).size()); + Assert.assertEquals(3, switchStatements.get(0).findChildrenOfType(ASTValueWhenBlock.class) + .get(1).findChildrenOfType(ASTLiteralCase.class).size()); + Assert.assertEquals(1, switchStatements.get(0).findChildrenOfType(ASTElseWhenBlock.class).size()); + + Assert.assertTrue(switchStatements.get(1).getChild(0) instanceof ASTMethodCallExpression); + Assert.assertEquals(2, switchStatements.get(1).findChildrenOfType(ASTValueWhenBlock.class).size()); + Assert.assertEquals(1, switchStatements.get(1).findChildrenOfType(ASTElseWhenBlock.class).size()); + + Assert.assertTrue(switchStatements.get(2).getChild(0) instanceof ASTVariableExpression); + Assert.assertEquals(2, switchStatements.get(2).findChildrenOfType(ASTTypeWhenBlock.class).size()); + Assert.assertEquals(1, switchStatements.get(2).findChildrenOfType(ASTValueWhenBlock.class).size()); + Assert.assertEquals(1, switchStatements.get(2).findChildrenOfType(ASTElseWhenBlock.class).size()); + + Assert.assertTrue(switchStatements.get(3).getChild(0) instanceof ASTVariableExpression); + Assert.assertEquals(2, switchStatements.get(3).findChildrenOfType(ASTValueWhenBlock.class).size()); + Assert.assertEquals(1, switchStatements.get(3).findChildrenOfType(ASTElseWhenBlock.class).size()); + } + +} diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/SwitchStatements.cls b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/SwitchStatements.cls new file mode 100644 index 0000000000..621ab5c727 --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/SwitchStatements.cls @@ -0,0 +1,74 @@ +public class ApexSwitchStatements { + public void example1() { + int i = 3; + switch on i { + when 2 { + System.debug('when block 2'); + } + when 3, 4, 5 { + System.debug('when block 3 and 4 and 5'); + } + when 6, 7 { + System.debug('when block 6 and 7'); + } + when -3 { + System.debug('when block -3'); + } + when null { + System.debug('bad integer'); + } + when else { + System.debug('default'); + } + } + } + + public void example2() { + int i = 1; + switch on someInteger(i) { + when 2 { + System.debug('when block 2'); + } + when 3 { + System.debug('when block 3'); + } + when else { + System.debug('default'); + } + } + } + private int someInteger(int i) { + return i + 1; + } + + public void example3() { + switch on sobject { + when Account a { + System.debug('account ' + a); + } + when Contact c { + System.debug('contact ' + c); + } + when null { + System.debug('null'); + } + when else { + System.debug('default'); + } + } + } + + public void example4() { + switch on season { + when WINTER { + System.debug('boots'); + } + when SPRING, SUMMER { + System.debug('sandals'); + } + when else { + System.debug('none of the above'); + } + } + } +} \ No newline at end of file From c090bfbd8b219c7995f37f377f1c5e3dbb38bd94 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 22 Feb 2020 15:02:48 +0100 Subject: [PATCH 136/235] [apex] Add parser support for EmptyReferenceExpression --- .../apex/ast/ASTEmptyReferenceExpression.java | 22 +++++++++++++++++++ .../pmd/lang/apex/ast/ApexParserVisitor.java | 2 ++ .../apex/ast/ApexParserVisitorAdapter.java | 5 +++++ .../pmd/lang/apex/ast/ApexTreeBuilder.java | 7 ++++++ .../pmd/lang/apex/rule/AbstractApexRule.java | 6 +++++ .../pmd/lang/apex/ast/ApexParserTest.java | 2 +- 6 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTEmptyReferenceExpression.java 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 new file mode 100644 index 0000000000..e973874cd0 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTEmptyReferenceExpression.java @@ -0,0 +1,22 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import apex.jorje.semantic.ast.expression.EmptyReferenceExpression; + +public class ASTEmptyReferenceExpression extends AbstractApexNode { + + + ASTEmptyReferenceExpression(EmptyReferenceExpression node) { + super(node); + } + + + @Override + public Object jjtAccept(ApexParserVisitor visitor, Object data) { + return visitor.visit(this, 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 fe6d70edb1..cb6497ce7d 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 @@ -203,4 +203,6 @@ public interface ApexParserVisitor { 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 b50a29c296..3a58a233f1 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 @@ -498,4 +498,9 @@ public class ApexParserVisitorAdapter implements ApexParserVisitor { 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/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index 368e863eaf..40e1577601 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -40,6 +40,7 @@ import apex.jorje.semantic.ast.expression.BindExpressions; import apex.jorje.semantic.ast.expression.BooleanExpression; import apex.jorje.semantic.ast.expression.CastExpression; import apex.jorje.semantic.ast.expression.ClassRefExpression; +import apex.jorje.semantic.ast.expression.EmptyReferenceExpression; import apex.jorje.semantic.ast.expression.Expression; import apex.jorje.semantic.ast.expression.IllegalStoreExpression; import apex.jorje.semantic.ast.expression.InstanceOfExpression; @@ -221,6 +222,7 @@ public final class ApexTreeBuilder extends AstVisitor { register(ValueWhenBlock.class, ASTValueWhenBlock.class); register(LiteralCase.class, ASTLiteralCase.class); register(IdentifierCase.class, ASTIdentifierCase.class); + register(EmptyReferenceExpression.class, ASTEmptyReferenceExpression.class); } private static void register(Class nodeType, @@ -849,4 +851,9 @@ public final class ApexTreeBuilder extends AstVisitor { public boolean visit(IdentifierCase node, AdditionalPassScope scope) { return visit(node); } + + @Override + public boolean visit(EmptyReferenceExpression node, AdditionalPassScope scope) { + return visit(node); + } } 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 ef3482bdc7..8f1a29b57d 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 @@ -37,6 +37,7 @@ 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; @@ -640,4 +641,9 @@ public abstract class AbstractApexRule extends AbstractRule 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/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java index 79ecc234c6..0cc7c50297 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java @@ -179,7 +179,7 @@ public class ApexParserTest extends ApexParserTestBase { Assert.assertNotNull(rootNode); int count = visitPosition(rootNode, 0); - Assert.assertEquals(427, count); + Assert.assertEquals(487, count); } private int visitPosition(Node node, int count) { From 4c7b48c8e95c542eb7a4f3d09ea66f7b01b5731d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 22 Feb 2020 15:21:44 +0100 Subject: [PATCH 137/235] [apex] Expose type and name of TypeWhenBlock --- .../pmd/lang/apex/ast/ASTTypeWhenBlock.java | 16 ++++++++++++++++ .../lang/apex/ast/ASTSwitchStatementTest.java | 4 ++++ 2 files changed, 20 insertions(+) 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 7a63c32105..77984c06df 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 @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.apex.ast; +import java.lang.reflect.Field; + import apex.jorje.semantic.ast.statement.TypeWhenBlock; public class ASTTypeWhenBlock extends AbstractApexNode { @@ -13,6 +15,20 @@ public class ASTTypeWhenBlock extends AbstractApexNode { super(node); } + public String getType() { + return String.valueOf(node.getTypeRef()); + } + + public String getName() { + // unfortunately the name is not exposed... + try { + Field nameField = TypeWhenBlock.class.getDeclaredField("name"); + nameField.setAccessible(true); + return String.valueOf(nameField.get(node)); + } catch (SecurityException | ReflectiveOperationException e) { + return null; + } + } @Override public Object jjtAccept(ApexParserVisitor visitor, Object data) { diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatementTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatementTest.java index 03ef4a0513..72623c8ecc 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatementTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTSwitchStatementTest.java @@ -31,6 +31,10 @@ public class ASTSwitchStatementTest extends ApexParserTestBase { Assert.assertTrue(switchStatements.get(2).getChild(0) instanceof ASTVariableExpression); Assert.assertEquals(2, switchStatements.get(2).findChildrenOfType(ASTTypeWhenBlock.class).size()); + Assert.assertEquals("Account", switchStatements.get(2).findChildrenOfType(ASTTypeWhenBlock.class) + .get(0).getType()); + Assert.assertEquals("a", switchStatements.get(2).findChildrenOfType(ASTTypeWhenBlock.class) + .get(0).getName()); Assert.assertEquals(1, switchStatements.get(2).findChildrenOfType(ASTValueWhenBlock.class).size()); Assert.assertEquals(1, switchStatements.get(2).findChildrenOfType(ASTElseWhenBlock.class).size()); From 36d6439270f3dccba0f37cd5aab80967a5f42b04 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 22 Feb 2020 15:38:30 +0100 Subject: [PATCH 138/235] [apex] Make the new ast nodes final --- .../net/sourceforge/pmd/lang/apex/ast/ASTElseWhenBlock.java | 2 +- .../pmd/lang/apex/ast/ASTEmptyReferenceExpression.java | 2 +- .../net/sourceforge/pmd/lang/apex/ast/ASTIdentifierCase.java | 2 +- .../java/net/sourceforge/pmd/lang/apex/ast/ASTLiteralCase.java | 2 +- .../net/sourceforge/pmd/lang/apex/ast/ASTTypeWhenBlock.java | 2 +- .../net/sourceforge/pmd/lang/apex/ast/ASTValueWhenBlock.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) 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 ce5c94b366..4280a35355 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 @@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.apex.ast; import apex.jorje.semantic.ast.statement.ElseWhenBlock; -public class ASTElseWhenBlock extends AbstractApexNode { +public final class ASTElseWhenBlock extends AbstractApexNode { ASTElseWhenBlock(ElseWhenBlock node) { 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 e973874cd0..39ca6a6dd7 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 @@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.apex.ast; import apex.jorje.semantic.ast.expression.EmptyReferenceExpression; -public class ASTEmptyReferenceExpression extends AbstractApexNode { +public final class ASTEmptyReferenceExpression extends AbstractApexNode { ASTEmptyReferenceExpression(EmptyReferenceExpression node) { 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 127fe3855a..dfd45cf184 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 @@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.apex.ast; import apex.jorje.semantic.ast.statement.WhenCases.IdentifierCase; -public class ASTIdentifierCase extends AbstractApexNode { +public final class ASTIdentifierCase extends AbstractApexNode { ASTIdentifierCase(IdentifierCase node) { 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 b866efd5d2..fc97e4bf9f 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 @@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.apex.ast; import apex.jorje.semantic.ast.statement.WhenCases.LiteralCase; -public class ASTLiteralCase extends AbstractApexNode { +public final class ASTLiteralCase extends AbstractApexNode { ASTLiteralCase(LiteralCase node) { 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 77984c06df..f568b9a012 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 @@ -8,7 +8,7 @@ import java.lang.reflect.Field; import apex.jorje.semantic.ast.statement.TypeWhenBlock; -public class ASTTypeWhenBlock extends AbstractApexNode { +public final class ASTTypeWhenBlock extends AbstractApexNode { ASTTypeWhenBlock(TypeWhenBlock node) { 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 12a6a85bd9..db976e06c4 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 @@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.apex.ast; import apex.jorje.semantic.ast.statement.ValueWhenBlock; -public class ASTValueWhenBlock extends AbstractApexNode { +public final class ASTValueWhenBlock extends AbstractApexNode { ASTValueWhenBlock(ValueWhenBlock node) { From 918be2a41969d33d23beadaee78336ef76bfa1d0 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 24 Feb 2020 19:55:57 +0100 Subject: [PATCH 139/235] [java] UselessOverridingMethod - add another test case for synchronized See https://sourceforge.net/p/pmd/bugs/423/ --- .../DirectSynchronizingSubclass.java | 14 ++++++++++++++ .../design/xml/UselessOverridingMethod.xml | 19 ++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSynchronizingSubclass.java diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSynchronizingSubclass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSynchronizingSubclass.java new file mode 100644 index 0000000000..284e0224b4 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/uselessoverridingmethod/DirectSynchronizingSubclass.java @@ -0,0 +1,14 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.design.uselessoverridingmethod; + +public class DirectSynchronizingSubclass extends BaseClass { + + @Override + protected synchronized void doBase() { + // overriding for synchronized + super.doBase(); + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml index e53b33f547..dc0889ee2e 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UselessOverridingMethod.xml @@ -182,7 +182,7 @@ public class Foo extends Bar { - adding synchronized is OK + adding synchronized is OK, see sf-bug #423 0 + + + + Make sure, overriding to add synchronized is Ok, see sf-bug #423 + 0 + From 4bd5a159e504b7f92e00e779da214c4ca102f0b8 Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Thu, 27 Feb 2020 11:36:28 +0100 Subject: [PATCH 140/235] Rewrite to avoid Guava dependency. --- pmd-apex-jorje/pom.xml | 2 +- pmd-core/pom.xml | 6 -- .../cpd/token/internal/BaseTokenFilter.java | 13 +++-- .../pmd/internal/util/IteratorUtil.java | 56 +++++++++++++++++++ .../token/internal/BaseTokenFilterTest.java | 6 +- 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/pmd-apex-jorje/pom.xml b/pmd-apex-jorje/pom.xml index 52c7b7c313..ab7238f975 100644 --- a/pmd-apex-jorje/pom.xml +++ b/pmd-apex-jorje/pom.xml @@ -81,7 +81,7 @@ com.google.guava guava - 26.0-android + 26.0-jre com.google.j2objc diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index 80d980a398..80aab40792 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -186,12 +186,6 @@ system-rules test - - com.google.guava - guava - 26.0-android - compile - diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java index 67cb75937c..7b7f11ca17 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.cpd.token.internal; +import static net.sourceforge.pmd.internal.util.IteratorUtil.AbstractIterator; + import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.LinkedList; @@ -12,8 +14,6 @@ import net.sourceforge.pmd.cpd.token.TokenFilter; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.GenericToken; -import com.google.common.collect.AbstractIterator; - /** * A generic filter for PMD token managers that allows to use comments * to enable / disable analysis of parts of the stream @@ -136,21 +136,22 @@ public abstract class BaseTokenFilter implements TokenFi } @Override - protected T computeNext() { + protected void computeNext() { assert index >= 0; if (startToken != currentToken) { // NOPMD - intentional check for reference equality throw new ConcurrentModificationException("Using iterator after next token has been requested."); } if (index < unprocessedTokens.size()) { - return unprocessedTokens.get(index++); + setNext(unprocessedTokens.get(index++)); } else { final T nextToken = (T) tokenManager.getNextToken(); if (shouldStopProcessing(nextToken)) { - return endOfData(); + done(); + return; } index++; unprocessedTokens.add(nextToken); - return nextToken; + setNext(nextToken); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/IteratorUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/IteratorUtil.java index b1d323cebe..e676447aef 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/IteratorUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/IteratorUtil.java @@ -9,6 +9,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ListIterator; +import java.util.NoSuchElementException; /** @@ -88,4 +89,59 @@ public final class IteratorUtil { } }; } + + public abstract static class AbstractIterator implements Iterator { + + private State state = State.NOT_READY; + private T next = null; + + + @Override + public boolean hasNext() { + switch (state) { + case DONE: + return false; + case READY: + return true; + default: + state = null; + computeNext(); + if (state == null) { + throw new IllegalStateException("Should have called done or setNext"); + } + return state == State.READY; + } + } + + @Override + public T next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + state = State.NOT_READY; + return next; + } + + protected final void setNext(T t) { + next = t; + state = State.READY; + } + + protected final void done() { + state = State.DONE; + } + + protected abstract void computeNext(); + + enum State { + READY, NOT_READY, DONE + } + + @Deprecated + @Override + public final void remove() { + throw new UnsupportedOperationException(); + } + + } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java index 21da8ccc19..2478e0c913 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java @@ -8,6 +8,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.util.Arrays; +import java.util.Collections; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.NoSuchElementException; @@ -17,8 +19,6 @@ import org.junit.Test; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.GenericToken; -import com.google.common.collect.ImmutableList; - public class BaseTokenFilterTest { class StringToken implements GenericToken { @@ -67,7 +67,7 @@ public class BaseTokenFilterTest { class StringTokenManager implements TokenManager { - Iterator iterator = ImmutableList.of("a", "b", "c").iterator(); + Iterator iterator = Collections.unmodifiableList(Arrays.asList("a", "b", "c")).iterator(); @Override public Object getNextToken() { From f3da33944bc89cadf803ddc0dd5e88ac17471c21 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 27 Feb 2020 15:15:50 +0100 Subject: [PATCH 141/235] [java] version 14 is now the new default --- docs/pages/pmd/userdocs/cli_reference.md | 3 ++- docs/pages/pmd/userdocs/tools/ant.md | 4 +++- .../net/sourceforge/pmd/lang/java/JavaLanguageModule.java | 4 ++-- .../net/sourceforge/pmd/LanguageVersionDiscovererTest.java | 6 +++--- .../test/java/net/sourceforge/pmd/LanguageVersionTest.java | 6 +++++- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/pages/pmd/userdocs/cli_reference.md b/docs/pages/pmd/userdocs/cli_reference.md index d4a0d0552a..ca45b101de 100644 --- a/docs/pages/pmd/userdocs/cli_reference.md +++ b/docs/pages/pmd/userdocs/cli_reference.md @@ -182,7 +182,8 @@ 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 (default), 13-preview + * 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 * [ecmascript](pmd_rules_ecmascript.html) (JavaScript) * [jsp](pmd_rules_jsp.html) * [modelica](pmd_rules_modelica.html) diff --git a/docs/pages/pmd/userdocs/tools/ant.md b/docs/pages/pmd/userdocs/tools/ant.md index d1e6c1917d..55a45fc12c 100644 --- a/docs/pages/pmd/userdocs/tools/ant.md +++ b/docs/pages/pmd/userdocs/tools/ant.md @@ -222,8 +222,10 @@ nested element. Possible values are: - + + + 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 4deafd44e9..fa44c5f596 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,9 @@ public class JavaLanguageModule extends BaseLanguageModule { addVersion("11", new JavaLanguageHandler(11), false); addVersion("12", new JavaLanguageHandler(12), false); addVersion("12-preview", new JavaLanguageHandler(12, true), false); - addVersion("13", new JavaLanguageHandler(13), true); // 13 is the default + addVersion("13", new JavaLanguageHandler(13), false); addVersion("13-preview", new JavaLanguageHandler(13, true), false); - addVersion("14", new JavaLanguageHandler(14), false); + addVersion("14", new JavaLanguageHandler(14), true); // 14 is the default addVersion("14-preview", new JavaLanguageHandler(14, true), false); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java index a4fb4a9822..98c660c09e 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionDiscovererTest.java @@ -26,8 +26,8 @@ public class LanguageVersionDiscovererTest { File javaFile = new File("/path/to/MyClass.java"); LanguageVersion languageVersion = discoverer.getDefaultLanguageVersionForFile(javaFile); - assertEquals("LanguageVersion must be Java 13 !", - LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("13"), languageVersion); + assertEquals("LanguageVersion must be Java 14 !", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("14"), languageVersion); } /** @@ -48,7 +48,7 @@ public class LanguageVersionDiscovererTest { public void testLanguageVersionDiscoverer() { PMDConfiguration configuration = new PMDConfiguration(); LanguageVersionDiscoverer languageVersionDiscoverer = configuration.getLanguageVersionDiscoverer(); - assertEquals("Default Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("13"), + assertEquals("Default Java version", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("14"), languageVersionDiscoverer .getDefaultLanguageVersion(LanguageRegistry.getLanguage(JavaLanguageModule.NAME))); configuration diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java index 406fe585ac..7c217d0a25 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/LanguageVersionTest.java @@ -20,7 +20,7 @@ public class LanguageVersionTest extends AbstractLanguageVersionTest { } @Parameters - public static Collection data() { + public static Collection data() { return Arrays.asList(new Object[][] { { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "1.3", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.3"), }, @@ -48,6 +48,10 @@ public class LanguageVersionTest extends AbstractLanguageVersionTest { LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("13"), }, { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "13-preview", LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("13-preview"), }, + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "14", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("14"), }, + { JavaLanguageModule.NAME, JavaLanguageModule.TERSE_NAME, "14-preview", + LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("14-preview"), }, // this one won't be found: case sensitive! { "JAVA", "JAVA", "1.7", null, }, }); From 9d5b7554f0b452fb6857316ce6aa99b2b73fe34c Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 27 Feb 2020 18:30:39 +0100 Subject: [PATCH 142/235] [java] Make sure, SwitchExpressions with yield work with java14 Add additional tests for java14, so that we can later simply remove the java13 preview tests --- pmd-java/etc/grammar/Java.jjt | 11 ++- .../pmd/lang/java/ast/Java14Test.java | 78 ++++++++++++++++ .../java14/SwitchExpressions.java | 90 +++++++++++++++++++ 3 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/SwitchExpressions.java diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 002b1009e3..289bf146ce 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,4 +1,7 @@ /** + * Switch Expressions are now a standard feature of Java 14. + * Andreas Dangel 02/2020 + *==================================================================== * Add support for the yield statement introduced as a preview language * feature with Java 13. See JEP 354. * Add support for text block literals introduces as a preview language @@ -422,6 +425,10 @@ public class JavaParser { return jdkVersion >= 14 || jdkVersion >= 12 && preview; } + private boolean isJava13PreviewOr14() { + return jdkVersion >= 14 || jdkVersion >= 13 && preview; + } + private void checkForSwitchRules() { if (!switchExprAllowed()) { throwParseException("Switch rules in switch statements are only supported with Java 12 or 13 Preview, or Java >= 14"); @@ -440,8 +447,8 @@ public class JavaParser { } private void checkForYieldStatement() { - if (jdkVersion != 13 || !preview) { - throwParseException("Yield statements are only supported with Java 13 Preview"); + if (!isJava13PreviewOr14()) { + throwParseException("Yield statements are only supported with Java 13 Preview or Java >= 14"); } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java new file mode 100644 index 0000000000..b2cb5e5d0c --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java @@ -0,0 +1,78 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + + +package net.sourceforge.pmd.lang.java.ast; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.lang.ast.ParseException; +import net.sourceforge.pmd.lang.java.JavaParsingHelper; + +public class Java14Test { + private final JavaParsingHelper java14 = + JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("14") + .withResourceContext(Java14Test.class, "jdkversiontests/java14/"); + + private final JavaParsingHelper java14p = java14.withDefaultVersion("14-preview"); + private final JavaParsingHelper java13 = java14.withDefaultVersion("13"); + private final JavaParsingHelper java13p = java14.withDefaultVersion("13-preview"); + + /** + * Tests switch expressions with yield. + * The switch expressions have no changed between java 13-preview and 14, so behave exactly the same. + */ + @Test + public void switchExpressions() { + parseAndCheckSwitchExpression(java13p); + parseAndCheckSwitchExpression(java14); + parseAndCheckSwitchExpression(java14p); + } + + /** + * In java13, switch expressions are only available with preview. + */ + @Test(expected = ParseException.class) + public void switchExpressions13ShouldFail() { + parseAndCheckSwitchExpression(java13); + } + + private void parseAndCheckSwitchExpression(JavaParsingHelper parser) { + ASTCompilationUnit compilationUnit = parser.parseResource("SwitchExpressions.java"); + List switchStatements = compilationUnit.findDescendantsOfType(ASTSwitchStatement.class); + Assert.assertEquals(2, switchStatements.size()); + + Assert.assertTrue(switchStatements.get(0).getChild(0) instanceof ASTExpression); + Assert.assertTrue(switchStatements.get(0).getChild(1) instanceof ASTSwitchLabeledExpression); + Assert.assertTrue(switchStatements.get(0).getChild(1).getChild(0) instanceof ASTSwitchLabel); + Assert.assertEquals(3, switchStatements.get(0).getChild(1).getChild(0).getNumChildren()); + Assert.assertTrue(switchStatements.get(0).getChild(2).getChild(0) instanceof ASTSwitchLabel); + Assert.assertFalse(((ASTSwitchLabel) switchStatements.get(0).getChild(2).getChild(0)).isDefault()); + Assert.assertEquals(1, switchStatements.get(0).getChild(2).getChild(0).getNumChildren()); + + Assert.assertTrue(switchStatements.get(1).getChild(3) instanceof ASTSwitchLabeledExpression); + Assert.assertTrue(switchStatements.get(1).getChild(3).getChild(0) instanceof ASTSwitchLabel); + Assert.assertTrue(((ASTSwitchLabel) switchStatements.get(1).getChild(3).getChild(0)).isDefault()); + + List switchExpressions = compilationUnit.findDescendantsOfType(ASTSwitchExpression.class); + Assert.assertEquals(4, switchExpressions.size()); + + Assert.assertEquals(Integer.TYPE, switchExpressions.get(0).getType()); + Assert.assertEquals(4, switchExpressions.get(0).findChildrenOfType(ASTSwitchLabeledExpression.class).size()); + Assert.assertEquals(Integer.TYPE, switchExpressions.get(0).getFirstChildOfType(ASTSwitchLabeledExpression.class) + .getFirstChildOfType(ASTExpression.class).getType()); + + Assert.assertTrue(switchExpressions.get(1).getChild(3) instanceof ASTSwitchLabeledBlock); + + Assert.assertEquals(Integer.TYPE, switchExpressions.get(2).getType()); + List yields = switchExpressions.get(2).findDescendantsOfType(ASTYieldStatement.class); + Assert.assertEquals(4, yields.size()); + Assert.assertEquals("SwitchExpressions.BAZ", yields.get(2).getImage()); + + Assert.assertEquals(String.class, switchExpressions.get(3).getType()); + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/SwitchExpressions.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/SwitchExpressions.java new file mode 100644 index 0000000000..5b29acbd4a --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/SwitchExpressions.java @@ -0,0 +1,90 @@ +/** + * @see JEP 361: Switch Expressions (Standard) + */ +public class SwitchExpressions { + private enum Day { + MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY; + } + + public static final int BAZ = 3; + + public static void main(String[] args) { + Day day = Day.THURSDAY; + + // SwitchStatement + switch (day) { + case MONDAY, FRIDAY, SUNDAY -> System.out.println(6); + case TUESDAY -> System.out.println(7); + case THURSDAY, SATURDAY -> System.out.println(8); + case WEDNESDAY -> System.out.println(9); + } + + // SwitchExpression + int numLetters = switch (day) { + case MONDAY, FRIDAY, SUNDAY -> 6; + case TUESDAY -> 7; + case THURSDAY, SATURDAY -> 8; + case WEDNESDAY -> 9; + }; + System.out.printf("numLetters=%d%n", numLetters); + + howMany(1); + howMany(2); + howMany(3); + + howManyExpr(1); + howManyExpr(2); + howManyExpr(3); + + // SwitchExpression + int j = switch (day) { + case MONDAY -> 0; + case TUESDAY -> 1; + default -> { + int k = day.toString().length(); + int result = f(k); + yield result; + } + }; + System.out.printf("j=%d%n", j); + + String s = "Foo"; + // SwitchExpression + int result = switch (s) { + case "Foo": + yield 1; + case "Bar": + yield 2; + case "Baz": + yield SwitchExpressions.BAZ; + default: + System.out.println("Neither Foo nor Bar, hmmm..."); + yield 0; + }; + System.out.printf("result=%d%n", result); + } + + private static void howMany(int k) { + // SwitchStatement + switch (k) { + case 1 -> System.out.println("one"); + case 2 -> System.out.println("two"); + default -> System.out.println("many"); + } + } + + private static void howManyExpr(int k) { + System.out.println( + // SwitchExpression + switch (k) { + case 1 -> "one"; + case 2 -> "two"; + default -> "many"; + } + ); + } + + private static int f(int k) { + return k*2; + } +} \ No newline at end of file From d16751d136fe4c6e4baf2a8c91b4abe69c3b5298 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 27 Feb 2020 21:11:02 +0100 Subject: [PATCH 143/235] [java] Add support for TextBlocks in Java14 * New escape sequence "\s" added * Added experimental ASTLiteral::getTextBlockContent to retrieve the text block with stripped indentation --- pmd-java/etc/grammar/Java.jjt | 18 ++- .../pmd/lang/java/ast/ASTLiteral.java | 102 ++++++++++++++- .../pmd/lang/java/ast/Java14PreviewTest.java | 119 ++++++++++++++++++ .../pmd/lang/java/ast/Java14Test.java | 3 + .../jdkversiontests/java14/TextBlocks.java | 100 +++++++++++++++ 5 files changed, 335 insertions(+), 7 deletions(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 289bf146ce..fa6df16f37 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -453,8 +453,14 @@ public class JavaParser { } private void checkForTextBlockLiteral() { - if (jdkVersion != 13 || !preview) { - throwParseException("Text block literals are only supported with Java 13 Preview"); + if (jdkVersion != 13 && jdkVersion != 14 || !preview) { + throwParseException("Text block literals are only supported with Java 13 Preview or Java 14 Preview"); + } + } + + private void checkForNewStringSpaceEscape(String s) { + if ((jdkVersion != 14 || !preview) && s.contains("\\s")) { + throwParseException("The escape sequence \"\\s\" is only supported with Java 14 Preview"); } } @@ -688,7 +694,7 @@ TOKEN : > | < #STRING_ESCAPE: "\\" - ( ["n","t","b","r","f","\\","'","\""] + ( ["n","t","b","r","f", "s", "\\","'","\""] // octal escapes | ["0"-"7"] ( ["0"-"7"] )? | ["0"-"3"] ["0"-"7"] ["0"-"7"] @@ -705,7 +711,7 @@ TOKEN : | < TEXT_BLOCK_LITERAL: "\"\"\"" ()* - ( ~["\"", "\\"] | "\"" ~["\""] | "\"\"" ~["\""] | )* + ( ~["\"", "\\"] | "\"" ~["\""] | "\"\"" ~["\""] | | "\\" )* "\"\"\"" > } @@ -1636,8 +1642,8 @@ void Literal() : | t= { checkForBadNumericalLiteralslUsage(t); jjtThis.setImage(t.image); jjtThis.setFloatLiteral();} | t= { checkForBadHexFloatingPointLiteral(); checkForBadNumericalLiteralslUsage(t); jjtThis.setImage(t.image); jjtThis.setFloatLiteral();} | t= {jjtThis.setImage(t.image); jjtThis.setCharLiteral();} -| t= {jjtThis.setImage(t.image); jjtThis.setStringLiteral();} -| t= { checkForTextBlockLiteral(); jjtThis.setImage(t.image); jjtThis.setStringLiteral();} +| t= {jjtThis.setImage(t.image); checkForNewStringSpaceEscape(t.image); jjtThis.setStringLiteral(); } +| t= { checkForTextBlockLiteral(); checkForNewStringSpaceEscape(t.image); jjtThis.setImage(t.image); jjtThis.setStringLiteral();} | BooleanLiteral() | NullLiteral() } 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 7bb2a3e4f9..1920e42b69 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 @@ -5,13 +5,19 @@ package net.sourceforge.pmd.lang.java.ast; import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; import java.util.Locale; import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; + +import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.annotation.InternalApi; public class ASTLiteral extends AbstractJavaTypeNode { + private static final String TEXTBLOCK_DELIMITER = "\"\"\""; private boolean isInt; private boolean isFloat; private boolean isChar; @@ -252,6 +258,100 @@ public class ASTLiteral extends AbstractJavaTypeNode { } public boolean isTextBlock() { - return isString && getImage().startsWith("\"\"\""); + return isString && getImage().startsWith(TEXTBLOCK_DELIMITER); + } + + /** + * Returns the content of the text block after normalizing line endings to LF, + * removing incidental white space surrounding the text block and interpreting + * escape sequences. + */ + @Experimental + public String getTextBlockContent() { + if (!isTextBlock()) { + throw new IllegalArgumentException("This is not a text block"); + } + + int start = determineContentStart(getImage()); + String content = getImage().substring(start, getImage().length() - TEXTBLOCK_DELIMITER.length()); + // normalize line endings to LF + content = content.replaceAll("\r\n|\r", "\n"); + + int prefixLength = Integer.MAX_VALUE; + List lines = Arrays.asList(content.split("\\n")); + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + // compute common prefix + if (!StringUtils.isAllBlank(line) || i == lines.size() - 1) { + prefixLength = Math.min(prefixLength, countLeadingWhitespace(line)); + } + } + if (prefixLength == Integer.MAX_VALUE) { + // common prefix not found + prefixLength = 0; + } + StringBuilder sb = new StringBuilder(content.length()); + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + // remove common whitespace prefix + if (!StringUtils.isAllBlank(line) && line.length() >= prefixLength) { + line = line.substring(prefixLength); + } + line = removeTrailingWhitespace(line); + sb.append(line); + + boolean isLastLine = i == lines.size() - 1; + boolean isFirstLine = i == 0; + if (!isLastLine || !isFirstLine && !StringUtils.isAllBlank(line)) { + sb.append('\n'); + } + } + String result = sb.toString(); + + // interpret escape sequences "\NL" "n","t","b","r","f", "s", "\"", "\'" + result = result + .replaceAll("\\\\\n", "") + .replaceAll("\\\\n", "\n") + .replaceAll("\\\\t", "\t") + .replaceAll("\\\\b", "\b") + .replaceAll("\\\\r", "\r") + .replaceAll("\\\\f", "\f") + .replaceAll("\\\\s", " ") + .replaceAll("\\\\\"", "\"") + .replaceAll("\\\\'", "'"); + return result; + } + + private static int determineContentStart(String s) { + int start = TEXTBLOCK_DELIMITER.length(); // this is the opening delimiter + boolean lineTerminator = false; + // the content begins after at the first character after the line terminator + // of the opening delimiter + while (start < s.length() && Character.isWhitespace(s.charAt(start))) { + if (s.charAt(start) == '\r' || s.charAt(start) == '\n') { + lineTerminator = true; + } else if (lineTerminator) { + // first character after the line terminator + break; + } + start++; + } + return start; + } + + private static int countLeadingWhitespace(String s) { + int count = 0; + while (count < s.length() && Character.isWhitespace(s.charAt(count))) { + count++; + } + return count; + } + + private static String removeTrailingWhitespace(String s) { + int endIndexIncluding = s.length() - 1; + while (endIndexIncluding >= 0 && Character.isWhitespace(s.charAt(endIndexIncluding))) { + endIndexIncluding--; + } + return s.substring(0, endIndexIncluding + 1); } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java new file mode 100644 index 0000000000..30b1d7daa9 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -0,0 +1,119 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + + +package net.sourceforge.pmd.lang.java.ast; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.lang.ast.ParseException; +import net.sourceforge.pmd.lang.java.JavaParsingHelper; + +/** + * Tests new java14 preview features. + */ +public class Java14PreviewTest { + private final JavaParsingHelper java14 = + JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("14") + .withResourceContext(Java14Test.class, "jdkversiontests/java14/"); + + private final JavaParsingHelper java14p = java14.withDefaultVersion("14-preview"); + private final JavaParsingHelper java13 = java14.withDefaultVersion("13"); + + @Test + public void textBlocks() { + ASTCompilationUnit compilationUnit = java14p.parseResource("TextBlocks.java"); + List literals = compilationUnit.findDescendantsOfType(ASTLiteral.class); + Assert.assertEquals(16, literals.size()); + Assert.assertFalse(literals.get(2).isTextBlock()); + Assert.assertFalse(literals.get(12).isTextBlock()); + + List textBlocks = new ArrayList<>(); + for (ASTLiteral literal : literals) { + if (literal.isTextBlock()) { + textBlocks.add(literal); + } + } + Assert.assertEquals(14, textBlocks.size()); + Assert.assertEquals("\"\"\"\n" + + " \n" + + " \n" + + "

Hello, world

\n" + + " \n" + + " \n" + + " \"\"\"", + textBlocks.get(0).getImage()); + Assert.assertEquals("\n" + + " \n" + + "

Hello, world

\n" + + " \n" + + "\n", textBlocks.get(0).getTextBlockContent()); + + // with escapes + Assert.assertEquals("\"\"\"\n" + + " \\r\n" + + " \\r\n" + + "

Hello, world

\\r\n" + + " \\r\n" + + " \\r\n" + + " \"\"\"", textBlocks.get(3).getImage()); + Assert.assertEquals("\r\n" + + " \r\n" + + "

Hello, world

\r\n" + + " \r\n" + + "\r\n", textBlocks.get(3).getTextBlockContent()); + // season + Assert.assertEquals("\"\"\"\n winter\"\"\"", textBlocks.get(4).getImage()); + Assert.assertEquals("winter", textBlocks.get(4).getTextBlockContent()); + // period + Assert.assertEquals("\"\"\"\n" + + " winter\n" + + " \"\"\"", textBlocks.get(5).getImage()); + Assert.assertEquals("winter\n", textBlocks.get(5).getTextBlockContent()); + // empty + Assert.assertEquals("\"\"\"\n \"\"\"", textBlocks.get(8).getImage()); + Assert.assertEquals("", textBlocks.get(8).getTextBlockContent()); + // escaped text block in inside text block + Assert.assertEquals("\"\"\"\n" + + " String text = \\\"\"\"\n" + + " A text block inside a text block\n" + + " \\\"\"\";\n" + + " \"\"\"", textBlocks.get(11).getImage()); + Assert.assertEquals("String text = \"\"\"\n" + + " A text block inside a text block\n" + + "\"\"\";\n", textBlocks.get(11).getTextBlockContent()); + // new escape: line continuation + Assert.assertEquals("\"\"\"\n" + + " Lorem ipsum dolor sit amet, consectetur adipiscing \\\n" + + " elit, sed do eiusmod tempor incididunt ut labore \\\n" + + " et dolore magna aliqua.\\\n" + + " \"\"\"", textBlocks.get(12).getImage()); + Assert.assertEquals("Lorem ipsum dolor sit amet, consectetur adipiscing " + + "elit, sed do eiusmod tempor incididunt ut labore " + + "et dolore magna aliqua.", textBlocks.get(12).getTextBlockContent()); + // new escape: space escape + Assert.assertEquals("\"\"\"\n" + + " red \\s\n" + + " green\\s\n" + + " blue \\s\n" + + " \"\"\"", textBlocks.get(13).getImage()); + Assert.assertEquals("red \n" + + "green \n" + + "blue \n", textBlocks.get(13).getTextBlockContent()); + } + + @Test(expected = ParseException.class) + public void textBlocksBeforeJava14PreviewShouldFail() { + java13.parseResource("TextBlocks.java"); + } + + @Test(expected = ParseException.class) + public void stringEscapeSequenceShouldFail() { + java14.parse("class Foo { String s =\"a\\sb\"; }"); + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java index b2cb5e5d0c..c05e1736c4 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java @@ -13,6 +13,9 @@ import org.junit.Test; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.java.JavaParsingHelper; +/** + * Tests new java14 standard features. + */ public class Java14Test { private final JavaParsingHelper java14 = JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("14") diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java new file mode 100644 index 0000000000..0502961c4c --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java @@ -0,0 +1,100 @@ +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; + +/** + * @see JEP 368: Text Blocks (Second Preview) + */ +public class TextBlocks { + + + public static void main(String[] args) throws Exception { + // note: there is trailing whitespace!! + String html = """ + + +

Hello, world

+ + + """; + System.out.println(html); + + String query = """ + SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB` + WHERE `CITY` = 'INDIANAPOLIS' + ORDER BY `EMP_ID`, `LAST_NAME`; + """; + System.out.println(query); + + ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); + Object obj = engine.eval(""" + function hello() { + print('"Hello, world"'); + } + + hello(); + """); + + // Escape sequences + String htmlWithEscapes = """ + \r + \r +

Hello, world

\r + \r + \r + """; + System.out.println(htmlWithEscapes); + + String season = """ + winter"""; // the six characters w i n t e r + + String period = """ + winter + """; // the seven characters w i n t e r LF + + String greeting = + """ + Hi, "Bob" + """; // the ten characters H i , SP " B o b " LF + + String salutation = + """ + Hi, + "Bob" + """; // the eleven characters H i , LF SP " B o b " LF + + String empty = """ + """; // the empty string (zero length) + + String quote = """ + " + """; // the two characters " LF + + String backslash = """ + \\ + """; // the two characters \ LF + + String normalStringLiteral = "test"; + + String code = + """ + String text = \""" + A text block inside a text block + \"""; + """; + + // new escape sequences + String text = """ + Lorem ipsum dolor sit amet, consectetur adipiscing \ + elit, sed do eiusmod tempor incididunt ut labore \ + et dolore magna aliqua.\ + """; + System.out.println(text); + + String colors = """ + red \s + green\s + blue \s + """; + System.out.println(colors); + } +} From da01ed4fdec616c3914427c66db4f0b6a724cae2 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 27 Feb 2020 21:11:52 +0100 Subject: [PATCH 144/235] Fix checkstyle --- .../pmd/lang/java/symboltable/AbstractJavaScope.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3e7eb4fa51..8d9b368158 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 @@ -27,7 +27,7 @@ public abstract class AbstractJavaScope extends AbstractScope { // Don't throw an exception, type tests patterns are tricky to implement // and given it's a preview feature, and the sym table will be replaced // for 7.0, it's not useful to support them. - // See https://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html#scoping-of-pattern-variables + // See https://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html#scoping-of-pattern-variables // if (declaration instanceof VariableNameDeclaration && getDeclarations().keySet().contains(declaration)) { // throw new RuntimeException(declaration + " is already in the symbol table"); From 81bb8090cf58fc46531a3ed3adfa2918742d0cc9 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 27 Feb 2020 21:14:29 +0100 Subject: [PATCH 145/235] [java] Don't throw IllegalArgument if Literal is not a text block --- .../main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1920e42b69..1a9047d11a 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 @@ -269,7 +269,7 @@ public class ASTLiteral extends AbstractJavaTypeNode { @Experimental public String getTextBlockContent() { if (!isTextBlock()) { - throw new IllegalArgumentException("This is not a text block"); + return getImage(); } int start = determineContentStart(getImage()); From 9a80f1316427f16e4a61d3ae8831fc07f2aec2df Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 27 Feb 2020 21:23:33 +0100 Subject: [PATCH 146/235] [java] Fix new escape sequence "\s" detection --- pmd-java/etc/grammar/Java.jjt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index fa6df16f37..5050ae1e88 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -459,7 +459,7 @@ public class JavaParser { } private void checkForNewStringSpaceEscape(String s) { - if ((jdkVersion != 14 || !preview) && s.contains("\\s")) { + if ((jdkVersion != 14 || !preview) && s.contains("\\s") && !s.contains("\\\\s")) { throwParseException("The escape sequence \"\\s\" is only supported with Java 14 Preview"); } } From 01db024df75baa0634c83ba26961672411d75fc5 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 27 Feb 2020 21:29:21 +0100 Subject: [PATCH 147/235] Update asm to 7.3.1 This add support for java 14 and java 15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3fa29edb15..b12c295799 100644 --- a/pom.xml +++ b/pom.xml @@ -623,7 +623,7 @@ org.ow2.asm asm - 7.1 + 7.3.1 net.sourceforge.pmd From 8a90c2d11d21ed5f0a72ff8fc24f40a32107f3a5 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 09:42:15 +0100 Subject: [PATCH 148/235] [java] ASTLiteral - move the tests for text block content Also fix determining the start of the content, when there are multiple line terminators without indenting whitespace. --- .../pmd/lang/java/ast/ASTLiteral.java | 21 ++-- .../pmd/lang/java/ast/ASTLiteralTest.java | 109 ++++++++++++++++++ .../pmd/lang/java/ast/Java14PreviewTest.java | 58 +--------- .../jdkversiontests/java14/TextBlocks.java | 7 ++ 4 files changed, 132 insertions(+), 63 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java index 1a9047d11a..c9d2d5e4ea 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 @@ -265,17 +265,22 @@ public class ASTLiteral extends AbstractJavaTypeNode { * Returns the content of the text block after normalizing line endings to LF, * removing incidental white space surrounding the text block and interpreting * escape sequences. + * + *

Note: This is a Java 14 Preview Feature. */ @Experimental public String getTextBlockContent() { if (!isTextBlock()) { return getImage(); } + return determineTextBlockContent(getImage()); + } - int start = determineContentStart(getImage()); - String content = getImage().substring(start, getImage().length() - TEXTBLOCK_DELIMITER.length()); + static String determineTextBlockContent(String image) { // normalize line endings to LF - content = content.replaceAll("\r\n|\r", "\n"); + String content = image.replaceAll("\r\n|\r", "\n"); + int start = determineContentStart(content); + content = content.substring(start, content.length() - TEXTBLOCK_DELIMITER.length()); int prefixLength = Integer.MAX_VALUE; List lines = Arrays.asList(content.split("\\n")); @@ -308,7 +313,7 @@ public class ASTLiteral extends AbstractJavaTypeNode { } String result = sb.toString(); - // interpret escape sequences "\NL" "n","t","b","r","f", "s", "\"", "\'" + // interpret escape sequences "\" (line continuation), "n","t","b","r","f", "s", "\"", "\'" result = result .replaceAll("\\\\\n", "") .replaceAll("\\\\n", "\n") @@ -324,15 +329,11 @@ public class ASTLiteral extends AbstractJavaTypeNode { private static int determineContentStart(String s) { int start = TEXTBLOCK_DELIMITER.length(); // this is the opening delimiter - boolean lineTerminator = false; // the content begins after at the first character after the line terminator // of the opening delimiter while (start < s.length() && Character.isWhitespace(s.charAt(start))) { - if (s.charAt(start) == '\r' || s.charAt(start) == '\n') { - lineTerminator = true; - } else if (lineTerminator) { - // first character after the line terminator - break; + if (s.charAt(start) == '\n') { + return start + 1; } start++; } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java index f069ce8a5f..a7ddebeb0e 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java @@ -153,4 +153,113 @@ public class ASTLiteralTest extends BaseParserTest { private static final String TEST6 = "public class Foo {\n double x = 3.14159;\n}"; private static final String TEST7 = "public class Foo {\n char x = 'x';\n}"; + + @Test + public void testTextBlockContent() { + assertEquals("empty text block", "", + ASTLiteral.determineTextBlockContent("\"\"\"\n \"\"\"")); + assertEquals("single line text block", "winter", + ASTLiteral.determineTextBlockContent("\"\"\"\n winter\"\"\"")); + assertEquals("single line text block with LF", "winter\n", + ASTLiteral.determineTextBlockContent("\"\"\"\n" + + " winter\n" + + " \"\"\"")); + assertEquals("basic text block example with html", + "\n" + + " \n" + + "

Hello, world

\n" + + " \n" + + "\n", + ASTLiteral.determineTextBlockContent("\"\"\"\n" + + " \n" + + " \n" + + "

Hello, world

\n" + + " \n" + + " \n" + + " \"\"\"")); + assertEquals("text block with escapes", + "\r\n" + + " \r\n" + + "

Hello, world

\r\n" + + " \r\n" + + "\r\n", + ASTLiteral.determineTextBlockContent("\"\"\"\n" + + " \\r\n" + + " \\r\n" + + "

Hello, world

\\r\n" + + " \\r\n" + + " \\r\n" + + " \"\"\"")); + assertEquals("escaped text block in inside text block", + "String text = \"\"\"\n" + + " A text block inside a text block\n" + + "\"\"\";\n", + ASTLiteral.determineTextBlockContent("\"\"\"\n" + + " String text = \\\"\"\"\n" + + " A text block inside a text block\n" + + " \\\"\"\";\n" + + " \"\"\"")); + assertEquals("new escape: line continuation", + "Lorem ipsum dolor sit amet, consectetur adipiscing " + + "elit, sed do eiusmod tempor incididunt ut labore " + + "et dolore magna aliqua.", + ASTLiteral.determineTextBlockContent("\"\"\"\n" + + " Lorem ipsum dolor sit amet, consectetur adipiscing \\\n" + + " elit, sed do eiusmod tempor incididunt ut labore \\\n" + + " et dolore magna aliqua.\\\n" + + " \"\"\"")); + assertEquals("new escape: space escape", + "red \n" + + "green \n" + + "blue \n", + ASTLiteral.determineTextBlockContent("\"\"\"\n" + + " red \\s\n" + + " green\\s\n" + + " blue \\s\n" + + " \"\"\"")); + assertEquals("with crlf line endings", + "\n" + + " \n" + + "

Hello, world

\n" + + " \n" + + "\n", ASTLiteral.determineTextBlockContent("\"\"\"\r\n" + + " \r\n" + + " \r\n" + + "

Hello, world

\r\n" + + " \r\n" + + " \r\n" + + " \"\"\"")); + assertEquals("with cr line endings", + "\n" + + " \n" + + "

Hello, world

\n" + + " \n" + + "\n", ASTLiteral.determineTextBlockContent("\"\"\"\r" + + " \r" + + " \r" + + "

Hello, world

\r" + + " \r" + + " \r" + + " \"\"\"")); + assertEquals("empty line directly after opening", + "\ntest\n", ASTLiteral.determineTextBlockContent("\"\"\"\n" + + " \n" + + " test\n" + + " \"\"\"")); + assertEquals("empty crlf line directly after opening", + "\ntest\n", ASTLiteral.determineTextBlockContent("\"\"\"\r\n" + + " \r\n" + + " test\r\n" + + " \"\"\"")); + assertEquals("empty line directly after opening without indentation", + "\ntest\n", ASTLiteral.determineTextBlockContent("\"\"\"\n" + + "\n" + + "test\n" + + "\"\"\"")); + assertEquals("empty crlf line directly after opening without indentation", + "\ntest\n", ASTLiteral.determineTextBlockContent("\"\"\"\r\n" + + "\r\n" + + "test\r\n" + + "\"\"\"")); + } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 30b1d7daa9..0b887ead6d 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -29,9 +29,11 @@ public class Java14PreviewTest { public void textBlocks() { ASTCompilationUnit compilationUnit = java14p.parseResource("TextBlocks.java"); List literals = compilationUnit.findDescendantsOfType(ASTLiteral.class); - Assert.assertEquals(16, literals.size()); + Assert.assertEquals(19, literals.size()); Assert.assertFalse(literals.get(2).isTextBlock()); Assert.assertFalse(literals.get(12).isTextBlock()); + Assert.assertFalse(literals.get(17).isTextBlock()); + Assert.assertFalse(literals.get(18).isTextBlock()); List textBlocks = new ArrayList<>(); for (ASTLiteral literal : literals) { @@ -39,7 +41,7 @@ public class Java14PreviewTest { textBlocks.add(literal); } } - Assert.assertEquals(14, textBlocks.size()); + Assert.assertEquals(15, textBlocks.size()); Assert.assertEquals("\"\"\"\n" + " \n" + " \n" @@ -54,57 +56,7 @@ public class Java14PreviewTest { + " \n" + "\n", textBlocks.get(0).getTextBlockContent()); - // with escapes - Assert.assertEquals("\"\"\"\n" - + " \\r\n" - + " \\r\n" - + "

Hello, world

\\r\n" - + " \\r\n" - + " \\r\n" - + " \"\"\"", textBlocks.get(3).getImage()); - Assert.assertEquals("\r\n" - + " \r\n" - + "

Hello, world

\r\n" - + " \r\n" - + "\r\n", textBlocks.get(3).getTextBlockContent()); - // season - Assert.assertEquals("\"\"\"\n winter\"\"\"", textBlocks.get(4).getImage()); - Assert.assertEquals("winter", textBlocks.get(4).getTextBlockContent()); - // period - Assert.assertEquals("\"\"\"\n" - + " winter\n" - + " \"\"\"", textBlocks.get(5).getImage()); - Assert.assertEquals("winter\n", textBlocks.get(5).getTextBlockContent()); - // empty - Assert.assertEquals("\"\"\"\n \"\"\"", textBlocks.get(8).getImage()); - Assert.assertEquals("", textBlocks.get(8).getTextBlockContent()); - // escaped text block in inside text block - Assert.assertEquals("\"\"\"\n" - + " String text = \\\"\"\"\n" - + " A text block inside a text block\n" - + " \\\"\"\";\n" - + " \"\"\"", textBlocks.get(11).getImage()); - Assert.assertEquals("String text = \"\"\"\n" - + " A text block inside a text block\n" - + "\"\"\";\n", textBlocks.get(11).getTextBlockContent()); - // new escape: line continuation - Assert.assertEquals("\"\"\"\n" - + " Lorem ipsum dolor sit amet, consectetur adipiscing \\\n" - + " elit, sed do eiusmod tempor incididunt ut labore \\\n" - + " et dolore magna aliqua.\\\n" - + " \"\"\"", textBlocks.get(12).getImage()); - Assert.assertEquals("Lorem ipsum dolor sit amet, consectetur adipiscing " - + "elit, sed do eiusmod tempor incididunt ut labore " - + "et dolore magna aliqua.", textBlocks.get(12).getTextBlockContent()); - // new escape: space escape - Assert.assertEquals("\"\"\"\n" - + " red \\s\n" - + " green\\s\n" - + " blue \\s\n" - + " \"\"\"", textBlocks.get(13).getImage()); - Assert.assertEquals("red \n" - + "green \n" - + "blue \n", textBlocks.get(13).getTextBlockContent()); + // Note: More tests are in ASTLiteralTest. } @Test(expected = ParseException.class) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java index 0502961c4c..78d13191bc 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java @@ -96,5 +96,12 @@ public class TextBlocks { blue \s """; System.out.println(colors); + + // empty new line as first content + String emptyLine = """ + +test +"""; + System.out.println(emptyLine.replaceAll("\n", "")); } } From 09ff74ea7a27d8dc999ebacd5bc11d88b27e68cb Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 10:38:44 +0100 Subject: [PATCH 149/235] [java] Don't consider VariableDeclaratorIds of Pattern Bindings for now --- .../java/symboltable/AbstractJavaScope.java | 11 ++---- .../ScopeAndDeclarationFinder.java | 10 ++++++ .../pmd/lang/java/ast/Java14PreviewTest.java | 19 +++++++++++ .../java14/PatternMatchingInstanceof.java | 34 +++++++++++++++++++ 4 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java 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 8d9b368158..d93cf75f01 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 @@ -24,14 +24,9 @@ public abstract class AbstractJavaScope extends AbstractScope { } protected void checkForDuplicatedNameDeclaration(NameDeclaration declaration) { - // Don't throw an exception, type tests patterns are tricky to implement - // and given it's a preview feature, and the sym table will be replaced - // for 7.0, it's not useful to support them. - // See https://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html#scoping-of-pattern-variables - - // if (declaration instanceof VariableNameDeclaration && getDeclarations().keySet().contains(declaration)) { - // throw new RuntimeException(declaration + " is already in the symbol table"); - // } + if (declaration instanceof VariableNameDeclaration && getDeclarations().keySet().contains(declaration)) { + throw new RuntimeException(declaration + " is already in the symbol table"); + } } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java index dd3ffd021f..5c3e3a12f9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java @@ -263,6 +263,16 @@ public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter { @Override public Object visit(ASTVariableDeclaratorId node, Object data) { + if (node.isPatternBinding()) { + // Don't consider type test patterns here. It could bind to a name + // that is already in the scope (e.g. field names). + // type tests patterns are tricky to implement + // and given it's a preview feature, and the sym table will be replaced + // for 7.0, it's not useful to support them. + // See https://cr.openjdk.java.net/~briangoetz/amber/pattern-semantics.html#scoping-of-pattern-variables + return super.visit(node, data); + } + VariableNameDeclaration decl = new VariableNameDeclaration(node); node.getScope().addDeclaration(decl); node.setNameDeclaration(decl); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 0b887ead6d..eebc6b7afe 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -68,4 +68,23 @@ public class Java14PreviewTest { public void stringEscapeSequenceShouldFail() { java14.parse("class Foo { String s =\"a\\sb\"; }"); } + + @Test + public void patternMatchingInstanceof() { + ASTCompilationUnit compilationUnit = java14p.parseResource("PatternMatchingInstanceof.java"); + List instanceOfExpressions = compilationUnit.findDescendantsOfType(ASTInstanceOfExpression.class); + Assert.assertEquals(4, instanceOfExpressions.size()); + for (ASTInstanceOfExpression expr : instanceOfExpressions) { + Assert.assertTrue(expr.getChild(1) instanceof ASTTypeTestPattern); + ASTVariableDeclaratorId variable = expr.getChild(1).getFirstChildOfType(ASTVariableDeclaratorId.class); + Assert.assertEquals(String.class, variable.getType()); + Assert.assertEquals("s", variable.getVariableName()); + Assert.assertTrue(variable.isPatternBinding()); + } + } + + @Test(expected = ParseException.class) + public void patternMatchingInstanceofBeforeJava14PreviewShouldFail() { + java14.parseResource("PatternMatchingInstanceof.java"); + } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java new file mode 100644 index 0000000000..9a3fea6d71 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java @@ -0,0 +1,34 @@ +/** + * + * @see JEP 305: Pattern Matching for instanceof (Preview) + */ +public class PatternMatchingInstanceof { + private String s = "other string"; + + public void test() { + Object obj = "abc"; + obj = 1; + if (obj instanceof String s) { + System.out.println("a) obj == s: " + (obj == s)); // true + } else { + System.out.println("b) obj == s: " + (obj == s)); // false + } + + if (!(obj instanceof String s)) { + System.out.println("c) obj == s: " + (obj == s)); // false + } else { + System.out.println("d) obj == s: " + (obj == s)); // true + } + + if (obj instanceof String s && s.length() > 2) { + System.out.println("e) obj == s: " + (obj == s)); // true + } + if (obj instanceof String s || s.length() > 5) { + System.out.println("f) obj == s: " + (obj == s)); // false + } + } + + public static void main(String[] args) { + new PatternMatchingInstanceof().test(); + } +} \ No newline at end of file From b1acb292572640e0336beb2a4a9046f0fb046ad4 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 10:50:00 +0100 Subject: [PATCH 150/235] [java] VariableDeclarationId of pattern bindings is implicitly final --- .../sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java | 3 +++ .../net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java | 1 + .../ast/jdkversiontests/java14/PatternMatchingInstanceof.java | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java index c5383b7c19..331d91edc9 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 @@ -175,6 +175,9 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim return true; } else if (isLambdaParamWithNoType()) { return false; + } else if (isPatternBinding()) { + // implicitly like final, assignment of a pattern binding is not allowed + return true; } if (getParent() instanceof ASTFormalParameter) { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index eebc6b7afe..1f21aa7c54 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -80,6 +80,7 @@ public class Java14PreviewTest { Assert.assertEquals(String.class, variable.getType()); Assert.assertEquals("s", variable.getVariableName()); Assert.assertTrue(variable.isPatternBinding()); + Assert.assertTrue(variable.isFinal()); } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java index 9a3fea6d71..8ec838a50b 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/PatternMatchingInstanceof.java @@ -7,7 +7,7 @@ public class PatternMatchingInstanceof { public void test() { Object obj = "abc"; - obj = 1; + //obj = 1; if (obj instanceof String s) { System.out.println("a) obj == s: " + (obj == s)); // true } else { From adfb2ab129b86698282971f6a147a6707da82509 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 10:51:38 +0100 Subject: [PATCH 151/235] [java] Update grammar --- pmd-java/etc/grammar/Java.jjt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 5050ae1e88..c96bf37657 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,4 +1,8 @@ /** + * Add support for pattern matching for instance of introduced as + * as a preview language feature with Java 14. See JEP 305. + * Clément Fournier 02/2020 + *==================================================================== * Switch Expressions are now a standard feature of Java 14. * Andreas Dangel 02/2020 *==================================================================== From 524925f8cb160b8e839c11d3ba84d8568ff35122 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 11:23:24 +0100 Subject: [PATCH 152/235] [java] Rewrite escape sequence interpreting for text blocks --- .../pmd/lang/java/ast/ASTLiteral.java | 68 +++++++++++++++---- .../pmd/lang/java/ast/ASTLiteralTest.java | 2 + .../pmd/lang/java/ast/Java14PreviewTest.java | 6 +- .../jdkversiontests/java14/TextBlocks.java | 6 ++ 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java index c9d2d5e4ea..86c30b139e 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 @@ -311,20 +311,62 @@ public class ASTLiteral extends AbstractJavaTypeNode { sb.append('\n'); } } - String result = sb.toString(); - // interpret escape sequences "\" (line continuation), "n","t","b","r","f", "s", "\"", "\'" - result = result - .replaceAll("\\\\\n", "") - .replaceAll("\\\\n", "\n") - .replaceAll("\\\\t", "\t") - .replaceAll("\\\\b", "\b") - .replaceAll("\\\\r", "\r") - .replaceAll("\\\\f", "\f") - .replaceAll("\\\\s", " ") - .replaceAll("\\\\\"", "\"") - .replaceAll("\\\\'", "'"); - return result; + interpretEscapeSequences(sb); + return sb.toString(); + } + + private static void interpretEscapeSequences(StringBuilder sb) { + // interpret escape sequences "\" (line continuation), "n","t","b","r","f", "s", "\"", "\'", "\\" + for (int i = 0; i < sb.length(); i++) { + char c = sb.charAt(i); + if (c == '\\' && i < sb.length() - 1) { + char cnext = sb.charAt(i + 1); + switch (cnext) { + case '\n': + // line continuation + sb.delete(i, i + 2); + break; + case '\\': + sb.deleteCharAt(i); + break; + case 'n': + sb.deleteCharAt(i); + sb.setCharAt(i, '\n'); + break; + case 't': + sb.deleteCharAt(i); + sb.setCharAt(i, '\t'); + break; + case 'b': + sb.deleteCharAt(i); + sb.setCharAt(i, '\b'); + break; + case 'r': + sb.deleteCharAt(i); + sb.setCharAt(i, '\r'); + break; + case 'f': + sb.deleteCharAt(i); + sb.setCharAt(i, '\f'); + break; + case 's': + sb.deleteCharAt(i); + sb.setCharAt(i, ' '); + break; + case '"': + sb.deleteCharAt(i); + sb.setCharAt(i, '"'); + break; + case '\'': + sb.deleteCharAt(i); + sb.setCharAt(i, '\''); + break; + default: + // unknown escape - do nothing - it stays + } + } + } } private static int determineContentStart(String s) { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java index a7ddebeb0e..5a460a6327 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTLiteralTest.java @@ -261,5 +261,7 @@ public class ASTLiteralTest extends BaseParserTest { + "\r\n" + "test\r\n" + "\"\"\"")); + assertEquals("text block with backslash escape", "\\test\n", + ASTLiteral.determineTextBlockContent("\"\"\"\n \\\\test\n \"\"\"")); } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 1f21aa7c54..1c4d0aca64 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -29,11 +29,13 @@ public class Java14PreviewTest { public void textBlocks() { ASTCompilationUnit compilationUnit = java14p.parseResource("TextBlocks.java"); List literals = compilationUnit.findDescendantsOfType(ASTLiteral.class); - Assert.assertEquals(19, literals.size()); + Assert.assertEquals(22, literals.size()); Assert.assertFalse(literals.get(2).isTextBlock()); Assert.assertFalse(literals.get(12).isTextBlock()); Assert.assertFalse(literals.get(17).isTextBlock()); Assert.assertFalse(literals.get(18).isTextBlock()); + Assert.assertFalse(literals.get(20).isTextBlock()); + Assert.assertFalse(literals.get(21).isTextBlock()); List textBlocks = new ArrayList<>(); for (ASTLiteral literal : literals) { @@ -41,7 +43,7 @@ public class Java14PreviewTest { textBlocks.add(literal); } } - Assert.assertEquals(15, textBlocks.size()); + Assert.assertEquals(16, textBlocks.size()); Assert.assertEquals("\"\"\"\n" + " \n" + " \n" diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java index 78d13191bc..5ff553185f 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/TextBlocks.java @@ -103,5 +103,11 @@ public class TextBlocks { test """; System.out.println(emptyLine.replaceAll("\n", "")); + + // backslash escapes + String bs = """ + \\test + """; + System.out.println(bs.replaceAll("\n", "")); } } From 8a224462fd333221ad83f02a5f44c87090f8ae6c Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 14:58:52 +0100 Subject: [PATCH 153/235] [java] Add initial support for Java 14 Preview record types --- pmd-java/etc/grammar/Java.jjt | 78 ++++++++++++++++++- .../lang/java/ast/ASTAnyTypeDeclaration.java | 2 +- .../pmd/lang/java/ast/ASTRecordBody.java | 24 ++++++ .../java/ast/ASTRecordBodyDeclaration.java | 24 ++++++ .../pmd/lang/java/ast/ASTRecordComponent.java | 24 ++++++ .../lang/java/ast/ASTRecordComponents.java | 24 ++++++ .../ast/ASTRecordConstructorDeclaration.java | 24 ++++++ .../lang/java/ast/ASTRecordDeclaration.java | 37 +++++++++ .../java/ast/JavaParserDecoratedVisitor.java | 42 ++++++++++ .../java/ast/JavaParserVisitorAdapter.java | 39 ++++++++++ .../java/ast/JavaParserVisitorDecorator.java | 38 +++++++++ .../ast/JavaParserVisitorReducedAdapter.java | 6 ++ .../pmd/lang/java/rule/AbstractJavaRule.java | 42 ++++++++++ .../ScopeAndDeclarationFinder.java | 8 ++ .../pmd/lang/java/ast/Java14PreviewTest.java | 29 +++++++ .../ast/jdkversiontests/java14/Point.java | 10 +++ .../ast/jdkversiontests/java14/Records.java | 17 ++++ 17 files changed, 466 insertions(+), 2 deletions(-) create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordConstructorDeclaration.java create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index c96bf37657..acbb1caf29 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,5 +1,9 @@ /** - * Add support for pattern matching for instance of introduced as + * Add support for record types introduced as a preview language + * feature with Java 14. See JEP 359. + * Andreas Dangel 02/2020 + *==================================================================== + * Add support for pattern matching for instance of introduced * as a preview language feature with Java 14. See JEP 305. * Clément Fournier 02/2020 *==================================================================== @@ -409,6 +413,9 @@ public class JavaParser { if (jdkVersion >= 10 && "var".equals(image)) { throwParseException("With JDK 10, 'var' is a restricted local variable type and cannot be used for type declarations!"); } + if (jdkVersion >= 14 && preview && "record".equals(image)) { + throwParseException("With JDK 14 Preview, 'record' is a restricted identifier and cannot be used for type declarations!"); + } } private void checkForMultipleCaseLabels() { if (!switchExprAllowed()) { @@ -468,6 +475,12 @@ public class JavaParser { } } + private void checkForRecordType() { + if (jdkVersion != 14 || !preview) { + throwParseException("Records are only supported with Java 14 Preview"); + } + } + // 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 @@ -1024,6 +1037,8 @@ void TypeDeclaration(): LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(modifiers) | AnnotationTypeDeclaration(modifiers) + | + LOOKAHEAD({isKeyword("record")}) RecordDeclaration(modifiers) ) } @@ -1102,6 +1117,66 @@ void EnumConstant(): t= {jjtThis.setImage(t.image);} [ Arguments() ] [ ClassOrInterfaceBody() ] } +void RecordDeclaration(int modifiers): +{ + Token t; + jjtThis.setModifiers(modifiers); + checkForRecordType(); +} +{ + t = { + if (!"record".equals(t.image)) { + throw new ParseException("ERROR: expecting record"); + } + } + t= {checkForBadTypeIdentifierUsage(t.image); jjtThis.setImage(t.image);} + [ TypeParameters() ] + "(" RecordComponents() ")" + [ ImplementsList() ] + RecordBody() +} + +void RecordComponents() : +{} +{ + RecordComponent() ("," RecordComponent())* +} + +void RecordComponent(): +{} +{ + (TypeAnnotation())* Type() { jjtThis.setImage(token.image); } +} + +void RecordBody(): +{} +{ + "{" + ( RecordBodyDeclaration() )* + "}" +} + +void RecordBodyDeclaration(): +{} +{ + LOOKAHEAD(4) RecordConstructorDeclaration() + | + ClassOrInterfaceBodyDeclaration() +} + +void RecordConstructorDeclaration(): +{ + int modifiers; +} +{ + (TypeAnnotation())* + modifiers = Modifiers() { jjtThis.setModifiers(modifiers); } + [TypeParameters()] + Name() + [ "throws" NameList() ] + [ "{" ( BlockStatement() )* "}" ] +} + void TypeParameters(): {} { @@ -1135,6 +1210,7 @@ void ClassOrInterfaceBodyDeclaration(): | modifiers = Modifiers() ( LOOKAHEAD(3) ClassOrInterfaceDeclaration(modifiers) | LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(modifiers) + | LOOKAHEAD({isKeyword("record")}) RecordDeclaration(modifiers) | LOOKAHEAD( [ TypeParameters() ] "(" ) ConstructorDeclaration(modifiers) | LOOKAHEAD( Type() ( "[" "]" )* ( "," | "=" | ";" ) ) FieldDeclaration(modifiers) | LOOKAHEAD(2) MethodDeclaration(modifiers) 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 79efaee07c..9ceaa09653 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,7 +12,7 @@ import net.sourceforge.pmd.lang.java.qname.JavaTypeQualifiedName; /** - * Groups enum, class, annotation and interface declarations. + * Groups class, enum, record, annotation and interface declarations. * * @author Clément Fournier */ 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 new file mode 100644 index 0000000000..86a206c63f --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java @@ -0,0 +1,24 @@ +/* + * 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; + +@Experimental +public class ASTRecordBody extends AbstractJavaNode { + ASTRecordBody(int id) { + super(id); + } + + ASTRecordBody(JavaParser p, int id) { + super(p, id); + } + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java new file mode 100644 index 0000000000..0be25c4241 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java @@ -0,0 +1,24 @@ +/* + * 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; + +@Experimental +public class ASTRecordBodyDeclaration extends AbstractJavaNode { + ASTRecordBodyDeclaration(int id) { + super(id); + } + + ASTRecordBodyDeclaration(JavaParser p, int id) { + super(p, id); + } + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} 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 new file mode 100644 index 0000000000..ceca525500 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java @@ -0,0 +1,24 @@ +/* + * 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; + +@Experimental +public class ASTRecordComponent extends AbstractJavaNode { + ASTRecordComponent(int id) { + super(id); + } + + ASTRecordComponent(JavaParser p, int id) { + super(p, id); + } + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java new file mode 100644 index 0000000000..fe1f56d536 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java @@ -0,0 +1,24 @@ +/* + * 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; + +@Experimental +public class ASTRecordComponents extends AbstractJavaNode { + ASTRecordComponents(int id) { + super(id); + } + + ASTRecordComponents(JavaParser p, int id) { + super(p, id); + } + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} 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 new file mode 100644 index 0000000000..e40cc3b51d --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordConstructorDeclaration.java @@ -0,0 +1,24 @@ +/* + * 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; + +@Experimental +public class ASTRecordConstructorDeclaration extends AbstractJavaAccessNode { + ASTRecordConstructorDeclaration(int id) { + super(id); + } + + ASTRecordConstructorDeclaration(JavaParser p, int id) { + super(p, id); + } + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} 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 new file mode 100644 index 0000000000..ae16d26543 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java @@ -0,0 +1,37 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + + +package net.sourceforge.pmd.lang.java.ast; + +import java.util.List; + +import net.sourceforge.pmd.annotation.Experimental; + +@Experimental +public class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { + ASTRecordDeclaration(int id) { + super(id); + } + + ASTRecordDeclaration(JavaParser p, int id) { + super(p, id); + } + + @Override + public Object jjtAccept(JavaParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + @Override + public TypeKind getTypeKind() { + return null; + } + + @Override + public List getDeclarations() { + // TODO Auto-generated method stub + return null; + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java index 1512a3084c..cc67518b6a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java @@ -907,4 +907,46 @@ public class JavaParserDecoratedVisitor implements JavaParserVisitor { visitor.visit(node, data); return visit((JavaNode) node, data); } + + @Override + @Experimental + public Object visit(ASTRecordDeclaration node, Object data) { + visitor.visit(node, data); + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordComponents node, Object data) { + visitor.visit(node, data); + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordComponent node, Object data) { + visitor.visit(node, data); + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordBody node, Object data) { + visitor.visit(node, data); + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordBodyDeclaration node, Object data) { + visitor.visit(node, data); + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordConstructorDeclaration node, Object data) { + visitor.visit(node, data); + return visit((JavaNode) node, data); + } } 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 10a6c0c735..608caecc6a 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 @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.Experimental; + public class JavaParserVisitorAdapter implements JavaParserVisitor { @Override @@ -627,7 +629,44 @@ public class JavaParserVisitorAdapter implements JavaParserVisitor { } @Override + @Experimental public Object visit(ASTTypeTestPattern node, Object data) { return visit((JavaNode) node, data); } + + @Override + @Experimental + public Object visit(ASTRecordDeclaration node, Object data) { + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordComponents node, Object data) { + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordComponent node, Object data) { + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordBody node, Object data) { + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordBodyDeclaration node, Object data) { + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordConstructorDeclaration node, Object data) { + return visit((JavaNode) node, data); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java index aa8f4f46c9..6833b14869 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.annotation.InternalApi; /** @@ -760,7 +761,44 @@ public class JavaParserVisitorDecorator implements JavaParserControllessVisitor } @Override + @Experimental public Object visit(ASTTypeTestPattern node, Object data) { return visitor.visit(node, data); } + + @Override + @Experimental + public Object visit(ASTRecordDeclaration node, Object data) { + return visitor.visit(node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordComponents node, Object data) { + return visitor.visit(node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordComponent node, Object data) { + return visitor.visit(node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordBody node, Object data) { + return visitor.visit(node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordBodyDeclaration node, Object data) { + return visitor.visit(node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordConstructorDeclaration node, Object data) { + return visitor.visit(node, data); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorReducedAdapter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorReducedAdapter.java index a33423ac6a..3c038f5e3a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorReducedAdapter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorReducedAdapter.java @@ -29,6 +29,12 @@ public class JavaParserVisitorReducedAdapter extends JavaParserVisitorAdapter { } + @Override + public Object visit(ASTRecordDeclaration node, Object data) { + return visit((ASTAnyTypeDeclaration) node, data); + } + + public Object visit(ASTAnyTypeDeclaration node, Object data) { return visit((JavaNode) 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 80c9c6fd52..e54b54800e 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 @@ -96,6 +96,12 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; import net.sourceforge.pmd.lang.java.ast.ASTRSIGNEDSHIFT; import net.sourceforge.pmd.lang.java.ast.ASTRUNSIGNEDSHIFT; +import net.sourceforge.pmd.lang.java.ast.ASTRecordBody; +import net.sourceforge.pmd.lang.java.ast.ASTRecordBodyDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTRecordComponent; +import net.sourceforge.pmd.lang.java.ast.ASTRecordComponents; +import net.sourceforge.pmd.lang.java.ast.ASTRecordConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTRecordDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; import net.sourceforge.pmd.lang.java.ast.ASTRelationalExpression; import net.sourceforge.pmd.lang.java.ast.ASTResource; @@ -842,4 +848,40 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse public Object visit(ASTTypeTestPattern node, Object data) { return visit((JavaNode) node, data); } + + @Override + @Experimental + public Object visit(ASTRecordDeclaration node, Object data) { + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordComponents node, Object data) { + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordComponent node, Object data) { + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordBody node, Object data) { + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordBodyDeclaration node, Object data) { + return visit((JavaNode) node, data); + } + + @Override + @Experimental + public Object visit(ASTRecordConstructorDeclaration node, Object data) { + return visit((JavaNode) node, data); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java index 5c3e3a12f9..b2773f4bdc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java @@ -21,6 +21,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; import net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTRecordDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; import net.sourceforge.pmd.lang.java.ast.ASTTryStatement; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; @@ -188,6 +189,13 @@ public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter { return data; } + @Override + public Object visit(ASTRecordDeclaration node, Object data) { + createClassScope(node); + cont(node); + return data; + } + @Override public Object visit(ASTClassOrInterfaceBody node, Object data) { if (node.isAnonymousInnerClass() || node.isEnumChild()) { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 1c4d0aca64..0478d23a7e 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -90,4 +90,33 @@ public class Java14PreviewTest { public void patternMatchingInstanceofBeforeJava14PreviewShouldFail() { java14.parseResource("PatternMatchingInstanceof.java"); } + + @Test + public void recordPoint() { + ASTCompilationUnit compilationUnit = java14p.parseResource("Point.java"); + ASTRecordDeclaration recordDecl = compilationUnit.getFirstDescendantOfType(ASTRecordDeclaration.class); + Assert.assertEquals("Point", recordDecl.getImage()); + List components = recordDecl.getFirstChildOfType(ASTRecordComponents.class) + .findChildrenOfType(ASTRecordComponent.class); + Assert.assertEquals(2, components.size()); + Assert.assertEquals("x", components.get(0).getImage()); + Assert.assertEquals("y", components.get(1).getImage()); + } + + @Test(expected = ParseException.class) + public void recordPointBeforeJava14PreviewShouldFail() { + java14.parseResource("Point.java"); + } + + @Test + public void innerRecords() { + ASTCompilationUnit compilationUnit = java14p.parseResource("Records.java"); + List recordDecls = compilationUnit.findDescendantsOfType(ASTRecordDeclaration.class); + Assert.assertEquals(2, recordDecls.size()); + } + + @Test(expected = ParseException.class) + public void recordIsARestrictedIdentifier() { + java14p.parse("public class record {}"); + } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java new file mode 100644 index 0000000000..ac3fe4fd46 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Point.java @@ -0,0 +1,10 @@ +/** + * @see JEP 359: Records (Preview) + */ +public record Point(int x, int y) { + + public static void main(String[] args) { + Point p = new Point(1, 2); + System.out.println("p = " + p); + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java new file mode 100644 index 0000000000..c8ad6a0f49 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java @@ -0,0 +1,17 @@ +/** + * @see JEP 359: Records (Preview) + */ +public class Records { + + + public record MyComplex(int real, int imaginary) { + }; + + + public record Range(int lo, int hi) { + public Range { + if (lo > hi) /* referring here to the implicit constructor parameters */ + throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi)); + } + } +} From e2d84d6741c65bd1e2f843c72e9e9775f355edb7 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 16:50:57 +0100 Subject: [PATCH 154/235] [java] Add grammar jdoc for new Record types --- pmd-java/etc/grammar/Java.jjt | 2 +- .../ast/ASTClassOrInterfaceDeclaration.java | 2 +- .../pmd/lang/java/ast/ASTPattern.java | 2 +- .../pmd/lang/java/ast/ASTRecordBody.java | 11 +++++++++ .../java/ast/ASTRecordBodyDeclaration.java | 13 +++++++++++ .../pmd/lang/java/ast/ASTRecordComponent.java | 11 +++++++++ .../lang/java/ast/ASTRecordComponents.java | 9 ++++++++ .../ast/ASTRecordConstructorDeclaration.java | 15 ++++++++++++ .../lang/java/ast/ASTRecordDeclaration.java | 23 +++++++++++++++++++ .../java/ast/AbstractAnyTypeDeclaration.java | 3 ++- .../ast/jdkversiontests/java14/Records.java | 1 + 11 files changed, 88 insertions(+), 4 deletions(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index acbb1caf29..34eaf84fc0 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1174,7 +1174,7 @@ void RecordConstructorDeclaration(): [TypeParameters()] Name() [ "throws" NameList() ] - [ "{" ( BlockStatement() )* "}" ] + "{" ( BlockStatement() )* "}" } void TypeParameters(): 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 7c4899e3e3..936083b83b 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 @@ -16,7 +16,7 @@ import net.sourceforge.pmd.util.CollectionUtil; * Represents class and interface declarations. This is a {@linkplain Node#isFindBoundary() find boundary} * for tree traversal methods. * - *
+ * 
  *
  * ClassOrInterfaceDeclaration ::= ( "class" | "interface" )
  *                                 <IDENTIFIER>
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 db9f2b0e8c..7df29d5c58 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
@@ -16,7 +16,7 @@ import net.sourceforge.pmd.annotation.Experimental;
  *
  * 

See https://openjdk.java.net/jeps/305, https://openjdk.java.net/jeps/8235186 * - *

+ * 
  *
  * Pattern ::= {@link ASTTypeTestPattern TypeTestPattern}
  *
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 86a206c63f..7b8f19039c 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
@@ -7,6 +7,17 @@ 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).
+ * This can contain additional methods and or constructors.
+ *
+ * 
+ *
+ * RecordBody ::= "{" ({@linkplain ASTRecordBodyDeclaration RecordBodyDeclaration})* "}"
+ *
+ * 
+ * + */ @Experimental public class ASTRecordBody extends AbstractJavaNode { ASTRecordBody(int id) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java index 0be25c4241..20c5c99ef2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java @@ -7,6 +7,19 @@ package net.sourceforge.pmd.lang.java.ast; import net.sourceforge.pmd.annotation.Experimental; +/** + * This is part of {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature). + * It is can contain either a normal method or constructor or a compact + * {@linkplain ASTRecordConstructorDeclaration RecordConstructorDeclaration}. + * + *
+ *
+ * RecordBodyDeclaration ::=   {@linkplain ASTRecordConstructorDeclaration RecordConstructorDeclaration}
+ *                           | {@linkplain ASTClassOrInterfaceBodyDeclaration ClassOrInterfaceBodyDeclaration}
+ *
+ * 
+ * + */ @Experimental public class ASTRecordBodyDeclaration extends AbstractJavaNode { ASTRecordBodyDeclaration(int id) { 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 ceca525500..fea7905177 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 @@ -7,6 +7,17 @@ package net.sourceforge.pmd.lang.java.ast; import net.sourceforge.pmd.annotation.Experimental; +/** + * Defines a single component of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature). + * + *
+ *
+ * RecordComponent ::= ({@linkplain ASTTypeAnnotation TypeAnnotation})*
+ *                     {@linkplain ASTType Type}
+ *                     <IDENTIFIER>
+ *
+ * 
+ */ @Experimental public class ASTRecordComponent extends AbstractJavaNode { ASTRecordComponent(int id) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java index fe1f56d536..527ad8c2e7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java @@ -7,6 +7,15 @@ package net.sourceforge.pmd.lang.java.ast; import net.sourceforge.pmd.annotation.Experimental; +/** + * Defines the state description of a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature). + * + *
+ *
+ * RecordComponents ::= {@linkplain ASTRecordComponent RecordComponent} ( "," {@linkplain ASTRecordComponent RecordComponent} )*
+ *
+ * 
+ */ @Experimental public class ASTRecordComponents extends AbstractJavaNode { ASTRecordComponents(int id) { 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 e40cc3b51d..e6b2ff793c 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 @@ -7,6 +7,21 @@ package net.sourceforge.pmd.lang.java.ast; import net.sourceforge.pmd.annotation.Experimental; +/** + * This defines a compact constructor for a {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature). + * + *
+ *
+ * RecordConstructorDeclaration ::=  ({@linkplain ASTTypeAnnotation TypeAnnotation})*
+ *                                   {@linkplain ASTModifiers Modifiers}
+ *                                   {@linkplain ASTTypeParameters TypeParameters}?
+ *                                   {@linkplain ASTName Name}
+ *                                   ( "throws" {@linkplain ASTNameList NameList} )?
+ *                                   "{" ( {@linkplain ASTBlockStatement ASTBlockStatement} )* "}"
+ *
+ * 
+ * + */ @Experimental public class ASTRecordConstructorDeclaration extends AbstractJavaAccessNode { ASTRecordConstructorDeclaration(int id) { 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 ae16d26543..924b95a818 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 @@ -8,7 +8,25 @@ package net.sourceforge.pmd.lang.java.ast; import java.util.List; import net.sourceforge.pmd.annotation.Experimental; +import net.sourceforge.pmd.lang.ast.Node; +/** + * A record declaration is a special data class type (JDK 14 preview feature). + * This is a {@linkplain Node#isFindBoundary() find boundary} for tree traversal methods. + * + *
+ *
+ * RecordDeclaration ::= "record"
+ *                       <IDENTIFIER>
+ *                       {@linkplain ASTTypeParameters TypeParameters}?
+ *                       "(" {@linkplain ASTRecordComponents RecordComponents} ")"
+ *                       {@linkplain ASTImplementsList ImplementsList}?
+ *                       {@linkplain ASTRecordBody RecordBody}
+ *
+ * 
+ * + * @see JEP 359: Records (Preview) + */ @Experimental public class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { ASTRecordDeclaration(int id) { @@ -34,4 +52,9 @@ public class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { // TODO Auto-generated method stub return null; } + + @Override + public boolean isFindBoundary() { + return isNested(); + } } 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 9a446bbb4c..52f8c63d0e 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 @@ -33,7 +33,8 @@ public abstract class AbstractAnyTypeDeclaration extends AbstractJavaAccessTypeN @Override public final boolean isNested() { return getParent() instanceof ASTClassOrInterfaceBodyDeclaration - || getParent() instanceof ASTAnnotationTypeMemberDeclaration; + || getParent() instanceof ASTAnnotationTypeMemberDeclaration + || getParent() instanceof ASTRecordBodyDeclaration; } @Override diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java index c8ad6a0f49..32c95eb6ec 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java @@ -5,6 +5,7 @@ public class Records { public record MyComplex(int real, int imaginary) { + public record Nested(int a) {}; }; From 9917e3f422a81cb033ad4dbb091d68f69c2665b6 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 16:56:43 +0100 Subject: [PATCH 155/235] [java] RecordComponents -> RecordComponentList --- pmd-java/etc/grammar/Java.jjt | 6 +++--- ...RecordComponents.java => ASTRecordComponentList.java} | 9 +++++---- .../pmd/lang/java/ast/ASTRecordDeclaration.java | 2 +- .../pmd/lang/java/ast/JavaParserDecoratedVisitor.java | 2 +- .../pmd/lang/java/ast/JavaParserVisitorAdapter.java | 2 +- .../pmd/lang/java/ast/JavaParserVisitorDecorator.java | 2 +- .../sourceforge/pmd/lang/java/rule/AbstractJavaRule.java | 4 ++-- .../sourceforge/pmd/lang/java/ast/Java14PreviewTest.java | 2 +- 8 files changed, 15 insertions(+), 14 deletions(-) rename pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/{ASTRecordComponents.java => ASTRecordComponentList.java} (62%) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 34eaf84fc0..325ad6b74a 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1131,15 +1131,15 @@ void RecordDeclaration(int modifiers): } t= {checkForBadTypeIdentifierUsage(t.image); jjtThis.setImage(t.image);} [ TypeParameters() ] - "(" RecordComponents() ")" + RecordComponentList() [ ImplementsList() ] RecordBody() } -void RecordComponents() : +void RecordComponentList() : {} { - RecordComponent() ("," RecordComponent())* + "(" RecordComponent() ("," RecordComponent())* ")" } void RecordComponent(): diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java similarity index 62% rename from pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java rename to pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java index 527ad8c2e7..ca3108235c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponents.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java @@ -12,17 +12,18 @@ import net.sourceforge.pmd.annotation.Experimental; * *
  *
- * RecordComponents ::= {@linkplain ASTRecordComponent RecordComponent} ( "," {@linkplain ASTRecordComponent RecordComponent} )*
+ * RecordComponentList ::= "("       {@linkplain ASTRecordComponent RecordComponent}
+ *                             ( "," {@linkplain ASTRecordComponent RecordComponent} )* ")"
  *
  * 
*/ @Experimental -public class ASTRecordComponents extends AbstractJavaNode { - ASTRecordComponents(int id) { +public class ASTRecordComponentList extends AbstractJavaNode { + ASTRecordComponentList(int id) { super(id); } - ASTRecordComponents(JavaParser p, int id) { + ASTRecordComponentList(JavaParser p, int id) { super(p, id); } 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 924b95a818..ddc805d601 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 @@ -19,7 +19,7 @@ import net.sourceforge.pmd.lang.ast.Node; * RecordDeclaration ::= "record" * <IDENTIFIER> * {@linkplain ASTTypeParameters TypeParameters}? - * "(" {@linkplain ASTRecordComponents RecordComponents} ")" + * {@linkplain ASTRecordComponentList RecordComponents} * {@linkplain ASTImplementsList ImplementsList}? * {@linkplain ASTRecordBody RecordBody} * diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java index cc67518b6a..a7f99ff1a3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java @@ -917,7 +917,7 @@ public class JavaParserDecoratedVisitor implements JavaParserVisitor { @Override @Experimental - public Object visit(ASTRecordComponents node, Object data) { + public Object visit(ASTRecordComponentList node, Object data) { visitor.visit(node, data); return visit((JavaNode) node, data); } 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 608caecc6a..dd25b22a72 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 @@ -642,7 +642,7 @@ public class JavaParserVisitorAdapter implements JavaParserVisitor { @Override @Experimental - public Object visit(ASTRecordComponents node, Object data) { + public Object visit(ASTRecordComponentList node, Object data) { return visit((JavaNode) node, data); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java index 6833b14869..3aeb67f59a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java @@ -774,7 +774,7 @@ public class JavaParserVisitorDecorator implements JavaParserControllessVisitor @Override @Experimental - public Object visit(ASTRecordComponents node, Object data) { + public Object visit(ASTRecordComponentList node, Object data) { return visitor.visit(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 e54b54800e..37557fef30 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 @@ -99,7 +99,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTRUNSIGNEDSHIFT; import net.sourceforge.pmd.lang.java.ast.ASTRecordBody; import net.sourceforge.pmd.lang.java.ast.ASTRecordBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTRecordComponent; -import net.sourceforge.pmd.lang.java.ast.ASTRecordComponents; +import net.sourceforge.pmd.lang.java.ast.ASTRecordComponentList; import net.sourceforge.pmd.lang.java.ast.ASTRecordConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTRecordDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; @@ -857,7 +857,7 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse @Override @Experimental - public Object visit(ASTRecordComponents node, Object data) { + public Object visit(ASTRecordComponentList node, Object data) { return visit((JavaNode) node, data); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 0478d23a7e..163cfee673 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -96,7 +96,7 @@ public class Java14PreviewTest { ASTCompilationUnit compilationUnit = java14p.parseResource("Point.java"); ASTRecordDeclaration recordDecl = compilationUnit.getFirstDescendantOfType(ASTRecordDeclaration.class); Assert.assertEquals("Point", recordDecl.getImage()); - List components = recordDecl.getFirstChildOfType(ASTRecordComponents.class) + List components = recordDecl.getFirstChildOfType(ASTRecordComponentList.class) .findChildrenOfType(ASTRecordComponent.class); Assert.assertEquals(2, components.size()); Assert.assertEquals("x", components.get(0).getImage()); From 5f43e198d560df26e5a526d9e3cde8a8087d1d81 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 17:01:57 +0100 Subject: [PATCH 156/235] [java] RecordConstructorDeclaration - do not use Name() --- pmd-java/etc/grammar/Java.jjt | 2 +- .../pmd/lang/java/ast/ASTRecordConstructorDeclaration.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 325ad6b74a..1082fe3cc8 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1172,7 +1172,7 @@ void RecordConstructorDeclaration(): (TypeAnnotation())* modifiers = Modifiers() { jjtThis.setModifiers(modifiers); } [TypeParameters()] - Name() + { jjtThis.setImage(token.image); } [ "throws" NameList() ] "{" ( BlockStatement() )* "}" } 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 e6b2ff793c..bbdcbc2830 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 @@ -15,7 +15,7 @@ import net.sourceforge.pmd.annotation.Experimental; * RecordConstructorDeclaration ::= ({@linkplain ASTTypeAnnotation TypeAnnotation})* * {@linkplain ASTModifiers Modifiers} * {@linkplain ASTTypeParameters TypeParameters}? - * {@linkplain ASTName Name} + * <IDENTIFIER> * ( "throws" {@linkplain ASTNameList NameList} )? * "{" ( {@linkplain ASTBlockStatement ASTBlockStatement} )* "}" * From e017def280d7a853a7d27b25fa02dfef7d0d62b6 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 17:35:44 +0100 Subject: [PATCH 157/235] [java] Support vararg/array in RecordComponent and empty components --- pmd-java/etc/grammar/Java.jjt | 7 +++-- .../pmd/lang/java/ast/ASTRecordComponent.java | 23 ++++++++++++++-- .../lang/java/ast/ASTRecordComponentList.java | 3 +-- .../lang/java/ast/ASTRecordDeclaration.java | 4 +++ .../java/ast/ASTVariableDeclaratorId.java | 2 ++ .../pmd/lang/java/ast/Java14PreviewTest.java | 27 ++++++++++++++++--- .../ast/jdkversiontests/java14/Records.java | 6 +++++ 7 files changed, 63 insertions(+), 9 deletions(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 1082fe3cc8..6d9dfc4125 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1139,13 +1139,16 @@ void RecordDeclaration(int modifiers): void RecordComponentList() : {} { - "(" RecordComponent() ("," RecordComponent())* ")" + "(" [ RecordComponent() ("," RecordComponent())* ] ")" } void RecordComponent(): {} { - (TypeAnnotation())* Type() { jjtThis.setImage(token.image); } + (Annotation())* + Type() + [ (Annotation())* "..." {jjtThis.setVarargs();} ] + VariableDeclaratorId() } void RecordBody(): 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 fea7905177..3b3e474a43 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 @@ -12,14 +12,17 @@ import net.sourceforge.pmd.annotation.Experimental; * *
  *
- * RecordComponent ::= ({@linkplain ASTTypeAnnotation TypeAnnotation})*
+ * RecordComponent ::= ({@linkplain ASTAnnotation Annotation})*
  *                     {@linkplain ASTType Type}
- *                     <IDENTIFIER>
+ *                     ( ({@linkplain ASTAnnotation Annotation})* "..." )?
+ *                     {@linkplain ASTVariableDeclaratorId VariableDeclaratorId}
  *
  * 
*/ @Experimental public class ASTRecordComponent extends AbstractJavaNode { + private boolean varargs; + ASTRecordComponent(int id) { super(id); } @@ -32,4 +35,20 @@ public class ASTRecordComponent extends AbstractJavaNode { public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + public boolean isVarargs() { + return varargs; + } + + void setVarargs() { + varargs = true; + } + + public ASTType getTypeNode() { + return getFirstChildOfType(ASTType.class); + } + + public ASTVariableDeclaratorId getVariableDeclaratorId() { + return getFirstChildOfType(ASTVariableDeclaratorId.class); + } } 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 ca3108235c..dbf7367601 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 @@ -12,8 +12,7 @@ import net.sourceforge.pmd.annotation.Experimental; * *
  *
- * RecordComponentList ::= "("       {@linkplain ASTRecordComponent RecordComponent}
- *                             ( "," {@linkplain ASTRecordComponent RecordComponent} )* ")"
+ * RecordComponentList ::= "(" ( {@linkplain ASTRecordComponent RecordComponent} ( "," {@linkplain ASTRecordComponent RecordComponent} )* )? ")"
  *
  * 
*/ 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 ddc805d601..8eebc3450b 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 @@ -57,4 +57,8 @@ public class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { public boolean isFindBoundary() { return isNested(); } + + public List getRecordComponents() { + return getFirstChildOfType(ASTRecordComponentList.class).findChildrenOfType(ASTRecordComponent.class); + } } 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 331d91edc9..a96c120041 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 @@ -303,6 +303,8 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim return null; } else if (getParent() instanceof ASTTypeTestPattern) { return ((ASTTypeTestPattern) getParent()).getTypeNode(); + } else if (getParent() instanceof ASTRecordComponent) { + return ((ASTRecordComponent) getParent()).getTypeNode(); } else { Node n = getParent().getParent(); if (n instanceof ASTLocalVariableDeclaration || n instanceof ASTFieldDeclaration) { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 163cfee673..3c428197c1 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -99,8 +99,8 @@ public class Java14PreviewTest { List components = recordDecl.getFirstChildOfType(ASTRecordComponentList.class) .findChildrenOfType(ASTRecordComponent.class); Assert.assertEquals(2, components.size()); - Assert.assertEquals("x", components.get(0).getImage()); - Assert.assertEquals("y", components.get(1).getImage()); + Assert.assertEquals("x", components.get(0).getVariableDeclaratorId().getImage()); + Assert.assertEquals("y", components.get(1).getVariableDeclaratorId().getImage()); } @Test(expected = ParseException.class) @@ -112,7 +112,28 @@ public class Java14PreviewTest { public void innerRecords() { ASTCompilationUnit compilationUnit = java14p.parseResource("Records.java"); List recordDecls = compilationUnit.findDescendantsOfType(ASTRecordDeclaration.class); - Assert.assertEquals(2, recordDecls.size()); + Assert.assertEquals(5, recordDecls.size()); + + ASTRecordDeclaration range = recordDecls.get(1); + Assert.assertEquals("Range", range.getImage()); + Assert.assertEquals(2, range.getRecordComponents().size()); + List rangeConstructors = range.findDescendantsOfType(ASTRecordConstructorDeclaration.class); + Assert.assertEquals(1, rangeConstructors.size()); + Assert.assertEquals("Range", rangeConstructors.get(0).getImage()); + + ASTRecordDeclaration varRec = recordDecls.get(2); + Assert.assertEquals("VarRec", varRec.getImage()); + Assert.assertEquals("x", varRec.getRecordComponents().get(0).getVariableDeclaratorId().getImage()); + Assert.assertTrue(varRec.getRecordComponents().get(0).isVarargs()); + + ASTRecordDeclaration arrayRec = recordDecls.get(3); + Assert.assertEquals("ArrayRec", arrayRec.getImage()); + Assert.assertEquals("x", arrayRec.getRecordComponents().get(0).getVariableDeclaratorId().getImage()); + Assert.assertTrue(arrayRec.getRecordComponents().get(0).getVariableDeclaratorId().hasArrayType()); + + ASTRecordDeclaration emptyRec = recordDecls.get(4); + Assert.assertEquals("EmptyRec", emptyRec.getImage()); + Assert.assertEquals(0, emptyRec.getRecordComponents().size()); } @Test(expected = ParseException.class) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java index 32c95eb6ec..5f12b5a159 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java @@ -15,4 +15,10 @@ public class Records { throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi)); } } + + public record VarRec(int ... x) {}; + + public record ArrayRec(int x[]) {}; + + public record EmptyRec() {}; } From 68ba8a967dd000847edf8f7a0e7e865e285558c4 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 17:41:26 +0100 Subject: [PATCH 158/235] [java] Test nested record type --- .../pmd/lang/java/ast/Java14PreviewTest.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 3c428197c1..7c788c2af4 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -96,6 +96,7 @@ public class Java14PreviewTest { ASTCompilationUnit compilationUnit = java14p.parseResource("Point.java"); ASTRecordDeclaration recordDecl = compilationUnit.getFirstDescendantOfType(ASTRecordDeclaration.class); Assert.assertEquals("Point", recordDecl.getImage()); + Assert.assertFalse(recordDecl.isNested()); List components = recordDecl.getFirstChildOfType(ASTRecordComponentList.class) .findChildrenOfType(ASTRecordComponent.class); Assert.assertEquals(2, components.size()); @@ -111,27 +112,35 @@ public class Java14PreviewTest { @Test public void innerRecords() { ASTCompilationUnit compilationUnit = java14p.parseResource("Records.java"); - List recordDecls = compilationUnit.findDescendantsOfType(ASTRecordDeclaration.class); - Assert.assertEquals(5, recordDecls.size()); + List recordDecls = compilationUnit.findDescendantsOfType(ASTRecordDeclaration.class, true); + Assert.assertEquals(6, recordDecls.size()); - ASTRecordDeclaration range = recordDecls.get(1); + ASTRecordDeclaration complex = recordDecls.get(0); + Assert.assertEquals("MyComplex", complex.getImage()); + Assert.assertTrue(complex.isNested()); + + ASTRecordDeclaration nested = recordDecls.get(1); + Assert.assertEquals("Nested", nested.getImage()); + Assert.assertTrue(nested.isNested()); + + ASTRecordDeclaration range = recordDecls.get(2); Assert.assertEquals("Range", range.getImage()); Assert.assertEquals(2, range.getRecordComponents().size()); List rangeConstructors = range.findDescendantsOfType(ASTRecordConstructorDeclaration.class); Assert.assertEquals(1, rangeConstructors.size()); Assert.assertEquals("Range", rangeConstructors.get(0).getImage()); - ASTRecordDeclaration varRec = recordDecls.get(2); + ASTRecordDeclaration varRec = recordDecls.get(3); Assert.assertEquals("VarRec", varRec.getImage()); Assert.assertEquals("x", varRec.getRecordComponents().get(0).getVariableDeclaratorId().getImage()); Assert.assertTrue(varRec.getRecordComponents().get(0).isVarargs()); - ASTRecordDeclaration arrayRec = recordDecls.get(3); + ASTRecordDeclaration arrayRec = recordDecls.get(4); Assert.assertEquals("ArrayRec", arrayRec.getImage()); Assert.assertEquals("x", arrayRec.getRecordComponents().get(0).getVariableDeclaratorId().getImage()); Assert.assertTrue(arrayRec.getRecordComponents().get(0).getVariableDeclaratorId().hasArrayType()); - ASTRecordDeclaration emptyRec = recordDecls.get(4); + ASTRecordDeclaration emptyRec = recordDecls.get(5); Assert.assertEquals("EmptyRec", emptyRec.getImage()); Assert.assertEquals(0, emptyRec.getRecordComponents().size()); } From fa28aa7e2328c88bb5a054d3bd0fdd48d57c9046 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 17:59:39 +0100 Subject: [PATCH 159/235] [java] Test annotations with RecordComponents --- pmd-java/etc/grammar/Java.jjt | 2 +- .../pmd/lang/java/ast/ASTRecordComponent.java | 2 +- .../pmd/lang/java/ast/Java14PreviewTest.java | 4 ++++ .../java/ast/jdkversiontests/java14/Records.java | 16 +++++++++++----- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 6d9dfc4125..10e7f995bd 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1147,7 +1147,7 @@ void RecordComponent(): { (Annotation())* Type() - [ (Annotation())* "..." {jjtThis.setVarargs();} ] + [ "..." {jjtThis.setVarargs();} ] VariableDeclaratorId() } 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 3b3e474a43..390a8ab8df 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 @@ -14,7 +14,7 @@ import net.sourceforge.pmd.annotation.Experimental; * * RecordComponent ::= ({@linkplain ASTAnnotation Annotation})* * {@linkplain ASTType Type} - * ( ({@linkplain ASTAnnotation Annotation})* "..." )? + * ( "..." )? * {@linkplain ASTVariableDeclaratorId VariableDeclaratorId} * *
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 7c788c2af4..204dd41944 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -118,6 +118,8 @@ public class Java14PreviewTest { ASTRecordDeclaration complex = recordDecls.get(0); Assert.assertEquals("MyComplex", complex.getImage()); Assert.assertTrue(complex.isNested()); + Assert.assertEquals(0, complex.getRecordComponents().get(0).findChildrenOfType(ASTAnnotation.class).size()); + Assert.assertEquals(1, complex.getRecordComponents().get(1).findChildrenOfType(ASTAnnotation.class).size()); ASTRecordDeclaration nested = recordDecls.get(1); Assert.assertEquals("Nested", nested.getImage()); @@ -134,6 +136,8 @@ public class Java14PreviewTest { Assert.assertEquals("VarRec", varRec.getImage()); Assert.assertEquals("x", varRec.getRecordComponents().get(0).getVariableDeclaratorId().getImage()); Assert.assertTrue(varRec.getRecordComponents().get(0).isVarargs()); + Assert.assertEquals(2, varRec.getRecordComponents().get(0).findChildrenOfType(ASTAnnotation.class).size()); + Assert.assertEquals(1, varRec.getRecordComponents().get(0).getTypeNode().findDescendantsOfType(ASTAnnotation.class).size()); ASTRecordDeclaration arrayRec = recordDecls.get(4); Assert.assertEquals("ArrayRec", arrayRec.getImage()); diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java index 5f12b5a159..507116941e 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java @@ -1,12 +1,18 @@ +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + /** * @see JEP 359: Records (Preview) */ public class Records { + @Target(ElementType.TYPE_USE) + @interface Nullable { + } - public record MyComplex(int real, int imaginary) { + public record MyComplex(int real, @Deprecated int imaginary) { public record Nested(int a) {}; - }; + } public record Range(int lo, int hi) { @@ -16,9 +22,9 @@ public class Records { } } - public record VarRec(int ... x) {}; + public record VarRec(@Nullable @Deprecated String @Nullable ... x) {} - public record ArrayRec(int x[]) {}; + public record ArrayRec(int x[]) {} - public record EmptyRec() {}; + public record EmptyRec() {} } From 0ecd1da200ae59c03048fe6e99c19fd598a0dbe3 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 18:16:19 +0100 Subject: [PATCH 160/235] [java] Get rid of RecordBodyDeclaration node --- pmd-java/etc/grammar/Java.jjt | 2 +- .../pmd/lang/java/ast/ASTRecordBody.java | 3 +- .../java/ast/ASTRecordBodyDeclaration.java | 37 ------------------- .../lang/java/ast/ASTRecordDeclaration.java | 4 ++ .../java/ast/AbstractAnyTypeDeclaration.java | 2 +- .../java/ast/JavaParserDecoratedVisitor.java | 7 ---- .../java/ast/JavaParserVisitorAdapter.java | 6 --- .../java/ast/JavaParserVisitorDecorator.java | 6 --- .../pmd/lang/java/rule/AbstractJavaRule.java | 7 ---- .../pmd/lang/java/ast/Java14PreviewTest.java | 12 +++--- 10 files changed, 14 insertions(+), 72 deletions(-) delete mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 10e7f995bd..1e80bc67d7 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1159,7 +1159,7 @@ void RecordBody(): "}" } -void RecordBodyDeclaration(): +void RecordBodyDeclaration() #void : {} { LOOKAHEAD(4) RecordConstructorDeclaration() 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 7b8f19039c..a066bfa2aa 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 @@ -13,7 +13,8 @@ import net.sourceforge.pmd.annotation.Experimental; * *
  *
- * RecordBody ::= "{" ({@linkplain ASTRecordBodyDeclaration RecordBodyDeclaration})* "}"
+ * RecordBody ::= "{" (   {@linkplain ASTRecordConstructorDeclaration RecordConstructorDeclaration}
+ *                      | {@linkplain ASTClassOrInterfaceBodyDeclaration ClassOrInterfaceBodyDeclaration} )* "}"
  *
  * 
* diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.java deleted file mode 100644 index 20c5c99ef2..0000000000 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRecordBodyDeclaration.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.java.ast; - -import net.sourceforge.pmd.annotation.Experimental; - -/** - * This is part of {@linkplain ASTRecordDeclaration RecordDeclaration} (JDK 14 preview feature). - * It is can contain either a normal method or constructor or a compact - * {@linkplain ASTRecordConstructorDeclaration RecordConstructorDeclaration}. - * - *
- *
- * RecordBodyDeclaration ::=   {@linkplain ASTRecordConstructorDeclaration RecordConstructorDeclaration}
- *                           | {@linkplain ASTClassOrInterfaceBodyDeclaration ClassOrInterfaceBodyDeclaration}
- *
- * 
- * - */ -@Experimental -public class ASTRecordBodyDeclaration extends AbstractJavaNode { - ASTRecordBodyDeclaration(int id) { - super(id); - } - - ASTRecordBodyDeclaration(JavaParser p, int id) { - super(p, id); - } - - @Override - public Object jjtAccept(JavaParserVisitor visitor, Object data) { - return visitor.visit(this, data); - } -} 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 8eebc3450b..aeb882f884 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 @@ -61,4 +61,8 @@ public class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { public List getRecordComponents() { return getFirstChildOfType(ASTRecordComponentList.class).findChildrenOfType(ASTRecordComponent.class); } + + public String getName() { + return getImage(); + } } 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 52f8c63d0e..fbdacd93bc 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 @@ -34,7 +34,7 @@ public abstract class AbstractAnyTypeDeclaration extends AbstractJavaAccessTypeN public final boolean isNested() { return getParent() instanceof ASTClassOrInterfaceBodyDeclaration || getParent() instanceof ASTAnnotationTypeMemberDeclaration - || getParent() instanceof ASTRecordBodyDeclaration; + || getParent() instanceof ASTRecordBody; } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java index a7f99ff1a3..ab614443bc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserDecoratedVisitor.java @@ -936,13 +936,6 @@ public class JavaParserDecoratedVisitor implements JavaParserVisitor { return visit((JavaNode) node, data); } - @Override - @Experimental - public Object visit(ASTRecordBodyDeclaration node, Object data) { - visitor.visit(node, data); - return visit((JavaNode) node, data); - } - @Override @Experimental public Object visit(ASTRecordConstructorDeclaration node, Object data) { 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 dd25b22a72..fc0cc8e59f 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 @@ -658,12 +658,6 @@ public class JavaParserVisitorAdapter implements JavaParserVisitor { return visit((JavaNode) node, data); } - @Override - @Experimental - public Object visit(ASTRecordBodyDeclaration node, Object data) { - return visit((JavaNode) node, data); - } - @Override @Experimental public Object visit(ASTRecordConstructorDeclaration node, Object data) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java index 3aeb67f59a..e56a5b0925 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaParserVisitorDecorator.java @@ -790,12 +790,6 @@ public class JavaParserVisitorDecorator implements JavaParserControllessVisitor return visitor.visit(node, data); } - @Override - @Experimental - public Object visit(ASTRecordBodyDeclaration node, Object data) { - return visitor.visit(node, data); - } - @Override @Experimental public Object visit(ASTRecordConstructorDeclaration node, Object 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 37557fef30..2c243390d3 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 @@ -97,7 +97,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; import net.sourceforge.pmd.lang.java.ast.ASTRSIGNEDSHIFT; import net.sourceforge.pmd.lang.java.ast.ASTRUNSIGNEDSHIFT; import net.sourceforge.pmd.lang.java.ast.ASTRecordBody; -import net.sourceforge.pmd.lang.java.ast.ASTRecordBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTRecordComponent; import net.sourceforge.pmd.lang.java.ast.ASTRecordComponentList; import net.sourceforge.pmd.lang.java.ast.ASTRecordConstructorDeclaration; @@ -873,12 +872,6 @@ public abstract class AbstractJavaRule extends AbstractRule implements JavaParse return visit((JavaNode) node, data); } - @Override - @Experimental - public Object visit(ASTRecordBodyDeclaration node, Object data) { - return visit((JavaNode) node, data); - } - @Override @Experimental public Object visit(ASTRecordConstructorDeclaration node, Object data) { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 204dd41944..1b92c6b7dc 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -116,36 +116,36 @@ public class Java14PreviewTest { Assert.assertEquals(6, recordDecls.size()); ASTRecordDeclaration complex = recordDecls.get(0); - Assert.assertEquals("MyComplex", complex.getImage()); + Assert.assertEquals("MyComplex", complex.getName()); Assert.assertTrue(complex.isNested()); Assert.assertEquals(0, complex.getRecordComponents().get(0).findChildrenOfType(ASTAnnotation.class).size()); Assert.assertEquals(1, complex.getRecordComponents().get(1).findChildrenOfType(ASTAnnotation.class).size()); ASTRecordDeclaration nested = recordDecls.get(1); - Assert.assertEquals("Nested", nested.getImage()); + Assert.assertEquals("Nested", nested.getName()); Assert.assertTrue(nested.isNested()); ASTRecordDeclaration range = recordDecls.get(2); - Assert.assertEquals("Range", range.getImage()); + Assert.assertEquals("Range", range.getName()); Assert.assertEquals(2, range.getRecordComponents().size()); List rangeConstructors = range.findDescendantsOfType(ASTRecordConstructorDeclaration.class); Assert.assertEquals(1, rangeConstructors.size()); Assert.assertEquals("Range", rangeConstructors.get(0).getImage()); ASTRecordDeclaration varRec = recordDecls.get(3); - Assert.assertEquals("VarRec", varRec.getImage()); + Assert.assertEquals("VarRec", varRec.getName()); Assert.assertEquals("x", varRec.getRecordComponents().get(0).getVariableDeclaratorId().getImage()); Assert.assertTrue(varRec.getRecordComponents().get(0).isVarargs()); Assert.assertEquals(2, varRec.getRecordComponents().get(0).findChildrenOfType(ASTAnnotation.class).size()); Assert.assertEquals(1, varRec.getRecordComponents().get(0).getTypeNode().findDescendantsOfType(ASTAnnotation.class).size()); ASTRecordDeclaration arrayRec = recordDecls.get(4); - Assert.assertEquals("ArrayRec", arrayRec.getImage()); + Assert.assertEquals("ArrayRec", arrayRec.getName()); Assert.assertEquals("x", arrayRec.getRecordComponents().get(0).getVariableDeclaratorId().getImage()); Assert.assertTrue(arrayRec.getRecordComponents().get(0).getVariableDeclaratorId().hasArrayType()); ASTRecordDeclaration emptyRec = recordDecls.get(5); - Assert.assertEquals("EmptyRec", emptyRec.getImage()); + Assert.assertEquals("EmptyRec", emptyRec.getName()); Assert.assertEquals(0, emptyRec.getRecordComponents().size()); } From 7d3df99134379629b1848ad324840592b592477b Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 18:41:22 +0100 Subject: [PATCH 161/235] [java] RecordBody - test with more annotation and use deep lookahead Record constructors are not allowed to throw exceptions. --- pmd-java/etc/grammar/Java.jjt | 5 ++--- .../pmd/lang/java/ast/Java14PreviewTest.java | 1 + .../java/ast/jdkversiontests/java14/Records.java | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 1e80bc67d7..90b89ac6ff 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1162,9 +1162,9 @@ void RecordBody(): void RecordBodyDeclaration() #void : {} { - LOOKAHEAD(4) RecordConstructorDeclaration() + LOOKAHEAD(ClassOrInterfaceBodyDeclaration()) ClassOrInterfaceBodyDeclaration() | - ClassOrInterfaceBodyDeclaration() + RecordConstructorDeclaration() } void RecordConstructorDeclaration(): @@ -1176,7 +1176,6 @@ void RecordConstructorDeclaration(): modifiers = Modifiers() { jjtThis.setModifiers(modifiers); } [TypeParameters()] { jjtThis.setImage(token.image); } - [ "throws" NameList() ] "{" ( BlockStatement() )* "}" } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 1b92c6b7dc..8b1645e660 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -120,6 +120,7 @@ public class Java14PreviewTest { Assert.assertTrue(complex.isNested()); Assert.assertEquals(0, complex.getRecordComponents().get(0).findChildrenOfType(ASTAnnotation.class).size()); Assert.assertEquals(1, complex.getRecordComponents().get(1).findChildrenOfType(ASTAnnotation.class).size()); + Assert.assertTrue(complex.getChild(1).getChild(0).getChild(1) instanceof ASTConstructorDeclaration); ASTRecordDeclaration nested = recordDecls.get(1); Assert.assertEquals("Nested", nested.getName()); diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java index 507116941e..4135ed7044 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java @@ -7,15 +7,26 @@ import java.lang.annotation.ElementType; public class Records { @Target(ElementType.TYPE_USE) - @interface Nullable { - } + @interface Nullable { } + + @Target({ElementType.CONSTRUCTOR, ElementType.PARAMETER}) + @interface MyAnnotation { } public record MyComplex(int real, @Deprecated int imaginary) { + // explicit declaration of a canonical constructor + @MyAnnotation + public MyComplex(@MyAnnotation int real, int imaginary) { + if (real > 100) throw new IllegalArgumentException("too big"); + this.real = real; + this.imaginary = imaginary; + } public record Nested(int a) {}; } public record Range(int lo, int hi) { + // compact record constructor + @MyAnnotation public Range { if (lo > hi) /* referring here to the implicit constructor parameters */ throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi)); From 2ace55f635a9ddd655d932737c11266b3858207c Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 18:59:16 +0100 Subject: [PATCH 162/235] [java] Support RecordConstructorDeclaration as AnyTypeBodyDeclaration --- .../pmd/lang/java/ast/ASTAnyTypeBodyDeclaration.java | 4 +++- .../pmd/lang/java/ast/ASTAnyTypeDeclaration.java | 2 +- .../java/ast/ASTRecordConstructorDeclaration.java | 12 +++++++++++- .../pmd/lang/java/ast/ASTRecordDeclaration.java | 5 ++--- .../lang/java/ast/internal/PrettyPrintingUtil.java | 3 +++ .../multifile/signature/JavaOperationSignature.java | 10 ++++++---- .../pmd/lang/java/ast/Java14PreviewTest.java | 5 ++++- .../java/ast/jdkversiontests/java14/Records.java | 8 ++++++-- 8 files changed, 36 insertions(+), 13 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeBodyDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeBodyDeclaration.java index 5196b3f993..74465075ae 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeBodyDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeBodyDeclaration.java @@ -58,7 +58,9 @@ public interface ASTAnyTypeBodyDeclaration extends JavaNode { /** See {@link ASTAnnotationTypeDeclaration}. */ ANNOTATION, /** No child, {@link #getDeclarationNode()} will return null. */ - EMPTY + EMPTY, + /** See {@link ASTRecordConstructorDeclaration}. */ + RECORD_CONSTRUCTOR } } 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 9ceaa09653..2c39b1dbf8 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 @@ -101,7 +101,7 @@ public interface ASTAnyTypeDeclaration extends TypeNode, JavaQualifiableNode, Ac */ @Deprecated enum TypeKind { - CLASS, INTERFACE, ENUM, ANNOTATION; + CLASS, INTERFACE, ENUM, ANNOTATION, RECORD; public String getPrintableName() { 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 bbdcbc2830..9ab85f673b 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 @@ -23,7 +23,7 @@ import net.sourceforge.pmd.annotation.Experimental; * */ @Experimental -public class ASTRecordConstructorDeclaration extends AbstractJavaAccessNode { +public class ASTRecordConstructorDeclaration extends AbstractJavaAccessNode implements ASTAnyTypeBodyDeclaration { ASTRecordConstructorDeclaration(int id) { super(id); } @@ -36,4 +36,14 @@ public class ASTRecordConstructorDeclaration extends AbstractJavaAccessNode { public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + @Override + public ASTRecordConstructorDeclaration getDeclarationNode() { + return this; + } + + @Override + public DeclarationKind getKind() { + return DeclarationKind.RECORD_CONSTRUCTOR; + } } 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 aeb882f884..6cc2355ef4 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 @@ -44,13 +44,12 @@ public class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { @Override public TypeKind getTypeKind() { - return null; + return TypeKind.RECORD; } @Override public List getDeclarations() { - // TODO Auto-generated method stub - return null; + return getFirstChildOfType(ASTRecordBody.class).findChildrenOfType(ASTAnyTypeBodyDeclaration.class); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtil.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtil.java index c79eb94ddf..ca16c0d473 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtil.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/internal/PrettyPrintingUtil.java @@ -12,6 +12,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTRecordDeclaration; /** * @author Clément Fournier @@ -70,6 +71,8 @@ public final class PrettyPrintingUtil { return "annotation"; } else if (decl instanceof ASTEnumDeclaration) { return "enum"; + } else if (decl instanceof ASTRecordDeclaration) { + return "record"; } return "class"; } 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 2c20589f93..a41a066c1e 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 @@ -125,11 +125,13 @@ public final class JavaOperationSignature extends JavaSignature rangeConstructors = range.findDescendantsOfType(ASTRecordConstructorDeclaration.class); Assert.assertEquals(1, rangeConstructors.size()); Assert.assertEquals("Range", rangeConstructors.get(0).getImage()); + Assert.assertEquals(2, range.getDeclarations().size()); ASTRecordDeclaration varRec = recordDecls.get(3); Assert.assertEquals("VarRec", varRec.getName()); diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java index 4135ed7044..cdd93fc7cd 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java @@ -20,7 +20,7 @@ public class Records { this.real = real; this.imaginary = imaginary; } - public record Nested(int a) {}; + public record Nested(int a) {} } @@ -31,11 +31,15 @@ public class Records { if (lo > hi) /* referring here to the implicit constructor parameters */ throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi)); } + + public void foo() { } } public record VarRec(@Nullable @Deprecated String @Nullable ... x) {} public record ArrayRec(int x[]) {} - public record EmptyRec() {} + public record EmptyRec() { + public void foo() { } + } } From ee211d42b1e3368cb226a9a00ea159d63c1f5e0d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 19:07:03 +0100 Subject: [PATCH 163/235] [java] Remove unneccessary annotation parsing --- pmd-java/etc/grammar/Java.jjt | 1 - .../net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 90b89ac6ff..255e06ef5b 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1172,7 +1172,6 @@ void RecordConstructorDeclaration(): int modifiers; } { - (TypeAnnotation())* modifiers = Modifiers() { jjtThis.setModifiers(modifiers); } [TypeParameters()] { jjtThis.setImage(token.image); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 78013f6c00..c39e293399 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -134,6 +134,7 @@ public class Java14PreviewTest { List rangeConstructors = range.findDescendantsOfType(ASTRecordConstructorDeclaration.class); Assert.assertEquals(1, rangeConstructors.size()); Assert.assertEquals("Range", rangeConstructors.get(0).getImage()); + Assert.assertTrue(rangeConstructors.get(0).getChild(0) instanceof ASTAnnotation); Assert.assertEquals(2, range.getDeclarations().size()); ASTRecordDeclaration varRec = recordDecls.get(3); From eae6e96db0b469e72e61e6e0cd1ee23465c7f30d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 19:11:01 +0100 Subject: [PATCH 164/235] [java] Add type parameters for test --- .../pmd/lang/java/ast/jdkversiontests/java14/Records.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java index cdd93fc7cd..1da8915791 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java @@ -39,7 +39,12 @@ public class Records { public record ArrayRec(int x[]) {} - public record EmptyRec() { + public record EmptyRec() { public void foo() { } + public Type bar() { return null; } + public static void baz() { + EmptyRec r = new EmptyRec<>(); + System.out.println(r); + } } } From f1fe8ce5e1883f2fbeae3e93bdbabdf8eb7511e0 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 19:37:13 +0100 Subject: [PATCH 165/235] [java] Remove version java 12 preview Keep the tests and move them to java 14 except for the break expression --- pmd-java/etc/grammar/Java.jjt | 24 ++-- .../pmd/lang/java/JavaLanguageModule.java | 1 - .../pmd/lang/java/ast/Java12Test.java | 104 ------------------ .../pmd/lang/java/ast/Java14Test.java | 64 +++++++++++ .../pmd/lang/java/ast/KotlinTestingDsl.kt | 2 +- .../java12/SwitchExpressionsBreak.java | 36 ------ .../MultipleCaseLabels.java | 0 .../SimpleSwitchExpressions.java} | 4 +- .../{java12 => java14}/SwitchRules.java | 0 9 files changed, 74 insertions(+), 161 deletions(-) delete mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java12Test.java delete mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java rename pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/{java12 => java14}/MultipleCaseLabels.java (100%) rename pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/{java12/SwitchExpressions.java => java14/SimpleSwitchExpressions.java} (93%) rename pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/{java12 => java14}/SwitchRules.java (100%) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 255e06ef5b..06c4b35c72 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -418,8 +418,8 @@ public class JavaParser { } } private void checkForMultipleCaseLabels() { - if (!switchExprAllowed()) { - throwParseException("Multiple case labels in switch statements are only supported with Java 12 or 13 Preview"); + if (!isJava13PreviewOr14()) { + throwParseException("Multiple case labels in switch statements are only supported with Java 13 Preview, or Java >= 14"); } } /** @@ -432,28 +432,18 @@ public class JavaParser { */ private boolean inSwitchLabel = false; - private boolean switchExprAllowed() { - return jdkVersion >= 14 || jdkVersion >= 12 && preview; - } - private boolean isJava13PreviewOr14() { return jdkVersion >= 14 || jdkVersion >= 13 && preview; } private void checkForSwitchRules() { - if (!switchExprAllowed()) { - throwParseException("Switch rules in switch statements are only supported with Java 12 or 13 Preview, or Java >= 14"); + if (!isJava13PreviewOr14()) { + throwParseException("Switch rules in switch statements are only supported with Java 13 Preview, or Java >= 14"); } } private void checkForSwitchExpression() { - if (!switchExprAllowed()) { - throwParseException("Switch expressions are only supported with Java 12 or 13 Preview, or Java >= 14"); - } - } - - private void checkForBreakExpression() { - if (jdkVersion != 12 || !preview) { - throwParseException("Expressions in break statements are only supported with Java 12 Preview"); + if (!isJava13PreviewOr14()) { + throwParseException("Switch expressions are only supported with Java 13 Preview, or Java >= 14"); } } @@ -2031,7 +2021,7 @@ void ForUpdate() : void BreakStatement() : {Token t;} { - "break" [ LOOKAHEAD( ";") t= {jjtThis.setImage(t.image);} | Expression() {checkForBreakExpression();} ] ";" + "break" [ t= {jjtThis.setImage(t.image);} ] ";" } void ContinueStatement() : 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 fa44c5f596..fbd0d7671c 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 @@ -27,7 +27,6 @@ public class JavaLanguageModule extends BaseLanguageModule { addVersions(new JavaLanguageHandler(10), false, "10", "1.10"); addVersion("11", new JavaLanguageHandler(11), false); addVersion("12", new JavaLanguageHandler(12), false); - addVersion("12-preview", new JavaLanguageHandler(12, true), false); addVersion("13", new JavaLanguageHandler(13), false); addVersion("13-preview", new JavaLanguageHandler(13, true), false); addVersion("14", new JavaLanguageHandler(14), true); // 14 is the default diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java12Test.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java12Test.java deleted file mode 100644 index 18d767c26c..0000000000 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java12Test.java +++ /dev/null @@ -1,104 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang.java.ast; - -import org.junit.Assert; -import org.junit.Test; - -import net.sourceforge.pmd.lang.ast.ParseException; -import net.sourceforge.pmd.lang.java.JavaParsingHelper; - -public class Java12Test { - - - private final JavaParsingHelper java11 = - JavaParsingHelper.WITH_PROCESSING.withDefaultVersion("11") - .withResourceContext(Java12Test.class, "jdkversiontests/java12/"); - - private final JavaParsingHelper java12p = java11.withDefaultVersion("12-preview"); - - - @Test(expected = ParseException.class) - public void testMultipleCaseLabelsJava11() { - java11.parseResource("MultipleCaseLabels.java"); - } - - @Test - public void testMultipleCaseLabels() { - ASTCompilationUnit compilationUnit = java12p.parseResource("MultipleCaseLabels.java"); - ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class); - Assert.assertTrue(switchStatement.getChild(0) instanceof ASTExpression); - Assert.assertTrue(switchStatement.getChild(1) instanceof ASTSwitchLabel); - ASTSwitchLabel switchLabel = switchStatement.getFirstChildOfType(ASTSwitchLabel.class); - Assert.assertEquals(3, switchLabel.findChildrenOfType(ASTExpression.class).size()); - } - - @Test(expected = ParseException.class) - public void testSwitchRulesJava11() { - java11.parseResource("SwitchRules.java"); - } - - @Test - public void testSwitchRules() { - ASTCompilationUnit compilationUnit = java12p.parseResource("SwitchRules.java"); - ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class); - Assert.assertTrue(switchStatement.getChild(0) instanceof ASTExpression); - Assert.assertTrue(switchStatement.getChild(1) instanceof ASTSwitchLabeledExpression); - ASTSwitchLabeledExpression switchLabeledExpression = (ASTSwitchLabeledExpression) switchStatement.getChild(1); - Assert.assertEquals(2, switchLabeledExpression.getNumChildren()); - Assert.assertTrue(switchLabeledExpression.getChild(0) instanceof ASTSwitchLabel); - Assert.assertTrue(switchLabeledExpression.getChild(1) instanceof ASTExpression); - - ASTSwitchLabeledBlock switchLabeledBlock = (ASTSwitchLabeledBlock) switchStatement.getChild(4); - Assert.assertEquals(2, switchLabeledBlock.getNumChildren()); - Assert.assertTrue(switchLabeledBlock.getChild(0) instanceof ASTSwitchLabel); - Assert.assertTrue(switchLabeledBlock.getChild(1) instanceof ASTBlock); - - ASTSwitchLabeledThrowStatement switchLabeledThrowStatement = (ASTSwitchLabeledThrowStatement) switchStatement.getChild(5); - Assert.assertEquals(2, switchLabeledThrowStatement.getNumChildren()); - Assert.assertTrue(switchLabeledThrowStatement.getChild(0) instanceof ASTSwitchLabel); - Assert.assertTrue(switchLabeledThrowStatement.getChild(1) instanceof ASTThrowStatement); - } - - @Test(expected = ParseException.class) - public void testSwitchExpressionsJava11() { - java11.parseResource("SwitchExpressions.java"); - } - - @Test - public void testSwitchExpressions() { - ASTCompilationUnit compilationUnit = java12p.parseResource("SwitchExpressions.java"); - - ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class); - Assert.assertEquals(6, switchExpression.getNumChildren()); - Assert.assertTrue(switchExpression.getChild(0) instanceof ASTExpression); - Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabeledRule.class).size()); - - ASTLocalVariableDeclaration localVar = compilationUnit.findDescendantsOfType(ASTLocalVariableDeclaration.class).get(1); - ASTVariableDeclarator localVarDecl = localVar.getFirstChildOfType(ASTVariableDeclarator.class); - Assert.assertEquals(Integer.TYPE, localVarDecl.getType()); - Assert.assertEquals(Integer.TYPE, switchExpression.getType()); - } - - @Test - public void testSwitchExpressionsBreak() { - ASTCompilationUnit compilationUnit = java12p.parseResource("SwitchExpressionsBreak.java"); - - ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class); - Assert.assertEquals(11, switchExpression.getNumChildren()); - Assert.assertTrue(switchExpression.getChild(0) instanceof ASTExpression); - Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabel.class).size()); - - ASTBreakStatement breakStatement = switchExpression.getFirstDescendantOfType(ASTBreakStatement.class); - Assert.assertEquals("SwitchExpressionsBreak.SIX", breakStatement.getImage()); - Assert.assertTrue(breakStatement.getChild(0) instanceof ASTExpression); - - ASTLocalVariableDeclaration localVar = compilationUnit.findDescendantsOfType(ASTLocalVariableDeclaration.class).get(1); - ASTVariableDeclarator localVarDecl = localVar.getFirstChildOfType(ASTVariableDeclarator.class); - Assert.assertEquals(Integer.TYPE, localVarDecl.getType()); - Assert.assertEquals(Integer.TYPE, switchExpression.getType()); - } - -} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java index c05e1736c4..334335db65 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14Test.java @@ -78,4 +78,68 @@ public class Java14Test { Assert.assertEquals(String.class, switchExpressions.get(3).getType()); } + + @Test + public void multipleCaseLabels() { + multipleCaseLabels(java13p); + multipleCaseLabels(java14); + multipleCaseLabels(java14p); + } + + private void multipleCaseLabels(JavaParsingHelper parser) { + ASTCompilationUnit compilationUnit = parser.parseResource("MultipleCaseLabels.java"); + ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class); + Assert.assertTrue(switchStatement.getChild(0) instanceof ASTExpression); + Assert.assertTrue(switchStatement.getChild(1) instanceof ASTSwitchLabel); + ASTSwitchLabel switchLabel = switchStatement.getFirstChildOfType(ASTSwitchLabel.class); + Assert.assertEquals(3, switchLabel.findChildrenOfType(ASTExpression.class).size()); + } + + @Test + public void switchRules() { + switchRules(java13p); + switchRules(java14); + switchRules(java14p); + } + + private void switchRules(JavaParsingHelper parser) { + ASTCompilationUnit compilationUnit = parser.parseResource("SwitchRules.java"); + ASTSwitchStatement switchStatement = compilationUnit.getFirstDescendantOfType(ASTSwitchStatement.class); + Assert.assertTrue(switchStatement.getChild(0) instanceof ASTExpression); + Assert.assertTrue(switchStatement.getChild(1) instanceof ASTSwitchLabeledExpression); + ASTSwitchLabeledExpression switchLabeledExpression = (ASTSwitchLabeledExpression) switchStatement.getChild(1); + Assert.assertEquals(2, switchLabeledExpression.getNumChildren()); + Assert.assertTrue(switchLabeledExpression.getChild(0) instanceof ASTSwitchLabel); + Assert.assertTrue(switchLabeledExpression.getChild(1) instanceof ASTExpression); + + ASTSwitchLabeledBlock switchLabeledBlock = (ASTSwitchLabeledBlock) switchStatement.getChild(4); + Assert.assertEquals(2, switchLabeledBlock.getNumChildren()); + Assert.assertTrue(switchLabeledBlock.getChild(0) instanceof ASTSwitchLabel); + Assert.assertTrue(switchLabeledBlock.getChild(1) instanceof ASTBlock); + + ASTSwitchLabeledThrowStatement switchLabeledThrowStatement = (ASTSwitchLabeledThrowStatement) switchStatement.getChild(5); + Assert.assertEquals(2, switchLabeledThrowStatement.getNumChildren()); + Assert.assertTrue(switchLabeledThrowStatement.getChild(0) instanceof ASTSwitchLabel); + Assert.assertTrue(switchLabeledThrowStatement.getChild(1) instanceof ASTThrowStatement); + } + + @Test + public void simpleSwitchExpressions() { + simpleSwitchExpressions(java13p); + simpleSwitchExpressions(java14); + simpleSwitchExpressions(java14p); + } + + private void simpleSwitchExpressions(JavaParsingHelper parser) { + ASTCompilationUnit compilationUnit = parser.parseResource("SimpleSwitchExpressions.java"); + ASTSwitchExpression switchExpression = compilationUnit.getFirstDescendantOfType(ASTSwitchExpression.class); + Assert.assertEquals(6, switchExpression.getNumChildren()); + Assert.assertTrue(switchExpression.getChild(0) instanceof ASTExpression); + Assert.assertEquals(5, switchExpression.findChildrenOfType(ASTSwitchLabeledRule.class).size()); + + ASTLocalVariableDeclaration localVar = compilationUnit.findDescendantsOfType(ASTLocalVariableDeclaration.class).get(1); + ASTVariableDeclarator localVarDecl = localVar.getFirstChildOfType(ASTVariableDeclarator.class); + Assert.assertEquals(Integer.TYPE, localVarDecl.getType()); + Assert.assertEquals(Integer.TYPE, switchExpression.getType()); + } } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt index cbc9ed4da2..dc34b3db28 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt @@ -14,7 +14,7 @@ import net.sourceforge.pmd.lang.java.JavaParsingHelper */ enum class JavaVersion : Comparable { J1_3, J1_4, J1_5, J1_6, J1_7, J1_8, J9, J10, J11, - J12, J12__PREVIEW, + J12, J13, J13__PREVIEW, J14, J14__PREVIEW; diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java deleted file mode 100644 index 6584e4f5df..0000000000 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressionsBreak.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * - * @see JEP 325: Switch Expressions (Preview) - */ -public class SwitchExpressionsBreak { - private static final int MONDAY = 1; - private static final int TUESDAY = 2; - private static final int WEDNESDAY = 3; - private static final int THURSDAY = 4; - private static final int FRIDAY = 5; - private static final int SATURDAY = 6; - private static final int SUNDAY = 7; - - private static final int SIX = 6; - - public static void main(String[] args) { - int day = FRIDAY; - - var numLetters = switch (day) { - case MONDAY, FRIDAY, SUNDAY: break SwitchExpressionsBreak.SIX; - case TUESDAY : break 7; - case THURSDAY, SATURDAY : break 8; - case WEDNESDAY : break 9; - default : { - int k = day * 2; - int result = f(k); - break result; - } - }; - System.out.printf("NumLetters: %d%n", numLetters); - } - - private static int f(int k) { - return k*3; - } -} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/MultipleCaseLabels.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/MultipleCaseLabels.java similarity index 100% rename from pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/MultipleCaseLabels.java rename to pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/MultipleCaseLabels.java diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressions.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/SimpleSwitchExpressions.java similarity index 93% rename from pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressions.java rename to pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/SimpleSwitchExpressions.java index 86ff120576..c452ab0412 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchExpressions.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/SimpleSwitchExpressions.java @@ -2,7 +2,7 @@ * * @see JEP 325: Switch Expressions (Preview) */ -public class SwitchExpressions { +public class SimpleSwitchExpressions { private static final int MONDAY = 1; private static final int TUESDAY = 2; private static final int WEDNESDAY = 3; @@ -23,7 +23,7 @@ public class SwitchExpressions { default -> { int k = day * 2; int result = f(k); - break result; + yield result; } }; System.out.printf("NumLetters: %d%n", numLetters); diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchRules.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/SwitchRules.java similarity index 100% rename from pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java12/SwitchRules.java rename to pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/SwitchRules.java From 0bcfda5619ce75c701e4b201f1ff6253d4343dd8 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 28 Feb 2020 19:48:00 +0100 Subject: [PATCH 166/235] [doc] Update release notes: Java 14 Support Fixes #2159 --- docs/pages/release_notes.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index a6b5973f9e..b39fcd8aa5 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,6 +14,29 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### Java 14 Support + +This release of PMD brings support for Java 14. PMD can parse [Switch Expressions](https://openjdk.java.net/jeps/361), +which have been promoted to be a standard language feature of Java. + +PMD also parses [Text Blocks](https://openjdk.java.net/jeps/368) as String literals, which is still a preview +language feature in Java 14. + +The new [Pattern Matching for instanceof](https://openjdk.java.net/jeps/305) can be used as well as +[Records](https://openjdk.java.net/jeps/359). + +Note: The Text Blocks, Pattern Matching for instanceof and Records are all preview language features of OpenJDK 14 +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 `14-preview`: + + export PMD_JAVA_OPTS=--enable-preview + ./run.sh pmd -language java -version 14-preview ... + +Note: Support for the extended break statement introduced in Java 12 as a preview language feature +has been removed from PMD with this version. The version "12-preview" is no longer available. + + #### Updated PMD Designer This PMD release ships a new version of the pmd-designer. @@ -40,6 +63,7 @@ the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs * doc * [#2274](https://github.com/pmd/pmd/issues/2274): \[doc] Java API documentation for PMD * java + * [#2159](https://github.com/pmd/pmd/issues/2159): \[java] Prepare for JDK 14 * [#2268](https://github.com/pmd/pmd/issues/2268): \[java] Improve TypeHelper resilience * java-bestpractices * [#2277](https://github.com/pmd/pmd/issues/2277): \[java] FP in UnusedImports for ambiguous static on-demand imports From b65a6a52eace051d05fa7b99c4b33a773c5c56de Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 29 Feb 2020 11:34:50 +0100 Subject: [PATCH 167/235] [doc] Update release notes, fixes #2139, refs #2280. --- docs/pages/release_notes.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index ed2b154b84..01b00b90f9 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -19,8 +19,16 @@ This is a {{ site.pmd.release_type }} release. This PMD release ships a new version of the pmd-designer. For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/6.21.0). +#### Improved CPD support for C# + +The C# tokenizer is now based on an antlr grammar instead of a manual written tokenizer. This +should give more accurate results and especially fixes the problems with the using statement syntax +(see [#2139](https://github.com/pmd/pmd/issues/2139)). + ### Fixed Issues +* cs + * [#2139](https://github.com/pmd/pmd/issues/2139): \[cs] CPD doesn't understand alternate using statement syntax with C# 8.0 * java-errorprone * [#2250](https://github.com/pmd/pmd/issues/2250): \[java] InvalidLogMessageFormat flags logging calls using a slf4j-Marker @@ -31,6 +39,7 @@ For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designe * [#2251](https://github.com/pmd/pmd/pull/2251): \[java] FP for InvalidLogMessageFormat when using slf4j-Markers - [Kris Scheibe](https://github.com/kris-scheibe) * [#2253](https://github.com/pmd/pmd/pull/2253): \[modelica] Remove duplicated dependencies - [Piotrek Żygieło](https://github.com/pzygielo) * [#2256](https://github.com/pmd/pmd/pull/2256): \[doc] Corrected XML attributes in release notes - [Maikel Steneker](https://github.com/maikelsteneker) +* [#2280](https://github.com/pmd/pmd/pull/2280): \[cs] CPD: Replace C# tokenizer by an Antlr-based one - [Maikel Steneker](https://github.com/maikelsteneker) {% endtocmaker %} From 548326d2e1754e335ecfa18049ce65449eea82e5 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 29 Feb 2020 17:58:45 +0100 Subject: [PATCH 168/235] [java] Make the new AST node classes final --- .../java/net/sourceforge/pmd/lang/java/ast/ASTRecordBody.java | 2 +- .../net/sourceforge/pmd/lang/java/ast/ASTRecordComponent.java | 2 +- .../sourceforge/pmd/lang/java/ast/ASTRecordComponentList.java | 2 +- .../pmd/lang/java/ast/ASTRecordConstructorDeclaration.java | 2 +- .../net/sourceforge/pmd/lang/java/ast/ASTRecordDeclaration.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) 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 a066bfa2aa..904b62e56b 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 @@ -20,7 +20,7 @@ import net.sourceforge.pmd.annotation.Experimental; * */ @Experimental -public class ASTRecordBody extends AbstractJavaNode { +public final class ASTRecordBody extends AbstractJavaNode { ASTRecordBody(int id) { super(id); } 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 390a8ab8df..4c9943e258 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 @@ -20,7 +20,7 @@ import net.sourceforge.pmd.annotation.Experimental; *
*/ @Experimental -public class ASTRecordComponent extends AbstractJavaNode { +public final class ASTRecordComponent extends AbstractJavaNode { private boolean varargs; ASTRecordComponent(int id) { 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 dbf7367601..8139e687cb 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 @@ -17,7 +17,7 @@ import net.sourceforge.pmd.annotation.Experimental; *
*/ @Experimental -public class ASTRecordComponentList extends AbstractJavaNode { +public final class ASTRecordComponentList extends AbstractJavaNode { ASTRecordComponentList(int id) { super(id); } 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 9ab85f673b..9d5fb279d5 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 @@ -23,7 +23,7 @@ import net.sourceforge.pmd.annotation.Experimental; * */ @Experimental -public class ASTRecordConstructorDeclaration extends AbstractJavaAccessNode implements ASTAnyTypeBodyDeclaration { +public final class ASTRecordConstructorDeclaration extends AbstractJavaAccessNode implements ASTAnyTypeBodyDeclaration { ASTRecordConstructorDeclaration(int id) { super(id); } 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 6cc2355ef4..1d84939d8c 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 @@ -28,7 +28,7 @@ import net.sourceforge.pmd.lang.ast.Node; * @see JEP 359: Records (Preview) */ @Experimental -public class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { +public final class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { ASTRecordDeclaration(int id) { super(id); } From 9442a32ce60449278788f9d43c6578bdd51bfb10 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 29 Feb 2020 18:48:33 +0100 Subject: [PATCH 169/235] [vm] More deprecations: package directive and util classes --- docs/pages/release_notes.md | 7 +++++-- pmd-vm/etc/grammar/VmParser.jjt | 8 +++++--- .../main/java/net/sourceforge/pmd/lang/vm/VmHandler.java | 2 +- .../net/sourceforge/pmd/lang/vm/VmLanguageModule.java | 3 +++ .../main/java/net/sourceforge/pmd/lang/vm/VmParser.java | 2 +- .../java/net/sourceforge/pmd/lang/vm/VmTokenManager.java | 2 +- .../java/net/sourceforge/pmd/lang/vm/ast/ASTEscape.java | 8 ++++++++ .../java/net/sourceforge/pmd/lang/vm/ast/ASTMathNode.java | 2 ++ .../java/net/sourceforge/pmd/lang/vm/ast/NodeUtils.java | 2 ++ .../java/net/sourceforge/pmd/lang/vm/directive/Block.java | 2 ++ .../net/sourceforge/pmd/lang/vm/directive/BlockMacro.java | 2 ++ .../java/net/sourceforge/pmd/lang/vm/directive/Break.java | 2 ++ .../net/sourceforge/pmd/lang/vm/directive/Define.java | 2 ++ .../net/sourceforge/pmd/lang/vm/directive/Directive.java | 2 ++ .../net/sourceforge/pmd/lang/vm/directive/Evaluate.java | 2 ++ .../net/sourceforge/pmd/lang/vm/directive/Foreach.java | 2 ++ .../net/sourceforge/pmd/lang/vm/directive/Include.java | 2 ++ .../net/sourceforge/pmd/lang/vm/directive/InputBase.java | 2 ++ .../net/sourceforge/pmd/lang/vm/directive/Literal.java | 2 +- .../java/net/sourceforge/pmd/lang/vm/directive/Macro.java | 2 ++ .../java/net/sourceforge/pmd/lang/vm/directive/Parse.java | 2 ++ .../sourceforge/pmd/lang/vm/directive/RuntimeMacro.java | 2 ++ .../java/net/sourceforge/pmd/lang/vm/directive/Stop.java | 2 ++ .../pmd/lang/vm/directive/VelocimacroProxy.java | 2 ++ .../net/sourceforge/pmd/lang/vm/util/DirectiveMapper.java | 4 ++++ .../java/net/sourceforge/pmd/lang/vm/util/LogUtil.java | 2 ++ 26 files changed, 63 insertions(+), 9 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index c37e536179..9fcd670f00 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -126,14 +126,17 @@ The following usages are now deprecated **in the VM AST** (with other languages marked {% jdoc core::annotation.InternalApi %}. Nodes should only be obtained from the parser, which for rules, means that they never need to instantiate node themselves. Those constructors will be made package private with 7.0.0. -* **Subclassing of abstract node classes, or usage of their type**. Version 7.0.0 the base classes are and will - stay internal. You should not couple your code to them. +* **Subclassing of abstract node classes, or usage of their type**. The base classes are internal API + and will be hidden in version 7.0.0. You should not couple your code to them. * In the meantime you should use interfaces like {% jdoc vm::lang.vm.ast.VmNode %} or {% jdoc core::ast.Node %}, or the other published interfaces in this package, to refer to nodes generically. * Concrete node classes will **be made final** with 7.0.0. * Setters found in any node class or interface. **Rules should consider the AST immutable**. We will make those setters package private with 7.0.0. +* The package {% jdoc_package vm::lang.vm.directice %} as well as the classes + {% jdoc vm::lang.vm.util.DirectiveMapper %} and {% jdoc vm::lang.vm.util.LogUtil %} are deprecated + for removal. They were only used internally during parsing. Please look at {% jdoc_package vm::lang.vm.ast %} to find out the full list of deprecations. diff --git a/pmd-vm/etc/grammar/VmParser.jjt b/pmd-vm/etc/grammar/VmParser.jjt index 4fab39c65a..3873806180 100644 --- a/pmd-vm/etc/grammar/VmParser.jjt +++ b/pmd-vm/etc/grammar/VmParser.jjt @@ -1247,10 +1247,12 @@ void Escape() : {} control = true; } - jjtThis.val = ""; + String value = ""; - for( int i = 0; i < count; i++) - jjtThis.val += ( control ? "\\" : "\\\\"); + for( int i = 0; i < count; i++) { + value += ( control ? "\\" : "\\\\"); + } + jjtThis.setValue(value); } } diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmHandler.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmHandler.java index 6c35508584..c3cf2a665a 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmHandler.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmHandler.java @@ -1,4 +1,4 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmLanguageModule.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmLanguageModule.java index 9218faa6a7..bfcf727c70 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmLanguageModule.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmLanguageModule.java @@ -1,3 +1,6 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ package net.sourceforge.pmd.lang.vm; diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmParser.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmParser.java index 8721e782ed..e4ed467178 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmParser.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmParser.java @@ -1,4 +1,4 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmTokenManager.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmTokenManager.java index 4d8f01e46c..55669a4bd6 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmTokenManager.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmTokenManager.java @@ -1,4 +1,4 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTEscape.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTEscape.java index 54d5ed43ca..53486785d2 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTEscape.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTEscape.java @@ -49,6 +49,14 @@ public class ASTEscape extends AbstractVmNode { super(p, id); } + void setValue(String value) { + this.val = value; + } + + public String getValue() { + return val; + } + @Override public Object jjtAccept(final VmParserVisitor visitor, final Object data) { return visitor.visit(this, data); diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMathNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMathNode.java index c642288b73..82fed159b4 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMathNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/ASTMathNode.java @@ -36,6 +36,8 @@ import net.sourceforge.pmd.annotation.InternalApi; * @author Nathan Bubna * @version $Id: ASTMathNode.java 517553 2007-03-13 06:09:58Z wglass $ */ +@InternalApi +@Deprecated public abstract class ASTMathNode extends AbstractVmNode { protected boolean strictMode = false; diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/NodeUtils.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/NodeUtils.java index 270d1395c0..d3e99c68fb 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/NodeUtils.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/NodeUtils.java @@ -28,7 +28,9 @@ import org.apache.commons.lang3.text.StrBuilder; * @author Jason van Zyl * @author Geir Magnusson Jr. * @version $Id: NodeUtils.java 687386 2008-08-20 16:57:07Z nbubna $ + * @deprecated for removal with PMD 7.0.0 */ +@Deprecated public final class NodeUtils { private NodeUtils() { } diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Block.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Block.java index b10b9dbe75..29eb9f3eb6 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Block.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Block.java @@ -29,7 +29,9 @@ package net.sourceforge.pmd.lang.vm.directive; * @author Jarkko Viinamaki * @since 1.7 * @version $Id: Block.java 686842 2008-08-18 18:29:31Z nbubna $ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public abstract class Block extends Directive { protected String key; diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/BlockMacro.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/BlockMacro.java index e1b80173af..38c2496bc9 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/BlockMacro.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/BlockMacro.java @@ -52,7 +52,9 @@ package net.sourceforge.pmd.lang.vm.directive; * @author Jarkko Viinamaki * @since 1.7 * @version $Id$ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class BlockMacro extends Block { private String name; diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Break.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Break.java index ee3bf5b629..9b2a7744bf 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Break.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Break.java @@ -26,7 +26,9 @@ package net.sourceforge.pmd.lang.vm.directive; * @author Jarkko Viinamaki * @author Nathan Bubna * @version $Id$ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class Break extends Directive { /** diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Define.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Define.java index 08683debf5..b911f976ee 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Define.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Define.java @@ -27,7 +27,9 @@ package net.sourceforge.pmd.lang.vm.directive; * @author Andrew Tetlaw * @author Nathan Bubna * @version $Id: Define.java 686842 2008-08-18 18:29:31Z nbubna $ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class Define extends Block { /** * Return name of this directive. diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Directive.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Directive.java index 0baaee2eae..a79ae54a06 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Directive.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Directive.java @@ -26,7 +26,9 @@ package net.sourceforge.pmd.lang.vm.directive; * @author Jason van Zyl * @author Nathan Bubna * @version $Id: Directive.java 778045 2009-05-23 22:17:46Z nbubna $ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public abstract class Directive implements Cloneable { /** Block directive indicator */ public static final int BLOCK = 1; diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Evaluate.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Evaluate.java index ab48ac2392..e0226ea48d 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Evaluate.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Evaluate.java @@ -26,7 +26,9 @@ package net.sourceforge.pmd.lang.vm.directive; * @author Will Glass-Husain * @version $Id: Evaluate.java 898032 2010-01-11 19:51:03Z nbubna $ * @since 1.6 + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class Evaluate extends Directive { /** diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Foreach.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Foreach.java index 715f17f5f0..1fc9b1c17f 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Foreach.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Foreach.java @@ -28,7 +28,9 @@ package net.sourceforge.pmd.lang.vm.directive; * @author Geir Magnusson Jr. * @author Daniel Rall * @version $Id: Foreach.java 945927 2010-05-18 22:21:41Z nbubna $ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class Foreach extends Directive { /** * Return name of this directive. diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Include.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Include.java index fa6e04fe36..4062926fbc 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Include.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Include.java @@ -53,7 +53,9 @@ package net.sourceforge.pmd.lang.vm.directive; * @author Jason van Zyl * @author Kasper Nielsen * @version $Id: Include.java 746438 2009-02-21 05:41:24Z nbubna $ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class Include extends InputBase { /** diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/InputBase.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/InputBase.java index 5c47a5fe36..bb7573fab0 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/InputBase.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/InputBase.java @@ -26,7 +26,9 @@ package net.sourceforge.pmd.lang.vm.directive; * * @author Daniel Rall * @since 1.4 + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public abstract class InputBase extends Directive { /** * Return name of this directive. diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Literal.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Literal.java index 0d81c6c919..a3d3141ef2 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Literal.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Literal.java @@ -28,7 +28,7 @@ package net.sourceforge.pmd.lang.vm.directive; * * @author Jason van Zyl * @version $Id: Literal.java 746438 2009-02-21 05:41:24Z nbubna $ - * @deprecated Use the #[[unparsed content]]# syntax instead. + * @deprecated Use the #[[unparsed content]]# syntax instead. Deprecated for removal in PMD 7.0.0 */ @Deprecated public class Literal extends Directive { diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Macro.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Macro.java index 1c15e2c6a8..6d5ea84461 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Macro.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Macro.java @@ -33,7 +33,9 @@ package net.sourceforge.pmd.lang.vm.directive; * @author Geir Magnusson Jr. * @author Henning P. Schmiedehausen * @version $Id: Macro.java 746438 2009-02-21 05:41:24Z nbubna $ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class Macro extends Directive { /** * Return name of this directive. diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Parse.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Parse.java index 9aa23dfa05..f895292d74 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Parse.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Parse.java @@ -41,7 +41,9 @@ package net.sourceforge.pmd.lang.vm.directive; * @author Jason van Zyl * @author Christoph Reck * @version $Id: Parse.java 928253 2010-03-27 19:39:04Z nbubna $ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class Parse extends InputBase { /** diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/RuntimeMacro.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/RuntimeMacro.java index 2b2b513cb6..289ef617cd 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/RuntimeMacro.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/RuntimeMacro.java @@ -28,7 +28,9 @@ package net.sourceforge.pmd.lang.vm.directive; * rendered. * * @since 1.6 + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class RuntimeMacro extends Directive { /** * Name of the macro diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Stop.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Stop.java index 83a92cb731..0bd325d7e4 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Stop.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/Stop.java @@ -24,7 +24,9 @@ package net.sourceforge.pmd.lang.vm.directive; * This class implements the #stop directive which allows a user to stop the * merging and rendering process. The #stop directive will accept a single * message argument with info about the reason for stopping. + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class Stop extends Directive { /** diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/VelocimacroProxy.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/VelocimacroProxy.java index 5f1f79f2a9..503c122173 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/VelocimacroProxy.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/directive/VelocimacroProxy.java @@ -27,7 +27,9 @@ package net.sourceforge.pmd.lang.vm.directive; * * @author Geir Magnusson Jr. * @version $Id: VelocimacroProxy.java 898032 2010-01-11 19:51:03Z nbubna $ + * @deprecated for removal in PMD 7.0.0 */ +@Deprecated public class VelocimacroProxy extends Directive { private String macroName; private int numMacroArgs = 0; diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/util/DirectiveMapper.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/util/DirectiveMapper.java index 6b72a0d9a8..25f41aef25 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/util/DirectiveMapper.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/util/DirectiveMapper.java @@ -20,6 +20,10 @@ import net.sourceforge.pmd.lang.vm.directive.Macro; import net.sourceforge.pmd.lang.vm.directive.Parse; import net.sourceforge.pmd.lang.vm.directive.Stop; +/** + * @deprecated for removal in PMD 7.0.0 + */ +@Deprecated public final class DirectiveMapper { private DirectiveMapper() { } diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/util/LogUtil.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/util/LogUtil.java index 9a97f4ca6e..bb35427548 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/util/LogUtil.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/util/LogUtil.java @@ -31,7 +31,9 @@ import net.sourceforge.pmd.lang.vm.directive.Directive; * @author Nathan Bubna * @version $Id: Log.java 724825 2008-12-09 18:56:06Z nbubna $ * @since 1.5 + * @deprecated for removal with PMD 7.0.0 */ +@Deprecated public final class LogUtil { private LogUtil() { } From f49a6dbc3d0872e345ecea6c13926dd939bc119d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 29 Feb 2020 20:00:18 +0100 Subject: [PATCH 170/235] [java] Add test with record implementing a interface --- .../sourceforge/pmd/lang/java/ast/Java14PreviewTest.java | 7 ++++++- .../pmd/lang/java/ast/jdkversiontests/java14/Records.java | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index c39e293399..27fb1b1ac1 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -113,7 +113,7 @@ public class Java14PreviewTest { public void innerRecords() { ASTCompilationUnit compilationUnit = java14p.parseResource("Records.java"); List recordDecls = compilationUnit.findDescendantsOfType(ASTRecordDeclaration.class, true); - Assert.assertEquals(6, recordDecls.size()); + Assert.assertEquals(7, recordDecls.size()); ASTRecordDeclaration complex = recordDecls.get(0); Assert.assertEquals("MyComplex", complex.getName()); @@ -152,6 +152,11 @@ public class Java14PreviewTest { ASTRecordDeclaration emptyRec = recordDecls.get(5); Assert.assertEquals("EmptyRec", emptyRec.getName()); Assert.assertEquals(0, emptyRec.getRecordComponents().size()); + + ASTRecordDeclaration personRec = recordDecls.get(6); + Assert.assertEquals("PersonRecord", personRec.getName()); + ASTImplementsList impl = personRec.getFirstChildOfType(ASTImplementsList.class); + Assert.assertEquals(2, impl.findChildrenOfType(ASTClassOrInterfaceType.class).size()); } @Test(expected = ParseException.class) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java index 1da8915791..24be286303 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java @@ -47,4 +47,12 @@ public class Records { System.out.println(r); } } + + // see https://www.javaspecialists.eu/archive/Issue276.html + public interface Person { + String firstName(); + String lastName(); + } + public record PersonRecord(String firstName, String lastName) + implements Person, java.io.Serializable { } } From 4f318380ec38abbc3f714d913eb359b29d20d893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brian=20N=C3=B8rremark?= Date: Thu, 27 Feb 2020 20:19:37 +0100 Subject: [PATCH 171/235] =?UTF-8?q?[apex]=C2=A0New=20Rule=20-=20Test=20Met?= =?UTF-8?q?hods=20Must=20Be=20In=20Test=20Classes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/category/apex/errorprone.xml | 64 +++++++++++++++++++ .../TestMethodsMustBeInTestClassesTest.java | 11 ++++ .../xml/TestMethodsMustBeInTestClasses.xml | 57 +++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/errorprone/TestMethodsMustBeInTestClassesTest.java create mode 100644 pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/TestMethodsMustBeInTestClasses.xml diff --git a/pmd-apex/src/main/resources/category/apex/errorprone.xml b/pmd-apex/src/main/resources/category/apex/errorprone.xml index 884c0f31f0..c96110f960 100644 --- a/pmd-apex/src/main/resources/category/apex/errorprone.xml +++ b/pmd-apex/src/main/resources/category/apex/errorprone.xml @@ -328,4 +328,68 @@ public class MyClass { ]]> + + + + Test methods marked as a testMethod or annotated with @IsTest, + but not residing in a test class should be moved to a proper + class or have the @IsTest annotation added to the class. + + Support for tests inside functional classes was removed in Spring-13 (API Version 27.0), + making classes that violate this rule fail compile-time. This rule is mostly usable when + dealing with legacy code. + + 3 + + + + + + + + + + + + diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/errorprone/TestMethodsMustBeInTestClassesTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/errorprone/TestMethodsMustBeInTestClassesTest.java new file mode 100644 index 0000000000..6557797677 --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/errorprone/TestMethodsMustBeInTestClassesTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.errorprone; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class TestMethodsMustBeInTestClassesTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/TestMethodsMustBeInTestClasses.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/TestMethodsMustBeInTestClasses.xml new file mode 100644 index 0000000000..92b2da3d68 --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/TestMethodsMustBeInTestClasses.xml @@ -0,0 +1,57 @@ + + + + Class without @IsTest, method with @IsTest + 1 + 1 + + + + + Class without @IsTest, method with testMethod + 1 + 1 + + + + + Class with @IsTest, method with @IsTest + 0 + + + + + Class with @IsTest, method with testMethod + 0 + + + + \ No newline at end of file From a32d12b796ce7f3e6f94f9af553f01664a8a2121 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Mon, 2 Mar 2020 11:52:12 +0000 Subject: [PATCH 172/235] Support switch statements correctly in Cognitive Complexity --- .../visitors/CognitiveComplexityVisitor.java | 12 +++++++ .../impl/xml/CognitiveComplexityTest.xml | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+) 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 8cdcddcb55..9cfb32b325 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 @@ -16,6 +16,7 @@ import net.sourceforge.pmd.lang.apex.ast.ASTIfElseBlockStatement; import net.sourceforge.pmd.lang.apex.ast.ASTMethod; import net.sourceforge.pmd.lang.apex.ast.ASTMethodCallExpression; import net.sourceforge.pmd.lang.apex.ast.ASTPrefixExpression; +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; @@ -231,4 +232,15 @@ public class CognitiveComplexityVisitor extends ApexParserVisitorAdapter { state.methodCall(node.getNode().getMethodName()); return super.visit(node, data); } + + @Override + public Object visit(ASTSwitchStatement node, Object data) { + State state = (State) data; + + state.increaseNestingLevel(); + super.visit(node, data); + state.decreaseNestingLevel(); + + return state; + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml index 2abee77abb..4ab68beecc 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/metrics/impl/xml/CognitiveComplexityTest.xml @@ -359,4 +359,35 @@ ]]> + + + Switch statements only gain 1 complexity regardless of the number of cases + 1 + + 'c__Foo#foo(Integer)' has value 3. + + + + + \ No newline at end of file From fc0b437ad7174b5f8e199d500ef91b341af0877f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 2 Mar 2020 19:00:59 +0100 Subject: [PATCH 173/235] Fix record ctor with throws --- pmd-java/etc/grammar/Java.jjt | 11 +++++++++-- .../lang/java/ast/jdkversiontests/java14/Records.java | 8 +++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 06c4b35c72..29ce5dd111 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1152,9 +1152,15 @@ void RecordBody(): void RecordBodyDeclaration() #void : {} { - LOOKAHEAD(ClassOrInterfaceBodyDeclaration()) ClassOrInterfaceBodyDeclaration() + LOOKAHEAD(RecordCtorLookahead()) RecordConstructorDeclaration() | - RecordConstructorDeclaration() + ClassOrInterfaceBodyDeclaration() +} + +private void RecordCtorLookahead() #void: +{} +{ + Modifiers() [ TypeParameters() ] ("throws" | "{") } void RecordConstructorDeclaration(): @@ -1165,6 +1171,7 @@ void RecordConstructorDeclaration(): modifiers = Modifiers() { jjtThis.setModifiers(modifiers); } [TypeParameters()] { jjtThis.setImage(token.image); } + [ "throws" NameList() ] "{" ( BlockStatement() )* "}" } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java index 24be286303..a1be788be7 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java @@ -1,3 +1,4 @@ +import java.io.IOException; import java.lang.annotation.Target; import java.lang.annotation.ElementType; @@ -54,5 +55,10 @@ public class Records { String lastName(); } public record PersonRecord(String firstName, String lastName) - implements Person, java.io.Serializable { } + implements Person, java.io.Serializable { + + PersonRecord throws IOException { // compact ctor with throws list + throw new IOException(); + } + } } From e535c3edab905e64cd9cf12e2aa27a6b26274c29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 2 Mar 2020 19:05:53 +0100 Subject: [PATCH 174/235] Add comment --- .../main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java | 1 + 1 file changed, 1 insertion(+) 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 86c30b139e..8b63c0002d 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 @@ -318,6 +318,7 @@ public class ASTLiteral extends AbstractJavaTypeNode { private static void interpretEscapeSequences(StringBuilder sb) { // interpret escape sequences "\" (line continuation), "n","t","b","r","f", "s", "\"", "\'", "\\" + // we need to interpret everything in one pass, so regex replacement is inappropriate for (int i = 0; i < sb.length(); i++) { char c = sb.charAt(i); if (c == '\\' && i < sb.length() - 1) { From bd5720749d8fe8d2bdfb159b57fe920c1d2fb254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 2 Mar 2020 19:18:50 +0100 Subject: [PATCH 175/235] Fix CS module --- pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java index 49229f3170..9978cb4d93 100644 --- a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java +++ b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java @@ -8,9 +8,10 @@ import java.util.Properties; import org.antlr.v4.runtime.CharStream; +import net.sourceforge.pmd.cpd.internal.AntlrTokenizer; import net.sourceforge.pmd.cpd.token.AntlrToken; import net.sourceforge.pmd.cpd.token.AntlrTokenFilter; -import net.sourceforge.pmd.lang.antlr.AntlrTokenManager; +import net.sourceforge.pmd.lang.ast.impl.antlr4.AntlrTokenManager; import net.sourceforge.pmd.lang.cs.antlr4.CSharpLexer; /** From bfc704fa0513f83b5e121c98717f4ed47a1da2ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 2 Mar 2020 19:54:31 +0100 Subject: [PATCH 176/235] Cleanup language level checker --- .../ast/internal/LanguageLevelChecker.java | 141 +++++++++++------- 1 file changed, 89 insertions(+), 52 deletions(-) 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 570398da80..667a148786 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 @@ -6,8 +6,10 @@ package net.sourceforge.pmd.lang.java.ast.internal; import java.util.Locale; +import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; +import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; @@ -27,6 +29,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodReference; import net.sourceforge.pmd.lang.java.ast.ASTModuleDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; +import net.sourceforge.pmd.lang.java.ast.ASTRecordDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; import net.sourceforge.pmd.lang.java.ast.ASTResource; import net.sourceforge.pmd.lang.java.ast.ASTResourceSpecification; @@ -38,6 +41,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTTryStatement; import net.sourceforge.pmd.lang.java.ast.ASTType; import net.sourceforge.pmd.lang.java.ast.ASTTypeArguments; import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters; +import net.sourceforge.pmd.lang.java.ast.ASTTypeTestPattern; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.ASTYieldStatement; import net.sourceforge.pmd.lang.java.ast.JavaNode; @@ -51,6 +55,8 @@ import net.sourceforge.pmd.lang.java.ast.SideEffectingVisitorAdapter; */ public class LanguageLevelChecker { + private static final Pattern SPACE_ESCAPE_PATTERN = Pattern.compile("(?!\\\\)\\\\s"); + private final int jdkVersion; private final boolean preview; private final CheckVisitor visitor = new CheckVisitor(); @@ -77,13 +83,13 @@ public class LanguageLevelChecker { reportingStrategy.done(accumulator); } - private boolean check(Node node, LanguageFeature message, T acc) { - if (message.isAvailable(this.jdkVersion, this.preview)) { - return true; + private boolean check(Node node, LanguageFeature feature, T acc) { + String message = feature.errorMessage(this.jdkVersion, this.preview); + if (message != null) { + reportingStrategy.report(node, message, acc); + return false; } - - reportingStrategy.report(node, message.whenUnavailableMessage(), acc); - return false; + return true; } private static String displayNameLower(String name) { @@ -101,37 +107,56 @@ public class LanguageLevelChecker { } - /** Those are hacked just for the preview features. */ + /** Those are just for the preview features. */ private enum PreviewFeature implements LanguageFeature { - BREAK__WITH__VALUE_STATEMENTS(12, false), + BREAK__WITH__VALUE_STATEMENTS(12, 12, false), - COMPOSITE_CASE_LABEL(12, true), - SWITCH_EXPRESSIONS(12, true), - SWITCH_RULES(12, true), + COMPOSITE_CASE_LABEL(12, 13, true), + SWITCH_EXPRESSIONS(12, 13, true), + SWITCH_RULES(12, 13, true), - TEXT_BLOCK_LITERALS(13, false), - YIELD_STATEMENTS(13, false); + TEXT_BLOCK_LITERALS(13, 14, false), + 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), + ; - private final int minJdkVersion; - private final boolean alsoAbove; + private final int minPreviewVersion; + private final int maxPreviewVersion; + private final boolean wasStandardized; - PreviewFeature(int minJdkVersion, boolean alsoAbove) { - this.minJdkVersion = minJdkVersion; - this.alsoAbove = alsoAbove; - } - - @Override - public boolean isAvailable(int jdk, boolean preview) { - return preview && (jdk == minJdkVersion || alsoAbove && jdk > minJdkVersion); + PreviewFeature(int minPreviewVersion, int maxPreviewVersion, boolean wasStandardized) { + this.minPreviewVersion = minPreviewVersion; + this.maxPreviewVersion = maxPreviewVersion; + this.wasStandardized = wasStandardized; } @Override - public String whenUnavailableMessage() { - return StringUtils.capitalize(displayNameLower(name())) - + " is a feature of JDK >= " + "Java " + minJdkVersion + " preview" - + ", you should select your language version accordingly"; + public String errorMessage(int jdk, boolean preview) { + boolean isStandard = wasStandardized && jdk > maxPreviewVersion; + boolean canBePreview = jdk >= minPreviewVersion && jdk <= maxPreviewVersion; + boolean isPreview = preview && canBePreview; + + if (isStandard || isPreview) { + return null; + } + + String message = StringUtils.capitalize(displayNameLower(name())); + if (canBePreview) { + message += " is a only a preview feature on JDK " + jdk; + } else if (wasStandardized) { + message = message + " was only standardized in Java " + (maxPreviewVersion + 1); + } else if (minPreviewVersion == maxPreviewVersion) { + message += " is a preview feature of JDK " + minPreviewVersion; + } else { + message += " is a preview feature of JDKs " + minPreviewVersion + " to " + maxPreviewVersion; + } + return message + ", you should select your language version accordingly"; } } @@ -140,7 +165,9 @@ public class LanguageLevelChecker { ASSERT_AS_AN_IDENTIFIER(4, "assert"), ENUM_AS_AN_IDENTIFIER(5, "enum"), UNDERSCORE_AS_AN_IDENTIFIER(9, "_"), - VAR_AS_A_TYPE_NAME(10, "var"); + VAR_AS_A_TYPE_NAME(10, "var"), + RECORD_AS_A_TYPE_NAME(14, "record") // TODO + ; private final int maxJdkVersion; private final String reserved; @@ -151,12 +178,10 @@ public class LanguageLevelChecker { } @Override - public boolean isAvailable(int jdk, boolean preview) { - return jdk < this.maxJdkVersion; - } - - @Override - public String whenUnavailableMessage() { + public String errorMessage(int jdk, boolean preview) { + if (jdk < this.maxJdkVersion) { + return null; + } String s = displayNameLower(name()); String usageType = s.substring(s.indexOf(' ') + 1); // eg "as an identifier" return "Since " + LanguageLevelChecker.versionDisplayName(maxJdkVersion) + ", '" + reserved + "'" @@ -203,13 +228,10 @@ public class LanguageLevelChecker { @Override - public boolean isAvailable(int jdk, boolean preview) { - return jdk >= this.minJdkLevel; - } - - - @Override - public String whenUnavailableMessage() { + public String errorMessage(int jdk, boolean preview) { + if (jdk >= this.minJdkLevel) { + return null; + } return StringUtils.capitalize(displayNameLower(name())) + " are a feature of " + versionDisplayName(minJdkLevel) + ", you should select your language version accordingly"; @@ -219,10 +241,8 @@ public class LanguageLevelChecker { interface LanguageFeature { - boolean isAvailable(int jdk, boolean preview); - - - String whenUnavailableMessage(); + @Nullable + String errorMessage(int jdk, boolean preview); } private class CheckVisitor extends SideEffectingVisitorAdapter { @@ -240,10 +260,11 @@ public class LanguageLevelChecker { @Override public void visit(ASTLiteral node, T data) { - if (jdkVersion != 13 || !preview) { - if (node.isTextBlock()) { - check(node, PreviewFeature.TEXT_BLOCK_LITERALS, data); - } + if (node.isStringLiteral() && SPACE_ESCAPE_PATTERN.matcher(node.getImage()).find()) { + check(node, PreviewFeature.SPACE_STRING_ESCAPES, data); + } + if (node.isTextBlock()) { + check(node, PreviewFeature.TEXT_BLOCK_LITERALS, data); } visitChildren(node, data); } @@ -259,7 +280,7 @@ public class LanguageLevelChecker { @Override public void visit(ASTYieldStatement node, T data) { - check(node, PreviewFeature.YIELD_STATEMENTS, data); + check(node, PreviewFeature.RECORD_DECLARATIONS, data); visitChildren(node, data); } @@ -277,6 +298,12 @@ public class LanguageLevelChecker { visitChildren(node, data); } + @Override + public void visit(ASTRecordDeclaration node, T data) { + check(node, PreviewFeature.RECORD_DECLARATIONS, data); + visitChildren(node, data); + } + // @Override // public void visit(ASTConstructorCall node, T data) { // if (node.usesDiamondTypeArgs()) { @@ -354,6 +381,7 @@ public class LanguageLevelChecker { super.visit(node, data); } + // @Override // public void visit(ASTNumericLiteral node, T data) { // int base = node.getBase(); @@ -399,6 +427,12 @@ public class LanguageLevelChecker { visitChildren(node, data); } + @Override + public void visit(ASTTypeTestPattern node, T data) { + check(node, PreviewFeature.TYPE_TEST_PATTERNS_IN_INSTANCEOF, data); + visitChildren(node, data); + } + // @Override // public void visit(ASTTryStatement node, T data) { // if (node.isTryWithResources()) { @@ -483,10 +517,13 @@ public class LanguageLevelChecker { @Override public void visit(ASTAnyTypeDeclaration node, T data) { - if ("var".equals(node.getSimpleName())) { + String simpleName = node.getSimpleName(); + if ("var".equals(simpleName)) { check(node, ReservedIdentifiers.VAR_AS_A_TYPE_NAME, data); + } else if ("record".equals(simpleName)) { + check(node, ReservedIdentifiers.RECORD_AS_A_TYPE_NAME, data); } - checkIdent(node, node.getSimpleName(), data); + checkIdent(node, simpleName, data); visitChildren(node, data); } From b50f4f48d8a5b757ddfc64faa4414feba5d56304 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 2 Mar 2020 20:17:33 +0100 Subject: [PATCH 177/235] [doc] Update release notes, fixes #639, refs #2317 --- docs/pages/release_notes.md | 8 ++++++++ pmd-core/src/main/resources/rulesets/releases/6220.xml | 1 + 2 files changed, 9 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index a6b5973f9e..37b11bdee8 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -31,12 +31,19 @@ the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs to cyclomatic complexity, this rule uses "Cognitive Complexity", which is a measure of how difficult it is for humans to read and understand a method. +* The Rule {% rule "apex/errorprone/TestMethodsMustBeInTestClasses" %} (`apex-errorprone`) finds test methods + that are not residing in a test class. The test methods should be moved to a proper test class. + Support for tests inside functional classes was removed in Spring-13 (API Version 27.0), making classes + that violate this rule fail compile-time. This rule is however useful when dealing with legacy code. + ### Fixed Issues * apex * [#1087](https://github.com/pmd/pmd/issues/1087): \[apex] Support suppression via //NOPMD * apex-design * [#2162](https://github.com/pmd/pmd/issues/2162): \[apex] Cognitive Complexity rule +* apex-errorprone + * [#639](https://github.com/pmd/pmd/issues/639): \[apex] Test methods should not be in classes other than test classes * doc * [#2274](https://github.com/pmd/pmd/issues/2274): \[doc] Java API documentation for PMD * java @@ -135,6 +142,7 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * [#2278](https://github.com/pmd/pmd/pull/2278): \[java] fix UnusedImports rule for ambiguous static on-demand imports - [Kris Scheibe](https://github.com/kris-scheibe) * [#2279](https://github.com/pmd/pmd/pull/2279): \[apex] Add support for suppressing violations using the // NOPMD comment - [Gwilym Kuiper](https://github.com/gwilymatgearset) * [#2297](https://github.com/pmd/pmd/pull/2297): \[apex] Cognitive complexity metrics - [Gwilym Kuiper](https://github.com/gwilymatgearset) +* [#2317](https://github.com/pmd/pmd/pull/2317): \[apex] New Rule - Test Methods Must Be In Test Classes - [Brian Nørremark](https://github.com/noerremark) {% endtocmaker %} diff --git a/pmd-core/src/main/resources/rulesets/releases/6220.xml b/pmd-core/src/main/resources/rulesets/releases/6220.xml index e810572d8e..13b0cbc5b7 100644 --- a/pmd-core/src/main/resources/rulesets/releases/6220.xml +++ b/pmd-core/src/main/resources/rulesets/releases/6220.xml @@ -9,5 +9,6 @@ This ruleset contains links to rules that are new in PMD v6.22.0 + From 4f78b14803686c0d9ab324b5eda0a9a5cb34b082 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 2 Mar 2020 20:26:41 +0100 Subject: [PATCH 178/235] Update apex quickstart ruleset --- pmd-apex/src/main/resources/rulesets/apex/quickstart.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml b/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml index 4d318d6f4f..bb202931c4 100644 --- a/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml +++ b/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml @@ -268,6 +268,7 @@ + From c8c8a04dda2be8104c54ed730378ced7af8007b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Mon, 2 Mar 2020 20:13:56 +0100 Subject: [PATCH 179/235] Fix new java nodes --- pmd-java/etc/grammar/Java.jjt | 5 ++--- .../pmd/lang/java/ast/ASTRecordBody.java | 9 +++++---- .../pmd/lang/java/ast/ASTRecordComponent.java | 9 +++++---- .../pmd/lang/java/ast/ASTRecordComponentList.java | 9 +++++---- .../java/ast/ASTRecordConstructorDeclaration.java | 13 +++++++------ .../pmd/lang/java/ast/ASTRecordDeclaration.java | 9 +++++---- .../pmd/lang/java/ast/ASTTypeTestPattern.java | 8 ++++---- .../java/ast/internal/LanguageLevelChecker.java | 12 +++++------- .../rule/design/UselessOverridingMethodRule.java | 7 ------- .../sourceforge/pmd/lang/java/ast/ASTPatternTest.kt | 7 +++++-- .../pmd/lang/java/ast/KotlinTestingDsl.kt | 4 +--- 11 files changed, 44 insertions(+), 48 deletions(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index e353957ef3..34a5347f04 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -876,7 +876,6 @@ void RecordDeclaration(int modifiers): { Token t; jjtThis.setModifiers(modifiers); - checkForRecordType(); } { t = { @@ -884,7 +883,7 @@ void RecordDeclaration(int modifiers): throw new ParseException("ERROR: expecting record"); } } - t= {checkForBadTypeIdentifierUsage(t.image); jjtThis.setImage(t.image);} + t= {jjtThis.setImage(t.image);} [ TypeParameters() ] RecordComponentList() [ ImplementsList() ] @@ -1286,7 +1285,7 @@ void EqualityExpression() #EqualityExpression(>1): void InstanceOfExpression() #InstanceOfExpression(>1): {} { - RelationalExpression() [ LOOKAHEAD(2) "instanceof" Type() [ {checkforBadInstanceOfPattern();} VariableDeclaratorId() #TypeTestPattern(2) ] ] + RelationalExpression() [ LOOKAHEAD(2) "instanceof" Type() [ VariableDeclaratorId() #TypeTestPattern(2) ] ] } void RelationalExpression() #RelationalExpression(>1): 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 904b62e56b..2f80ab773b 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 @@ -25,12 +25,13 @@ public final class ASTRecordBody extends AbstractJavaNode { super(id); } - ASTRecordBody(JavaParser p, int id) { - super(p, id); - } - @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + @Override + public void jjtAccept(SideEffectingVisitor visitor, T data) { + visitor.visit(this, data); + } } 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 4c9943e258..e58d185704 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 @@ -27,15 +27,16 @@ public final class ASTRecordComponent extends AbstractJavaNode { super(id); } - ASTRecordComponent(JavaParser p, int id) { - super(p, id); - } - @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + @Override + public void jjtAccept(SideEffectingVisitor visitor, T data) { + visitor.visit(this, data); + } + public boolean isVarargs() { return varargs; } 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 8139e687cb..f3344a6e8b 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 @@ -22,12 +22,13 @@ public final class ASTRecordComponentList extends AbstractJavaNode { super(id); } - ASTRecordComponentList(JavaParser p, int id) { - super(p, id); - } - @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + @Override + public void jjtAccept(SideEffectingVisitor visitor, T data) { + visitor.visit(this, data); + } } 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 9d5fb279d5..f05bbb978f 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 @@ -12,8 +12,8 @@ import net.sourceforge.pmd.annotation.Experimental; * *
  *
- * RecordConstructorDeclaration ::=  ({@linkplain ASTTypeAnnotation TypeAnnotation})*
- *                                   {@linkplain ASTModifiers Modifiers}
+ * RecordConstructorDeclaration ::=  ({@linkplain ASTAnnotation TypeAnnotation})*
+ *                                   {@linkplain ASTModifierList Modifiers}
  *                                   {@linkplain ASTTypeParameters TypeParameters}?
  *                                   <IDENTIFIER>
  *                                   ( "throws" {@linkplain ASTNameList NameList} )?
@@ -28,15 +28,16 @@ public final class ASTRecordConstructorDeclaration extends AbstractJavaAccessNod
         super(id);
     }
 
-    ASTRecordConstructorDeclaration(JavaParser p, int id) {
-        super(p, id);
-    }
-
     @Override
     public Object jjtAccept(JavaParserVisitor visitor, Object data) {
         return visitor.visit(this, data);
     }
 
+    @Override
+    public  void jjtAccept(SideEffectingVisitor visitor, T data) {
+        visitor.visit(this, data);
+    }
+
     @Override
     public ASTRecordConstructorDeclaration getDeclarationNode() {
         return this;
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 1d84939d8c..660f6b52b4 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
@@ -33,15 +33,16 @@ public final class ASTRecordDeclaration extends AbstractAnyTypeDeclaration {
         super(id);
     }
 
-    ASTRecordDeclaration(JavaParser p, int id) {
-        super(p, id);
-    }
-
     @Override
     public Object jjtAccept(JavaParserVisitor visitor, Object data) {
         return visitor.visit(this, data);
     }
 
+    @Override
+    public  void jjtAccept(SideEffectingVisitor visitor, T data) {
+        visitor.visit(this, data);
+    }
+
     @Override
     public TypeKind getTypeKind() {
         return TypeKind.RECORD;
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java
index c126b89198..f04ecab633 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeTestPattern.java
@@ -24,16 +24,16 @@ public final class ASTTypeTestPattern extends AbstractJavaNode implements ASTPat
         super(id);
     }
 
-    ASTTypeTestPattern(JavaParser p, int id) {
-        super(p, id);
-    }
-
 
     @Override
     public Object jjtAccept(JavaParserVisitor visitor, Object data) {
         return visitor.visit(this, data);
     }
 
+    @Override
+    public  void jjtAccept(SideEffectingVisitor visitor, T data) {
+        visitor.visit(this, data);
+    }
 
     /**
      * Gets the type against which the expression is tested.
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 667a148786..7b5758e5d0 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
@@ -55,7 +55,7 @@ import net.sourceforge.pmd.lang.java.ast.SideEffectingVisitorAdapter;
  */
 public class LanguageLevelChecker {
 
-    private static final Pattern SPACE_ESCAPE_PATTERN = Pattern.compile("(?!\\\\)\\\\s");
+    private static final Pattern SPACE_ESCAPE_PATTERN = Pattern.compile("(? {
         /** \s */
         SPACE_STRING_ESCAPES(14, 14, false),
         RECORD_DECLARATIONS(14, 14, false),
-        TYPE_TEST_PATTERNS_IN_INSTANCEOF(14, 14, false),
-        ;
+        TYPE_TEST_PATTERNS_IN_INSTANCEOF(14, 14, false);
 
 
         private final int minPreviewVersion;
@@ -148,7 +147,7 @@ public class LanguageLevelChecker {
 
             String message = StringUtils.capitalize(displayNameLower(name()));
             if (canBePreview) {
-                message += " is a only a preview feature on JDK " + jdk;
+                message += " is a preview feature of JDK " + jdk;
             } else if (wasStandardized) {
                 message = message + " was only standardized in Java " + (maxPreviewVersion + 1);
             } else if (minPreviewVersion == maxPreviewVersion) {
@@ -166,8 +165,7 @@ public class LanguageLevelChecker {
         ENUM_AS_AN_IDENTIFIER(5, "enum"),
         UNDERSCORE_AS_AN_IDENTIFIER(9, "_"),
         VAR_AS_A_TYPE_NAME(10, "var"),
-        RECORD_AS_A_TYPE_NAME(14, "record") // TODO
-        ;
+        RECORD_AS_A_TYPE_NAME(14, "record");
 
         private final int maxJdkVersion;
         private final String reserved;
@@ -280,7 +278,7 @@ public class LanguageLevelChecker {
 
         @Override
         public void visit(ASTYieldStatement node, T data) {
-            check(node, PreviewFeature.RECORD_DECLARATIONS, data);
+            check(node, PreviewFeature.YIELD_STATEMENTS, data);
             visitChildren(node, data);
         }
 
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java
index f73a34ebad..a32e7f8417 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UselessOverridingMethodRule.java
@@ -292,11 +292,4 @@ public class UselessOverridingMethodRule extends AbstractJavaRule {
                 || elevatingIntoDifferentPackage;
     }
 
-    /**
-     * @deprecated this method will be removed. Just use {@link Node#findChildrenOfType(Class)} directly.
-     */
-    @Deprecated
-    public  List findFirstDegreeChaildrenOfType(Node n, Class targetType) {
-        return n.findChildrenOfType(targetType);
-    }
 }
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt
index 64dc9dd6c1..e77efc7ec6 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/ASTPatternTest.kt
@@ -1,5 +1,6 @@
 package net.sourceforge.pmd.lang.java.ast
 
+import io.kotlintest.matchers.string.shouldContain
 import net.sourceforge.pmd.lang.ast.test.shouldBe
 import net.sourceforge.pmd.lang.java.ast.JavaVersion.J14__PREVIEW
 import java.io.IOException
@@ -8,8 +9,10 @@ class ASTPatternTest : ParserTestSpec({
 
     parserTest("Test patterns only available on JDK 14 (preview)", javaVersions = !J14__PREVIEW) {
 
-        expectParseException("Cannot use type test patterns in instanceof when running in JDK other than 14-preview") {
-            parseAstExpression("obj instanceof Class c")
+        inContext(ExpressionParsingCtx) {
+            "obj instanceof Class c" should throwParseException {
+                it.message.shouldContain("Type test patterns in instanceof is a preview feature of JDK 14, you should select your language version accordingly")
+            }
         }
 
     }
diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt
index 3e05589036..1a1cb69e96 100644
--- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt
+++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/ast/KotlinTestingDsl.kt
@@ -8,9 +8,7 @@ import io.kotlintest.matchers.string.shouldContain
 import io.kotlintest.shouldThrow
 import net.sourceforge.pmd.lang.ast.Node
 import net.sourceforge.pmd.lang.ast.ParseException
-import net.sourceforge.pmd.lang.ast.test.Assertions
-import net.sourceforge.pmd.lang.ast.test.NodeSpec
-import net.sourceforge.pmd.lang.ast.test.matchNode
+import net.sourceforge.pmd.lang.ast.test.*
 import net.sourceforge.pmd.lang.ast.test.shouldMatchNode
 import net.sourceforge.pmd.lang.java.JavaParsingHelper
 import java.beans.PropertyDescriptor

From f63deac878aa9a51506bbb73726050b1611fcc7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= 
Date: Mon, 2 Mar 2020 20:32:42 +0100
Subject: [PATCH 180/235] Remove wrongly committed file

---
 TODO.md | 33 ---------------------------------
 1 file changed, 33 deletions(-)
 delete mode 100644 TODO.md

diff --git a/TODO.md b/TODO.md
deleted file mode 100644
index cc51eff000..0000000000
--- a/TODO.md
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-Overload specificity:
-
-At:   /home/clifrr/Bureau/jdk13-src/java.base/jdk/nashorn/internal/runtime/Context.java:1792 :24
-Expr: Stream.of(addModules.split(\",\")).map(String::trim)
-[WARNING] CTDecl resolution failed. Summary of failures:
-    STRICT:
-        Incompatible formals: java.lang.String[] is not convertible to java.lang.String		map(java.util.function.Function) -> java.util.stream.Stream
-    
-    LOOSE:
-        Incompatible formals: java.lang.String[] is not convertible to java.lang.String		map(java.util.function.Function) -> java.util.stream.Stream
-  
-
-
-Raw type mistake:
-
-At:   /home/clifrr/Bureau/jdk13-src/java.base/java/util/Collections.java:710 :23
-Expr: max((Collection) coll)
-[WARNING] CTDecl resolution failed. Summary of failures:
-    STRICT:
-        Incompatible bounds: π291 = java.lang.Object and π291 <: java.lang.Comparable		max(java.util.Collection) -> T
-    
-    LOOSE:
-        Incompatible bounds: ρ291 = java.lang.Object and ρ291 <: java.lang.Comparable		max(java.util.Collection) -> T
-    
-
- public static  T max(Collection coll, Comparator comp) {
-        if (comp==null)
-            return (T)max((Collection) coll);
-
-

From 18cc6a3e4e467e3ca6d03cd9f5fd317f1108d11b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= 
Date: Mon, 2 Mar 2020 20:46:40 +0100
Subject: [PATCH 181/235] Disallow throws clause on record constructor

---
 pmd-java/etc/grammar/Java.jjt                            | 1 -
 .../sourceforge/pmd/lang/java/ast/Java14PreviewTest.java | 9 ++++++++-
 .../lang/java/ast/jdkversiontests/java14/Records.java    | 3 ---
 3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt
index 29ce5dd111..2f4db088d1 100644
--- a/pmd-java/etc/grammar/Java.jjt
+++ b/pmd-java/etc/grammar/Java.jjt
@@ -1171,7 +1171,6 @@ void RecordConstructorDeclaration():
   modifiers = Modifiers() { jjtThis.setModifiers(modifiers); }
   [TypeParameters()]
    { jjtThis.setImage(token.image); }
-  [ "throws" NameList() ]
   "{" ( BlockStatement() )* "}"
 }
 
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java
index 27fb1b1ac1..be98bbb9d5 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java
@@ -98,7 +98,7 @@ public class Java14PreviewTest {
         Assert.assertEquals("Point", recordDecl.getImage());
         Assert.assertFalse(recordDecl.isNested());
         List components = recordDecl.getFirstChildOfType(ASTRecordComponentList.class)
-                .findChildrenOfType(ASTRecordComponent.class);
+                                                        .findChildrenOfType(ASTRecordComponent.class);
         Assert.assertEquals(2, components.size());
         Assert.assertEquals("x", components.get(0).getVariableDeclaratorId().getImage());
         Assert.assertEquals("y", components.get(1).getVariableDeclaratorId().getImage());
@@ -109,6 +109,13 @@ public class Java14PreviewTest {
         java14.parseResource("Point.java");
     }
 
+    @Test(expected = ParseException.class)
+    public void recordCtorWithThrowsShouldFail() {
+        java14p.parse("  record R {"
+                          + "   R throws IOException {}"
+                          + "  }");
+    }
+
     @Test
     public void innerRecords() {
         ASTCompilationUnit compilationUnit = java14p.parseResource("Records.java");
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java
index a1be788be7..2368b2ae7c 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java14/Records.java
@@ -57,8 +57,5 @@ public class Records {
     public record PersonRecord(String firstName, String lastName)
         implements Person, java.io.Serializable {
 
-        PersonRecord throws IOException { // compact ctor with throws list
-            throw new IOException();
-        }
     }
 }

From f698a2e7aa3de0851e353d17a1b491d4bb6e911c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= 
Date: Mon, 2 Mar 2020 22:18:13 +0100
Subject: [PATCH 182/235] Small API improvements for records

---
 pmd-java/etc/grammar/Java.jjt                 |  2 +-
 .../pmd/lang/java/ast/ASTRecordComponent.java |  4 +-
 .../lang/java/ast/ASTRecordComponentList.java | 13 +++++-
 .../ast/ASTRecordConstructorDeclaration.java  | 11 +++--
 .../lang/java/ast/ASTRecordDeclaration.java   |  8 +---
 .../pmd/lang/java/ast/Java14PreviewTest.java  | 43 +++++++++++--------
 6 files changed, 48 insertions(+), 33 deletions(-)

diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt
index 2f4db088d1..80186c015e 100644
--- a/pmd-java/etc/grammar/Java.jjt
+++ b/pmd-java/etc/grammar/Java.jjt
@@ -1171,7 +1171,7 @@ void RecordConstructorDeclaration():
   modifiers = Modifiers() { jjtThis.setModifiers(modifiers); }
   [TypeParameters()]
    { jjtThis.setImage(token.image); }
-  "{" ( BlockStatement() )* "}"
+  Block()
 }
 
 void TypeParameters():
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 4c9943e258..b19f983d06 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
@@ -20,7 +20,7 @@ import net.sourceforge.pmd.annotation.Experimental;
  * 
*/ @Experimental -public final class ASTRecordComponent extends AbstractJavaNode { +public final class ASTRecordComponent extends AbstractJavaAnnotatableNode { private boolean varargs; ASTRecordComponent(int id) { @@ -48,7 +48,7 @@ public final class ASTRecordComponent extends AbstractJavaNode { return getFirstChildOfType(ASTType.class); } - public ASTVariableDeclaratorId getVariableDeclaratorId() { + public ASTVariableDeclaratorId getVarId() { return getFirstChildOfType(ASTVariableDeclaratorId.class); } } 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 8139e687cb..9bf152df08 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 @@ -5,6 +5,8 @@ package net.sourceforge.pmd.lang.java.ast; +import java.util.Iterator; + import net.sourceforge.pmd.annotation.Experimental; /** @@ -17,7 +19,7 @@ import net.sourceforge.pmd.annotation.Experimental; *
*/ @Experimental -public final class ASTRecordComponentList extends AbstractJavaNode { +public final class ASTRecordComponentList extends AbstractJavaNode implements Iterable { ASTRecordComponentList(int id) { super(id); } @@ -30,4 +32,13 @@ public final class ASTRecordComponentList extends AbstractJavaNode { public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + public int size() { + return getNumChildren(); + } + + @Override + public Iterator iterator() { + return new NodeChildrenIterator<>(this, ASTRecordComponent.class); + } } 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 9d5fb279d5..f262de9ea9 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 @@ -12,12 +12,11 @@ import net.sourceforge.pmd.annotation.Experimental; * *
  *
- * RecordConstructorDeclaration ::=  ({@linkplain ASTTypeAnnotation TypeAnnotation})*
- *                                   {@linkplain ASTModifiers Modifiers}
+ * RecordConstructorDeclaration ::=  ({@linkplain ASTAnnotation Annotation})*
+ *                                   RecordModifiers
  *                                   {@linkplain ASTTypeParameters TypeParameters}?
  *                                   <IDENTIFIER>
- *                                   ( "throws" {@linkplain ASTNameList NameList} )?
- *                                   "{" ( {@linkplain ASTBlockStatement ASTBlockStatement} )* "}"
+ *                                   {@link ASTBlock Block}
  *
  * 
* @@ -46,4 +45,8 @@ public final class ASTRecordConstructorDeclaration extends AbstractJavaAccessNod public DeclarationKind getKind() { return DeclarationKind.RECORD_CONSTRUCTOR; } + + public ASTBlock getBody() { + return getFirstChildOfType(ASTBlock.class); + } } 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 1d84939d8c..553190dd74 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 @@ -57,11 +57,7 @@ public final class ASTRecordDeclaration extends AbstractAnyTypeDeclaration { return isNested(); } - public List getRecordComponents() { - return getFirstChildOfType(ASTRecordComponentList.class).findChildrenOfType(ASTRecordComponent.class); - } - - public String getName() { - return getImage(); + public ASTRecordComponentList getComponentList() { + return getFirstChildOfType(ASTRecordComponentList.class); } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index be98bbb9d5..b137fe5c2d 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -100,8 +100,8 @@ public class Java14PreviewTest { List components = recordDecl.getFirstChildOfType(ASTRecordComponentList.class) .findChildrenOfType(ASTRecordComponent.class); Assert.assertEquals(2, components.size()); - Assert.assertEquals("x", components.get(0).getVariableDeclaratorId().getImage()); - Assert.assertEquals("y", components.get(1).getVariableDeclaratorId().getImage()); + Assert.assertEquals("x", components.get(0).getVarId().getImage()); + Assert.assertEquals("y", components.get(1).getVarId().getImage()); } @Test(expected = ParseException.class) @@ -123,21 +123,21 @@ public class Java14PreviewTest { Assert.assertEquals(7, recordDecls.size()); ASTRecordDeclaration complex = recordDecls.get(0); - Assert.assertEquals("MyComplex", complex.getName()); + Assert.assertEquals("MyComplex", complex.getSimpleName()); Assert.assertTrue(complex.isNested()); - Assert.assertEquals(0, complex.getRecordComponents().get(0).findChildrenOfType(ASTAnnotation.class).size()); - Assert.assertEquals(1, complex.getRecordComponents().get(1).findChildrenOfType(ASTAnnotation.class).size()); + Assert.assertEquals(0, getComponent(complex, 0).findChildrenOfType(ASTAnnotation.class).size()); + Assert.assertEquals(1, getComponent(complex, 1).findChildrenOfType(ASTAnnotation.class).size()); Assert.assertEquals(2, complex.getDeclarations().size()); Assert.assertTrue(complex.getDeclarations().get(0).getChild(1) instanceof ASTConstructorDeclaration); Assert.assertTrue(complex.getDeclarations().get(1).getChild(0) instanceof ASTRecordDeclaration); ASTRecordDeclaration nested = recordDecls.get(1); - Assert.assertEquals("Nested", nested.getName()); + Assert.assertEquals("Nested", nested.getSimpleName()); Assert.assertTrue(nested.isNested()); ASTRecordDeclaration range = recordDecls.get(2); - Assert.assertEquals("Range", range.getName()); - Assert.assertEquals(2, range.getRecordComponents().size()); + Assert.assertEquals("Range", range.getSimpleName()); + Assert.assertEquals(2, range.getComponentList().size()); List rangeConstructors = range.findDescendantsOfType(ASTRecordConstructorDeclaration.class); Assert.assertEquals(1, rangeConstructors.size()); Assert.assertEquals("Range", rangeConstructors.get(0).getImage()); @@ -145,27 +145,32 @@ public class Java14PreviewTest { Assert.assertEquals(2, range.getDeclarations().size()); ASTRecordDeclaration varRec = recordDecls.get(3); - Assert.assertEquals("VarRec", varRec.getName()); - Assert.assertEquals("x", varRec.getRecordComponents().get(0).getVariableDeclaratorId().getImage()); - Assert.assertTrue(varRec.getRecordComponents().get(0).isVarargs()); - Assert.assertEquals(2, varRec.getRecordComponents().get(0).findChildrenOfType(ASTAnnotation.class).size()); - Assert.assertEquals(1, varRec.getRecordComponents().get(0).getTypeNode().findDescendantsOfType(ASTAnnotation.class).size()); + Assert.assertEquals("VarRec", varRec.getSimpleName()); + Assert.assertEquals("x", getComponent(varRec, 0).getVarId().getImage()); + Assert.assertTrue(getComponent(varRec, 0).isVarargs()); + Assert.assertEquals(2, getComponent(varRec, 0).findChildrenOfType(ASTAnnotation.class).size()); + Assert.assertEquals(1, getComponent(varRec, 0).getTypeNode().findDescendantsOfType(ASTAnnotation.class).size()); ASTRecordDeclaration arrayRec = recordDecls.get(4); - Assert.assertEquals("ArrayRec", arrayRec.getName()); - Assert.assertEquals("x", arrayRec.getRecordComponents().get(0).getVariableDeclaratorId().getImage()); - Assert.assertTrue(arrayRec.getRecordComponents().get(0).getVariableDeclaratorId().hasArrayType()); + Assert.assertEquals("ArrayRec", arrayRec.getSimpleName()); + Assert.assertEquals("x", getComponent(arrayRec, 0).getVarId().getImage()); + Assert.assertTrue(getComponent(arrayRec, 0).getVarId().hasArrayType()); ASTRecordDeclaration emptyRec = recordDecls.get(5); - Assert.assertEquals("EmptyRec", emptyRec.getName()); - Assert.assertEquals(0, emptyRec.getRecordComponents().size()); + Assert.assertEquals("EmptyRec", emptyRec.getSimpleName()); + Assert.assertEquals(0, emptyRec.getComponentList().size()); ASTRecordDeclaration personRec = recordDecls.get(6); - Assert.assertEquals("PersonRecord", personRec.getName()); + Assert.assertEquals("PersonRecord", personRec.getSimpleName()); ASTImplementsList impl = personRec.getFirstChildOfType(ASTImplementsList.class); Assert.assertEquals(2, impl.findChildrenOfType(ASTClassOrInterfaceType.class).size()); } + private ASTRecordComponent getComponent(ASTRecordDeclaration arrayRec, int index) { + return (ASTRecordComponent) arrayRec.getComponentList().getChild(index); + } + + @Test(expected = ParseException.class) public void recordIsARestrictedIdentifier() { java14p.parse("public class record {}"); From 69025d75228d664e66747c0a1059746220c5d0f4 Mon Sep 17 00:00:00 2001 From: Piotr Szymanski Date: Wed, 4 Mar 2020 15:10:24 +0100 Subject: [PATCH 183/235] extract(xml), xml_root, xml_forest fix --- pmd-plsql/etc/grammar/PldocAST.jjt | 17 +++++++++++++---- .../pmd/lang/plsql/ast/FunctionsTest.java | 5 +++++ .../pmd/lang/plsql/ast/ExtractExpressions.pls | 10 ++++++++++ .../pmd/lang/plsql/ast/XMLFunctions.pls | 15 +++++++++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index a6d3df7886..36bf8a5eee 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -1640,8 +1640,9 @@ ASTFunctionCall FunctionCall() : | LOOKAHEAD({"XMLCAST".equalsIgnoreCase(token.getImage())}) "(" Expression() Datatype() ")" | LOOKAHEAD({"XMLQUERY".equalsIgnoreCase(token.getImage())}) "(" StringLiteral() [ LOOKAHEAD({isKeyword("PASSING")}) XMLPassingClause() ] KEYWORD("CONTENT") [ ] ")" | LOOKAHEAD({"CAST".equalsIgnoreCase(token.getImage())}) "(" ( "(" Subquery() ")" | Expression() ) Datatype() ")" - | LOOKAHEAD({"XMLFOREST".equalsIgnoreCase(token.getImage())}) "(" SqlExpression() [ ID() ] ( "," SqlExpression() [ ID() ] )* ")" + | LOOKAHEAD({"XMLFOREST".equalsIgnoreCase(token.getImage())}) "(" SqlExpression() [ ] [ ID() ] ( "," SqlExpression() [ ] [ ID() ] )* ")" | LOOKAHEAD({"XMLELEMENT".equalsIgnoreCase(token.getImage())}) XMLElement() + | LOOKAHEAD({"XMLROOT".equalsIgnoreCase(token.getImage())}) "(" Expression() "," KEYWORD("VERSION") (LOOKAHEAD(2) ( "VALUE") | Expression() ) [ "," KEYWORD("STANDALONE") ( | )] [ "VALUE" ] ")" | Arguments() ) @@ -3240,14 +3241,22 @@ ASTUnaryExpression UnaryExpression(boolean isUnarySign) #UnaryExpression(>1) : ASTExtractExpression ExtractExpression() : {} { + LOOKAHEAD(4) "(" ( | | | | | | | | | ) - (LOOKAHEAD(2) FunctionCall() - |LOOKAHEAD(2) DateTimeLiteral() - |LOOKAHEAD(1) Name() ) ")" + ( + LOOKAHEAD(FunctionCall()) FunctionCall() + | + LOOKAHEAD(DateTimeLiteral()) DateTimeLiteral() + | + LOOKAHEAD(Name()) Name() + ) ")" + { return jjtThis ; } + | + LOOKAHEAD(3) "(" Argument() "," Expression() ["," SchemaName() ] ")" { return jjtThis ; } } diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/FunctionsTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/FunctionsTest.java index 2f4b1bd2dd..5a6b8ef7a7 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/FunctionsTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/FunctionsTest.java @@ -19,4 +19,9 @@ public class FunctionsTest extends AbstractPLSQLParserTst { public void parseSelectExtractExpression() { plsql.parseResource("ExtractExpressions.pls"); } + + @Test + public void parseXMLExpression() { + plsql.parseResource("XMLFunctions.pls"); + } } diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExtractExpressions.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExtractExpressions.pls index 0e4e7f3b90..f9dd1d5f68 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExtractExpressions.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExtractExpressions.pls @@ -19,3 +19,13 @@ SELECT last_name, employee_id, hire_date SELECT EXTRACT(TIMEZONE_REGION FROM TIMESTAMP '1999-01-01 10:00:00 -08:00') FROM DUAL; + +declare + v_months NUMBER; +begin + v_months := (extract(YEAR FROM v_rec.v_rec_rec.v_rec_rec_field) - + extract(YEAR FROM v_rec.v_rec_rec.v_rec_rec_field)) * 12 + + (extract(MONTH FROM v_rec.v_rec_rec.v_rec_rec_field) - + extract(MONTH FROM v_rec.v_rec_rec.v_rec_rec_field)); + +end; \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls new file mode 100644 index 0000000000..55a1df4146 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls @@ -0,0 +1,15 @@ +SELECT xmlroot(xmlelement("BODY", + xmlagg(xmlconcat(extract(v_1, '/BODY/child::node()'), + extract(v_2, '/BODY/child::node()')))), + version '1.0') + FROM (SELECT dummy FROM dual CONNECT BY LEVEL <= 2); + +SELECT warehouse_name, EXTRACT(warehouse_spec, '/Warehouse/Docks') + "Number of Docks" + FROM warehouses + WHERE warehouse_spec IS NOT NULL; + +SELECT XMLELEMENT("Emp", + XMLFOREST(e.employee_id, e.last_name, e.salary)) + "Emp Element" + FROM employees e WHERE employee_id = 204; \ No newline at end of file From 97043a75c565b7eeaa279796a2493fdffb3dc172 Mon Sep 17 00:00:00 2001 From: Piotr Szymanski Date: Wed, 4 Mar 2020 17:22:15 +0100 Subject: [PATCH 184/235] parsing where_current_of added --- pmd-plsql/etc/grammar/PldocAST.jjt | 4 +++ .../pmd/lang/plsql/ast/WhereClauseTest.java | 5 ++++ .../pmd/lang/plsql/ast/WhereCurrentOf.pls | 26 +++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereCurrentOf.pls diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index a6d3df7886..ef71886a47 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -1354,7 +1354,11 @@ ASTGroupingExpressionList GroupingExpressionList() : ASTWhereClause WhereClause() : {} { + ( + LOOKAHEAD(3) Expression() + | Condition() + ) { return jjtThis; } } diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/WhereClauseTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/WhereClauseTest.java index 96440c0b15..3c0b724362 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/WhereClauseTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/WhereClauseTest.java @@ -85,4 +85,9 @@ public class WhereClauseTest extends AbstractPLSQLParserTst { public void testParentheses() { plsql.parseResource("WhereClauseParens.pls"); } + + @Test + public void testCurrentOf() { + plsql.parseResource("WhereCurrentOf.pls"); + } } diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereCurrentOf.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereCurrentOf.pls new file mode 100644 index 0000000000..418c4b3cc4 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereCurrentOf.pls @@ -0,0 +1,26 @@ +declare + thisstudent student%rowtype; + + cursor maths_student is + select * + from student + where sid in (select sid + from take + where cid = ’cs145’) + for update; + +begin + open maths_student; + loop + fetch maths_student + into thisstudent; + exit when(maths_student%notfound); + if (thisstudent.gpa < 4.0) then + update student + set gpa = 4.0 + where current of maths_student; + end if; + end loop; + + close maths_student; +end; From b83a4c31123e3f03dc26ded1e19b121f8529dc91 Mon Sep 17 00:00:00 2001 From: Piotr Szymanski Date: Thu, 5 Mar 2020 11:22:47 +0100 Subject: [PATCH 185/235] fixed test case --- .../net/sourceforge/pmd/lang/plsql/ast/WhereCurrentOf.pls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereCurrentOf.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereCurrentOf.pls index 418c4b3cc4..f9464b2f16 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereCurrentOf.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereCurrentOf.pls @@ -6,7 +6,7 @@ declare from student where sid in (select sid from take - where cid = ’cs145’) + where cid = 'cs145') for update; begin From 3329374214781bc3c2e5b92424fc9919a00be6a2 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 5 Mar 2020 12:02:56 +0100 Subject: [PATCH 186/235] [plsql] Refactor ExtractExpression * Separate helper productions for datetime/xml * Use StringLiteral for xpath and namespace --- pmd-plsql/etc/grammar/PldocAST.jjt | 30 ++++++++-- pmd-plsql/src/main/ant/alljavacc.xml | 1 + .../lang/plsql/ast/ASTExtractExpression.java | 57 +++++++++++++++++++ .../plsql/ast/ASTExtractExpressionTest.java | 26 +++++++++ .../pmd/lang/plsql/ast/XMLFunctions.pls | 8 ++- 5 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpression.java create mode 100644 pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpressionTest.java diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 36bf8a5eee..8fffbd88b2 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -27,6 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** + * Add support for XMLROOT, improve ExtractExpression to support xml + * + * Piotr Szymanski 03/2020 + *==================================================================== * Add basic support for with clause in select statements * * Andreas Dangel 09/2019 @@ -3241,7 +3245,16 @@ ASTUnaryExpression UnaryExpression(boolean isUnarySign) #UnaryExpression(>1) : ASTExtractExpression ExtractExpression() : {} { - LOOKAHEAD(4) + LOOKAHEAD(4) ExtractDatetime() { return jjtThis ; } + | + LOOKAHEAD(3) ExtractXml(jjtThis) { return jjtThis ; } +} + +/** + * See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/EXTRACT-datetime.html#GUID-36E52BF8-945D-437D-9A3C-6860CABD210E + */ +void ExtractDatetime() #void : {} +{ "(" ( | | | | | | | @@ -3254,10 +3267,17 @@ ASTExtractExpression ExtractExpression() : | LOOKAHEAD(Name()) Name() ) ")" - { return jjtThis ; } - | - LOOKAHEAD(3) "(" Argument() "," Expression() ["," SchemaName() ] ")" - { return jjtThis ; } +} + +/** + * See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/EXTRACT-XML.html#GUID-593295AA-4F46-4D75-B8DC-E7BCEDB1D4D7 + */ +void ExtractXml(ASTExtractExpression extractExpr) #void : +{ + extractExpr.setXml(); +} +{ + "(" Argument() "," StringLiteral() ["," StringLiteral() ] ")" } ASTUnaryExpressionNotPlusMinus UnaryExpressionNotPlusMinus() #UnaryExpressionNotPlusMinus(>1) : diff --git a/pmd-plsql/src/main/ant/alljavacc.xml b/pmd-plsql/src/main/ant/alljavacc.xml index e963988534..d5c39fe95b 100644 --- a/pmd-plsql/src/main/ant/alljavacc.xml +++ b/pmd-plsql/src/main/ant/alljavacc.xml @@ -47,6 +47,7 @@ + diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpression.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpression.java new file mode 100644 index 0000000000..90d51eab8f --- /dev/null +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpression.java @@ -0,0 +1,57 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.plsql.ast; + +import java.util.List; + +import net.sourceforge.pmd.annotation.InternalApi; + +public final class ASTExtractExpression extends AbstractPLSQLNode { + + private boolean xml; + + @InternalApi + @Deprecated + public ASTExtractExpression(int id) { + super(id); + } + + + @InternalApi + @Deprecated + public ASTExtractExpression(PLSQLParser p, int id) { + super(p, id); + } + + + public Object jjtAccept(PLSQLParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } + + void setXml() { + xml = true; + } + + public boolean isXml() { + return xml; + } + + public String getXPath() { + if (xml) { + return getFirstChildOfType(ASTStringLiteral.class).getString(); + } + return ""; + } + + public String getNamespace() { + if (xml) { + List literals = findChildrenOfType(ASTStringLiteral.class); + if (literals.size() == 2) { + return literals.get(1).getString(); + } + } + return ""; + } +} diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpressionTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpressionTest.java new file mode 100644 index 0000000000..84f9a3550c --- /dev/null +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpressionTest.java @@ -0,0 +1,26 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.plsql.ast; + +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.lang.plsql.PlsqlParsingHelper; + +public class ASTExtractExpressionTest { + + + @Test + public void testXml() { + PlsqlParsingHelper parser = PlsqlParsingHelper.JUST_PARSE; + ASTInput unit = parser.parse("SELECT warehouse_name, EXTRACT(warehouse_spec, '/Warehouse/Docks', " + + "'xmlns:a=\"http://warehouse/1\" xmlns:b=\"http://warehouse/2\"') \"Number of Docks\" " + + " FROM warehouses WHERE warehouse_spec IS NOT NULL;"); + ASTExtractExpression extract = unit.getFirstDescendantOfType(ASTExtractExpression.class); + Assert.assertTrue(extract.isXml()); + Assert.assertEquals("/Warehouse/Docks", extract.getXPath()); + Assert.assertEquals("xmlns:a=\"http://warehouse/1\" xmlns:b=\"http://warehouse/2\"", extract.getNamespace()); + } +} diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls index 55a1df4146..84fb445628 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls @@ -8,7 +8,13 @@ SELECT warehouse_name, EXTRACT(warehouse_spec, '/Warehouse/Docks') "Number of Docks" FROM warehouses WHERE warehouse_spec IS NOT NULL; - + +SELECT warehouse_name, EXTRACT(warehouse_spec, '/Warehouse/Docks', 'xmlns:a="http://warehouse/1" xmlns:b="http://warehouse/2"') + "Number of Docks" + FROM warehouses + WHERE warehouse_spec IS NOT NULL; + + SELECT XMLELEMENT("Emp", XMLFOREST(e.employee_id, e.last_name, e.salary)) "Emp Element" From 2c68e135983117f13d7f9f7acfb5913ce71ddc78 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 5 Mar 2020 12:04:07 +0100 Subject: [PATCH 187/235] [plsql] Refactor XMLROOT and XMLFOREST * Undo changes for XMLFOREST - is not optional alone * Remove token for keyword "VALUE" --- pmd-plsql/etc/grammar/PldocAST.jjt | 17 +++++++++++----- .../pmd/lang/plsql/ast/XMLFunctions.pls | 20 ++++++++++++++++++- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 8fffbd88b2..825b02c29e 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -1626,6 +1626,10 @@ ASTOuterJoinExpression OuterJoinExpression() : * See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Functions.html#GUID-D079EFD3-C683-441F-977E-2C9503089982 * See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/About-User-Defined-Functions.html#GUID-4EB3E236-8216-471C-BA44-23D87BDFEA67 * + * XML Functions: + * https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/XMLROOT.html#GUID-5BD300E2-7138-436D-87AF-21658840CF9D + * https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/XMLFOREST.html#GUID-68E5C67E-CE97-4BF8-B7FF-2365E062C363 + * * A function reference/name might be: * function_name * package.function_name @@ -1644,9 +1648,12 @@ ASTFunctionCall FunctionCall() : | LOOKAHEAD({"XMLCAST".equalsIgnoreCase(token.getImage())}) "(" Expression() Datatype() ")" | LOOKAHEAD({"XMLQUERY".equalsIgnoreCase(token.getImage())}) "(" StringLiteral() [ LOOKAHEAD({isKeyword("PASSING")}) XMLPassingClause() ] KEYWORD("CONTENT") [ ] ")" | LOOKAHEAD({"CAST".equalsIgnoreCase(token.getImage())}) "(" ( "(" Subquery() ")" | Expression() ) Datatype() ")" - | LOOKAHEAD({"XMLFOREST".equalsIgnoreCase(token.getImage())}) "(" SqlExpression() [ ] [ ID() ] ( "," SqlExpression() [ ] [ ID() ] )* ")" + | LOOKAHEAD({"XMLFOREST".equalsIgnoreCase(token.getImage())}) "(" SqlExpression() [ ID() ] ( "," SqlExpression() [ ID() ] )* ")" | LOOKAHEAD({"XMLELEMENT".equalsIgnoreCase(token.getImage())}) XMLElement() - | LOOKAHEAD({"XMLROOT".equalsIgnoreCase(token.getImage())}) "(" Expression() "," KEYWORD("VERSION") (LOOKAHEAD(2) ( "VALUE") | Expression() ) [ "," KEYWORD("STANDALONE") ( | )] [ "VALUE" ] ")" + | LOOKAHEAD({"XMLROOT".equalsIgnoreCase(token.getImage())}) + "(" Expression() "," KEYWORD("VERSION") ( KEYWORD("VALUE") | Expression() ) + [ "," KEYWORD("STANDALONE") ( | [ LOOKAHEAD({isKeyword("VALUE")}) KEYWORD("VALUE") ] ) ] + ")" | Arguments() ) @@ -1732,7 +1739,7 @@ ASTXMLPassingClause XMLPassingClause() : {} { KEYWORD("PASSING") - [ "VALUE" ] + [ KEYWORD("VALUE") ] ( SqlExpression() [ LOOKAHEAD(2) ID() ] ) ( "," SqlExpression() [ LOOKAHEAD(2) ID() ] )* { return jjtThis; } @@ -2485,7 +2492,7 @@ ASTUpdateSetClause UpdateSetClause() : ( LOOKAHEAD(1) "=" Name() | - "VALUE" "(" TableAlias() ")" "=" ( LOOKAHEAD(1) "(" Subquery() ")" | Expression() ) + LOOKAHEAD({isKeyword("VALUE")}) KEYWORD("VALUE") "(" TableAlias() ")" "=" ( LOOKAHEAD(1) "(" Subquery() ")" | Expression() ) | ( ( @@ -5280,7 +5287,7 @@ ASTKEYWORD_UNRESERVED KEYWORD_UNRESERVED (): {} // PL/SQL UNRESERVED KEYWORDS - V$RESERVED.RESERVED='N' ( "REF" | "LAST" | "TRIM" | "OVER" | "UNBOUNDED" | "PRECEDING" | "FOLLOWING" | "WITHIN" | -"OVERFLOW" | "ERROR" | "WITHOUT" | "COUNT" | "VALUE" | "SUBPARTITION" | "LOG" | "ERRORS" | "REJECT" | "UNLIMITED" | +"OVERFLOW" | "ERROR" | "WITHOUT" | "COUNT" | "SUBPARTITION" | "LOG" | "ERRORS" | "REJECT" | "UNLIMITED" | | | diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls index 84fb445628..a3e887eee7 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/XMLFunctions.pls @@ -18,4 +18,22 @@ SELECT warehouse_name, EXTRACT(warehouse_spec, '/Warehouse/Docks', 'xmlns:a="htt SELECT XMLELEMENT("Emp", XMLFOREST(e.employee_id, e.last_name, e.salary)) "Emp Element" - FROM employees e WHERE employee_id = 204; \ No newline at end of file + FROM employees e WHERE employee_id = 204; + +SELECT XMLROOT ( XMLType('143598'), VERSION '1.0', STANDALONE YES) + AS "XMLROOT" FROM DUAL; + +SELECT XMLROOT ( XMLType('143598'), VERSION '1.0', STANDALONE NO) + AS "XMLROOT" FROM DUAL; + +SELECT XMLROOT ( XMLType('143598'), VERSION '1.0', STANDALONE NO VALUE) + AS "XMLROOT" FROM DUAL; + +SELECT XMLROOT ( XMLType('143598'), VERSION NO VALUE, STANDALONE YES) + AS "XMLROOT" FROM DUAL; + +SELECT XMLROOT ( XMLType('143598'), VERSION NO VALUE) + AS "XMLROOT" FROM DUAL; + +SELECT XMLROOT ( XMLType('143598'), VERSION '1.0') + AS "XMLROOT" FROM DUAL; From 7df397f1b66c80f8804b6518868c5dc29a2c67d8 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 5 Mar 2020 12:06:26 +0100 Subject: [PATCH 188/235] [doc] Update release notes, fixes #2328, refs #2326 --- docs/pages/release_notes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index ef150a24a3..976f0305b0 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -91,6 +91,8 @@ should give more accurate results and especially fixes the problems with the usi * [#2255](https://github.com/pmd/pmd/issues/2255): \[java] InvalidLogMessageFormat false-positive for a lambda argument * java-performance * [#2275](https://github.com/pmd/pmd/issues/2275): \[java] AppendCharacterWithChar flags literals in an expression +* plsql + * [#2328](https://github.com/pmd/pmd/issues/2328): \[plsql] Support XMLROOT ### API Changes @@ -181,6 +183,7 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * [#2297](https://github.com/pmd/pmd/pull/2297): \[apex] Cognitive complexity metrics - [Gwilym Kuiper](https://github.com/gwilymatgearset) * [#2317](https://github.com/pmd/pmd/pull/2317): \[apex] New Rule - Test Methods Must Be In Test Classes - [Brian Nørremark](https://github.com/noerremark) * [#2321](https://github.com/pmd/pmd/pull/2321): \[apex] Support switch statements correctly in Cognitive Complexity - [Gwilym Kuiper](https://github.com/gwilymatgearset) +* [#2326](https://github.com/pmd/pmd/pull/2326): \[plsql] Added XML functions to parser: extract(xml), xml_root and fixed xml_forest - [Piotr Szymanski](https://github.com/szyman23) {% endtocmaker %} From cc19671c5ddd46d5dc0b2007dd27baa12152baa4 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 5 Mar 2020 12:14:30 +0100 Subject: [PATCH 189/235] Add missing override --- .../net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpression.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpression.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpression.java index 90d51eab8f..eba5fadc37 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpression.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpression.java @@ -26,6 +26,7 @@ public final class ASTExtractExpression extends AbstractPLSQLNode { } + @Override public Object jjtAccept(PLSQLParserVisitor visitor, Object data) { return visitor.visit(this, data); } From 24e5667a72718c1a53abdd482b975d64fb6f6aa7 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 5 Mar 2020 12:21:23 +0100 Subject: [PATCH 190/235] [doc] Update release notes, refs #2327 --- docs/pages/release_notes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index ef150a24a3..6328cce62d 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -91,6 +91,8 @@ should give more accurate results and especially fixes the problems with the usi * [#2255](https://github.com/pmd/pmd/issues/2255): \[java] InvalidLogMessageFormat false-positive for a lambda argument * java-performance * [#2275](https://github.com/pmd/pmd/issues/2275): \[java] AppendCharacterWithChar flags literals in an expression +* plsql + * [#2327](https://github.com/pmd/pmd/pull/2327): \[plsql] Parsing of WHERE CURRENT OF ### API Changes @@ -181,6 +183,7 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * [#2297](https://github.com/pmd/pmd/pull/2297): \[apex] Cognitive complexity metrics - [Gwilym Kuiper](https://github.com/gwilymatgearset) * [#2317](https://github.com/pmd/pmd/pull/2317): \[apex] New Rule - Test Methods Must Be In Test Classes - [Brian Nørremark](https://github.com/noerremark) * [#2321](https://github.com/pmd/pmd/pull/2321): \[apex] Support switch statements correctly in Cognitive Complexity - [Gwilym Kuiper](https://github.com/gwilymatgearset) +* [#2327](https://github.com/pmd/pmd/pull/2327): \[plsql] Parsing of WHERE CURRENT OF added - [Piotr Szymanski](https://github.com/szyman23) {% endtocmaker %} From 72587706b3a80fc005dfe7ee8efa6ead2076c17f Mon Sep 17 00:00:00 2001 From: Piotr Szymanski Date: Thu, 5 Mar 2020 16:50:46 +0100 Subject: [PATCH 191/235] small fix in Comment statement, removed not needed cursorSpecification, code formatting --- pmd-plsql/etc/grammar/PldocAST.jjt | 59 ++++--------------- .../plsql/ast/PLSQLParserVisitorAdapter.java | 5 -- .../lang/plsql/rule/AbstractPLSQLRule.java | 6 -- .../plsql/ast/MultipleDDLStatementsTest.java | 4 +- .../pmd/lang/plsql/ast/DDLCommands.sql | 4 ++ 5 files changed, 16 insertions(+), 62 deletions(-) diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index a6d3df7886..4b84bb8f59 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -264,9 +264,9 @@ ASTInput Input(String sourcecode) : {} | LOOKAHEAD(6) Global() | (LOOKAHEAD(6) DDLCommand())+ | LOOKAHEAD(2) SqlPlusCommand() - | UpdateStatement() - | DeleteStatement() - | InsertStatement() + | UpdateStatement() [";"] + | DeleteStatement() [";"] + | InsertStatement() [";"] | SelectStatement() [";"] |(|||||) ReadPastNextOccurrence(";") //Ignore SQL statements in scripts ) @@ -473,8 +473,6 @@ ASTDeclarativeUnit DeclarativeUnit() : ProgramUnit() | LOOKAHEAD(4) VariableOrConstantDeclaration() | - LOOKAHEAD(2) - CursorSpecification() | CursorBody() | CollectionDeclaration() | //ProgramUnit() @@ -1064,13 +1062,11 @@ void Skip2NextTokenOccurrence(int target) : Token specToken = null ; while (nextToken.kind!=target && (null == nextToken.specialToken || nextToken.specialToken.kind!=target ) //In case the target is a Special Token - && nextToken.kind!=EOF //SRT 20110521 - Prevent endless loop when target does not exist in the input stream - ) + && nextToken.kind!=EOF) //SRT 20110521 - Prevent endless loop when target does not exist in the input stream { /* Check if the target appears as a SpecialToken - nextToken.specialToken points to the _LAST_ of any SpecialTokens before the current normal Token. It is the head of a doubly-linked list: @@ -1083,19 +1079,13 @@ void Skip2NextTokenOccurrence(int target) : */ specToken = nextToken.specialToken; if (null!= specToken) - { - //Walk backwards through the list looking for this Token as a Special Token - while (specToken != null && specToken.kind != target) - { - specToken = specToken.specialToken; - } + //Walk backwards through the list looking for this Token as a Special Token + while (specToken != null && specToken.kind != target) + specToken = specToken.specialToken; //We have found the target as a SpecialToken - break out of normal Token search - if (null != specToken && specToken.kind == target) - { - break; - } - } + if (null != specToken && specToken.kind == target) + break; nextToken = getNextToken(); nextToken = getToken(1); @@ -2874,37 +2864,12 @@ ASTCursorUnit CursorUnit() : { jjtThis.setImage(simpleNode.getImage()) ; return jjtThis ; } } -ASTCursorSpecification CursorSpecification() : {} -{ - CursorUnit() - { return jjtThis ; } -} - ASTCursorBody CursorBody() : {} { CursorUnit() -// /**/ { return jjtThis ; } } - - -// ============================================================================ -// E X P R E S S I O N S -// ============================================================================ - -/* -String expression() : -{} -{ - "test" - { return ""; } -} -*/ - - - - ASTExpression Expression() : { PLSQLNode simpleNode = null; @@ -3885,12 +3850,10 @@ ASTComment Comment() : ( [LOOKAHEAD(ID()"."ID()"."ID()) ID()"."] ID() "." ID()) ) StringLiteral() - ";" + (";" | "/") { return jjtThis ; } } - - ASTTypeMethod TypeMethod() : { } @@ -4426,8 +4389,6 @@ ASTCompoundTriggerBlock CompoundTriggerBlock() : SubTypeDefinition() | LOOKAHEAD(4) VariableOrConstantDeclaration() | - LOOKAHEAD(2) - CursorSpecification() | CursorBody() | CollectionDeclaration() | ProgramUnit() diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java index c9631b54b0..2534ebc50a 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java @@ -341,11 +341,6 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor { return visit((PLSQLNode) node, data); } - @Override - public Object visit(ASTCursorSpecification node, Object data) { - return visit((PLSQLNode) node, data); - } - @Override public Object visit(ASTCursorBody node, Object data) { return visit((PLSQLNode) node, data); diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java index f5af7d86e5..c03be89c69 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java @@ -53,7 +53,6 @@ import net.sourceforge.pmd.lang.plsql.ast.ASTContinueStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTCrossOuterApplyClause; import net.sourceforge.pmd.lang.plsql.ast.ASTCursorBody; import net.sourceforge.pmd.lang.plsql.ast.ASTCursorForLoopStatement; -import net.sourceforge.pmd.lang.plsql.ast.ASTCursorSpecification; import net.sourceforge.pmd.lang.plsql.ast.ASTCursorUnit; import net.sourceforge.pmd.lang.plsql.ast.ASTDDLCommand; import net.sourceforge.pmd.lang.plsql.ast.ASTDDLEvent; @@ -657,11 +656,6 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar return visit((PLSQLNode) node, data); } - @Override - public Object visit(ASTCursorSpecification node, Object data) { - return visit((PLSQLNode) node, data); - } - @Override public Object visit(ASTCursorBody node, Object data) { return visit((PLSQLNode) node, data); diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/MultipleDDLStatementsTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/MultipleDDLStatementsTest.java index d318911662..5b21d5711a 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/MultipleDDLStatementsTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/MultipleDDLStatementsTest.java @@ -17,9 +17,9 @@ public class MultipleDDLStatementsTest extends AbstractPLSQLParserTst { public void parseDDLCommands() throws Exception { ASTInput input = plsql.parseResource("DDLCommands.sql"); List ddlcommands = input.findDescendantsOfType(ASTDDLCommand.class); - Assert.assertEquals(4, ddlcommands.size()); + Assert.assertEquals(6, ddlcommands.size()); List comments = input.findDescendantsOfType(ASTComment.class); - Assert.assertEquals(3, comments.size()); + Assert.assertEquals(5, comments.size()); Assert.assertEquals("'abbreviated job title'", comments.get(0).getFirstChildOfType(ASTStringLiteral.class).getImage()); } } diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/DDLCommands.sql b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/DDLCommands.sql index 5833689339..d6b4e6714b 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/DDLCommands.sql +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/DDLCommands.sql @@ -5,3 +5,7 @@ COMMENT ON COLUMN employees.job_id IS 'abbreviated job title'; DROP TABLE employees; COMMENT ON COLUMN employees.job_id IS 'abbreviated job title'; + +comment on COLUMN employees.job_id is 'abbreviated job title' +/ +comment on COLUMN employees.job_id is 'abbreviated job title'; \ No newline at end of file From 8ae59231a2a41fba73ee07bfe8bc7dac8d515140 Mon Sep 17 00:00:00 2001 From: Piotr Szymanski Date: Thu, 5 Mar 2020 17:47:45 +0100 Subject: [PATCH 192/235] fixed and turned on Execute Immediate --- pmd-plsql/etc/grammar/PldocAST.jjt | 10 ++++------ .../pmd/lang/plsql/ast/ExecuteImmediateTest.java | 5 +++++ .../pmd/lang/plsql/ast/ExecuteImmediateString.pls | 9 +++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateString.pls diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index a6d3df7886..710e5c88aa 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -1161,7 +1161,7 @@ ASTReadPastNextOccurrence ReadPastNextOccurrence(String target) : ASTSqlStatement SqlStatement(String initiator, String terminator) : {} { - (
||) + (
||) Skip2NextTerminator(initiator,terminator) { return jjtThis ; @@ -2220,7 +2220,7 @@ ASTUnlabelledStatement UnlabelledStatement() : UpdateStatement() ";" | DeleteStatement() ";" | InsertStatement() ";" | - LOOKAHEAD(["("]
||) SqlStatement(null,";") [";"] + LOOKAHEAD(["("]
||) SqlStatement(null,";") [";"] | LOOKAHEAD(3) ContinueStatement() ";" // CONTINUE keyword was added in 11G, so Oracle compilation supports CONTINUE as a variable name | CaseStatement() ";" | IfStatement() ";" @@ -2237,7 +2237,7 @@ ASTUnlabelledStatement UnlabelledStatement() : | OpenStatement() ";" | FetchStatement() ";" | Block() ";" - | EmbeddedSqlStatement() ";" + | LOOKAHEAD(2) EmbeddedSqlStatement() | PipelineStatement() ";" | ConditionalCompilationStatement() // Conditional Compilation works outside the normal parsing rules | InlinePragma() ";" @@ -2660,9 +2660,7 @@ ASTFetchStatement FetchStatement() : ASTEmbeddedSqlStatement EmbeddedSqlStatement() : {} { - Expression() // StringLiteral() /* */ - //SRT 20110429 | StringExpression() [ Expression() ("," Expression())*] ";" - //SRT 20121126 | StringExpression() + (StringLiteral() | Expression()) [ Name() ("," Name())* ] [ [ [ ] | ] Expression() ("," [ [ ] | ] Expression())* ] [ ( | ) Expression() ("," Expression())*] ";" diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateTest.java index 0e459ec1b2..d72ccfb037 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateTest.java @@ -19,4 +19,9 @@ public class ExecuteImmediateTest extends AbstractPLSQLParserTst { public void parseExecuteImmediate1047b() { plsql.parseResource("ExecuteImmediate1047b.pls"); } + + @Test + public void parseExecuteImmediateString() { + plsql.parseResource("ExecuteImmediateString.pls"); + } } diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateString.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateString.pls new file mode 100644 index 0000000000..b7a738ab2f --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExecuteImmediateString.pls @@ -0,0 +1,9 @@ +-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + +CREATE OR REPLACE PROCEDURE test ( p_num_reg OUT number ) +AS +BEGIN + execute immediate 'select count(1) from test_tbl where id =:param' into p_num_reg USING 'P'; +END test; From 144c767469f608eb10d5000f36a0b9b2de79b02f Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 5 Mar 2020 18:19:55 +0100 Subject: [PATCH 193/235] [vm] Really deprecate+internalize lang.vm.ast.VmParser --- pmd-vm/src/main/ant/alljavacc.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pmd-vm/src/main/ant/alljavacc.xml b/pmd-vm/src/main/ant/alljavacc.xml index 9d5483e1bc..a6ab82544c 100644 --- a/pmd-vm/src/main/ant/alljavacc.xml +++ b/pmd-vm/src/main/ant/alljavacc.xml @@ -127,17 +127,17 @@ public class Token implements GenericToken, java.io.Serializable]]> - - + + + - - + + From ff7dfd9eb6b28bc9da1327e0d854f4f8c1d5de99 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 5 Mar 2020 20:11:03 +0100 Subject: [PATCH 194/235] [jsp] Deprecate AST constructors and setters Also remove useless javadoc comments and fix license header --- docs/pages/release_notes.md | 24 +++++++++++++ pmd-jsp/src/main/ant/alljavacc.xml | 10 +++--- .../sourceforge/pmd/lang/jsp/JspParser.java | 6 ++++ .../pmd/lang/jsp/ast/ASTAttribute.java | 21 +++++------- .../pmd/lang/jsp/ast/ASTAttributeValue.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTCData.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTCommentTag.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTCompilationUnit.java | 11 +++--- .../pmd/lang/jsp/ast/ASTContent.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTDeclaration.java | 21 +++++------- .../lang/jsp/ast/ASTDoctypeDeclaration.java | 21 +++++------- .../lang/jsp/ast/ASTDoctypeExternalId.java | 31 +++++++---------- .../pmd/lang/jsp/ast/ASTElExpression.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTElement.java | 34 ++++++++----------- .../pmd/lang/jsp/ast/ASTHtmlScript.java | 11 +++--- .../pmd/lang/jsp/ast/ASTJspComment.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTJspDeclaration.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTJspDeclarations.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTJspDirective.java | 21 +++++------- .../jsp/ast/ASTJspDirectiveAttribute.java | 30 ++++++---------- .../pmd/lang/jsp/ast/ASTJspDocument.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTJspExpression.java | 12 ++++--- .../jsp/ast/ASTJspExpressionInAttribute.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTJspScriptlet.java | 12 ++++--- .../sourceforge/pmd/lang/jsp/ast/ASTText.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTUnparsedText.java | 12 ++++--- .../pmd/lang/jsp/ast/ASTValueBinding.java | 12 ++++--- .../pmd/lang/jsp/ast/AbstractJspNode.java | 3 ++ .../pmd/lang/jsp/ast/OpenTagRegister.java | 5 ++- .../ast/StartAndEndTagMismatchException.java | 5 +++ .../lang/jsp/ast/SyntaxErrorException.java | 5 +++ 31 files changed, 244 insertions(+), 195 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index adad5e462f..edc7d93590 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -171,6 +171,30 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * pmd-apex * {% jdoc apex::lang.apex.metrics.ApexMetrics %}, {% jdoc apex::lang.apex.metrics.ApexMetricsComputer %} +##### In ASTs (JSP) + +As part of the changes we'd like to do to AST classes for 7.0.0, we would like to +hide some methods and constructors that rule writers should not have access to. +The following usages are now deprecated **in the JSP AST** (with other languages to come): + +* Manual instantiation of nodes. **Constructors of node classes are deprecated** and + marked {% jdoc core::annotation.InternalApi %}. Nodes should only be obtained from the parser, + which for rules, means that they never need to instantiate node themselves. + Those constructors will be made package private with 7.0.0. +* **Subclassing of abstract node classes, or usage of their type**. The base classes are internal API + and will be hidden in version 7.0.0. You should not couple your code to them. + * In the meantime you should use interfaces like {% jdoc jsp::lang.jsp.ast.JspNode %} or + {% jdoc core::lang.ast.Node %}, or the other published interfaces in this package, + to refer to nodes generically. + * Concrete node classes will **be made final** with 7.0.0. +* Setters found in any node class or interface. **Rules should consider the AST immutable**. + We will make those setters package private with 7.0.0. +* The class {% jdoc jsp::lang.jsp.JspParser %} is deprecated and should not be used directly. + Use {% jdoc !!core::lang.LanguageVersionHandler#getParser(ParserOptions) %} instead. + +Please look at {% jdoc_package jsp::lang.jsp.ast %} to find out the full list of deprecations. + + ### External Contributions diff --git a/pmd-jsp/src/main/ant/alljavacc.xml b/pmd-jsp/src/main/ant/alljavacc.xml index 066a3c7c03..c7bfd8bd85 100644 --- a/pmd-jsp/src/main/ant/alljavacc.xml +++ b/pmd-jsp/src/main/ant/alljavacc.xml @@ -120,17 +120,17 @@ public class Token implements GenericToken, java.io.Serializable]]> - - + + + - - + + diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/JspParser.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/JspParser.java index 0409ca6024..f6bb1579d5 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/JspParser.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/JspParser.java @@ -8,7 +8,9 @@ import java.io.Reader; import java.util.HashMap; import java.util.Map; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.AbstractParser; +import net.sourceforge.pmd.lang.LanguageVersionHandler; import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.AbstractTokenManager; @@ -18,7 +20,11 @@ import net.sourceforge.pmd.lang.ast.SimpleCharStream; /** * Adapter for the JspParser. + * + * @deprecated This is internal API, use {@link LanguageVersionHandler#getParser(ParserOptions)}. */ +@InternalApi +@Deprecated public class JspParser extends AbstractParser { public JspParser(ParserOptions parserOptions) { diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTAttribute.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTAttribute.java index b41bec84d5..deaf9d9aef 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTAttribute.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTAttribute.java @@ -1,33 +1,33 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAttribute.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTAttribute extends AbstractJspNode { private String name; + @InternalApi + @Deprecated public ASTAttribute(int id) { super(id); } + @InternalApi + @Deprecated public ASTAttribute(JspParser p, int id) { super(p, id); } - /** - * @return Returns the name. - */ public String getName() { return name; } - /** - * @param name - * The name to set. - */ + @InternalApi + @Deprecated public void setName(String name) { this.name = name; } @@ -59,9 +59,6 @@ public class ASTAttribute extends AbstractJspNode { return colonIndex >= 0 ? name.substring(colonIndex + 1) : name; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTAttributeValue.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTAttributeValue.java index 8c56e9bfd5..f84c97b55f 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTAttributeValue.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTAttributeValue.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAttributeValue.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTAttributeValue extends AbstractJspNode { + @InternalApi + @Deprecated public ASTAttributeValue(int id) { super(id); } + @InternalApi + @Deprecated public ASTAttributeValue(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCData.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCData.java index 00e04452d1..b4aa3c6831 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCData.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCData.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTCData.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTCData extends AbstractJspNode { + @InternalApi + @Deprecated public ASTCData(int id) { super(id); } + @InternalApi + @Deprecated public ASTCData(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCommentTag.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCommentTag.java index 2dbc4f0f61..0fcc4f175d 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCommentTag.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCommentTag.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTCommentTag.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTCommentTag extends AbstractJspNode { + @InternalApi + @Deprecated public ASTCommentTag(int id) { super(id); } + @InternalApi + @Deprecated public ASTCommentTag(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCompilationUnit.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCompilationUnit.java index dd4b411f4a..d3232029ab 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCompilationUnit.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTCompilationUnit.java @@ -1,24 +1,25 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTCompilationUnit.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.RootNode; public class ASTCompilationUnit extends AbstractJspNode implements RootNode { + @InternalApi + @Deprecated public ASTCompilationUnit(int id) { super(id); } + @InternalApi + @Deprecated public ASTCompilationUnit(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTContent.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTContent.java index 5a17814f1c..b3c7dbac0d 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTContent.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTContent.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTContent.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTContent extends AbstractJspNode { + @InternalApi + @Deprecated public ASTContent(int id) { super(id); } + @InternalApi + @Deprecated public ASTContent(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDeclaration.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDeclaration.java index 534b7e3451..d2c0bc815d 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDeclaration.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDeclaration.java @@ -1,40 +1,37 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTDeclaration.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTDeclaration extends AbstractJspNode { private String name; + @InternalApi + @Deprecated public ASTDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTDeclaration(JspParser p, int id) { super(p, id); } - /** - * @return Returns the name. - */ public String getName() { return name; } - /** - * @param name - * The name to set. - */ + @InternalApi + @Deprecated public void setName(String name) { this.name = name; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDoctypeDeclaration.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDoctypeDeclaration.java index 169587e625..b8936498db 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDoctypeDeclaration.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDoctypeDeclaration.java @@ -1,10 +1,11 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTDoctypeDeclaration.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTDoctypeDeclaration extends AbstractJspNode { /** @@ -12,32 +13,28 @@ public class ASTDoctypeDeclaration extends AbstractJspNode { */ private String name; + @InternalApi + @Deprecated public ASTDoctypeDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTDoctypeDeclaration(JspParser p, int id) { super(p, id); } - /** - * @return Returns the name. - */ public String getName() { return name; } - /** - * @param name - * The name to set. - */ + @InternalApi + @Deprecated public void setName(String name) { this.name = name; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDoctypeExternalId.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDoctypeExternalId.java index d92194b209..d78ab5136f 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDoctypeExternalId.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTDoctypeExternalId.java @@ -1,10 +1,11 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTDoctypeExternalId.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTDoctypeExternalId extends AbstractJspNode { /** @@ -17,10 +18,14 @@ public class ASTDoctypeExternalId extends AbstractJspNode { */ private String publicId; + @InternalApi + @Deprecated public ASTDoctypeExternalId(int id) { super(id); } + @InternalApi + @Deprecated public ASTDoctypeExternalId(JspParser p, int id) { super(p, id); } @@ -29,19 +34,14 @@ public class ASTDoctypeExternalId extends AbstractJspNode { return null != publicId; } - /** - * @return Returns the name. - */ public String getUri() { return uri; } - /** - * @param name - * The name to set. - */ - public void setUri(String name) { - this.uri = name; + @InternalApi + @Deprecated + public void setUri(String uri) { + this.uri = uri; } /** @@ -52,17 +52,12 @@ public class ASTDoctypeExternalId extends AbstractJspNode { return null == publicId ? "" : publicId; } - /** - * @param publicId - * The publicId to set. - */ + @InternalApi + @Deprecated public void setPublicId(String publicId) { this.publicId = publicId; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTElExpression.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTElExpression.java index 9b41130210..5cdb60f8e3 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTElExpression.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTElExpression.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTElExpression.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTElExpression extends AbstractJspNode { + @InternalApi + @Deprecated public ASTElExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTElExpression(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTElement.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTElement.java index b7c7a56091..fe95d24606 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTElement.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTElement.java @@ -1,10 +1,11 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTElement.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTElement extends AbstractJspNode { /** @@ -19,14 +20,18 @@ public class ASTElement extends AbstractJspNode { /** * Flag indicating that the parser did not find a proper ending marker or - * ending tag for this element + * ending tag for this element. */ private boolean unclosed; + @InternalApi + @Deprecated public ASTElement(int id) { super(id); } + @InternalApi + @Deprecated public ASTElement(JspParser p, int id) { super(p, id); } @@ -58,24 +63,16 @@ public class ASTElement extends AbstractJspNode { return colonIndex >= 0 ? name.substring(colonIndex + 1) : name; } - /** - * @return Returns the name. - */ public String getName() { return name; } - /** - * @param name - * The name to set. - */ + @InternalApi + @Deprecated public void setName(String name) { this.name = name; } - /** - * @return Returns the empty. - */ public boolean isEmpty() { return empty; } @@ -84,21 +81,18 @@ public class ASTElement extends AbstractJspNode { return unclosed; } + @InternalApi + @Deprecated public void setUnclosed(boolean unclosed) { this.unclosed = unclosed; } - /** - * @param empty - * The empty to set. - */ + @InternalApi + @Deprecated public void setEmpty(boolean empty) { this.empty = empty; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTHtmlScript.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTHtmlScript.java index 338adc6cf2..4bfb1bc583 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTHtmlScript.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTHtmlScript.java @@ -1,21 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTHtmlScript.java Version 4.1 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY= */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTHtmlScript extends AbstractJspNode { + @InternalApi + @Deprecated public ASTHtmlScript(int id) { super(id); } + @InternalApi + @Deprecated public ASTHtmlScript(JspParser p, int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspComment.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspComment.java index 8d7c7b3d75..cc2fce9fc4 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspComment.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspComment.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTJspComment.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTJspComment extends AbstractJspNode { + @InternalApi + @Deprecated public ASTJspComment(int id) { super(id); } + @InternalApi + @Deprecated public ASTJspComment(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDeclaration.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDeclaration.java index 65814f382e..a2791a662c 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDeclaration.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDeclaration.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTJspDeclaration.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTJspDeclaration extends AbstractJspNode { + @InternalApi + @Deprecated public ASTJspDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTJspDeclaration(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDeclarations.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDeclarations.java index afc12ee48a..2d1cc558b7 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDeclarations.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDeclarations.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTJspDeclarations.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTJspDeclarations extends AbstractJspNode { + @InternalApi + @Deprecated public ASTJspDeclarations(int id) { super(id); } + @InternalApi + @Deprecated public ASTJspDeclarations(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDirective.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDirective.java index 85c84408db..b043817a3d 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDirective.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDirective.java @@ -1,10 +1,11 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTJspDirective.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTJspDirective extends AbstractJspNode { /** @@ -12,32 +13,28 @@ public class ASTJspDirective extends AbstractJspNode { */ private String name; + @InternalApi + @Deprecated public ASTJspDirective(int id) { super(id); } + @InternalApi + @Deprecated public ASTJspDirective(JspParser p, int id) { super(p, id); } - /** - * @return Returns the name. - */ public String getName() { return name; } - /** - * @param name - * The name to set. - */ + @InternalApi + @Deprecated public void setName(String name) { this.name = name; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDirectiveAttribute.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDirectiveAttribute.java index 700ea5d769..a85f104993 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDirectiveAttribute.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDirectiveAttribute.java @@ -1,56 +1,48 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTJspDirectiveAttribute.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTJspDirectiveAttribute extends AbstractJspNode { private String name; private String value; + @InternalApi + @Deprecated public ASTJspDirectiveAttribute(int id) { super(id); } + @InternalApi + @Deprecated public ASTJspDirectiveAttribute(JspParser p, int id) { super(p, id); } - /** - * @return Returns the name. - */ public String getName() { return name; } - /** - * @param name - * The name to set. - */ + @InternalApi + @Deprecated public void setName(String name) { this.name = name; } - /** - * @return Returns the value. - */ public String getValue() { return value; } - /** - * @param value - * The value to set. - */ + @InternalApi + @Deprecated public void setValue(String value) { this.value = value; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDocument.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDocument.java index 9826676aab..02290ece1d 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDocument.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspDocument.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTJspDocument.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTJspDocument extends AbstractJspNode { + @InternalApi + @Deprecated public ASTJspDocument(int id) { super(id); } + @InternalApi + @Deprecated public ASTJspDocument(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspExpression.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspExpression.java index 6a9f41ae8d..3d5945396b 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspExpression.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspExpression.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTJspExpression.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTJspExpression extends AbstractJspNode { + @InternalApi + @Deprecated public ASTJspExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTJspExpression(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspExpressionInAttribute.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspExpressionInAttribute.java index 8a1f88f9c4..0bbd10e434 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspExpressionInAttribute.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspExpressionInAttribute.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTJspExpressionInAttribute.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTJspExpressionInAttribute extends AbstractJspNode { + @InternalApi + @Deprecated public ASTJspExpressionInAttribute(int id) { super(id); } + @InternalApi + @Deprecated public ASTJspExpressionInAttribute(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspScriptlet.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspScriptlet.java index 8fec3d9414..2d574e179f 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspScriptlet.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTJspScriptlet.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTJspScriptlet.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTJspScriptlet extends AbstractJspNode { + @InternalApi + @Deprecated public ASTJspScriptlet(int id) { super(id); } + @InternalApi + @Deprecated public ASTJspScriptlet(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTText.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTText.java index 56a4654e01..6b0b15408d 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTText.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTText.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTText.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTText extends AbstractJspNode { + @InternalApi + @Deprecated public ASTText(int id) { super(id); } + @InternalApi + @Deprecated public ASTText(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTUnparsedText.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTUnparsedText.java index 07b5bff083..ff99b5b7e2 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTUnparsedText.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTUnparsedText.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTUnparsedText.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTUnparsedText extends AbstractJspNode { + @InternalApi + @Deprecated public ASTUnparsedText(int id) { super(id); } + @InternalApi + @Deprecated public ASTUnparsedText(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTValueBinding.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTValueBinding.java index d7ddf39a4d..afcfd76fa6 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTValueBinding.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/ASTValueBinding.java @@ -1,22 +1,24 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTValueBinding.java */ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTValueBinding extends AbstractJspNode { + @InternalApi + @Deprecated public ASTValueBinding(int id) { super(id); } + @InternalApi + @Deprecated public ASTValueBinding(JspParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JspParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/AbstractJspNode.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/AbstractJspNode.java index 8753fb1abb..ad031d0a30 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/AbstractJspNode.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/AbstractJspNode.java @@ -4,8 +4,11 @@ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.impl.javacc.AbstractJjtreeNode; +@InternalApi +@Deprecated public class AbstractJspNode extends AbstractJjtreeNode implements JspNode { protected JspParser parser; diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/OpenTagRegister.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/OpenTagRegister.java index 4b76e95e96..1795ad8d10 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/OpenTagRegister.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/OpenTagRegister.java @@ -1,4 +1,4 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.jsp.ast; import java.util.ArrayList; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.util.StringUtil; /** @@ -19,6 +20,8 @@ import net.sourceforge.pmd.util.StringUtil; * @author Victor Bucutea * */ +@Deprecated +@InternalApi public class OpenTagRegister { private List tagList = new ArrayList<>(); diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/StartAndEndTagMismatchException.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/StartAndEndTagMismatchException.java index 86c9131d9c..6a56f0a3d1 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/StartAndEndTagMismatchException.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/StartAndEndTagMismatchException.java @@ -4,10 +4,15 @@ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.lang.ast.ParseException; + /** * @author Pieter_Van_Raemdonck * @since Created on 11-jan-2006 + * + * @deprecated for removal with PMD 7.0.0. Use {@link ParseException} instead. */ +@Deprecated public class StartAndEndTagMismatchException extends SyntaxErrorException { private static final long serialVersionUID = 5434485938487458692L; diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/SyntaxErrorException.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/SyntaxErrorException.java index f886b882dc..37513a2c90 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/SyntaxErrorException.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/SyntaxErrorException.java @@ -4,12 +4,17 @@ package net.sourceforge.pmd.lang.jsp.ast; +import net.sourceforge.pmd.lang.ast.ParseException; + /** * Exception indicating that a syntactic error has been found. * * @author Pieter_Van_Raemdonck * @since Created on 11-jan-2006 + * + * @deprecated for removal with PMD 7.0.0. Use {@link ParseException} instead. */ +@Deprecated public abstract class SyntaxErrorException extends ParseException { private static final long serialVersionUID = -6702683724078264059L; From 846c7ad6e4f0f3b5bdd7a8a87ec5baa5f163844a Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 5 Mar 2020 20:17:26 +0100 Subject: [PATCH 195/235] [vm] Deprecate/Internalize VmParser as well This will be moved in PMD 7 to the subpackage ast --- docs/pages/release_notes.md | 6 ++++-- .../src/main/java/net/sourceforge/pmd/lang/vm/VmParser.java | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 9fcd670f00..501a4f934b 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -129,14 +129,16 @@ The following usages are now deprecated **in the VM AST** (with other languages * **Subclassing of abstract node classes, or usage of their type**. The base classes are internal API and will be hidden in version 7.0.0. You should not couple your code to them. * In the meantime you should use interfaces like {% jdoc vm::lang.vm.ast.VmNode %} or - {% jdoc core::ast.Node %}, or the other published interfaces in this package, + {% jdoc core::lang.ast.Node %}, or the other published interfaces in this package, to refer to nodes generically. * Concrete node classes will **be made final** with 7.0.0. * Setters found in any node class or interface. **Rules should consider the AST immutable**. We will make those setters package private with 7.0.0. -* The package {% jdoc_package vm::lang.vm.directice %} as well as the classes +* The package {% jdoc_package vm::lang.vm.directive %} as well as the classes {% jdoc vm::lang.vm.util.DirectiveMapper %} and {% jdoc vm::lang.vm.util.LogUtil %} are deprecated for removal. They were only used internally during parsing. +* The class {% jdoc vm::lang.vm.VmParser %} is deprecated and should not be used directly. + Use {% jdoc !!core::lang.LanguageVersionHandler#getParser(ParserOptions) %} instead. Please look at {% jdoc_package vm::lang.vm.ast %} to find out the full list of deprecations. diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmParser.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmParser.java index e4ed467178..69276ba09c 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmParser.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/VmParser.java @@ -8,6 +8,7 @@ import java.io.Reader; import java.util.HashMap; import java.util.Map; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.AbstractParser; import net.sourceforge.pmd.lang.ParserOptions; import net.sourceforge.pmd.lang.TokenManager; @@ -18,7 +19,11 @@ import net.sourceforge.pmd.lang.vm.util.VelocityCharStream; /** * Adapter for the VmParser. + * + * @deprecated This is internal API, use {@link LanguageVersionHandler#getParser(ParserOptions)}. */ +@Deprecated +@InternalApi public class VmParser extends AbstractParser { public VmParser(final ParserOptions parserOptions) { From d8afacd6a3f80783ab6253e93b64297210f1101c Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 6 Mar 2020 09:47:17 +0100 Subject: [PATCH 196/235] Formatting --- pmd-plsql/etc/grammar/PldocAST.jjt | 74 ++++++++++++++++-------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 4b84bb8f59..ac927c36fa 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -1053,46 +1053,48 @@ void SkipPastNextOccurrence(String target) : { return; } } -/* - Read Tokens up to but not including the target Token.kind. -*/ +/** + * Read Tokens up to but not including the target Token.kind. + */ void Skip2NextTokenOccurrence(int target) : { - Token nextToken = getToken(1); - Token specToken = null ; - while (nextToken.kind!=target - && (null == nextToken.specialToken || nextToken.specialToken.kind!=target ) //In case the target is a Special Token - && nextToken.kind!=EOF) //SRT 20110521 - Prevent endless loop when target does not exist in the input stream - { - /* - Check if the target appears as a SpecialToken + Token nextToken = getToken(1); + Token specToken = null ; + while (nextToken.kind!=target + && (null == nextToken.specialToken || nextToken.specialToken.kind!=target ) //In case the target is a Special Token + && nextToken.kind!=EOF) //SRT 20110521 - Prevent endless loop when target does not exist in the input stream + { + /* + * Check if the target appears as a SpecialToken + * + * nextToken.specialToken points to the _LAST_ of any SpecialTokens before the current normal Token. + * + * It is the head of a doubly-linked list: + * + * The ${specialToken}.specialToken field POINTS BACKWARDS TOWARDS the FIRST occurring SpecialToken + * The ${specialToken}.next field POINTS FORWARDS to to the LAST occurring SpecialToken + * + * This means that if the program is interested in a specific SpecialToken, it must examine the linked list for every Token which has nexToken.specialToken != null. + */ + specToken = nextToken.specialToken; + if (null!= specToken) { + //Walk backwards through the list looking for this Token as a Special Token + while (specToken != null && specToken.kind != target) { + specToken = specToken.specialToken; + } + } - nextToken.specialToken points to the _LAST_ of any SpecialTokens before the current normal Token. + //We have found the target as a SpecialToken - break out of normal Token search + if (null != specToken && specToken.kind == target) { + break; + } - It is the head of a doubly-linked list: - - The ${specialToken}.specialToken field POINTS BACKWARDS TOWARDS the FIRST occurring SpecialToken - The ${specialToken}.next field POINTS FORWARDS to to the LAST occurring SpecialToken - - This means that if the program is interested in a specific SpecialToken, it must examine the linked list for every Token which has nexToken.specialToken != null. - - */ - specToken = nextToken.specialToken; - if (null!= specToken) - //Walk backwards through the list looking for this Token as a Special Token - while (specToken != null && specToken.kind != target) - specToken = specToken.specialToken; - - //We have found the target as a SpecialToken - break out of normal Token search - if (null != specToken && specToken.kind == target) - break; - - nextToken = getNextToken(); - nextToken = getToken(1); - } + nextToken = getNextToken(); + nextToken = getToken(1); + } } { - { return; } + { return; } } /* @@ -2864,6 +2866,10 @@ ASTCursorUnit CursorUnit() : { jjtThis.setImage(simpleNode.getImage()) ; return jjtThis ; } } +/** + * This is in plsql actually called CursorDeclaration + * or CursorDefinition. + */ ASTCursorBody CursorBody() : {} { CursorUnit() From a682d36745988599dbb50879ef7748d5677d34b9 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 6 Mar 2020 10:18:27 +0100 Subject: [PATCH 197/235] [plsql] Remove CursorBody and keep CursorSpecification --- docs/pages/release_notes.md | 4 ++++ pmd-plsql/etc/grammar/PldocAST.jjt | 10 +++++----- .../lang/plsql/ast/PLSQLParserVisitorAdapter.java | 10 +++++----- .../pmd/lang/plsql/rule/AbstractPLSQLRule.java | 12 ++++++------ 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index ef150a24a3..57e0cd23fe 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -168,6 +168,10 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * pmd-apex * {% jdoc apex::lang.apex.metrics.ApexMetrics %}, {% jdoc apex::lang.apex.metrics.ApexMetricsComputer %} +#### PLSQL AST + +The production and node `ASTCursorBody` was unnecessary, not used and has been removed. Cursors have been already +parsed as `ASTCursorSpecification`. ### External Contributions diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index ac927c36fa..f1332ea59d 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -473,7 +473,7 @@ ASTDeclarativeUnit DeclarativeUnit() : ProgramUnit() | LOOKAHEAD(4) VariableOrConstantDeclaration() | - CursorBody() | + CursorSpecification() | CollectionDeclaration() | //ProgramUnit() //|TypeMethod() @@ -2870,10 +2870,10 @@ ASTCursorUnit CursorUnit() : * This is in plsql actually called CursorDeclaration * or CursorDefinition. */ -ASTCursorBody CursorBody() : {} +ASTCursorSpecification CursorSpecification() : {} { - CursorUnit() - { return jjtThis ; } + CursorUnit() + { return jjtThis ; } } ASTExpression Expression() : @@ -4395,7 +4395,7 @@ ASTCompoundTriggerBlock CompoundTriggerBlock() : SubTypeDefinition() | LOOKAHEAD(4) VariableOrConstantDeclaration() | - CursorBody() | + CursorSpecification() | CollectionDeclaration() | ProgramUnit() )* diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java index 2534ebc50a..81e247e122 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java @@ -341,11 +341,6 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor { return visit((PLSQLNode) node, data); } - @Override - public Object visit(ASTCursorBody node, Object data) { - return visit((PLSQLNode) node, data); - } - @Override public Object visit(ASTExpression node, Object data) { return visit((PLSQLNode) node, data); @@ -1116,4 +1111,9 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor { public Object visit(ASTWithClause node, Object data) { return visit((PLSQLNode) node, data); } + + @Override + public Object visit(ASTCursorSpecification node, Object data) { + return visit((PLSQLNode) node, data); + } } diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java index c03be89c69..f1c776c8dc 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java @@ -51,8 +51,8 @@ import net.sourceforge.pmd.lang.plsql.ast.ASTConditionalInsertClause; import net.sourceforge.pmd.lang.plsql.ast.ASTConditionalOrExpression; import net.sourceforge.pmd.lang.plsql.ast.ASTContinueStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTCrossOuterApplyClause; -import net.sourceforge.pmd.lang.plsql.ast.ASTCursorBody; import net.sourceforge.pmd.lang.plsql.ast.ASTCursorForLoopStatement; +import net.sourceforge.pmd.lang.plsql.ast.ASTCursorSpecification; import net.sourceforge.pmd.lang.plsql.ast.ASTCursorUnit; import net.sourceforge.pmd.lang.plsql.ast.ASTDDLCommand; import net.sourceforge.pmd.lang.plsql.ast.ASTDDLEvent; @@ -656,11 +656,6 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar return visit((PLSQLNode) node, data); } - @Override - public Object visit(ASTCursorBody node, Object data) { - return visit((PLSQLNode) node, data); - } - @Override public Object visit(ASTExpression node, Object data) { return visit((PLSQLNode) node, data); @@ -1435,6 +1430,11 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar return visit((PLSQLNode) node, data); } + @Override + public Object visit(ASTCursorSpecification node, Object data) { + return visit((PLSQLNode) node, data); + } + /* * Treat all Executable Code */ From d0772f76d2678b5bcbb0de692977d6bc01fa01fa Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 6 Mar 2020 10:18:36 +0100 Subject: [PATCH 198/235] [doc] Update release notes, refs #2331 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 57e0cd23fe..dfcf8b65be 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -185,6 +185,7 @@ parsed as `ASTCursorSpecification`. * [#2297](https://github.com/pmd/pmd/pull/2297): \[apex] Cognitive complexity metrics - [Gwilym Kuiper](https://github.com/gwilymatgearset) * [#2317](https://github.com/pmd/pmd/pull/2317): \[apex] New Rule - Test Methods Must Be In Test Classes - [Brian Nørremark](https://github.com/noerremark) * [#2321](https://github.com/pmd/pmd/pull/2321): \[apex] Support switch statements correctly in Cognitive Complexity - [Gwilym Kuiper](https://github.com/gwilymatgearset) +* [#2331](https://github.com/pmd/pmd/pull/2331): \[plsql] Fix in Comment statement - [Piotr Szymanski](https://github.com/szyman23) {% endtocmaker %} From e8167ede242d0e310a6c20554f20884eecf07adb Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 6 Mar 2020 10:23:13 +0100 Subject: [PATCH 199/235] [doc] Update release notes, refs #2332 --- docs/pages/release_notes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index ef150a24a3..c6779cd938 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -91,6 +91,8 @@ should give more accurate results and especially fixes the problems with the usi * [#2255](https://github.com/pmd/pmd/issues/2255): \[java] InvalidLogMessageFormat false-positive for a lambda argument * java-performance * [#2275](https://github.com/pmd/pmd/issues/2275): \[java] AppendCharacterWithChar flags literals in an expression +* plsql + * [#2332](https://github.com/pmd/pmd/pull/2332): \[plsql] Fixed Execute Immediate statement parsing ### API Changes @@ -181,6 +183,7 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * [#2297](https://github.com/pmd/pmd/pull/2297): \[apex] Cognitive complexity metrics - [Gwilym Kuiper](https://github.com/gwilymatgearset) * [#2317](https://github.com/pmd/pmd/pull/2317): \[apex] New Rule - Test Methods Must Be In Test Classes - [Brian Nørremark](https://github.com/noerremark) * [#2321](https://github.com/pmd/pmd/pull/2321): \[apex] Support switch statements correctly in Cognitive Complexity - [Gwilym Kuiper](https://github.com/gwilymatgearset) +* [#2332](https://github.com/pmd/pmd/pull/2332): \[plsql] Fixed Execute Immediate statement parsing - [Piotr Szymanski](https://github.com/szyman23) {% endtocmaker %} From 4468db24283a99f073103d84bcd66c1fc2420906 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 6 Mar 2020 10:59:02 +0100 Subject: [PATCH 200/235] [core] Call SymbolFacade without classloader by default This allows languages, that don't need a classloader while creating symbol table to just override the one method. In the test, we call always the overloaded method with class loader with made the symbol table processing not being run for tests in plsql. Fixes #2325 --- docs/pages/release_notes.md | 1 + .../lang/AbstractLanguageVersionHandler.java | 2 +- .../pmd/lang/plsql/ast/AbstractPLSQLNode.java | 5 ---- .../plsql/ast/ASTExtractExpressionTest.java | 7 ++--- .../pmd/lang/plsql/ast/TriggerTest.java | 28 +++++++++++++++++++ .../pmd/lang/plsql/ast/TriggerUnit.pls | 8 ++++++ 6 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/TriggerTest.java create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/TriggerUnit.pls diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 3bb96db641..d740d71abc 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -92,6 +92,7 @@ should give more accurate results and especially fixes the problems with the usi * java-performance * [#2275](https://github.com/pmd/pmd/issues/2275): \[java] AppendCharacterWithChar flags literals in an expression * plsql + * [#2325](https://github.com/pmd/pmd/issues/2325): \[plsql] NullPointerException while running parsing test for CREATE TRIGGER * [#2327](https://github.com/pmd/pmd/pull/2327): \[plsql] Parsing of WHERE CURRENT OF * [#2328](https://github.com/pmd/pmd/issues/2328): \[plsql] Support XMLROOT * [#2331](https://github.com/pmd/pmd/pull/2331): \[plsql] Fix in Comment statement diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java index 0f4aa6697d..9fb7fb820f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java @@ -45,7 +45,7 @@ public abstract class AbstractLanguageVersionHandler implements LanguageVersionH @Override public VisitorStarter getSymbolFacade(ClassLoader classLoader) { - return VisitorStarter.DUMMY; + return getSymbolFacade(); } @Override diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/AbstractPLSQLNode.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/AbstractPLSQLNode.java index b6578991d3..fe8b0b2750 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/AbstractPLSQLNode.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/AbstractPLSQLNode.java @@ -143,8 +143,3 @@ public abstract class AbstractPLSQLNode extends AbstractJjtreeNode im this.scope = scope; } } - -/* - * JavaCC - OriginalChecksum=3f651517d5069f856891d89230562ac4 (do not edit this - * line) - */ diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpressionTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpressionTest.java index 84f9a3550c..99a83f30e3 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpressionTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ASTExtractExpressionTest.java @@ -7,15 +7,14 @@ package net.sourceforge.pmd.lang.plsql.ast; import org.junit.Assert; import org.junit.Test; -import net.sourceforge.pmd.lang.plsql.PlsqlParsingHelper; +import net.sourceforge.pmd.lang.plsql.AbstractPLSQLParserTst; -public class ASTExtractExpressionTest { +public class ASTExtractExpressionTest extends AbstractPLSQLParserTst { @Test public void testXml() { - PlsqlParsingHelper parser = PlsqlParsingHelper.JUST_PARSE; - ASTInput unit = parser.parse("SELECT warehouse_name, EXTRACT(warehouse_spec, '/Warehouse/Docks', " + ASTInput unit = plsql.parse("SELECT warehouse_name, EXTRACT(warehouse_spec, '/Warehouse/Docks', " + "'xmlns:a=\"http://warehouse/1\" xmlns:b=\"http://warehouse/2\"') \"Number of Docks\" " + " FROM warehouses WHERE warehouse_spec IS NOT NULL;"); ASTExtractExpression extract = unit.getFirstDescendantOfType(ASTExtractExpression.class); diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/TriggerTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/TriggerTest.java new file mode 100644 index 0000000000..073d87274a --- /dev/null +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/TriggerTest.java @@ -0,0 +1,28 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + + +package net.sourceforge.pmd.lang.plsql.ast; + +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.lang.plsql.AbstractPLSQLParserTst; + + +public class TriggerTest extends AbstractPLSQLParserTst { + + /** + * Parsing a trigger should not result in a NPE. + * + * @see #2325 [plsql] NullPointerException while running parsing test for CREATE TRIGGER + */ + @Test + public void parseCreateTrigger() { + ASTInput input = plsql.parseResource("TriggerUnit.pls"); + PLSQLNode trigger = input.getChild(0); + Assert.assertEquals(ASTTriggerUnit.class, trigger.getClass()); + Assert.assertNotNull(trigger.getScope()); + } +} diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/TriggerUnit.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/TriggerUnit.pls new file mode 100644 index 0000000000..fe15216d28 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/TriggerUnit.pls @@ -0,0 +1,8 @@ +create or replace trigger test_trigger +instead of update +on test_table +for each row +begin + test.clr; +end; +/ From 6f78d54ba8659c6ef0c091b99e8c313704ef640f Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 6 Mar 2020 11:11:16 +0100 Subject: [PATCH 201/235] [plsql] Fix unit tests with duplicated symbol names --- .../net/sourceforge/pmd/lang/plsql/ast/StringLiterals.pls | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/StringLiterals.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/StringLiterals.pls index 66118495ad..6230c19f58 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/StringLiterals.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/StringLiterals.pls @@ -23,10 +23,10 @@ declare qliteral1f clob := Nq'[a"b"c]'; qliteral1g clob := nQ'[ab']cd]'; - qliteral1 clob := q'!name LIKE '%DBMS_%%'!'; - qliteral2 clob := Q'{SELECT * FROM employees WHERE last_name = 'Smith';}'; - qliteral1a clob := q'! test !'; - qliteral2a clob := q'{ + qliteral2a clob := q'!name LIKE '%DBMS_%%'!'; + qliteral2b clob := Q'{SELECT * FROM employees WHERE last_name = 'Smith';}'; + qliteral2c clob := q'! test !'; + qliteral2d clob := q'{ also multiple lines }'; From d0ae96090601f16dc245cec2b9113c09679162db Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 6 Mar 2020 11:19:47 +0100 Subject: [PATCH 202/235] Introduce properties checkstyle.version / checkstyle.plugin.version refs checkstyle/checkstyle#7534 --- pom.xml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index b12c295799..c37050acda 100644 --- a/pom.xml +++ b/pom.xml @@ -92,7 +92,8 @@ 5.0 2.22.1 - 3.1.0 + 8.29 + 3.1.0 3.13.0 1.10.1 3.1.1 @@ -291,7 +292,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - ${checkstyle.version} + ${checkstyle.plugin.version} checkstyle-check @@ -305,7 +306,7 @@ com.puppycrawl.tools checkstyle - 8.29 + ${checkstyle.version} net.sourceforge.pmd @@ -526,7 +527,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - ${checkstyle.version} + ${checkstyle.plugin.version} From 68872bec2429c10b3c94e5ef1352ad74771dbf05 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 6 Mar 2020 11:21:29 +0100 Subject: [PATCH 203/235] Update checkstyle to 8.30 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c37050acda..13f6226021 100644 --- a/pom.xml +++ b/pom.xml @@ -92,7 +92,7 @@ 5.0 2.22.1 - 8.29 + 8.30 3.1.0 3.13.0 1.10.1 From 7d9322734e73e0a9dd247210be0d4bae44099648 Mon Sep 17 00:00:00 2001 From: Piotr Szymanski Date: Fri, 6 Mar 2020 12:29:49 +0100 Subject: [PATCH 204/235] fixed parsing front slash --- pmd-plsql/etc/grammar/PldocAST.jjt | 2 +- .../lang/plsql/ast/SlashAsDivisionTest.java | 18 ++++++++++++++++++ .../pmd/lang/plsql/ast/SlashAsDivision.sql | 7 +++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivisionTest.java create mode 100644 pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivision.sql diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index f6489df759..8d2fa237bd 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -3191,7 +3191,7 @@ ASTMultiplicativeExpression MultiplicativeExpression() #MultiplicativeExpression //UnaryExpression() ( ( "*" | "/" | ) UnaryExpression() )* ( (simpleNode = UnaryExpression(true) ) { sb.append(simpleNode.getImage()); } - ( LOOKAHEAD(2) + ( LOOKAHEAD("**" | "*" | "/" | , {getToken(1).specialToken == null || getToken(1).specialToken.kind != EOL}) ( ("**" ) { sb.append(" ** "); } //Exponentiation | ("*" ) { sb.append(" * "); } | ("/" ) { sb.append(" / "); } diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivisionTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivisionTest.java new file mode 100644 index 0000000000..fe182fc25a --- /dev/null +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivisionTest.java @@ -0,0 +1,18 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.plsql.ast; + +import org.junit.Test; + +import net.sourceforge.pmd.lang.plsql.AbstractPLSQLParserTst; + +public class SlashAsDivisionTest extends AbstractPLSQLParserTst { + + @Test + public void parseSlashAsDivision() { + plsql.parseResource("SlashAsDivision.sql"); + } + +} diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivision.sql b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivision.sql new file mode 100644 index 0000000000..1600832175 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivision.sql @@ -0,0 +1,7 @@ +update name +set street = 'Main Street' +/ + +update name +set n01 = 2/2 +/ From d8e04ecc1150925c03e2c3e18d89eebdcb1b3390 Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Fri, 6 Mar 2020 12:12:34 +0100 Subject: [PATCH 205/235] [cs] CPD: Fix for issue where statements following a using directive were ignored. --- .../pmd/cpd/token/internal/BaseTokenFilter.java | 10 +++++++--- .../java/net/sourceforge/pmd/cpd/CsTokenizerTest.java | 11 +++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java index 7b7f11ca17..4baca41d37 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java @@ -41,9 +41,9 @@ public abstract class BaseTokenFilter implements TokenFi currentToken = null; if (!unprocessedTokens.isEmpty()) { currentToken = unprocessedTokens.poll(); - return currentToken; + } else { + currentToken = (T) tokenManager.getNextToken(); } - currentToken = (T) tokenManager.getNextToken(); while (!shouldStopProcessing(currentToken)) { analyzeToken(currentToken); analyzeTokens(currentToken, remainingTokens); @@ -53,7 +53,11 @@ public abstract class BaseTokenFilter implements TokenFi return currentToken; } - currentToken = (T) tokenManager.getNextToken(); + if (!unprocessedTokens.isEmpty()) { + currentToken = unprocessedTokens.poll(); + } else { + currentToken = (T) tokenManager.getNextToken(); + } } return null; diff --git a/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java b/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java index ed87562537..e3fe714131 100644 --- a/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java +++ b/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java @@ -125,6 +125,17 @@ public class CsTokenizerTest { assertEquals(TokenEntry.EOF, tokens.getTokens().get(0)); } + @Test + public void testStatementsAfterUsingDirectivesAreNotIgnored() { + tokenizer.setIgnoreUsings(true); + tokenizer.tokenize(toSourceCode( + "using System;\n" + + "public class MyClass {\n" + + "}\n"), + tokens); + assertEquals(6, tokens.size()); + } + @Test public void testUsingStatementsAreNotIgnored() { tokenizer.setIgnoreUsings(true); From 6a7e98924bf87c981844fd706865b32e4772994b Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Fri, 6 Mar 2020 12:17:17 +0100 Subject: [PATCH 206/235] [cs] CPD: fix issue where semicolons following using directives were not filtered --- .../src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java index 49229f3170..60c446af8e 100644 --- a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java +++ b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java @@ -58,6 +58,7 @@ public class CsTokenizer extends AntlrTokenizer { private final boolean ignoreUsings; private boolean discardingUsings = false; private boolean discardingNL = false; + private boolean discardCurrent = false; CsTokenFilter(final AntlrTokenManager tokenManager, boolean ignoreUsings) { super(tokenManager); @@ -71,6 +72,7 @@ public class CsTokenizer extends AntlrTokenizer { @Override protected void analyzeTokens(final AntlrToken currentToken, final Iterable remainingTokens) { + discardCurrent = false; skipUsingDirectives(currentToken, remainingTokens); } @@ -78,8 +80,9 @@ public class CsTokenizer extends AntlrTokenizer { final int type = currentToken.getType(); if (type == CSharpLexer.USING && isUsingDirective(remainingTokens)) { discardingUsings = true; - } else if (type == CSharpLexer.SEMICOLON) { + } else if (type == CSharpLexer.SEMICOLON && discardingUsings) { discardingUsings = false; + discardCurrent = true; } } @@ -147,7 +150,7 @@ public class CsTokenizer extends AntlrTokenizer { @Override protected boolean isLanguageSpecificDiscarding() { - return discardingUsings || discardingNL; + return discardingUsings || discardingNL || discardCurrent; } } } From d50ccd17670629de13fb30788b79493b0e0f386c Mon Sep 17 00:00:00 2001 From: Piotr Szymanski Date: Fri, 6 Mar 2020 12:50:00 +0100 Subject: [PATCH 207/235] extended test case --- .../sourceforge/pmd/lang/plsql/ast/SlashAsDivision.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivision.sql b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivision.sql index 1600832175..68d46635e6 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivision.sql +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SlashAsDivision.sql @@ -5,3 +5,13 @@ set street = 'Main Street' update name set n01 = 2/2 / + +update name +set n01 = 2 +/ + +update name +set n01 = 2/2; + +update name +set n01 = 2; From adb38ecbbc48628a9d2bb29368ddc4b0875dca38 Mon Sep 17 00:00:00 2001 From: Maikel Steneker Date: Fri, 6 Mar 2020 12:52:46 +0100 Subject: [PATCH 208/235] [cs] CPD: Fixed CPD --ignore-usings option --- .../java/net/sourceforge/pmd/cpd/CsTokenizer.java | 12 +++++++----- .../net/sourceforge/pmd/cpd/CsTokenizerTest.java | 8 ++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java index 49229f3170..881f0ce49d 100644 --- a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java +++ b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java @@ -75,11 +75,13 @@ public class CsTokenizer extends AntlrTokenizer { } private void skipUsingDirectives(final AntlrToken currentToken, final Iterable remainingTokens) { - final int type = currentToken.getType(); - if (type == CSharpLexer.USING && isUsingDirective(remainingTokens)) { - discardingUsings = true; - } else if (type == CSharpLexer.SEMICOLON) { - discardingUsings = false; + if (ignoreUsings) { + final int type = currentToken.getType(); + if (type == CSharpLexer.USING && isUsingDirective(remainingTokens)) { + discardingUsings = true; + } else if (type == CSharpLexer.SEMICOLON) { + discardingUsings = false; + } } } diff --git a/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java b/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java index ed87562537..823758a760 100644 --- a/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java +++ b/pmd-cs/src/test/java/net/sourceforge/pmd/cpd/CsTokenizerTest.java @@ -116,6 +116,14 @@ public class CsTokenizerTest { assertEquals(8, tokens.getTokens().get(14).getBeginLine()); } + @Test + public void testDoNotIgnoreUsingDirectives() { + tokenizer.setIgnoreUsings(false); + tokenizer.tokenize(toSourceCode("using System.Text;\n"), tokens); + assertEquals(6, tokens.size()); + assertEquals("using", tokens.getTokens().get(0).toString()); + } + @Test public void testIgnoreUsingDirectives() { tokenizer.setIgnoreUsings(true); From 7b06cfd04dca9a34a088f18c6c371e4d9c07c606 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 7 Mar 2020 09:13:37 +0100 Subject: [PATCH 209/235] [doc] Update release notes, refs #2338 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 3bb96db641..4b377079fa 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -194,6 +194,7 @@ parsed as `ASTCursorSpecification`. * [#2327](https://github.com/pmd/pmd/pull/2327): \[plsql] Parsing of WHERE CURRENT OF added - [Piotr Szymanski](https://github.com/szyman23) * [#2331](https://github.com/pmd/pmd/pull/2331): \[plsql] Fix in Comment statement - [Piotr Szymanski](https://github.com/szyman23) * [#2332](https://github.com/pmd/pmd/pull/2332): \[plsql] Fixed Execute Immediate statement parsing - [Piotr Szymanski](https://github.com/szyman23) +* [#2338](https://github.com/pmd/pmd/pull/2338): \[cs] CPD: fixes in filtering of using directives - [Maikel Steneker](https://github.com/maikelsteneker) {% endtocmaker %} From f866b63d09f72d19020e330538b5ad9c17f2e388 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 7 Mar 2020 09:15:50 +0100 Subject: [PATCH 210/235] [doc] Update release notes, refs #2339 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 4bbbd38986..a82e74d843 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -148,6 +148,7 @@ methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementati * [#2279](https://github.com/pmd/pmd/pull/2279): \[apex] Add support for suppressing violations using the // NOPMD comment - [Gwilym Kuiper](https://github.com/gwilymatgearset) * [#2280](https://github.com/pmd/pmd/pull/2280): \[cs] CPD: Replace C# tokenizer by an Antlr-based one - [Maikel Steneker](https://github.com/maikelsteneker) * [#2297](https://github.com/pmd/pmd/pull/2297): \[apex] Cognitive complexity metrics - [Gwilym Kuiper](https://github.com/gwilymatgearset) +* [#2339](https://github.com/pmd/pmd/pull/2339): \[cs] CPD: Fixed CPD --ignore-usings option - [Maikel Steneker](https://github.com/maikelsteneker) {% endtocmaker %} From d55fe56de9fbaa6725d2aa5dc31a409e13c3b8a2 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 7 Mar 2020 09:23:51 +0100 Subject: [PATCH 211/235] Update m-checkstyle-p to 3.1.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 13f6226021..a479a8f7c6 100644 --- a/pom.xml +++ b/pom.xml @@ -93,7 +93,7 @@ 5.0 2.22.1 8.30 - 3.1.0 + 3.1.1 3.13.0 1.10.1 3.1.1 From dc12a6ea914b6a4ac6cd14744aff135cf4ff792e Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 7 Mar 2020 09:41:48 +0100 Subject: [PATCH 212/235] [doc] Update release notes, refs #2340 --- 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 3bb96db641..d44d6881ba 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -96,6 +96,7 @@ should give more accurate results and especially fixes the problems with the usi * [#2328](https://github.com/pmd/pmd/issues/2328): \[plsql] Support XMLROOT * [#2331](https://github.com/pmd/pmd/pull/2331): \[plsql] Fix in Comment statement * [#2332](https://github.com/pmd/pmd/pull/2332): \[plsql] Fixed Execute Immediate statement parsing + * [#2340](https://github.com/pmd/pmd/pull/2340): \[plsql] Fixed parsing / as divide or execute ### API Changes @@ -194,6 +195,7 @@ parsed as `ASTCursorSpecification`. * [#2327](https://github.com/pmd/pmd/pull/2327): \[plsql] Parsing of WHERE CURRENT OF added - [Piotr Szymanski](https://github.com/szyman23) * [#2331](https://github.com/pmd/pmd/pull/2331): \[plsql] Fix in Comment statement - [Piotr Szymanski](https://github.com/szyman23) * [#2332](https://github.com/pmd/pmd/pull/2332): \[plsql] Fixed Execute Immediate statement parsing - [Piotr Szymanski](https://github.com/szyman23) +* [#2340](https://github.com/pmd/pmd/pull/2340): \[plsql] fix for parsing / as divide or execute - [Piotr Szymanski](https://github.com/szyman23) {% endtocmaker %} From 4749833534d03a120d184945b1480cb0f8746b8d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 7 Mar 2020 09:54:07 +0100 Subject: [PATCH 213/235] [doc] Add gearset pmd apex blog post --- docs/pages/pmd/projectdocs/trivia/news.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/pages/pmd/projectdocs/trivia/news.md b/docs/pages/pmd/projectdocs/trivia/news.md index e06151b013..2729f89bcb 100644 --- a/docs/pages/pmd/projectdocs/trivia/news.md +++ b/docs/pages/pmd/projectdocs/trivia/news.md @@ -9,7 +9,9 @@ author: Tom Copeland ### Salesforce / Apex Language Module -* July 2019 - [Apex PMD | Static code analysis - Apex Hours](https://youtu.be/34PxAHtAavU) +* March 2020 - [Helping Salesforce developers create readable and maintainable Apex code](https://gearset.com/blog/helping-sf-developers-create-readable-and-maintainable-apex-code) + +* July 2019 - [Apex PMD | Static code analysis - Apex Hours](https://youtu.be/34PxAHtAavU) * June 2019 - [Pluralsight](https://www.pluralsight.com/authors/don-robins) Course about leveraging PMD usage for Salesforce by [Robert Sösemann](https://github.com/rsoesemann) (Apex Language Module Contributor) [Play by Play: Automated Code Analysis in Salesforce - a Tools Deep-Dive](https://www.pluralsight.com/courses/play-by-play-automated-code-analysis-in-salesforce) From 1a412984ee9c3c11dffb1c7d7f7bcfdd0d4263c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20=C5=BBygie=C5=82o?= Date: Sat, 7 Mar 2020 22:01:55 +0100 Subject: [PATCH 214/235] [xml] Update property used in example --- pmd-xml/src/main/resources/category/pom/errorprone.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-xml/src/main/resources/category/pom/errorprone.xml b/pmd-xml/src/main/resources/category/pom/errorprone.xml index f3048a8884..d459a47a8c 100644 --- a/pmd-xml/src/main/resources/category/pom/errorprone.xml +++ b/pmd-xml/src/main/resources/category/pom/errorprone.xml @@ -90,7 +90,7 @@ By far the most common problem is the use of ${project.version} in a BOM or ... ... - ${project.dependency} + ${project.version} ]]> From 467e3a934356070fc87ccf33e84d71a3b926cf93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20=C5=BBygie=C5=82o?= Date: Sat, 7 Mar 2020 23:12:07 +0100 Subject: [PATCH 215/235] Disable checking for snapshots in jcenter --- pom.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pom.xml b/pom.xml index a479a8f7c6..55a48accc8 100644 --- a/pom.xml +++ b/pom.xml @@ -852,6 +852,9 @@ jcenter JCenter + + false + https://jcenter.bintray.com/ From 6a2c2302143a9830a9c26309bfa823bddff5bf69 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 8 Mar 2020 10:36:39 +0100 Subject: [PATCH 216/235] [test] Support java14-preview in test cases --- pmd-test/src/main/resources/rule-tests_1_0_0.xsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-test/src/main/resources/rule-tests_1_0_0.xsd b/pmd-test/src/main/resources/rule-tests_1_0_0.xsd index d45f2d9e27..f7b939ce00 100644 --- a/pmd-test/src/main/resources/rule-tests_1_0_0.xsd +++ b/pmd-test/src/main/resources/rule-tests_1_0_0.xsd @@ -50,7 +50,7 @@ - + From 5f9fbf3933b50096dff8640edbbdd951a00efbcc Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 8 Mar 2020 10:38:53 +0100 Subject: [PATCH 217/235] [java] Fix missing declaration kind RECORD --- .../pmd/lang/java/ast/ASTAnyTypeBodyDeclaration.java | 2 ++ .../pmd/lang/java/ast/AbstractTypeBodyDeclaration.java | 3 +++ .../net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeBodyDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeBodyDeclaration.java index 74465075ae..e35bfc3ceb 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeBodyDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeBodyDeclaration.java @@ -59,6 +59,8 @@ public interface ASTAnyTypeBodyDeclaration extends JavaNode { ANNOTATION, /** No child, {@link #getDeclarationNode()} will return null. */ EMPTY, + /** See {@link ASTRecordDeclaration}. */ + RECORD, /** See {@link ASTRecordConstructorDeclaration}. */ RECORD_CONSTRUCTOR } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractTypeBodyDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractTypeBodyDeclaration.java index 7608c44d9a..5edcde8aac 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractTypeBodyDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractTypeBodyDeclaration.java @@ -14,6 +14,7 @@ import static net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.Declar import static net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.DeclarationKind.INITIALIZER; import static net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.DeclarationKind.INTERFACE; import static net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.DeclarationKind.METHOD; +import static net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.DeclarationKind.RECORD; import net.sourceforge.pmd.annotation.InternalApi; @@ -77,6 +78,8 @@ abstract class AbstractTypeBodyDeclaration extends AbstractJavaNode implements A return ANNOTATION; } else if (node instanceof ASTEnumDeclaration) { return ENUM; + } else if (node instanceof ASTRecordDeclaration) { + return RECORD; } throw new IllegalStateException("Declaration node types should all be known"); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index b137fe5c2d..0cb4650866 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -13,6 +13,7 @@ import org.junit.Test; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.java.JavaParsingHelper; +import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.DeclarationKind; /** * Tests new java14 preview features. @@ -130,6 +131,10 @@ public class Java14PreviewTest { Assert.assertEquals(2, complex.getDeclarations().size()); Assert.assertTrue(complex.getDeclarations().get(0).getChild(1) instanceof ASTConstructorDeclaration); Assert.assertTrue(complex.getDeclarations().get(1).getChild(0) instanceof ASTRecordDeclaration); + Assert.assertTrue(complex.getParent() instanceof ASTClassOrInterfaceBodyDeclaration); + ASTClassOrInterfaceBodyDeclaration complexParent = complex.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class); + Assert.assertEquals(DeclarationKind.RECORD, complexParent.getKind()); + Assert.assertSame(complex, complexParent.getDeclarationNode()); ASTRecordDeclaration nested = recordDecls.get(1); Assert.assertEquals("Nested", nested.getSimpleName()); From 225bb8d5afd47a3a5bc6a630dabfd3afaa16cfa1 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 8 Mar 2020 10:41:44 +0100 Subject: [PATCH 218/235] [java] Deal with variable name declarations of record components --- .../java/symboltable/VariableNameDeclaration.java | 12 ++++++++++++ .../pmd/lang/java/ast/Java14PreviewTest.java | 3 +++ 2 files changed, 15 insertions(+) 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 b2a5abdf42..e23a04b7d6 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 @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.symboltable; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; +import net.sourceforge.pmd.lang.java.ast.ASTRecordComponent; import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; import net.sourceforge.pmd.lang.java.ast.ASTType; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; @@ -91,7 +92,15 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements && getAccessNodeParent().getFirstChildOfType(ASTType.class).getChild(0) instanceof ASTReferenceType; } + private boolean isRecordComponent() { + return node.getParent() instanceof ASTRecordComponent; + } + public AccessNode getAccessNodeParent() { + if (isRecordComponent()) { + return null; + } + if (node.getParent() instanceof ASTFormalParameter || node.getParent() instanceof ASTLambdaExpression) { return (AccessNode) node.getParent(); } @@ -103,6 +112,9 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements } private TypeNode getTypeNode() { + if (isRecordComponent()) { + return (TypeNode) node.getParent().getFirstChildOfType(ASTType.class).getChild(0); + } if (isPrimitiveType()) { return (TypeNode) getAccessNodeParent().getFirstChildOfType(ASTType.class).getChild(0); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index 0cb4650866..d50ec68cd7 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -103,6 +103,9 @@ public class Java14PreviewTest { Assert.assertEquals(2, components.size()); Assert.assertEquals("x", components.get(0).getVarId().getImage()); Assert.assertEquals("y", components.get(1).getVarId().getImage()); + Assert.assertNull(components.get(0).getVarId().getNameDeclaration().getAccessNodeParent()); + Assert.assertEquals(Integer.TYPE, components.get(0).getVarId().getNameDeclaration().getType()); + Assert.assertEquals("int", components.get(0).getVarId().getNameDeclaration().getTypeImage()); } @Test(expected = ParseException.class) From 8adfacb530a8ca989515d2047094bbb2c57f3f40 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 8 Mar 2020 10:42:05 +0100 Subject: [PATCH 219/235] [java] Fix MissingOverride with record --- .../rule/bestpractices/MissingOverrideRule.java | 2 +- .../java/rule/bestpractices/xml/MissingOverride.xml | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java index 9076e635de..d3bc8e39ed 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MissingOverrideRule.java @@ -209,7 +209,7 @@ public class MissingOverrideRule extends AbstractJavaRule { @Override public Object visit(ASTMethodDeclaration node, Object data) { - if (currentLookup.peek() == null) { + if (currentLookup.isEmpty() || currentLookup.peek() == null) { return super.visit(node, data); } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MissingOverride.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MissingOverride.xml index f631a8ad8c..e00c22fdd0 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MissingOverride.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MissingOverride.xml @@ -582,5 +582,18 @@ + + EmptyStackException with record top level + 0 + + java 14-preview + From ed3f7a4cf23a08f1f4291ec9d8f6ebd6e9887d4b Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 8 Mar 2020 10:42:55 +0100 Subject: [PATCH 220/235] [java] Deal with missing VariableNameDeclaration for pattern matching --- .../lang/java/ast/ASTVariableDeclaratorId.java | 3 +++ .../rule/AbstractInefficientZeroCheck.java | 1 + .../lang/java/rule/AbstractPoorMethodCall.java | 2 +- ...nsufficientStringBufferDeclarationRule.java | 3 ++- .../rule/performance/StringToStringRule.java | 3 ++- .../pmd/lang/java/ast/Java14PreviewTest.java | 3 +++ .../xml/InefficientEmptyStringCheck.xml | 18 ++++++++++++++++++ 7 files changed, 30 insertions(+), 3 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java index a96c120041..a8f04258ab 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 @@ -58,6 +58,9 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim return visitor.visit(this, data); } + /** + * Note: this might be null in certain cases. + */ public VariableNameDeclaration getNameDeclaration() { return nameDeclaration; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractInefficientZeroCheck.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractInefficientZeroCheck.java index 04cf59f456..d513e677b5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractInefficientZeroCheck.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractInefficientZeroCheck.java @@ -60,6 +60,7 @@ public abstract class AbstractInefficientZeroCheck extends AbstractJavaRule { public Object visit(ASTVariableDeclaratorId node, Object data) { Node nameNode = node.getTypeNameNode(); if (nameNode == null || nameNode instanceof ASTPrimitiveType + || node.getNameDeclaration() == null || !appliesToClassName(node.getNameDeclaration().getTypeImage())) { return data; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractPoorMethodCall.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractPoorMethodCall.java index 3469190a1a..221dee5080 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractPoorMethodCall.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/AbstractPoorMethodCall.java @@ -92,7 +92,7 @@ public abstract class AbstractPoorMethodCall extends AbstractJavaRule { */ @Override public Object visit(ASTVariableDeclaratorId node, Object data) { - if (!targetTypename().equals(node.getNameDeclaration().getTypeImage())) { + if (node.getNameDeclaration() == null || !targetTypename().equals(node.getNameDeclaration().getTypeImage())) { return data; } 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 e1a4183265..53c1bc4098 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 @@ -55,7 +55,8 @@ public class InsufficientStringBufferDeclarationRule extends AbstractJavaRule { @Override public Object visit(ASTVariableDeclaratorId node, Object data) { - if (!TypeHelper.isExactlyAny(node.getNameDeclaration(), StringBuffer.class, StringBuilder.class)) { + if (node.getNameDeclaration() == null + || !TypeHelper.isExactlyAny(node.getNameDeclaration(), StringBuffer.class, StringBuilder.class)) { return data; } Node rootNode = node; 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 95c4e29986..35b3d3a200 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 @@ -18,7 +18,8 @@ public class StringToStringRule extends AbstractJavaRule { @Override public Object visit(ASTVariableDeclaratorId node, Object data) { - if (!TypeHelper.isExactlyAny(node.getNameDeclaration(), String.class) + if (node.getNameDeclaration() == null + || !TypeHelper.isExactlyAny(node.getNameDeclaration(), String.class) && !TypeHelper.isExactlyAny(node.getNameDeclaration(), String[].class)) { return data; } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java index d50ec68cd7..b487c35267 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/Java14PreviewTest.java @@ -84,6 +84,9 @@ public class Java14PreviewTest { Assert.assertEquals("s", variable.getVariableName()); Assert.assertTrue(variable.isPatternBinding()); Assert.assertTrue(variable.isFinal()); + // Note: these variables are not part of the symbol table + // See ScopeAndDeclarationFinder#visit(ASTVariableDeclaratorId, Object) + Assert.assertNull(variable.getNameDeclaration()); } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientEmptyStringCheck.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientEmptyStringCheck.xml index b1d99ceef2..6c89aebc8a 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientEmptyStringCheck.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientEmptyStringCheck.xml @@ -196,4 +196,22 @@ public class Foo { } ]]> + + + Avoid NPE for pattern matching instanceof + 0 + + java 14-preview + From 241bf9ec108d5883af68ab48d3f1d05c48b5c8cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotrek=20=C5=BBygie=C5=82o?= Date: Fri, 14 Feb 2020 20:15:39 +0100 Subject: [PATCH 221/235] Replace deprecated rulesets/... Avoid: Use Rule name category/java/bestpractices.xml/ConstantsInInterface instead of the deprecated Rule name rulesets/java/design.xml/ConstantsInInterface. PMD 7.0.0 will remove support for this deprecated Rule name usage. --- docs/pages/pmd/userdocs/tools/ant.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/pages/pmd/userdocs/tools/ant.md b/docs/pages/pmd/userdocs/tools/ant.md index 55a45fc12c..d22397e5dc 100644 --- a/docs/pages/pmd/userdocs/tools/ant.md +++ b/docs/pages/pmd/userdocs/tools/ant.md @@ -57,7 +57,7 @@ The examples below won't repeat this taskdef element, as this is always required @@ -179,7 +179,7 @@ automatically and the latest language version is used. - rulesets/java/design.xml + rulesets/java/quickstart.xml java-basic @@ -297,7 +297,7 @@ need to be configured when defining the task: - + From bfe8a7ba45071ccdb26112a963bdbe568b90ba6a Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 10:33:47 +0100 Subject: [PATCH 222/235] [doc] Update release notes, refs #2342 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 2b061932c3..008416efcb 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -198,6 +198,7 @@ parsed as `ASTCursorSpecification`. * [#2338](https://github.com/pmd/pmd/pull/2338): \[cs] CPD: fixes in filtering of using directives - [Maikel Steneker](https://github.com/maikelsteneker) * [#2339](https://github.com/pmd/pmd/pull/2339): \[cs] CPD: Fixed CPD --ignore-usings option - [Maikel Steneker](https://github.com/maikelsteneker) * [#2340](https://github.com/pmd/pmd/pull/2340): \[plsql] fix for parsing / as divide or execute - [Piotr Szymanski](https://github.com/szyman23) +* [#2342](https://github.com/pmd/pmd/pull/2342): \[xml] Update property used in example - [Piotrek Żygieło](https://github.com/pzygielo) {% endtocmaker %} From 0aa88e82f5cd9562a628991d90d7f581e16501f7 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 10:59:46 +0100 Subject: [PATCH 223/235] [doc] remove more language-ruleset style references --- docs/pages/pmd/userdocs/tools/ant.md | 22 ++++++++++++---------- docs/pages/pmd/userdocs/tools/maven.md | 5 ++--- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/pages/pmd/userdocs/tools/ant.md b/docs/pages/pmd/userdocs/tools/ant.md index d22397e5dc..7f7c4ce14a 100644 --- a/docs/pages/pmd/userdocs/tools/ant.md +++ b/docs/pages/pmd/userdocs/tools/ant.md @@ -180,7 +180,7 @@ automatically and the latest language version is used. rulesets/java/quickstart.xml - java-basic + config/my-ruleset.xml @@ -261,7 +261,7 @@ Then, after the end of the PMD task, do this: Running one ruleset to produce a HTML report (and printing the report to the console as well) using a file cache - + @@ -274,7 +274,7 @@ Running one ruleset to produce a HTML report (and printing the report to the con Running multiple rulesets to produce an XML report with the same analysis cache - + @@ -297,7 +297,7 @@ need to be configured when defining the task: - + @@ -370,11 +370,13 @@ You can run pmd then with `ant pmd`. pmd: [pmd] Using the normal ClassLoader - [pmd] Using these rulesets: rulesets/java/imports.xml - [pmd] Using rule DontImportJavaLang - [pmd] Using rule UnusedImports - [pmd] Using rule ImportFromSamePackage - [pmd] Using rule DuplicateImports + [pmd] Using these rulesets: rulesets/java/quickstart.xml + [pmd] Using rule AvoidMessageDigestField + [pmd] Using rule AvoidStringBufferField + [pmd] Using rule AvoidUsingHardCodedIP + [pmd] Using rule CheckResultSet + [pmd] Using rule ConstantsInInterface + ... [pmd] Processing file /usr/local/java/src/java/lang/ref/Finalizer.java [pmd] Processing file /usr/local/java/src/java/lang/ref/FinalReference.java [pmd] Processing file /usr/local/java/src/java/lang/ref/PhantomReference.java @@ -394,7 +396,7 @@ An HTML report with the "linkPrefix" and "linePrefix" properties: - + diff --git a/docs/pages/pmd/userdocs/tools/maven.md b/docs/pages/pmd/userdocs/tools/maven.md index 2d07e1a07c..d6c6cb4e78 100644 --- a/docs/pages/pmd/userdocs/tools/maven.md +++ b/docs/pages/pmd/userdocs/tools/maven.md @@ -94,9 +94,8 @@ To specify a ruleset, simply edit the previous configuration: maven-pmd-plugin - /rulesets/java/braces.xml - /rulesets/java/naming.xml - d:\rulesets\strings.xml + /rulesets/java/quickstart.xml + d:\rulesets\my-ruleset.xml http://localhost/design.xml From 49072d91e5bff9895ebf4169f6a68d4f52f919dc Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 11:00:00 +0100 Subject: [PATCH 224/235] [doc] fix links to jxr in ant doc --- docs/pages/pmd/userdocs/tools/ant.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/pages/pmd/userdocs/tools/ant.md b/docs/pages/pmd/userdocs/tools/ant.md index 7f7c4ce14a..b34820e1f0 100644 --- a/docs/pages/pmd/userdocs/tools/ant.md +++ b/docs/pages/pmd/userdocs/tools/ant.md @@ -153,9 +153,10 @@ configure multiple formatters.
encoding
Specifies the encoding to be used in the generated report (only honored when used with `toFile`). When rendering `toConsole` PMD will automatically detect the terminal's encoding and use it, unless the output is being redirected / piped, in which case `file.encoding` is used. See example below.
linkPrefix
-
Used for linking to online HTMLized source (like this). See example below. Note, this only works with [maven-jxr-plugin](https://maven.apache.org/jxr/maven-jxr-plugin/index.html).
+
Used for linking to online HTMLized source (like this). See example below. Note, this only works with + maven-jxr-plugin.
linePrefix
-
Used for linking to online HTMLized source (like this). See example below. Note, this only works with [maven-jxr-plugin](https://maven.apache.org/jxr/maven-jxr-plugin/index.html).
+
Used for linking to online HTMLized source (like this). See example below. Note, this only works with maven-jxr-plugin.
From cad2825372fad30a734f28be36fbbc353e8f512c Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 11:00:15 +0100 Subject: [PATCH 225/235] [doc] Update release notes, refs #2344 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 2b061932c3..d65a9cc901 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -198,6 +198,7 @@ parsed as `ASTCursorSpecification`. * [#2338](https://github.com/pmd/pmd/pull/2338): \[cs] CPD: fixes in filtering of using directives - [Maikel Steneker](https://github.com/maikelsteneker) * [#2339](https://github.com/pmd/pmd/pull/2339): \[cs] CPD: Fixed CPD --ignore-usings option - [Maikel Steneker](https://github.com/maikelsteneker) * [#2340](https://github.com/pmd/pmd/pull/2340): \[plsql] fix for parsing / as divide or execute - [Piotr Szymanski](https://github.com/szyman23) +* [#2344](https://github.com/pmd/pmd/pull/2344): \[doc] Update ruleset examples for ant - [Piotrek Żygieło](https://github.com/pzygielo) {% endtocmaker %} From 037856bdfb060ab825898a2fc2e93ffadc41a359 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 11:18:14 +0100 Subject: [PATCH 226/235] [test] Add missing "." for version numbers in test cases --- pmd-test/src/main/resources/rule-tests_1_0_0.xsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-test/src/main/resources/rule-tests_1_0_0.xsd b/pmd-test/src/main/resources/rule-tests_1_0_0.xsd index f7b939ce00..4b1a7a6a5c 100644 --- a/pmd-test/src/main/resources/rule-tests_1_0_0.xsd +++ b/pmd-test/src/main/resources/rule-tests_1_0_0.xsd @@ -50,7 +50,7 @@ - + From 653c0df9c2d3058ca1459d553804fb10b20f958c Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 12:00:07 +0100 Subject: [PATCH 227/235] [doc] Update release notes, refs #2343 --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 2b061932c3..8ad1a89fcd 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -198,6 +198,7 @@ parsed as `ASTCursorSpecification`. * [#2338](https://github.com/pmd/pmd/pull/2338): \[cs] CPD: fixes in filtering of using directives - [Maikel Steneker](https://github.com/maikelsteneker) * [#2339](https://github.com/pmd/pmd/pull/2339): \[cs] CPD: Fixed CPD --ignore-usings option - [Maikel Steneker](https://github.com/maikelsteneker) * [#2340](https://github.com/pmd/pmd/pull/2340): \[plsql] fix for parsing / as divide or execute - [Piotr Szymanski](https://github.com/szyman23) +* [#2343](https://github.com/pmd/pmd/pull/2343): \[ci] Disable checking for snapshots in jcenter - [Piotrek Żygieło](https://github.com/pzygielo) {% endtocmaker %} From b29f01be5e90ac9f5607cdb8a044897a0bbacaf8 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 12:06:03 +0100 Subject: [PATCH 228/235] [ci] be more explicit about the used maven repositories --- pom.xml | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 55a48accc8..4e044d4101 100644 --- a/pom.xml +++ b/pom.xml @@ -806,6 +806,18 @@ + + central + Central Repository + https://repo.maven.apache.org/maven2 + + true + never + + + false + + sonatype-nexus-snapshots Sonatype Nexus Snapshots @@ -817,14 +829,6 @@ true - - central - Central Repository - https://repo.maven.apache.org/maven2 - - false - - @@ -832,6 +836,7 @@ Central Repository https://repo.maven.apache.org/maven2 + true never @@ -850,8 +855,13 @@ + jcenter JCenter + + true + never + false From abf0e18c2d7d4b7ba43ecac52188eff167b5df1e Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 12:06:41 +0100 Subject: [PATCH 229/235] [ci] Use pmd.build-tools.version 6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4e044d4101..8c38b7f861 100644 --- a/pom.xml +++ b/pom.xml @@ -105,7 +105,7 @@ -Xmx512m -Dfile.encoding=${project.build.sourceEncoding} - 6-SNAPSHOT + 6 6.21.0 From bc59bb2f97aa6bc849f90dfd3f1f20ae9b0257f1 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 14:21:04 +0100 Subject: [PATCH 230/235] Fix build --- .../java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java | 1 + 1 file changed, 1 insertion(+) diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java index dd1234e5e5..65b4dd9aa9 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java @@ -25,6 +25,7 @@ import java.io.Writer; import org.apache.commons.lang3.text.StrBuilder; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.impl.javacc.AbstractJjtreeNode; From 0d0c701f8ac73e5b2478dcf28e7023e86754a75a Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 14:56:25 +0100 Subject: [PATCH 231/235] [doc] Mention xpath rules deprecation in release notes Refs #1687 --- docs/pages/release_notes.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 9f5ca545ce..6d58cbd04a 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -53,6 +53,15 @@ The C# tokenizer is now based on an antlr grammar instead of a manual written to should give more accurate results and especially fixes the problems with the using statement syntax (see [#2139](https://github.com/pmd/pmd/issues/2139)). +#### XPath Rules + +See the new documentation about [Writing XPath Rules](pmd_userdocs_extending_writing_xpath_rules.html). + +*Note:* 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). + #### New Rules * The Rule {% rule "apex/design/CognitiveComplexity" %} (`apex-design`) finds methods and classes From 1c09ce1fc0d13219f2387981b17229b825b4acf4 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 15:04:20 +0100 Subject: [PATCH 232/235] Prepare pmd release 6.22.0 --- docs/_config.yml | 2 +- docs/pages/next_major_development.md | 130 +++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/docs/_config.yml b/docs/_config.yml index cddd951ae3..b79bed4de0 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -3,7 +3,7 @@ repository: pmd/pmd pmd: version: 6.22.0 previous_version: 6.21.0 - date: ??-????-2020 + date: 12-March-2020 release_type: minor # release types: major, minor, bugfix diff --git a/docs/pages/next_major_development.md b/docs/pages/next_major_development.md index 4c7704ef6c..1715aa3568 100644 --- a/docs/pages/next_major_development.md +++ b/docs/pages/next_major_development.md @@ -73,6 +73,136 @@ the breaking API changes will be performed in 7.0.0. an API is tagged as `@Deprecated` or not in the latest minor release. During the development of 7.0.0, we may decide to remove some APIs that were not tagged as deprecated, though we'll try to avoid it." %} +#### 6.22.0 + +##### Deprecated APIs + +###### Internal API + +Those APIs are not intended to be used by clients, and will be hidden or removed with PMD 7.0.0. +You can identify them with the `@InternalApi` annotation. You'll also get a deprecation warning. + +* {% jdoc java::lang.java.JavaLanguageHandler %} +* {% jdoc java::lang.java.JavaLanguageParser %} +* {% jdoc java::lang.java.JavaDataFlowHandler %} +* Implementations of {% jdoc core::lang.rule.RuleViolationFactory %} in each + language module, eg {% jdoc java::lang.java.rule.JavaRuleViolationFactory %}. + See javadoc of {% jdoc core::lang.rule.RuleViolationFactory %}. +* Implementations of {% jdoc core::RuleViolation %} in each language module, + eg {% jdoc java::lang.java.rule.JavaRuleViolation %}. See javadoc of + {% jdoc core::RuleViolation %}. + +* {% jdoc core::rules.RuleFactory %} +* {% jdoc core::rules.RuleBuilder %} +* Constructors of {% jdoc core::RuleSetFactory %}, use factory methods from {% jdoc core::RulesetsFactoryUtils %} instead +* {% jdoc core::RulesetsFactoryUtils#getRulesetFactory(core::PMDConfiguration, core::util.ResourceLoader) %} + +* {% jdoc apex::lang.apex.ast.AbstractApexNode %} +* {% jdoc apex::lang.apex.ast.AbstractApexNodeBase %}, and the related `visit` +methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementations. + Use {% jdoc apex::lang.apex.ast.ApexNode %} instead, now considers comments too. + +###### For removal + +* pmd-core + * {% jdoc core::lang.dfa.DFAGraphRule %} and its implementations + * {% jdoc core::lang.dfa.DFAGraphMethod %} + * Many methods on the {% jdoc core::lang.ast.Node %} interface + and {% jdoc core::lang.ast.AbstractNode %} base class. See their javadoc for details. + * {% jdoc !!core::lang.ast.Node#isFindBoundary() %} is deprecated for XPath queries. + * Many APIs of {% jdoc_package core::lang.metrics %}, though most of them were internal and + probably not used directly outside of PMD. Use {% jdoc core::lang.metrics.MetricsUtil %} as + a replacement for the language-specific façades too. + * {% jdoc core::lang.ast.QualifiableNode %}, {% jdoc core::lang.ast.QualifiedName %} +* pmd-java + * {% jdoc java::lang.java.AbstractJavaParser %} + * {% jdoc java::lang.java.AbstractJavaHandler %} + * [`ASTAnyTypeDeclaration.TypeKind`](https://javadoc.io/page/net.sourceforge.pmd/pmd-java/6.21.0/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.TypeKind.html) + * {% jdoc !!java::lang.java.ast.ASTAnyTypeDeclaration#getKind() %} + * {% jdoc java::lang.java.ast.JavaQualifiedName %} + * {% jdoc !!java::lang.java.ast.ASTCatchStatement#getBlock() %} + * {% jdoc !!java::lang.java.ast.ASTCompilationUnit#declarationsAreInDefaultPackage() %} + * {% jdoc java::lang.java.ast.JavaQualifiableNode %} + * {% jdoc !!java::lang.java.ast.ASTAnyTypeDeclaration#getQualifiedName() %} + * {% jdoc !!java::lang.java.ast.ASTMethodOrConstructorDeclaration#getQualifiedName() %} + * {% jdoc !!java::lang.java.ast.ASTLambdaExpression#getQualifiedName() %} + * {% jdoc_package java::lang.java.qname %} and its contents + * {% jdoc java::lang.java.ast.MethodLikeNode %} + * Its methods will also be removed from its implementations, + {% jdoc java::lang.java.ast.ASTMethodOrConstructorDeclaration %}, + {% jdoc java::lang.java.ast.ASTLambdaExpression %}. + * {% jdoc !!java::lang.java.ast.ASTAnyTypeDeclaration#getImage() %} will be removed. Please use `getSimpleName()` + instead. This affects {% jdoc !!java::lang.java.ast.ASTAnnotationTypeDeclaration#getImage() %}, + {% jdoc !!java::lang.java.ast.ASTClassOrInterfaceDeclaration#getImage() %}, and + {% jdoc !!java::lang.java.ast.ASTEnumDeclaration#getImage() %}. + * Several methods of {% jdoc java::lang.java.ast.ASTTryStatement %}, replacements with other names + have been added. This includes the XPath attribute `@Finally`, replace it with a test for `child::FinallyStatement`. + * Several methods named `getGuardExpressionNode` are replaced with `getCondition`. This affects the + following nodes: WhileStatement, DoStatement, ForStatement, IfStatement, AssertStatement, ConditionalExpression. + * {% jdoc java::lang.java.ast.ASTYieldStatement %} will not implement {% jdoc java::lang.java.ast.TypeNode %} + anymore come 7.0.0. Test the type of the expression nested within it. + * {% jdoc java::lang.java.metrics.JavaMetrics %}, {% jdoc java::lang.java.metrics.JavaMetricsComputer %} + * {% jdoc !!java::lang.java.ast.ASTArguments#getArgumentCount() %}. + Use {% jdoc java::lang.java.ast.ASTArguments#size() %} instead. + * {% jdoc !!java::lang.java.ast.ASTFormalParameters#getParameterCount() %}. + Use {% jdoc java::lang.java.ast.ASTFormalParameters#size() %} instead. +* pmd-apex + * {% jdoc apex::lang.apex.metrics.ApexMetrics %}, {% jdoc apex::lang.apex.metrics.ApexMetricsComputer %} + +###### In ASTs (JSP) + +As part of the changes we'd like to do to AST classes for 7.0.0, we would like to +hide some methods and constructors that rule writers should not have access to. +The following usages are now deprecated **in the JSP AST** (with other languages to come): + +* Manual instantiation of nodes. **Constructors of node classes are deprecated** and + marked {% jdoc core::annotation.InternalApi %}. Nodes should only be obtained from the parser, + which for rules, means that they never need to instantiate node themselves. + Those constructors will be made package private with 7.0.0. +* **Subclassing of abstract node classes, or usage of their type**. The base classes are internal API + and will be hidden in version 7.0.0. You should not couple your code to them. + * In the meantime you should use interfaces like {% jdoc jsp::lang.jsp.ast.JspNode %} or + {% jdoc core::lang.ast.Node %}, or the other published interfaces in this package, + to refer to nodes generically. + * Concrete node classes will **be made final** with 7.0.0. +* Setters found in any node class or interface. **Rules should consider the AST immutable**. + We will make those setters package private with 7.0.0. +* The class {% jdoc jsp::lang.jsp.JspParser %} is deprecated and should not be used directly. + Use {% jdoc !!core::lang.LanguageVersionHandler#getParser(ParserOptions) %} instead. + +Please look at {% jdoc_package jsp::lang.jsp.ast %} to find out the full list of deprecations. + +###### In ASTs (Velocity) + +As part of the changes we'd like to do to AST classes for 7.0.0, we would like to +hide some methods and constructors that rule writers should not have access to. +The following usages are now deprecated **in the VM AST** (with other languages to come): + +* Manual instantiation of nodes. **Constructors of node classes are deprecated** and + marked {% jdoc core::annotation.InternalApi %}. Nodes should only be obtained from the parser, + which for rules, means that they never need to instantiate node themselves. + Those constructors will be made package private with 7.0.0. +* **Subclassing of abstract node classes, or usage of their type**. The base classes are internal API + and will be hidden in version 7.0.0. You should not couple your code to them. + * In the meantime you should use interfaces like {% jdoc vm::lang.vm.ast.VmNode %} or + {% jdoc core::lang.ast.Node %}, or the other published interfaces in this package, + to refer to nodes generically. + * Concrete node classes will **be made final** with 7.0.0. +* Setters found in any node class or interface. **Rules should consider the AST immutable**. + We will make those setters package private with 7.0.0. +* The package {% jdoc_package vm::lang.vm.directive %} as well as the classes + {% jdoc vm::lang.vm.util.DirectiveMapper %} and {% jdoc vm::lang.vm.util.LogUtil %} are deprecated + for removal. They were only used internally during parsing. +* The class {% jdoc vm::lang.vm.VmParser %} is deprecated and should not be used directly. + Use {% jdoc !!core::lang.LanguageVersionHandler#getParser(ParserOptions) %} instead. + +Please look at {% jdoc_package vm::lang.vm.ast %} to find out the full list of deprecations. + +##### PLSQL AST + +The production and node `ASTCursorBody` was unnecessary, not used and has been removed. Cursors have been already +parsed as `ASTCursorSpecification`. + #### 6.21.0 ##### Deprecated APIs From eb93aaeca7e193de6e6bc275bebbe83f2b4c9c1a Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 15:15:09 +0100 Subject: [PATCH 233/235] [maven-release-plugin] prepare release pmd_releases/6.22.0 --- pmd-apex-jorje/pom.xml | 2 +- pmd-apex/pom.xml | 2 +- pmd-core/pom.xml | 2 +- pmd-cpp/pom.xml | 2 +- pmd-cs/pom.xml | 2 +- pmd-dart/pom.xml | 2 +- pmd-dist/pom.xml | 2 +- pmd-doc/pom.xml | 2 +- pmd-fortran/pom.xml | 2 +- pmd-go/pom.xml | 2 +- pmd-groovy/pom.xml | 2 +- pmd-java/pom.xml | 2 +- pmd-java8/pom.xml | 2 +- pmd-javascript/pom.xml | 2 +- pmd-jsp/pom.xml | 2 +- pmd-kotlin/pom.xml | 2 +- pmd-lang-test/pom.xml | 2 +- pmd-lua/pom.xml | 2 +- pmd-matlab/pom.xml | 2 +- pmd-modelica/pom.xml | 2 +- pmd-objectivec/pom.xml | 2 +- pmd-perl/pom.xml | 2 +- pmd-php/pom.xml | 2 +- pmd-plsql/pom.xml | 2 +- pmd-python/pom.xml | 2 +- pmd-ruby/pom.xml | 2 +- pmd-scala/pom.xml | 2 +- pmd-swift/pom.xml | 2 +- pmd-test/pom.xml | 2 +- pmd-visualforce/pom.xml | 2 +- pmd-vm/pom.xml | 2 +- pmd-xml/pom.xml | 2 +- pom.xml | 4 ++-- 33 files changed, 34 insertions(+), 34 deletions(-) diff --git a/pmd-apex-jorje/pom.xml b/pmd-apex-jorje/pom.xml index ab7238f975..bb461c0f87 100644 --- a/pmd-apex-jorje/pom.xml +++ b/pmd-apex-jorje/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-apex/pom.xml b/pmd-apex/pom.xml index c2351afc78..d7d10f8387 100644 --- a/pmd-apex/pom.xml +++ b/pmd-apex/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index 80aab40792..04cf5a1750 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-cpp/pom.xml b/pmd-cpp/pom.xml index 558e39b476..7d7a773a48 100644 --- a/pmd-cpp/pom.xml +++ b/pmd-cpp/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-cs/pom.xml b/pmd-cs/pom.xml index 39679d6150..d6429488d8 100644 --- a/pmd-cs/pom.xml +++ b/pmd-cs/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-dart/pom.xml b/pmd-dart/pom.xml index a03306c058..dd2fdb7948 100644 --- a/pmd-dart/pom.xml +++ b/pmd-dart/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml index 64e305156a..4d561eb3d0 100644 --- a/pmd-dist/pom.xml +++ b/pmd-dist/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-doc/pom.xml b/pmd-doc/pom.xml index 757a7b1499..fc0afc4fa5 100644 --- a/pmd-doc/pom.xml +++ b/pmd-doc/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-fortran/pom.xml b/pmd-fortran/pom.xml index 71ee42d897..2bc2a863ca 100644 --- a/pmd-fortran/pom.xml +++ b/pmd-fortran/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-go/pom.xml b/pmd-go/pom.xml index 59cf7ced16..6fbea19a82 100644 --- a/pmd-go/pom.xml +++ b/pmd-go/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-groovy/pom.xml b/pmd-groovy/pom.xml index 20af2c6cd5..cb907fdcd4 100644 --- a/pmd-groovy/pom.xml +++ b/pmd-groovy/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-java/pom.xml b/pmd-java/pom.xml index 0dff843f17..e38c94f62f 100644 --- a/pmd-java/pom.xml +++ b/pmd-java/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-java8/pom.xml b/pmd-java8/pom.xml index 8f5e6cb515..a1b4205ff2 100644 --- a/pmd-java8/pom.xml +++ b/pmd-java8/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-javascript/pom.xml b/pmd-javascript/pom.xml index d0105c34bb..5e276553a8 100644 --- a/pmd-javascript/pom.xml +++ b/pmd-javascript/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-jsp/pom.xml b/pmd-jsp/pom.xml index 78793cc8b3..ba6e83959f 100644 --- a/pmd-jsp/pom.xml +++ b/pmd-jsp/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-kotlin/pom.xml b/pmd-kotlin/pom.xml index 842ca25dfe..12a59b004c 100644 --- a/pmd-kotlin/pom.xml +++ b/pmd-kotlin/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-lang-test/pom.xml b/pmd-lang-test/pom.xml index a245fd9193..53974af824 100644 --- a/pmd-lang-test/pom.xml +++ b/pmd-lang-test/pom.xml @@ -12,7 +12,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-lua/pom.xml b/pmd-lua/pom.xml index feb9b7a771..ab5df1e20c 100644 --- a/pmd-lua/pom.xml +++ b/pmd-lua/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-matlab/pom.xml b/pmd-matlab/pom.xml index 83f9d5f217..ae232f07f9 100644 --- a/pmd-matlab/pom.xml +++ b/pmd-matlab/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-modelica/pom.xml b/pmd-modelica/pom.xml index 000634dbe8..918b53fce5 100644 --- a/pmd-modelica/pom.xml +++ b/pmd-modelica/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-objectivec/pom.xml b/pmd-objectivec/pom.xml index 2395593fdc..4eb64d30e1 100644 --- a/pmd-objectivec/pom.xml +++ b/pmd-objectivec/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-perl/pom.xml b/pmd-perl/pom.xml index b66870d5f6..89c65209e8 100644 --- a/pmd-perl/pom.xml +++ b/pmd-perl/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-php/pom.xml b/pmd-php/pom.xml index 38179be869..f7b65bfdae 100644 --- a/pmd-php/pom.xml +++ b/pmd-php/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-plsql/pom.xml b/pmd-plsql/pom.xml index d67851596b..86157e3573 100644 --- a/pmd-plsql/pom.xml +++ b/pmd-plsql/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-python/pom.xml b/pmd-python/pom.xml index 765ae300bb..ee30c6cc6c 100644 --- a/pmd-python/pom.xml +++ b/pmd-python/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-ruby/pom.xml b/pmd-ruby/pom.xml index 6121af2a8d..a92231d56c 100644 --- a/pmd-ruby/pom.xml +++ b/pmd-ruby/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-scala/pom.xml b/pmd-scala/pom.xml index b6369d189b..e9bf0cf9ae 100644 --- a/pmd-scala/pom.xml +++ b/pmd-scala/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-swift/pom.xml b/pmd-swift/pom.xml index 70ad321d8a..4fa5f2a104 100644 --- a/pmd-swift/pom.xml +++ b/pmd-swift/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-test/pom.xml b/pmd-test/pom.xml index 67a55a88df..3e64ffb1e0 100644 --- a/pmd-test/pom.xml +++ b/pmd-test/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-visualforce/pom.xml b/pmd-visualforce/pom.xml index 7c8c7dca2f..036e412ee3 100644 --- a/pmd-visualforce/pom.xml +++ b/pmd-visualforce/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-vm/pom.xml b/pmd-vm/pom.xml index 97c91b2cb8..f754219d7a 100644 --- a/pmd-vm/pom.xml +++ b/pmd-vm/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pmd-xml/pom.xml b/pmd-xml/pom.xml index c3a933694c..857a3b4faf 100644 --- a/pmd-xml/pom.xml +++ b/pmd-xml/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 diff --git a/pom.xml b/pom.xml index 8c38b7f861..6d78cad5fd 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 net.sourceforge.pmd pmd - 6.22.0-SNAPSHOT + 6.22.0 pom PMD @@ -55,7 +55,7 @@ scm:git:git://github.com/pmd/pmd.git scm:git:ssh://git@github.com/pmd/pmd.git https://github.com/pmd/pmd - HEAD + pmd_releases/6.22.0 From 4c020bfbf7afd6e0d4d59c669e62ce9f7e775dd5 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 15:15:18 +0100 Subject: [PATCH 234/235] [maven-release-plugin] prepare for next development iteration --- pmd-apex-jorje/pom.xml | 2 +- pmd-apex/pom.xml | 2 +- pmd-core/pom.xml | 2 +- pmd-cpp/pom.xml | 2 +- pmd-cs/pom.xml | 2 +- pmd-dart/pom.xml | 2 +- pmd-dist/pom.xml | 2 +- pmd-doc/pom.xml | 2 +- pmd-fortran/pom.xml | 2 +- pmd-go/pom.xml | 2 +- pmd-groovy/pom.xml | 2 +- pmd-java/pom.xml | 2 +- pmd-java8/pom.xml | 2 +- pmd-javascript/pom.xml | 2 +- pmd-jsp/pom.xml | 2 +- pmd-kotlin/pom.xml | 2 +- pmd-lang-test/pom.xml | 2 +- pmd-lua/pom.xml | 2 +- pmd-matlab/pom.xml | 2 +- pmd-modelica/pom.xml | 2 +- pmd-objectivec/pom.xml | 2 +- pmd-perl/pom.xml | 2 +- pmd-php/pom.xml | 2 +- pmd-plsql/pom.xml | 2 +- pmd-python/pom.xml | 2 +- pmd-ruby/pom.xml | 2 +- pmd-scala/pom.xml | 2 +- pmd-swift/pom.xml | 2 +- pmd-test/pom.xml | 2 +- pmd-visualforce/pom.xml | 2 +- pmd-vm/pom.xml | 2 +- pmd-xml/pom.xml | 2 +- pom.xml | 4 ++-- 33 files changed, 34 insertions(+), 34 deletions(-) diff --git a/pmd-apex-jorje/pom.xml b/pmd-apex-jorje/pom.xml index bb461c0f87..b4810b61f1 100644 --- a/pmd-apex-jorje/pom.xml +++ b/pmd-apex-jorje/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-apex/pom.xml b/pmd-apex/pom.xml index d7d10f8387..92bfa783d7 100644 --- a/pmd-apex/pom.xml +++ b/pmd-apex/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index 04cf5a1750..e3f696f202 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-cpp/pom.xml b/pmd-cpp/pom.xml index 7d7a773a48..8a30021432 100644 --- a/pmd-cpp/pom.xml +++ b/pmd-cpp/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-cs/pom.xml b/pmd-cs/pom.xml index d6429488d8..e6a92e6a53 100644 --- a/pmd-cs/pom.xml +++ b/pmd-cs/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-dart/pom.xml b/pmd-dart/pom.xml index dd2fdb7948..902e76cb84 100644 --- a/pmd-dart/pom.xml +++ b/pmd-dart/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml index 4d561eb3d0..245c5859ff 100644 --- a/pmd-dist/pom.xml +++ b/pmd-dist/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-doc/pom.xml b/pmd-doc/pom.xml index fc0afc4fa5..ba9cccc8b3 100644 --- a/pmd-doc/pom.xml +++ b/pmd-doc/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-fortran/pom.xml b/pmd-fortran/pom.xml index 2bc2a863ca..ac8839a98f 100644 --- a/pmd-fortran/pom.xml +++ b/pmd-fortran/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-go/pom.xml b/pmd-go/pom.xml index 6fbea19a82..a95c255240 100644 --- a/pmd-go/pom.xml +++ b/pmd-go/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-groovy/pom.xml b/pmd-groovy/pom.xml index cb907fdcd4..766b26f204 100644 --- a/pmd-groovy/pom.xml +++ b/pmd-groovy/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-java/pom.xml b/pmd-java/pom.xml index e38c94f62f..e880277f0f 100644 --- a/pmd-java/pom.xml +++ b/pmd-java/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-java8/pom.xml b/pmd-java8/pom.xml index a1b4205ff2..0e97c3b949 100644 --- a/pmd-java8/pom.xml +++ b/pmd-java8/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-javascript/pom.xml b/pmd-javascript/pom.xml index 5e276553a8..22562cdd64 100644 --- a/pmd-javascript/pom.xml +++ b/pmd-javascript/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-jsp/pom.xml b/pmd-jsp/pom.xml index ba6e83959f..23f92b1ea2 100644 --- a/pmd-jsp/pom.xml +++ b/pmd-jsp/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-kotlin/pom.xml b/pmd-kotlin/pom.xml index 12a59b004c..8f88a53ba6 100644 --- a/pmd-kotlin/pom.xml +++ b/pmd-kotlin/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-lang-test/pom.xml b/pmd-lang-test/pom.xml index 53974af824..910eda2842 100644 --- a/pmd-lang-test/pom.xml +++ b/pmd-lang-test/pom.xml @@ -12,7 +12,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-lua/pom.xml b/pmd-lua/pom.xml index ab5df1e20c..65568264f3 100644 --- a/pmd-lua/pom.xml +++ b/pmd-lua/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-matlab/pom.xml b/pmd-matlab/pom.xml index ae232f07f9..724a4b6469 100644 --- a/pmd-matlab/pom.xml +++ b/pmd-matlab/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-modelica/pom.xml b/pmd-modelica/pom.xml index 918b53fce5..dffa0255c1 100644 --- a/pmd-modelica/pom.xml +++ b/pmd-modelica/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-objectivec/pom.xml b/pmd-objectivec/pom.xml index 4eb64d30e1..01490b3f78 100644 --- a/pmd-objectivec/pom.xml +++ b/pmd-objectivec/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-perl/pom.xml b/pmd-perl/pom.xml index 89c65209e8..3d43cf531f 100644 --- a/pmd-perl/pom.xml +++ b/pmd-perl/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-php/pom.xml b/pmd-php/pom.xml index f7b65bfdae..6b5e14f05b 100644 --- a/pmd-php/pom.xml +++ b/pmd-php/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-plsql/pom.xml b/pmd-plsql/pom.xml index 86157e3573..39295303ba 100644 --- a/pmd-plsql/pom.xml +++ b/pmd-plsql/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-python/pom.xml b/pmd-python/pom.xml index ee30c6cc6c..19c27cde3f 100644 --- a/pmd-python/pom.xml +++ b/pmd-python/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-ruby/pom.xml b/pmd-ruby/pom.xml index a92231d56c..36b0a63eb0 100644 --- a/pmd-ruby/pom.xml +++ b/pmd-ruby/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-scala/pom.xml b/pmd-scala/pom.xml index e9bf0cf9ae..51bcf553c8 100644 --- a/pmd-scala/pom.xml +++ b/pmd-scala/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-swift/pom.xml b/pmd-swift/pom.xml index 4fa5f2a104..f16525129b 100644 --- a/pmd-swift/pom.xml +++ b/pmd-swift/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-test/pom.xml b/pmd-test/pom.xml index 3e64ffb1e0..09a2805b2b 100644 --- a/pmd-test/pom.xml +++ b/pmd-test/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-visualforce/pom.xml b/pmd-visualforce/pom.xml index 036e412ee3..a08375cd5f 100644 --- a/pmd-visualforce/pom.xml +++ b/pmd-visualforce/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-vm/pom.xml b/pmd-vm/pom.xml index f754219d7a..109f1303b6 100644 --- a/pmd-vm/pom.xml +++ b/pmd-vm/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pmd-xml/pom.xml b/pmd-xml/pom.xml index 857a3b4faf..f8cb17580c 100644 --- a/pmd-xml/pom.xml +++ b/pmd-xml/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index 6d78cad5fd..89b1ad875c 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 net.sourceforge.pmd pmd - 6.22.0 + 6.23.0-SNAPSHOT pom PMD @@ -55,7 +55,7 @@ scm:git:git://github.com/pmd/pmd.git scm:git:ssh://git@github.com/pmd/pmd.git https://github.com/pmd/pmd - pmd_releases/6.22.0 + HEAD From a0b4c4fe0afff977ff0b428f9a75ed07244cbac7 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 12 Mar 2020 15:16:48 +0100 Subject: [PATCH 235/235] Prepare next development version --- docs/_config.yml | 6 +- docs/pages/release_notes.md | 241 ---------------------------- docs/pages/release_notes_old.md | 274 ++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+), 244 deletions(-) diff --git a/docs/_config.yml b/docs/_config.yml index b79bed4de0..6096f80ba3 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,9 +1,9 @@ repository: pmd/pmd pmd: - version: 6.22.0 - previous_version: 6.21.0 - date: 12-March-2020 + version: 6.23.0 + previous_version: 6.22.0 + date: ??-??-2020 release_type: minor # release types: major, minor, bugfix diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 6d58cbd04a..b8f8783555 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,252 +14,11 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy -#### Java 14 Support - -This release of PMD brings support for Java 14. PMD can parse [Switch Expressions](https://openjdk.java.net/jeps/361), -which have been promoted to be a standard language feature of Java. - -PMD also parses [Text Blocks](https://openjdk.java.net/jeps/368) as String literals, which is still a preview -language feature in Java 14. - -The new [Pattern Matching for instanceof](https://openjdk.java.net/jeps/305) can be used as well as -[Records](https://openjdk.java.net/jeps/359). - -Note: The Text Blocks, Pattern Matching for instanceof and Records are all preview language features of OpenJDK 14 -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 `14-preview`: - - export PMD_JAVA_OPTS=--enable-preview - ./run.sh pmd -language java -version 14-preview ... - -Note: Support for the extended break statement introduced in Java 12 as a preview language feature -has been removed from PMD with this version. The version "12-preview" is no longer available. - - -#### Updated PMD Designer - -This PMD release ships a new version of the pmd-designer. -For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/6.21.0). - -#### Apex Suppressions - -In addition to suppressing violation with the `@SuppressWarnings` annotation, Apex now also supports -the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs_suppressing_warnings.html). - -#### Improved CPD support for C# - -The C# tokenizer is now based on an antlr grammar instead of a manual written tokenizer. This -should give more accurate results and especially fixes the problems with the using statement syntax -(see [#2139](https://github.com/pmd/pmd/issues/2139)). - -#### XPath Rules - -See the new documentation about [Writing XPath Rules](pmd_userdocs_extending_writing_xpath_rules.html). - -*Note:* 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). - -#### New Rules - -* The Rule {% rule "apex/design/CognitiveComplexity" %} (`apex-design`) finds methods and classes - that are highly complex and therefore difficult to read and more costly to maintain. In contrast - to cyclomatic complexity, this rule uses "Cognitive Complexity", which is a measure of how - difficult it is for humans to read and understand a method. - -* The Rule {% rule "apex/errorprone/TestMethodsMustBeInTestClasses" %} (`apex-errorprone`) finds test methods - that are not residing in a test class. The test methods should be moved to a proper test class. - Support for tests inside functional classes was removed in Spring-13 (API Version 27.0), making classes - that violate this rule fail compile-time. This rule is however useful when dealing with legacy code. - ### Fixed Issues -* apex - * [#1087](https://github.com/pmd/pmd/issues/1087): \[apex] Support suppression via //NOPMD - * [#2306](https://github.com/pmd/pmd/issues/2306): \[apex] Switch statements are not parsed/supported -* apex-design - * [#2162](https://github.com/pmd/pmd/issues/2162): \[apex] Cognitive Complexity rule -* apex-errorprone - * [#639](https://github.com/pmd/pmd/issues/639): \[apex] Test methods should not be in classes other than test classes -* cs - * [#2139](https://github.com/pmd/pmd/issues/2139): \[cs] CPD doesn't understand alternate using statement syntax with C# 8.0 -* doc - * [#2274](https://github.com/pmd/pmd/issues/2274): \[doc] Java API documentation for PMD -* java - * [#2159](https://github.com/pmd/pmd/issues/2159): \[java] Prepare for JDK 14 - * [#2268](https://github.com/pmd/pmd/issues/2268): \[java] Improve TypeHelper resilience -* java-bestpractices - * [#2277](https://github.com/pmd/pmd/issues/2277): \[java] FP in UnusedImports for ambiguous static on-demand imports -* java-design - * [#911](https://github.com/pmd/pmd/issues/911): \[java] UselessOverridingMethod false positive when elevating access modifier -* java-errorprone - * [#2242](https://github.com/pmd/pmd/issues/2242): \[java] False-positive MisplacedNullCheck reported - * [#2250](https://github.com/pmd/pmd/issues/2250): \[java] InvalidLogMessageFormat flags logging calls using a slf4j-Marker - * [#2255](https://github.com/pmd/pmd/issues/2255): \[java] InvalidLogMessageFormat false-positive for a lambda argument -* java-performance - * [#2275](https://github.com/pmd/pmd/issues/2275): \[java] AppendCharacterWithChar flags literals in an expression -* plsql - * [#2325](https://github.com/pmd/pmd/issues/2325): \[plsql] NullPointerException while running parsing test for CREATE TRIGGER - * [#2327](https://github.com/pmd/pmd/pull/2327): \[plsql] Parsing of WHERE CURRENT OF - * [#2328](https://github.com/pmd/pmd/issues/2328): \[plsql] Support XMLROOT - * [#2331](https://github.com/pmd/pmd/pull/2331): \[plsql] Fix in Comment statement - * [#2332](https://github.com/pmd/pmd/pull/2332): \[plsql] Fixed Execute Immediate statement parsing - * [#2340](https://github.com/pmd/pmd/pull/2340): \[plsql] Fixed parsing / as divide or execute - ### API Changes -#### Deprecated APIs - -##### Internal API - -Those APIs are not intended to be used by clients, and will be hidden or removed with PMD 7.0.0. -You can identify them with the `@InternalApi` annotation. You'll also get a deprecation warning. - -* {% jdoc java::lang.java.JavaLanguageHandler %} -* {% jdoc java::lang.java.JavaLanguageParser %} -* {% jdoc java::lang.java.JavaDataFlowHandler %} -* Implementations of {% jdoc core::lang.rule.RuleViolationFactory %} in each - language module, eg {% jdoc java::lang.java.rule.JavaRuleViolationFactory %}. - See javadoc of {% jdoc core::lang.rule.RuleViolationFactory %}. -* Implementations of {% jdoc core::RuleViolation %} in each language module, - eg {% jdoc java::lang.java.rule.JavaRuleViolation %}. See javadoc of - {% jdoc core::RuleViolation %}. - -* {% jdoc core::rules.RuleFactory %} -* {% jdoc core::rules.RuleBuilder %} -* Constructors of {% jdoc core::RuleSetFactory %}, use factory methods from {% jdoc core::RulesetsFactoryUtils %} instead -* {% jdoc core::RulesetsFactoryUtils#getRulesetFactory(core::PMDConfiguration, core::util.ResourceLoader) %} - -* {% jdoc apex::lang.apex.ast.AbstractApexNode %} -* {% jdoc apex::lang.apex.ast.AbstractApexNodeBase %}, and the related `visit` -methods on {% jdoc apex::lang.apex.ast.ApexParserVisitor %} and its implementations. - Use {% jdoc apex::lang.apex.ast.ApexNode %} instead, now considers comments too. - -##### For removal - -* pmd-core - * {% jdoc core::lang.dfa.DFAGraphRule %} and its implementations - * {% jdoc core::lang.dfa.DFAGraphMethod %} - * Many methods on the {% jdoc core::lang.ast.Node %} interface - and {% jdoc core::lang.ast.AbstractNode %} base class. See their javadoc for details. - * {% jdoc !!core::lang.ast.Node#isFindBoundary() %} is deprecated for XPath queries. - * Many APIs of {% jdoc_package core::lang.metrics %}, though most of them were internal and - probably not used directly outside of PMD. Use {% jdoc core::lang.metrics.MetricsUtil %} as - a replacement for the language-specific façades too. - * {% jdoc core::lang.ast.QualifiableNode %}, {% jdoc core::lang.ast.QualifiedName %} -* pmd-java - * {% jdoc java::lang.java.AbstractJavaParser %} - * {% jdoc java::lang.java.AbstractJavaHandler %} - * [`ASTAnyTypeDeclaration.TypeKind`](https://javadoc.io/page/net.sourceforge.pmd/pmd-java/6.21.0/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.TypeKind.html) - * {% jdoc !!java::lang.java.ast.ASTAnyTypeDeclaration#getKind() %} - * {% jdoc java::lang.java.ast.JavaQualifiedName %} - * {% jdoc !!java::lang.java.ast.ASTCatchStatement#getBlock() %} - * {% jdoc !!java::lang.java.ast.ASTCompilationUnit#declarationsAreInDefaultPackage() %} - * {% jdoc java::lang.java.ast.JavaQualifiableNode %} - * {% jdoc !!java::lang.java.ast.ASTAnyTypeDeclaration#getQualifiedName() %} - * {% jdoc !!java::lang.java.ast.ASTMethodOrConstructorDeclaration#getQualifiedName() %} - * {% jdoc !!java::lang.java.ast.ASTLambdaExpression#getQualifiedName() %} - * {% jdoc_package java::lang.java.qname %} and its contents - * {% jdoc java::lang.java.ast.MethodLikeNode %} - * Its methods will also be removed from its implementations, - {% jdoc java::lang.java.ast.ASTMethodOrConstructorDeclaration %}, - {% jdoc java::lang.java.ast.ASTLambdaExpression %}. - * {% jdoc !!java::lang.java.ast.ASTAnyTypeDeclaration#getImage() %} will be removed. Please use `getSimpleName()` - instead. This affects {% jdoc !!java::lang.java.ast.ASTAnnotationTypeDeclaration#getImage() %}, - {% jdoc !!java::lang.java.ast.ASTClassOrInterfaceDeclaration#getImage() %}, and - {% jdoc !!java::lang.java.ast.ASTEnumDeclaration#getImage() %}. - * Several methods of {% jdoc java::lang.java.ast.ASTTryStatement %}, replacements with other names - have been added. This includes the XPath attribute `@Finally`, replace it with a test for `child::FinallyStatement`. - * Several methods named `getGuardExpressionNode` are replaced with `getCondition`. This affects the - following nodes: WhileStatement, DoStatement, ForStatement, IfStatement, AssertStatement, ConditionalExpression. - * {% jdoc java::lang.java.ast.ASTYieldStatement %} will not implement {% jdoc java::lang.java.ast.TypeNode %} - anymore come 7.0.0. Test the type of the expression nested within it. - * {% jdoc java::lang.java.metrics.JavaMetrics %}, {% jdoc java::lang.java.metrics.JavaMetricsComputer %} - * {% jdoc !!java::lang.java.ast.ASTArguments#getArgumentCount() %}. - Use {% jdoc java::lang.java.ast.ASTArguments#size() %} instead. - * {% jdoc !!java::lang.java.ast.ASTFormalParameters#getParameterCount() %}. - Use {% jdoc java::lang.java.ast.ASTFormalParameters#size() %} instead. -* pmd-apex - * {% jdoc apex::lang.apex.metrics.ApexMetrics %}, {% jdoc apex::lang.apex.metrics.ApexMetricsComputer %} - -##### In ASTs (JSP) - -As part of the changes we'd like to do to AST classes for 7.0.0, we would like to -hide some methods and constructors that rule writers should not have access to. -The following usages are now deprecated **in the JSP AST** (with other languages to come): - -* Manual instantiation of nodes. **Constructors of node classes are deprecated** and - marked {% jdoc core::annotation.InternalApi %}. Nodes should only be obtained from the parser, - which for rules, means that they never need to instantiate node themselves. - Those constructors will be made package private with 7.0.0. -* **Subclassing of abstract node classes, or usage of their type**. The base classes are internal API - and will be hidden in version 7.0.0. You should not couple your code to them. - * In the meantime you should use interfaces like {% jdoc jsp::lang.jsp.ast.JspNode %} or - {% jdoc core::lang.ast.Node %}, or the other published interfaces in this package, - to refer to nodes generically. - * Concrete node classes will **be made final** with 7.0.0. -* Setters found in any node class or interface. **Rules should consider the AST immutable**. - We will make those setters package private with 7.0.0. -* The class {% jdoc jsp::lang.jsp.JspParser %} is deprecated and should not be used directly. - Use {% jdoc !!core::lang.LanguageVersionHandler#getParser(ParserOptions) %} instead. - -Please look at {% jdoc_package jsp::lang.jsp.ast %} to find out the full list of deprecations. - -##### In ASTs (Velocity) - -As part of the changes we'd like to do to AST classes for 7.0.0, we would like to -hide some methods and constructors that rule writers should not have access to. -The following usages are now deprecated **in the VM AST** (with other languages to come): - -* Manual instantiation of nodes. **Constructors of node classes are deprecated** and - marked {% jdoc core::annotation.InternalApi %}. Nodes should only be obtained from the parser, - which for rules, means that they never need to instantiate node themselves. - Those constructors will be made package private with 7.0.0. -* **Subclassing of abstract node classes, or usage of their type**. The base classes are internal API - and will be hidden in version 7.0.0. You should not couple your code to them. - * In the meantime you should use interfaces like {% jdoc vm::lang.vm.ast.VmNode %} or - {% jdoc core::lang.ast.Node %}, or the other published interfaces in this package, - to refer to nodes generically. - * Concrete node classes will **be made final** with 7.0.0. -* Setters found in any node class or interface. **Rules should consider the AST immutable**. - We will make those setters package private with 7.0.0. -* The package {% jdoc_package vm::lang.vm.directive %} as well as the classes - {% jdoc vm::lang.vm.util.DirectiveMapper %} and {% jdoc vm::lang.vm.util.LogUtil %} are deprecated - for removal. They were only used internally during parsing. -* The class {% jdoc vm::lang.vm.VmParser %} is deprecated and should not be used directly. - Use {% jdoc !!core::lang.LanguageVersionHandler#getParser(ParserOptions) %} instead. - -Please look at {% jdoc_package vm::lang.vm.ast %} to find out the full list of deprecations. - -#### PLSQL AST - -The production and node `ASTCursorBody` was unnecessary, not used and has been removed. Cursors have been already -parsed as `ASTCursorSpecification`. - ### External Contributions -* [#2251](https://github.com/pmd/pmd/pull/2251): \[java] FP for InvalidLogMessageFormat when using slf4j-Markers - [Kris Scheibe](https://github.com/kris-scheibe) -* [#2253](https://github.com/pmd/pmd/pull/2253): \[modelica] Remove duplicated dependencies - [Piotrek Żygieło](https://github.com/pzygielo) -* [#2256](https://github.com/pmd/pmd/pull/2256): \[doc] Corrected XML attributes in release notes - [Maikel Steneker](https://github.com/maikelsteneker) -* [#2276](https://github.com/pmd/pmd/pull/2276): \[java] AppendCharacterWithCharRule ignore literals in expressions - [Kris Scheibe](https://github.com/kris-scheibe) -* [#2278](https://github.com/pmd/pmd/pull/2278): \[java] fix UnusedImports rule for ambiguous static on-demand imports - [Kris Scheibe](https://github.com/kris-scheibe) -* [#2279](https://github.com/pmd/pmd/pull/2279): \[apex] Add support for suppressing violations using the // NOPMD comment - [Gwilym Kuiper](https://github.com/gwilymatgearset) -* [#2280](https://github.com/pmd/pmd/pull/2280): \[cs] CPD: Replace C# tokenizer by an Antlr-based one - [Maikel Steneker](https://github.com/maikelsteneker) -* [#2297](https://github.com/pmd/pmd/pull/2297): \[apex] Cognitive complexity metrics - [Gwilym Kuiper](https://github.com/gwilymatgearset) -* [#2317](https://github.com/pmd/pmd/pull/2317): \[apex] New Rule - Test Methods Must Be In Test Classes - [Brian Nørremark](https://github.com/noerremark) -* [#2321](https://github.com/pmd/pmd/pull/2321): \[apex] Support switch statements correctly in Cognitive Complexity - [Gwilym Kuiper](https://github.com/gwilymatgearset) -* [#2326](https://github.com/pmd/pmd/pull/2326): \[plsql] Added XML functions to parser: extract(xml), xml_root and fixed xml_forest - [Piotr Szymanski](https://github.com/szyman23) -* [#2327](https://github.com/pmd/pmd/pull/2327): \[plsql] Parsing of WHERE CURRENT OF added - [Piotr Szymanski](https://github.com/szyman23) -* [#2331](https://github.com/pmd/pmd/pull/2331): \[plsql] Fix in Comment statement - [Piotr Szymanski](https://github.com/szyman23) -* [#2332](https://github.com/pmd/pmd/pull/2332): \[plsql] Fixed Execute Immediate statement parsing - [Piotr Szymanski](https://github.com/szyman23) -* [#2338](https://github.com/pmd/pmd/pull/2338): \[cs] CPD: fixes in filtering of using directives - [Maikel Steneker](https://github.com/maikelsteneker) -* [#2339](https://github.com/pmd/pmd/pull/2339): \[cs] CPD: Fixed CPD --ignore-usings option - [Maikel Steneker](https://github.com/maikelsteneker) -* [#2340](https://github.com/pmd/pmd/pull/2340): \[plsql] fix for parsing / as divide or execute - [Piotr Szymanski](https://github.com/szyman23) -* [#2342](https://github.com/pmd/pmd/pull/2342): \[xml] Update property used in example - [Piotrek Żygieło](https://github.com/pzygielo) -* [#2344](https://github.com/pmd/pmd/pull/2344): \[doc] Update ruleset examples for ant - [Piotrek Żygieło](https://github.com/pzygielo) -* [#2343](https://github.com/pmd/pmd/pull/2343): \[ci] Disable checking for snapshots in jcenter - [Piotrek Żygieło](https://github.com/pzygielo) - {% endtocmaker %} diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index 8fc42da0fd..6efcfa4c6e 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -5,6 +5,280 @@ permalink: pmd_release_notes_old.html Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/releases +## 12-March-2020 - 6.22.0 + +The PMD team is pleased to announce PMD 6.22.0. + +This is a minor release. + +### Table Of Contents + +* [New and noteworthy](#new-and-noteworthy) + * [Java 14 Support](#java-14-support) + * [Updated PMD Designer](#updated-pmd-designer) + * [Apex Suppressions](#apex-suppressions) + * [Improved CPD support for C#](#improved-cpd-support-for-c#) + * [XPath Rules](#xpath-rules) + * [New Rules](#new-rules) +* [Fixed Issues](#fixed-issues) +* [API Changes](#api-changes) + * [Deprecated APIs](#deprecated-apis) + * [Internal API](#internal-api) + * [For removal](#for-removal) + * [In ASTs (JSP)](#in-asts-(jsp)) + * [In ASTs (Velocity)](#in-asts-(velocity)) + * [PLSQL AST](#plsql-ast) +* [External Contributions](#external-contributions) + +### New and noteworthy + +#### Java 14 Support + +This release of PMD brings support for Java 14. PMD can parse [Switch Expressions](https://openjdk.java.net/jeps/361), +which have been promoted to be a standard language feature of Java. + +PMD also parses [Text Blocks](https://openjdk.java.net/jeps/368) as String literals, which is still a preview +language feature in Java 14. + +The new [Pattern Matching for instanceof](https://openjdk.java.net/jeps/305) can be used as well as +[Records](https://openjdk.java.net/jeps/359). + +Note: The Text Blocks, Pattern Matching for instanceof and Records are all preview language features of OpenJDK 14 +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 `14-preview`: + + export PMD_JAVA_OPTS=--enable-preview + ./run.sh pmd -language java -version 14-preview ... + +Note: Support for the extended break statement introduced in Java 12 as a preview language feature +has been removed from PMD with this version. The version "12-preview" is no longer available. + + +#### Updated PMD Designer + +This PMD release ships a new version of the pmd-designer. +For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/6.21.0). + +#### Apex Suppressions + +In addition to suppressing violation with the `@SuppressWarnings` annotation, Apex now also supports +the suppressions with a `NOPMD` comment. See [Suppressing warnings](pmd_userdocs_suppressing_warnings.html). + +#### Improved CPD support for C# + +The C# tokenizer is now based on an antlr grammar instead of a manual written tokenizer. This +should give more accurate results and especially fixes the problems with the using statement syntax +(see [#2139](https://github.com/pmd/pmd/issues/2139)). + +#### XPath Rules + +See the new documentation about [Writing XPath Rules](pmd_userdocs_extending_writing_xpath_rules.html). + +*Note:* 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). + +#### New Rules + +* The Rule [`CognitiveComplexity`](https://pmd.github.io/pmd-6.22.0/pmd_rules_apex_design.html#cognitivecomplexity) (`apex-design`) finds methods and classes + that are highly complex and therefore difficult to read and more costly to maintain. In contrast + to cyclomatic complexity, this rule uses "Cognitive Complexity", which is a measure of how + difficult it is for humans to read and understand a method. + +* The Rule [`TestMethodsMustBeInTestClasses`](https://pmd.github.io/pmd-6.22.0/pmd_rules_apex_errorprone.html#testmethodsmustbeintestclasses) (`apex-errorprone`) finds test methods + that are not residing in a test class. The test methods should be moved to a proper test class. + Support for tests inside functional classes was removed in Spring-13 (API Version 27.0), making classes + that violate this rule fail compile-time. This rule is however useful when dealing with legacy code. + +### Fixed Issues + +* apex + * [#1087](https://github.com/pmd/pmd/issues/1087): \[apex] Support suppression via //NOPMD + * [#2306](https://github.com/pmd/pmd/issues/2306): \[apex] Switch statements are not parsed/supported +* apex-design + * [#2162](https://github.com/pmd/pmd/issues/2162): \[apex] Cognitive Complexity rule +* apex-errorprone + * [#639](https://github.com/pmd/pmd/issues/639): \[apex] Test methods should not be in classes other than test classes +* cs + * [#2139](https://github.com/pmd/pmd/issues/2139): \[cs] CPD doesn't understand alternate using statement syntax with C# 8.0 +* doc + * [#2274](https://github.com/pmd/pmd/issues/2274): \[doc] Java API documentation for PMD +* java + * [#2159](https://github.com/pmd/pmd/issues/2159): \[java] Prepare for JDK 14 + * [#2268](https://github.com/pmd/pmd/issues/2268): \[java] Improve TypeHelper resilience +* java-bestpractices + * [#2277](https://github.com/pmd/pmd/issues/2277): \[java] FP in UnusedImports for ambiguous static on-demand imports +* java-design + * [#911](https://github.com/pmd/pmd/issues/911): \[java] UselessOverridingMethod false positive when elevating access modifier +* java-errorprone + * [#2242](https://github.com/pmd/pmd/issues/2242): \[java] False-positive MisplacedNullCheck reported + * [#2250](https://github.com/pmd/pmd/issues/2250): \[java] InvalidLogMessageFormat flags logging calls using a slf4j-Marker + * [#2255](https://github.com/pmd/pmd/issues/2255): \[java] InvalidLogMessageFormat false-positive for a lambda argument +* java-performance + * [#2275](https://github.com/pmd/pmd/issues/2275): \[java] AppendCharacterWithChar flags literals in an expression +* plsql + * [#2325](https://github.com/pmd/pmd/issues/2325): \[plsql] NullPointerException while running parsing test for CREATE TRIGGER + * [#2327](https://github.com/pmd/pmd/pull/2327): \[plsql] Parsing of WHERE CURRENT OF + * [#2328](https://github.com/pmd/pmd/issues/2328): \[plsql] Support XMLROOT + * [#2331](https://github.com/pmd/pmd/pull/2331): \[plsql] Fix in Comment statement + * [#2332](https://github.com/pmd/pmd/pull/2332): \[plsql] Fixed Execute Immediate statement parsing + * [#2340](https://github.com/pmd/pmd/pull/2340): \[plsql] Fixed parsing / as divide or execute + +### API Changes + +#### Deprecated APIs + +##### Internal API + +Those APIs are not intended to be used by clients, and will be hidden or removed with PMD 7.0.0. +You can identify them with the `@InternalApi` annotation. You'll also get a deprecation warning. + +* JavaLanguageHandler +* JavaLanguageParser +* JavaDataFlowHandler +* Implementations of RuleViolationFactory in each + language module, eg JavaRuleViolationFactory. + See javadoc of RuleViolationFactory. +* Implementations of RuleViolation in each language module, + eg JavaRuleViolation. See javadoc of + RuleViolation. + +* RuleFactory +* RuleBuilder +* Constructors of RuleSetFactory, use factory methods from RulesetsFactoryUtils instead +* getRulesetFactory + +* AbstractApexNode +* AbstractApexNodeBase, and the related `visit` +methods on ApexParserVisitor and its implementations. + Use ApexNode instead, now considers comments too. + +##### For removal + +* pmd-core + * DFAGraphRule and its implementations + * DFAGraphMethod + * Many methods on the Node interface + and AbstractNode base class. See their javadoc for details. + * Node#isFindBoundary is deprecated for XPath queries. + * Many APIs of net.sourceforge.pmd.lang.metrics, though most of them were internal and + probably not used directly outside of PMD. Use MetricsUtil as + a replacement for the language-specific façades too. + * QualifiableNode, QualifiedName +* pmd-java + * AbstractJavaParser + * AbstractJavaHandler + * [`ASTAnyTypeDeclaration.TypeKind`](https://javadoc.io/page/net.sourceforge.pmd/pmd-java/6.21.0/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.TypeKind.html) + * ASTAnyTypeDeclaration#getKind + * JavaQualifiedName + * ASTCatchStatement#getBlock + * ASTCompilationUnit#declarationsAreInDefaultPackage + * JavaQualifiableNode + * ASTAnyTypeDeclaration#getQualifiedName + * ASTMethodOrConstructorDeclaration#getQualifiedName + * ASTLambdaExpression#getQualifiedName + * net.sourceforge.pmd.lang.java.qname and its contents + * MethodLikeNode + * Its methods will also be removed from its implementations, + ASTMethodOrConstructorDeclaration, + ASTLambdaExpression. + * ASTAnyTypeDeclaration#getImage will be removed. Please use `getSimpleName()` + instead. This affects ASTAnnotationTypeDeclaration#getImage, + ASTClassOrInterfaceDeclaration#getImage, and + ASTEnumDeclaration#getImage. + * Several methods of ASTTryStatement, replacements with other names + have been added. This includes the XPath attribute `@Finally`, replace it with a test for `child::FinallyStatement`. + * Several methods named `getGuardExpressionNode` are replaced with `getCondition`. This affects the + following nodes: WhileStatement, DoStatement, ForStatement, IfStatement, AssertStatement, ConditionalExpression. + * ASTYieldStatement will not implement TypeNode + anymore come 7.0.0. Test the type of the expression nested within it. + * JavaMetrics, JavaMetricsComputer + * ASTArguments#getArgumentCount. + Use size instead. + * ASTFormalParameters#getParameterCount. + Use size instead. +* pmd-apex + * ApexMetrics, ApexMetricsComputer + +##### In ASTs (JSP) + +As part of the changes we'd like to do to AST classes for 7.0.0, we would like to +hide some methods and constructors that rule writers should not have access to. +The following usages are now deprecated **in the JSP AST** (with other languages to come): + +* Manual instantiation of nodes. **Constructors of node classes are deprecated** and + marked InternalApi. Nodes should only be obtained from the parser, + which for rules, means that they never need to instantiate node themselves. + Those constructors will be made package private with 7.0.0. +* **Subclassing of abstract node classes, or usage of their type**. The base classes are internal API + and will be hidden in version 7.0.0. You should not couple your code to them. + * In the meantime you should use interfaces like JspNode or + Node, or the other published interfaces in this package, + to refer to nodes generically. + * Concrete node classes will **be made final** with 7.0.0. +* Setters found in any node class or interface. **Rules should consider the AST immutable**. + We will make those setters package private with 7.0.0. +* The class JspParser is deprecated and should not be used directly. + Use LanguageVersionHandler#getParser instead. + +Please look at net.sourceforge.pmd.lang.jsp.ast to find out the full list of deprecations. + +##### In ASTs (Velocity) + +As part of the changes we'd like to do to AST classes for 7.0.0, we would like to +hide some methods and constructors that rule writers should not have access to. +The following usages are now deprecated **in the VM AST** (with other languages to come): + +* Manual instantiation of nodes. **Constructors of node classes are deprecated** and + marked InternalApi. Nodes should only be obtained from the parser, + which for rules, means that they never need to instantiate node themselves. + Those constructors will be made package private with 7.0.0. +* **Subclassing of abstract node classes, or usage of their type**. The base classes are internal API + and will be hidden in version 7.0.0. You should not couple your code to them. + * In the meantime you should use interfaces like VmNode or + Node, or the other published interfaces in this package, + to refer to nodes generically. + * Concrete node classes will **be made final** with 7.0.0. +* Setters found in any node class or interface. **Rules should consider the AST immutable**. + We will make those setters package private with 7.0.0. +* The package net.sourceforge.pmd.lang.vm.directive as well as the classes + DirectiveMapper and LogUtil are deprecated + for removal. They were only used internally during parsing. +* The class VmParser is deprecated and should not be used directly. + Use LanguageVersionHandler#getParser instead. + +Please look at net.sourceforge.pmd.lang.vm.ast to find out the full list of deprecations. + +#### PLSQL AST + +The production and node `ASTCursorBody` was unnecessary, not used and has been removed. Cursors have been already +parsed as `ASTCursorSpecification`. + +### External Contributions + +* [#2251](https://github.com/pmd/pmd/pull/2251): \[java] FP for InvalidLogMessageFormat when using slf4j-Markers - [Kris Scheibe](https://github.com/kris-scheibe) +* [#2253](https://github.com/pmd/pmd/pull/2253): \[modelica] Remove duplicated dependencies - [Piotrek Żygieło](https://github.com/pzygielo) +* [#2256](https://github.com/pmd/pmd/pull/2256): \[doc] Corrected XML attributes in release notes - [Maikel Steneker](https://github.com/maikelsteneker) +* [#2276](https://github.com/pmd/pmd/pull/2276): \[java] AppendCharacterWithCharRule ignore literals in expressions - [Kris Scheibe](https://github.com/kris-scheibe) +* [#2278](https://github.com/pmd/pmd/pull/2278): \[java] fix UnusedImports rule for ambiguous static on-demand imports - [Kris Scheibe](https://github.com/kris-scheibe) +* [#2279](https://github.com/pmd/pmd/pull/2279): \[apex] Add support for suppressing violations using the // NOPMD comment - [Gwilym Kuiper](https://github.com/gwilymatgearset) +* [#2280](https://github.com/pmd/pmd/pull/2280): \[cs] CPD: Replace C# tokenizer by an Antlr-based one - [Maikel Steneker](https://github.com/maikelsteneker) +* [#2297](https://github.com/pmd/pmd/pull/2297): \[apex] Cognitive complexity metrics - [Gwilym Kuiper](https://github.com/gwilymatgearset) +* [#2317](https://github.com/pmd/pmd/pull/2317): \[apex] New Rule - Test Methods Must Be In Test Classes - [Brian Nørremark](https://github.com/noerremark) +* [#2321](https://github.com/pmd/pmd/pull/2321): \[apex] Support switch statements correctly in Cognitive Complexity - [Gwilym Kuiper](https://github.com/gwilymatgearset) +* [#2326](https://github.com/pmd/pmd/pull/2326): \[plsql] Added XML functions to parser: extract(xml), xml_root and fixed xml_forest - [Piotr Szymanski](https://github.com/szyman23) +* [#2327](https://github.com/pmd/pmd/pull/2327): \[plsql] Parsing of WHERE CURRENT OF added - [Piotr Szymanski](https://github.com/szyman23) +* [#2331](https://github.com/pmd/pmd/pull/2331): \[plsql] Fix in Comment statement - [Piotr Szymanski](https://github.com/szyman23) +* [#2332](https://github.com/pmd/pmd/pull/2332): \[plsql] Fixed Execute Immediate statement parsing - [Piotr Szymanski](https://github.com/szyman23) +* [#2338](https://github.com/pmd/pmd/pull/2338): \[cs] CPD: fixes in filtering of using directives - [Maikel Steneker](https://github.com/maikelsteneker) +* [#2339](https://github.com/pmd/pmd/pull/2339): \[cs] CPD: Fixed CPD --ignore-usings option - [Maikel Steneker](https://github.com/maikelsteneker) +* [#2340](https://github.com/pmd/pmd/pull/2340): \[plsql] fix for parsing / as divide or execute - [Piotr Szymanski](https://github.com/szyman23) +* [#2342](https://github.com/pmd/pmd/pull/2342): \[xml] Update property used in example - [Piotrek Żygieło](https://github.com/pzygielo) +* [#2344](https://github.com/pmd/pmd/pull/2344): \[doc] Update ruleset examples for ant - [Piotrek Żygieło](https://github.com/pzygielo) +* [#2343](https://github.com/pmd/pmd/pull/2343): \[ci] Disable checking for snapshots in jcenter - [Piotrek Żygieło](https://github.com/pzygielo) + ## 24-January-2020 - 6.21.0 The PMD team is pleased to announce PMD 6.21.0.
rulesetfiles - A comma delimited list of ruleset files ('rulesets/java/basic.xml,rulesets/java/design.xml'). + A comma delimited list of ruleset files ('rulesets/java/quickstart.xml,config/my-ruleset.xml'). If you write your own ruleset files, you can put them on the classpath and plug them in here. Yes, unless the ruleset nested element is used

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 R{r%y;B;Lu2mcG^Z`#(ZPcKiSU diff --git a/docs/images/userdocs/designer-overview-with-nums.png b/docs/images/userdocs/designer-overview-with-nums.png new file mode 100644 index 0000000000000000000000000000000000000000..a6e2eb386fdc23c964a46ebf40f376e2f74353b6 GIT binary patch literal 254594 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≷gRU7)<4!r9y*50kUgUP34fJZ+(KL-} ziwqQO2*3APwJ9sniOXpT{KwOaqTb*@UeuTL2KNE3J%P9?iqp~R`F_0EJW z^56n?hF(kl{IRjJp*dCEltWIKmnSs1h`KBY0Ej60vPn3okrb7=KO>y%v0Wg0J1H!G zC#Mi6FbfJ&%0aq523gpa$jo%M)GPS?xJix_jNJNM|%AE9>#bgO0fqhuK-{^>1V@ z1gIlj1tMZKnnGa4TO`V+*(!g)KT(Q zhFuFvo9%Qr;Y>0n5gE)3*MC}L#P5dBoK4XIc7;#oGu_`2%N|`w5Zw3pkU@WMKPxbE zobd#mT`f}{6rwiP$z(NF`>Axk@hu%Ycw_{vS$Zh)or^QHtkL^{$wxjg0|P^$8_dtJ zUn!)Iwal&z136XEfNn6f4qaEU84L{YLMY_Rz@4*4=&?CH7KemE8t%vG+ZW zDQC5*=)THVw2%4&O(V&77l;@AFCoSmYc16~{ah579`|15h=!&3T%nfM=K$Z&Pue`xX_cueP&gNk zMk102zL!w;98sp@v83algi>ruHp`e7Z7V`q{6NfB?44$2%K6a9e+hf8wsBeP1{lIS>OVC>ebqMnuO!g zSlOn+^6~cE?W{wWM4$aWsYE>Cg(KKwxyJlk$nhI{e)l}>!9tI;L8kdP_|7=cZ8=+& z$rJ69v@+PAMHT`PFz4Gn;578o%N^@4`0l9$CG_nRwC7fQr3;lr?UKip&0p}{Jv2A1 zGX^O86Tg1}YkF&_U*g4{-D{Ijq_bK)g#;lREtbzKylp%yW4pLLkhwzWH~mU5Cb zGhl0|7TouG9|Edw#L)TCfDPGexfo7z--Uxy=Yb)6lyD?F7D;^7m)SeD@w$p^H+bN8 z80+e1lzbJ8s38EJM-AZ4#vn^g7;}eCbsNEaXzEP1N<@Ty=@ssFSumhZFNN0%CqB)7kp`An11a^;vm!F+A`XZe$ zb?I}wM791@bz9Y1pP=bccGX9o8=uBpm`^t|AP(-&6?H(7-~?3jd6+lGfY)Bs{}Jz7$De!7Gr16AjJ6A899+kZ+5oITmAzMg+>1mU=f&dih~t66V{ zQp>dF8IaINar+bax&^4M6m4E!FR&O|dB(Yvl5q#mh~e*)YX!bApI}MKi6X`3G$$Hy zsWEYUJepD-W}RK`+=Dc8JXn%iIuRzMK(>+UkIo|7h3n^M`deR`qb#-_p4$NL?{yGg zNXc7$Ep{VCwhsxGx!He2sbYJ$ltXv8cMxx@d072YS5Xi87-jKfJ%bbY(S2C4k*+z- zb463+aYn4WyDp(z--mi_d6%R$um?q_Cr6I7VQT@gVS8Jdy5*9F;IZCjG1V9xD^UOK zF5GP+;^e%x9DRHwAg}##BNOyG-RZ3a&1#W}osR@O{@6#(M zh+?-o=XtAN^|~Cq*eDgXwIB3uk?Xx~9VR9wKF$>5jHGe8=8=1ol9QAF-{3eaIVrH4 zRbAVMsD-y@cbR@sDy~`~)Ouc0N&}zTJ#aJc@JM=#>x=I*yGSp{u1{I*JE=7aGKH=} zPoq+yBqb$da70Z0jWl>V{xkH2^UGg+A@U_ARc45z$=A2o1BP()`BRcjy4YeBLAK=r z0iG;TO7XUJ|Cx0x*{;@aK|*$zXt&GD$8Q8#;7@5cNnP^brvX;uF>SzK!Q>|Lh7Bqo z*YI;9uy>QL;}>Z8iJE#le&3JakN@xE(f=FNR9*J%U^+Y?;6+?~yp-$(kP-a9zn(c` zjxgmp-r|$jtCWtTcyTN4!2udolF95tQn7#iLs0gVN452e3Wc91UTpdlzpSrNgYDej z)TcV-W`$YNBIzk5e??n{t2u}>!{f_VjXja{?vR?@U5%~ssT|zf#db?01yCU;=j%mu zk;s3=#-G1cQPrdkQmr<;uTDrR<4U(&EuG6gewX9*x=f)hT+8MLe}i&mXwtS!{~Xl& zcJ<-4f{w31e!3GMG^0BLSUqRw*FQZ>a_!!H);^n}6m7kI;axG~MlbXH@W!?j8C~}r zR-vU4uuw0U5qIHzFQ51wy!f~$|32gDKC88jd`gGDw#?=2N4E>meJm1ck>Lty-T8V< z7k8-)Y{#)TfZ0O8!;jk5*uJyleMZ_D8Rf$!cGv_I85V)i>JfK9tNH9HRZVV@MjLsf zg!o&HYd$PwV2?Ya{MxtT_9Kq<+wdUP{bsBb2Ng`nPeLq#a2L6r@*hz~3;=s5N1%!G z$K-=~C?p<&yL2v3XJk?0C&Eo-Zz< zuLIWgV=MlydCDr^o4F4q6>kMR3=wRN)7v}7LCI&E@DH2GBok0i0n!uK1N706c}_62(zP+#ilXn&FP@pKBLff5n%!R1(?>HC8a-Mp-;t3KiCycA0DqZ z6^n`U4($4-DWkwE%D32n`^PY)$vNguF61=T3MXgs&j+uDgS+pwkryi15l zM!uK`>%*W|dqd8o44`LzFCqninyB{&YFex>aY|F4n-u}Y!w?_HX*E<*h2IDB3EN8| zS(nrpUMi_tTM;FsNQBqY_andv+`DW1cG~mt-)z;G-YHW_d6NFNz!oTB`UN(jM*HjI z27FV;){+P%??6W(woh0aK{}%c#iP|@;5HkN(UOEbu}ys!q?|9;{wpZ;lbbg)t8H@v z?h3+0izg<=IaVCk2?a&;uELW|e*62GHn-otdhS^EVK5Uu>pc?jx$UtM5QbLpCP2Q; zBZODNnT#BwqVT%mIu5bHS4YC5t}s8~=%R4Wop;?M%xtAUm$O-{+|#v^X1j{Xo`_S9 zK;-%1N3EvWgqb9TuV-Bbo$6T!W%|vuh$~CuGz&q4GtbaIZ3C!K#*Kve3j=6**w!a* zu&oz)<7{5T$p$EAJbmw#AdnF18l9uH@IuTay+i#JO@R7>88}}2m_E1 zv>apc-9L}6^}63)>;c5;4~!B)x})*R@@o& z&%=xbHNk>Gan)G=n9$xI42k=+SyClN8~ju9SBDB>D|0Y{d$~3FaOC4wOWMtbvGyxd?1u&{yPHs z;pobICOSJ$ zL#Gc9z^)YMl@{Jwv8Y6^yuwB?6ebsG7&Cd#&sDs+o!joR+~<6y9yy$ozAN^YX^c3t zJFC~mkHLhK-)+e5O}u=19AlaZTKX3+AQj4FOm;9_Pw(gSeJ}{dru43fAhhjgk3*54 zFxF0$Z=IvxyiI%{L>WEo!XJysw~dEDrPNkd5Qak49mrN&87?GNcE61n&4Dpgd9Z}a zE^SR0F^d3|>r6`n(2slqH_+nY?Gei!s3evA1QWr^YR`>cgon>$5Z;oIk+LnVy5p^wWL8LZaEFn$5IYDSs&iY^(dtl7xcAt zwff`Hc_24uz1A^4Tx5H@aO_YJiTMur3@I6*UA_<(F3JLL^Ne zlp|6rErc7~b9@@{XeCY0>7YKCOm(+XMRzdIXt*q1 zFGIKDPEMnoKJN?8w;RtfQQ5jS-7G6z%Yw8HQ7bc1u1{7wYKk9gtpUdvtcq!+?$Q2H zKz)G=Nb8mH1lwl=whn`}cubPX(`E7-kB?;=xAqb-7~l}V+(Y-9M6XFWn6&RKoS{*q zz0BtNtbVH>K6l8baxQlQE^E5yF`*=AG+GSq(H4m0G`HiX>|bn9Am_|8z+yfv1cUR2 z%s@5OYwTq#hmVg9N4NHP70yr^HMj722W+1|Lv*(}LE6MbY-_MJD+|jZO`w6J2E{a_ ziQX?$^jJR^k%qpx;szwvwR9E@jpZuOrmsJ`!8ihagYTdja<$@@kw1#O!DC6)BVR4a$T9h zX#1-`_2(z~u)nY@nh;UE?(?}!W2+};G{Z81Gwe$W$_Yi);ocyw?yiJ~OCJK=w@=$+ z@HLysnL6rj*Zj>jc|Ka|Z_Q)|pth5Oo;@!EH66O`N8F!3=WEn+zY3ssx1X z`KDoj*@N1nfQ?$0~vINZs~q9 z82aEYHZn6k7>j_(=gvRd4CqQpB9K|Lp*S6vLri%dm=S;ql`~&1fS!kczs~%!hA${n z2h-u2-?qZE?}gIO;Kf>5*@w95Yr9_-fGgU+jDl9t@)LCioJWaKH#=mA_h{z!59COm zS0rF+PUZ#E;816RLF#2?HxRBMx#+$DdUE|P=Yxx)ppDhI-{zik0!*XB%x2SE8_|Vc zAw%e^Y@accaG!ycK0dics1R4a(0HD_@{jlZnkYt{-Et4xb^bf9Mu?hZYE`9lLbFvA zjx-)vZJ&v^(x{#-xQQlZz{+xEI@m)EoWtZuOn9FZCt+Z-K(JWLt@~$Im#e+3 z6<_BzIGiEdpT{KVJzLYgU!blgjj_AAxfOF-0*7fd)QdK_r_@h7On!(fuiu>M=e%F| zlFeHF-Q;&p9!BmJ#eusCX%cGgH=8C0T=}2O6$h=_`Hf}R zxT=pU6#Gpj;rnWyA` zBXTjOBei(!277H?s{m#kp!ZIpW%La0aD9&Q@$7p6j@0O#r$0pf8MJtW_}j`2GQwHm z1PUGUnaUH4UAFYH99}7#r&SkmK*k}We6_vC6ZTXlClnm%=9T6?+Z5OgbctYR6_oWN z^i+cy2*mqd$IDGDmxM|f&H>cI~9tS;Pk+6lDTn=6A$zvZx#?~j8b);bT zB;>Y+mGe*X11V3_GNk@C3tJ5EhZ1dxrb=Aaa=GQ+uLE~^6Y(T0!9*T8vFR)A zjV43j=!P0ck{bHZaGumh3CdGD_O0od`1p#NxQ8z8<3VO8xhJp4zpTdicURA5$E{sO z-_8W1+CW!v4wJj&@1S0wioT!qLq^4T_u9UrQQbF8UF}_Q0*t8G>vsnvSt0r&8cn79 zG+BO7(v+Xc0%Br3;+McZ8b7~~gMLTsr90Mj{&9PBn0xg+J%!aVPjsHi<+;QSOY9vM zGXdOMp|gkfma+Am@MrGOgak4`9)DnADd;NFYQa2LC+X^of;61Wz zd#p|$gjyRS{;^uFs2BuqL`uZo=$?8XN0vN4ovHpCe zNsavRauX-1M3mK3<-y3rM>ATA{C2n}ZA=}(2=YFp_PYTV8bc#D@27BMM!cTy(F~yU zdGF9+?e5F2#P9ojSbEQRBop_DMgAb>!`QY8t4{Rda&g7_JuE;M=%karC4{9j!RsCZ zYq=Fk!NSuJYWLx$D2+IJc)d1$gK2}(ar_cV%K-_x7+79Rl6bv6W;}m`m^^-}q1&`Z zMbqaBX7xIiF1;}z(;IpFU8tnf&DTAM_GoE%tBkMXI|qj!HzCW_u`+YCd*p!kh%sGb zhQYB*e%T=|2Uptbl^cGIbQ`15t}ZEOoSULO_hATHAYBm=M;`4tC@Py|!xI}Sg5zaEfqKYA%(>qxBVeL<}Bz}E$_gk$FJ<){=r9hiwtJCzd7B&5%A)2 zcX#)c3l9%Bdbl}F9*J}#U^^h)FY2K?ui1{9k^hQ%Qeopx!q|GtuuOtPbaQ{}wXeQx z19{$;_v588)AJx={l>Nq-^l~ik%dXF*Wn~m+n#xAqZ0>+EZHt^x!)2f@TpI=p*dZT zuRWx|5yx$b-l_6fchdn)&nw=wNesfkBbp2SxIXZ~p=bHR4(Er?(0b1;fbS}Yzvt!V zQxX;dGHP3XA;&_7Cp%WY80xa;8)XLkfg0Bq(S_pH;zn1fwku#Str-Ql5ZT%0CaN1t zcdO&*wPIsxei`1tqb;C&iFVS5I%so|bm^;Jgq z>Fc+Un6G0+(xiz0X$5rKvH9G#TZp*4_C7K`p3G@AuW)jhQi)y>;;}qu$`t1uKtgY%V`WzRvepZuc}i?*O^S{ zLD_Y>W-CMIZnkm|q#!enHy=>EHJfxhzcRf3P-e*yvcnN^j!$^HfFc$EuUviRyn=GM z5oeTjHEdK_A1Y%7t{ZE5CSSK#(NX2lc4}~7$tKZTZQ{~;8e#J&ubff2G;k`N81%eN_Ofx-DKoz6|-KLeZt1gO;7obvhpMc)6m^u zxSxqXz~Q>1AC0EclLCmYPrE<1xB3HPsH_TLTrS?vP;z;{X2 z`rXaXmFG7b8mD_nq9{I545fpVmXNZ{{9MlyLzcI&b{JZ;cSy2Ed(cC>%tu~II-V#N zT1Ii-p1jIZLUKMvWThv-5@%K_cF$6&lyil9`NGNo-Th41`)rynvf`K9mmHXs^VCib zmQt43yh+92Td;lhxoq}kgA)DonOfF0wnv*ocX7idch~`1eaoV49G+MLDycFR>``uJ zmmVXrBd6G6n~6a#oDiduyq*?DwT2X;OgYxVU;*L%r+_Hv>yIVXs4(owc(zIY%wNks zKutaO907I5dTX~5?c{xePq4Gm0r9X)PM6$J`Wc75nrok>k^d1v#+Pa{o^ZioVEM4( zaHx6Go~kUcy{RRiwLaH*%xQJB3|krK3?^1zKRF-E{b;<;|9)7Ha}h4L9w2kP79i7yMy1~8iC((# zM7_*qBQBU_SxTD4O|Uv^oD|glf%_#Ml_VwSn=bfRQ*to71>V&K!pC0>2(M#34tx$B zv)k_P%~*%$=mi{D&rSk~55~5`LEDubt0%>I_2>-;n{*k?`|oG2>JwN~pSM#o^M3S_LRLQknJezo^u^M*LNE$G9dG(2PwdFl+latJfbE*36@ z?+8upmmmme87E7gyl#DjpxZ-{rWsXluBK@kT{ml(Kw_f$cw61nq25;@J0({BpG5Y- zg7_oc%O?kJ5TliZZ)+GABdHLwIx$G_Jcs|SzLE<=ONy{ulXea zk`J~7I0&1Jn|D=MM~{6QgxmKieP@r#&zoW(x#1QXDvI`*!Ur3P2_%VBpzM{CRCTI#@n8Pd7EuyJs3*8D4e$fa?tIW$Ph%I3JA zZ--Tf93&kaSh*a`eV*OV9W&2=v}vrXR(baqfn%)TNU2U!|KMQf{^hzI7X%f!*y6A> zdv}^ywv2%pAui;>MA*dL7?ijXVk-_Ps!*T_rhYi)*Jff)?891l$2t3%CK4E-#$a^A z`P_HUDj$HqNX^kRPS+9G5W7`KH776sy549bG_qXPH=0xBoq-Jl42Ee|eCk@kY00Ld z7;!@bj7oC0l*M+3%~Tx%Ac@*?dQ8N+WfxqC z)w21X>wP38Bh|e>C0kzmW<<70TJN)fN^=TO?Xf$~TyNqkYN1eP1?aNf^H}BNG z_9Jt7Tm@^48uauji?ZW8RfRB$f)7rlY6e}C&Bz3~Q6V90%zxhg+)%fUt=l7FMfR^U z1~(D4@PCB&Pyk94ehi;+(Roy=f?=OR?w_!aG^VBNC4t9{KK-(+Fi^{_JbE3>opENy zO8w#&gT}w!<@{lP)5ZL2v8KL6{)0j6C(8`m>p#cx^QJW?Vf%xN?^C_2F8r1jEI_^1ViQXc(DZLw$62ENMa}Vj+^Ud3~XMaoVn8 zZ)=v~^j0@3`Y=zdJ#dccz4uXzo4_2hnHvf?5ViAG;AQ*kAz3o0{=7}f*ILEcB`@24 zQo8wwgO0Nbt_bDlNT{vR)nzZ|+#d}!uTV$HO)d6~mmpY`S~Z}I(|6OjeL|v$Iv!X) zCouZB_}DCuH@yBB8eO@4k?*#xclc_)5zN?zM|1Jw4?1SZa+4uUfrpbW58uf$Jwb4O znA*@AM0npOzwtWf-d8FSZm~nbqno+xAbUL&+!a4zs8Z~u)8W?(rEE5AQ{Ge$dreGxWSYk&w-o9JXk7+lheUez&y$HL-3g~Ve% zBamWxv`6XezXF8-&0x4BP;0v+dY;XrTv?Q?XpHoJW-l<{vFCs$Xl^cKFqP~fl2&|G z95fhqvc4sfay#*Mw5bfPc9qUCzXo4tLBgPvW@vk4K4CsyQr;$N5h;L{YH+@jk^5Dg z@_I#32QJ%djqD=>-`7oH#3U3J3d@~OhAtQ|_C0QPJ0c-qcFlnCKbBBGko{o#%vpDa)+cV!oNFvqxG|#zQeUI_07`X($gg(Oj9kHEYk^uGuT27| zZ?7O38ohBcrmnhQOx&KTaf%S6^jK5&8T2Y_XYJ$EZeqi#3mRyM(H)Nf2P#jon6fvj znq9iy&q1D4?Do($tOv(>v0DmRV-T05N3H{)05=0SBP>RZE2B&H%l&S?XxWrrQQY*% z3LP{v>aZ;Cz1Dzr?H+(<{>gE(aA)*V$M&4DuD3nke0b6R(dknstJ>1Q_K@CMXr^^J zjN^^n!D@;HL6;@^{kozBm=6B6_#gKY3EZc7D^suufkY?(Xl`z9$pcp*GW$HZ4R4Ek zA#(oz!=zZC@nhVl#bi7mzl)n;57TIog+8(M`P`J3t$r`WaWRDukS`=L&A0!Mgj(UD1K*<;GpULVdTdcA+}_(LT(`sE=Z&5CY%1Mbp5x%V z(;epb)9eH3eUbhGy#!a4MrO>Xl+mUOC&q;|XK5yP^H=j|9Ci4joXQ+&9I6bYm1eFH z5^ctoJyN2$$YRUw(_7LM(VC+n`wUytLNAg8IKx)PJ+7<3G9~3tG3@|x_)o#_bJj;@L3z(6`%mnxzS{x@q+BqqI9}#| zIGsK#3#jmO2O)_xTZy;A`Ns;x{`QhNplskVbPk1u9-D7f@Fc1?gia>?eXM0 zATY8(EwLZR&P6*Vrelj(1F^;$NrZR{rL(vcQh-&dDqnD%h46FyiUqV zilT?z`DE4VX2XE{fIMaq#v3~%Ke|59L||eaEyJCCOXxn@FFjNh^xb@f&eS(UN^DD{ zJ7B0%qlE^}*9h}9gVEuTQF4YLAo#c?)?PU%j@25etdz0Lg96OSz1g4jhboQrCt_eI z{e1lN6i7$Ub-x|{Qob#jb*w4oe5~bjE^BlH z8D4h0DG(I_t8Ir(W)>EfSA(zZCiCR#wHd(efz83ZCM5JE_vHNi>G-@ZKQ29X9T&{o z(vIlqKg9fthfbl&a+aa8vhu{Eg$wUXHW|3lQ1P-eTMJLn?lighJG9s?>2Gw=2TKlk zrz0Vb>{n7-Oo7iW!H5*SXE&X^JKH=$f$(aI<@~`UOWnPFXa>`2USIiqTSj~)EqLbOkT%m;3%bsgEJU~FE(8#iD$IRMH~iS^k5=<;6KdhIqwhf#ZSI>h57$P5W_jBzmEB@cQ)kz zZ(!74Ytpx(zrP>)%=6!|+(S=XT->YvWA=Z;Z)aFCQc@i@b)0*3E=}nP2??6{=Kluh zHW?Ga&NF zw_X8qjFt0XM5Ml?m=)H zM2R#isa-SpCIJ?}{xU>UaB??9AIz%hHZC;RW3jQeI7}PgsVjq?Ri4NYxM?Qu=TYeU z?@Ntl;?ll4?ZXQENL&p4i>#~q?Ym~N2P_G&U`V{lh4%_v-Y+qfNIze1Ps+{B{RRsQ z9S28BNePXbn%Y_5wkb`_;LWeWzBZSZ6?G8+%EYJFM>0KS>AblYQF*gf;b;aCPYxB` z_n!MB9v!*axoPFl0U0^vjGM=D#?fz<0OG0npFUX9Ap!XO7v<&J55|ng zFT2zoh9Qc9blD^vL9?JX*@3!i$MM6Vlbl*gikQ*pwnm(@emWao?x;sXSdMZodXd!>q(OIR+hG$JoJ0`bV9y!`)-|zz-u(^%r?&SIe9Uosj${F1z&$|s6X$u&6ntOqa>@q|H0T-hPAbA?Y5;zixqcw zx8hJ*oZ?d4wYa;a1&S7TZ-GK_cPkQtQ=DMI9fCuEz)kl#=bpXq_x-r*M|jq=!pxj& z${2IZ@xE{Oq)o1=-l(^r_nr*X-SJZs^n_EV(!7StB-kv4p+LtcO-_-Ju~AxAV$Sj# zW^Cr7KMT^!zfZ{5u3=BtTrMB83iNSp4t_CUE7_QubC^Ic=W1U87^%kY5-PDfdyxWJ zO&E?;xy-spJYOOf$^jZ_s`vj5hYBkp@&K7xSxZl=Hm@ak+ak_G2aU77G}*nHUpQkA z^U&`t2j?Z}sb7LzNWf(}2^&=wR$(MX!rPnSR69wo5F0ds-D;KTVEq^dc^yeXBtWe;cDlHk8|&S?Re2;zc-l$0-X2f#I# zCu+vVV+%%dQ)L$E#zyA&^f(|9G z#i#D+*{<~t1p^2{GxE}lQ$xs(3O1pIHi=f97RKUV2~+uF0g{2W0(=5@62 zgZeMSHIP?SUtd3FD~gWUX;R?+uk{Lce#HLz>b?oFLEo%SO-cFBcWG$EQ77FokP#6~ z#Py(oFnI~RnR5ppUj57ZbET2iX}tSubR|dy|MlP7E<*Uv|5^kmeE$+_i;yQk)N{a$ zLqsI=Ew#(dp$A85Z)tl}!Ovv^RduI`1?gnf{Pa>~d{v-kGE;3=`x|u5EVm7{S{|k- z-5nJN>#ks$$>g}vzuF=B{S^Xa*vpLthdLmKyh8}A)aY0Eh*9#d1hH~*GQL7%j8}8$Tzl{RcGq+g2(na2U^;@J7t%)u|;$ycRmgy^PHR(*| zBt#@49N}e0^qQX#{c;dMQd3ud$BeJBam181EJOWDjXds`*YzFT&KprpGCMq+tt4|+ zJG?)2b|c;j1LM>7e~1MZE(zgp;)%QC0dsg{~vqU4}?}*a9@LS}gSb+xC zz1CM2#D19d@|uNAh-lKoNKWNo=%6Jn{>!!NJA!!lri;)CEFh|2!3ZDGe?OHG{TEg8 z6VZR_xdSxpJ&qu2baQ@G*TodF@Zft5CeF6J+E1FQPorO({qdM!=qgbcq`MOR+!)y^ z#l~Deyomni3ys*3EnEznvti&V)p{!YJhTTzRMAlAkP$JE{#{CvFgaFmH#MTUp}l^< zp$9jSoX}n~p!yMKR57#QG$ZX06HsfK5pkos`HFC>(L#WlrYBmVitG*jA+sAEm3r75 zlpcSUJ3(I4QXNfNdjA!t%|@^SdqhV9;7Yj%BXqd2_OMs=#%V((AeLSvXFiV4pWaOH zliE|rh)?>5;y5$QYqb4aks32%U3Nl@-fswzpW-Rl9o3ij^Y^2mfYV+^uUkiHruyxl z#~`gZ#^%NGcpnVUOZ zuPgjxkvCBxr@(VKICg!(Yiqt>5m#?VxrfG0f?_;yc+7gp2!!V;A5bc;B-0PjJsb79 z8pA-+Iorz)L=-f`g0&SibaR*LdX?NJ^gxY#6ETXJMBr^`&`Rn5+L3M)@Ui8`LE6bh zb`#9iK-hh!>mvMM#WZWWe5$d^=P^rCKkq6FzT$kvwkAQ7w!bn?wHomI;c~7a)mP#m%Fe^fe|*FzTLfY{|(Bk)A3p<=oK~St zU1R-cvM4mwA%M7!C_tc2&pYg_1^BPVJ5>Am)EwojW5A-fn#X*g-GGW@nz2WeaB~{g zm6hla_@1H);*Cky-!Uv;BF>X(FTRPjwO_<$avid(W z^7CA$F7C%kC8MehlB4t$&Vn6Z-ZfkI39VFA(PDbhy4`G^g3BeWUr*)woqd|=cn|;w zHvA0DGtTTU7gjy#TiiSR5bY8%xukS9B=zCZ;JuSIM zb)QwE1CNG2n1(CxI8ql`8Tdf=S^|=YZjgMdf-I62ou7AXT5qcp+AUpl#8NcmR#D9B zzW(uMGj9fa3if4;Yaf@y3`A8MPrOxO1yNU7xmK-l*b;gF{)`!1^Od0LF+|5WFe~`2 zk>cxWY0vK;qKTElM^>F9YGe3(EXH0pCIj&xt#lKOxV2q5gHcBWG2$8DZi+!SCbK-* zey}M+pLZr`jyB7Q#RHB2wjGmmd}0AweJVxC&`a#)-9&>;+DVcgs%iINTIGaB2b=_b z*nsXW3W>OLk(`H>&QRVZRjQNxS}T#Wr70hu%gda5`)0F2@6Agx`9$!qnN!1CAE?FY z!a2$EjGi}S!Kt{pIo*_7o}0MOp|W#^U+YA?iUX7PX5#eT#0HexWkQODCqRA3_5E9) z>VVEj<$b_2M)c!d=0ip_Uw3e7hNAi}1@py5`c_uxd5JS6+S;fxlQ=?gNYY?|q2+3c z0-u$wkbAXn<1DF8IOmx??x5p(HOVXHG4u0TT8GgjTRe-!wqBC6#H?Hum6n{)#v^&R zj8f5_FJGQ#Q!aH=IILvL2{m#IjxME>vfCUnr5abIsWD%)32F1qy@NX{oN^Db4}^;^_!9l zO${~4`6C*)>zt;wCk)8IP{Rpna0#pZYZZu>fDOL6!bjD`=b&7s*{f+_SIFodOn0$x zk}=<|R50!0f_&)cMZIHM=&+Xi%oj^1u${S@eGlmuTN_aj8$Y53mt={0m-$*(g-pu{nPd#1@zYunOno3N4K zrl#4#c7-+aXQ{|^3SUt~>;=^%VR)UaQ6RFzVxmIL+V>B4gwh|FWIGn~+$_AE$cKS* zT3cbxXjKpoOfGg^ImlwGd6`vS?gHa8O{2wtc{x`nlmj=4dRwAs0%r8gh@a}$LvUl_ zCZ@!FBlQ=^KpI29$4Auf!BoEfzG709s@ofaD>l6+>K?8Fov2#goF8`loMc6Wjrr6^ z7k-P(cG^%iRDlXId4#!J0=Taq8>k=$qhET19wBOPX55u9QsX;VLY}#kA1yGLva%HR zP%0-cQ?GIq(v!cdU)1=}^@>2|iGu9LeZmme4#eGe2hPd?*q*L}P?zfYgZn_AR8^^Zmai_HfMZypVR$n&C#fnf5S z-9CMSI$q}|S&K5&rg$)8wgd%7wyNdl(JV_fDQ=2<>v-lRE!!?KoXEZ{$>HSEjP(pX zPL(*}l0(5N*b=q%_$uEG`1hupv^DbWny#W@v;i+iPI%urfnu*`AGhMc71 z=Pj6P1ejhi>T175cFG>x4?s^LQloTR_YmGEryt|+nh>dsa1=FacD(g!ia=}_q+=sa zAxfS14n($sMTf$|yuuq1ymu$JlAl`6dZGkBjpAtrc6ZN4bzQ!6f0WB=ZnP)8G;(gx zuSg%YZa3yiNZ{uT550dL{B&p-DfD}5k~J~$TVTv_LOHVWGk~Bt$nZtgXrb5F{EtT>BY_~E zy<5BpKGXr@Gu29Xp=e;vFpPot9r(5(^mb(&4uTI{*yvce5}h9Sp%NkBI`(aHrmy;& zjw~p zO`{b-lKa>S`qf3Yt(=ZDd{c==;OYLAu&*>+%3Jm6YF0~cj{7rat8Qv~q&$ibGTt~K zJ+@!r`C&z@E~XGj*Tk6ACbf9=ONZ4rl`UhNw?P9bjr&`D1<%#`fnvgD)D;fz+$8e) zFjX^%`Ta2hM;7(Y#_eI%ic}5|=l%q=JqbsqtybG5fZ5A2Q!Ar4$6k!HRY8S4c*?~G z#cqoegpGmsLf0yfr0#Zd`BAgAV@qkSNtHXHLVOS9*y%#IuG%2a0;%M@oGiYGmNk;1 zTpXEMR6G*+joo^yC-qQQ(kKbf(#eSB*vaPE+PwXZ+wQQ^(MC5~TJ2TL>DNFfy2#~4 z+=UCiwn?W|6AP4t_19>YTqS~_eUY`rIiCewOp8a0m9fgaiZF#MVd6gQP;)c{nUs5)>p6p8^=9jS!kR0>upKM!h( z8O;&TprV4Kjx$K~OzALMl(i->!5b!)?x!HWHv1Wv3@BCy+pgzQB!>5!&rup{aYo?T z3W8!^Y^NRiFL{z$HuDVc%!qF1J8j&p%&Wz>M2eOHW-&Jar6#_LfJ+PH++CHCptITA zCQJY!l@j^rM%l*hEX~Wuu~EyurC)qWLc^Kf4KH`^>Z@=BPV`c*;Lt3Zy>yQ16l+rY4Ra+&%1B6M}Rt2z}YOP zr_(t|G-xY@MfD6;N!wFLN#8q_s;9anGj=!Q8OLe>YR{sg-B@SJ;I1ZUH08`wZT(!V zRFE!SG!8|jAzfyqIZN#Ts*a9rg>~lq^w|hnfo-vhP~lBPFd_9^?%-W09)WTsG0hNx`%41DQZdK(QWb}4%g|fUV=lA75>J1(8*ba5$hsH z`Y`C)u-8V)*nHoXC-lk}^27|%D0|`P$4k9#psme_4IZ51wOD_(P#5{7ZiTj2r*9aq z|1=gjrcQTkrFB*-a^1@a^yo78v!C;8oLF7)rTS^HNCI)Ixs5>_LLmrF%8bnpm(LN7 z-s@2|w{My{QIa#~a}wh6PBS$dIpL~5;Q@{p>i*`ZCoD9bS#AVe-oDx3w1%>M)aUc9 zCxlLh0?9kYmrN@rCY4i`xAB_eCx?;CPlf+w72pGiyiw`UMaiJ=?=-Yn49*MoyTb66 zU&OV9YE)qd`<4g!(jP45e%YI<eQ>3|Pj9N{ch=&Wt7r0^81ecYxYd0n*XODveI) zX6IEFHb1EXxsH{${l}}94~uB+DNS8oEgq`mc^SMNICw znJ5UN-+ju5I`72f#WDi#8T6iF(^dMXJ3uQYzlF$(g=QDMi z#>ZEE{k=lueRXeR3L0k5G#Sb$a4ODdaD!;qx?!MeV_R(!bbwERT{qCo0M;JWQ)mt) zXXia>r-4{V%nzB9wLtvl1=ooWI_C#vbYPElu`$)?o;>k1ptGgR#Z1yJsSTah1qs!t zFRsNe^0D`2{!fHn@v5(Sn%3;f)X@G3CkRW1MhRB)3MOb8Xyx5!;*GD)W@+;|uEQ;_ zk0aOs1jD?ltBq}b8{ny=+KF-m{jP}~aO^E<#Q}KuxRb51yxgG*k5==r216LG*AMYz z$WnQeveD{AbF^#hp<3DQKa=anV8IE`J$MidmSfCo-?=B&XyFd`!k_h2M`?gBWQL1*+}6v=DY;WE_J0}#B80#YL6NR#i%TCrl9fq~ z`-f+<0PZ-ei`9O7Z>zRjGG=IsMf1ho!3`urE$^-W~Lqv^hg5Ka6Gn?;fx|5`?f12cP z=ib+5#aF=e;_q4=I8plKC6H(>^Eyw zFUVgFZ;3%^YFLQqSuu_ zQ94DMDB6tR{Zg%vd9_#_2h)dSWZlZ3ur!p0ZbD8=*w+K%gEEnAf!7^j!PPm_3uAM^ z!u(jxJmh@4#JTA(oIN5F&C8-Vk2f&tv|~E|B-67bb>~Vsfs8kn913o~@8U(ee#2xO zY3U9(iBgk@_Z&^1%*#!*GFT!TBoZ3rkiiVrNdkJs63IO`WnJh**K@6QeUECMH=RzM z>zqv7OWqp7*o*u0UpN3Fzi_qprQ#JQklOZ4n$r_4pQ>i34sH1Ya)z=LiQ*R?{BTPv z_mI8Isn<)1NLEUD1@&`$SRWB&LM==&MJ=OGASko0VIB_c{FF*L@B%~Plt5E7V{O)Ge`{*wCJK{u^(jMLF8oD!LD z%vtv?_@_Ahl|5na!3i14pCP{xGT#DZTANl0IXWso`?p^DE3u~rvqy!*=&F88T}fey z)jan5ER1c`U8CNndpfr9wZn`!EzU$zR%V&1mAB1;+u3B0h^if!<=j3fcMwe6(pCMV zIW~?3RtJNE_Uc6%@QSiM5Omv;vO&*{M0-^smdCJ+iUU~oY>^xFQs(b3POe@W7%K^5x{ng$?Ejo&c@@Frf~DVlUo=q|PrK2D}4tyYFp+*0Yo#xp?`NA>;WSQ%^8x zMafm~Oc@Qx@TvnNEoP8&jG!ys)##k7J<(O`l|*O4-aX_H|v zu8mR~D>2@b1#W3>$6eJ>r(0QtbwPqpw6+-;gP9%H&f z+ixfwyq1Qs);`R1s<~6va?sQ0$zJ#1*y$RMjbsBd`%1QF-JK)oIy?o$AQ4Q=RWFj5 zW_%b?^>wyqLdlK)L?Y^VcS&~zYPxyTwH9|TkgWJ{SatKdjITG`qilt9gfqYN%q=fY z4wWGd`|1Gzaa(f%KR(t3+>Ux34{t9*-|xAumAr1!Hg=16FPc_oaJI=G~-bkyK{AEe9U=%92Bq>ApkjR6>S)qE$vwgU9deUWpYAgN$8 z8MTipy8HF;ns4go-W}`Lca}|`$xR+us2qL=uNYU5*K} zpdH0m?q5z7=LHa-v}NG^UT^x{$&+m^V}*4R?ZO z=a~($y_4%=3n1<7ForAQ^$Ow5G_6_SW<5>+rIn+w${R<;b44EyvDG0EfGc*g)pe zODsyJNTy{uXV5|W^&xX73)y=}o!>e)X;&A1LXn&*BC~ngi{zJOk94})&sH|A+o?LG zpvA#au9%&AUA$MTOWw{KLxWYWhvzfiF}PSb{nMs%CFSK9z1%J$_P*-%EWut(7@I?Q zD9@h049WxT(yd?J#_D|Fjx4V+tOH_vH@(DsZg-6|eat9k3ny_qRrl<~ou0jyzAYNtOh~a^ zn(XQ|hIBt;n|N`&U;K8&X`K!;>U`)4nJEoz<+gXXWU>Pnbv%rvO6(lTKl~d~R)BTl zcxT!v!MW~DkM4FM5#Aj9S!LTL)rBqiYaNtA71;izo!bj*59sRAwJPESm!rDstR(CI zBNNS7d7Gt{9x4B|hk3A<%)v7D$VQBAyg4%bVTG~{{LVx2*@V9l^NpjJok3_w#C~Xx zL*r_Mi#8y9jN5{z=XuYX?9L^$k;lN`7F%V#U$Bd=YmTQ}{{k}siL#)e?rhBaNfJ}c zgA`}w7MYPhZV2985$}0IO5yTk9+p27%Ixm*rEOB8;te{UsPlPu$6vVb3`dB=HPo4{NU+P>d6 z4?TiL48{!bHSc}znp$z{$H{psS^uxR#@i-e|4VZ+(wOhC$Uuc07#iD@({})>O#x@y z^fDuX!^1VILqnrkFKShiJ<2nf&^?>a!2w0KKsCvwk%TjIn&fB0C`VU+fW>hfdEAvN zJZ5++q~#HEZ79@!{TMS^3~|_5b9>n?AeJz@@5L(|88Z)>$O;4tzHW8K)7xlBwq}*m z(g_{8JPyYMdPtZr_^kP@1N4Ujsa|Mxo&E+phj#cTFKnDl8&-)Xd{m6Fcqcw}eXz8$ zoN=!588!8OXn?cCA>h&d9zZ5FCyx{mGjhrJJ6!BYP%!4_pMYf7{(XLPVX!IMS$n0v zdvC56pH1EpWi&XFj`eA=Cv>S==5;(-7@of;t!X-kF8LVgc{(>4jpT_S?dE z0Z_JNfX8z$!}OC4>{+EIAqRhg0*ahi`~H0Av^8bnutVpE@Q$4g`eWE`J&FH%q=&Lt zLgm|^7fh++9Vt~0%i&&hDj=`lvVQu%A9hs&;Kwf$$Aq(d3^pq58Dvrtbq=XlO8#;$ z{=^LJ7KLRSXjd*678Qe6Yo3_Buj4!IzbI4=wH@bt&G>`jxSeD3u5=9gVr_JkjyO-& z18I&CK{|{$Y4s7yMe&}=9V?zFz7%^i$o`D>DN@hc{=x8P_D&ynf)elc5eh(Az~u+i zthA;)h*lj@`?c6MTBd(_Jyie`-tElQ`}9D-b+j-73uW(*0ulZkbjo<;oY2K$BaX;T zARr)!i75Cynk3mp=4=C$pjDCv7T?>=Q^?b zM21Xay#}CSCA(9Q5iqpE)N@?O95C#D686is6vJVyF+g&nBZ3qqMan8>a9n7t z*dfb8J#ku--STv_Z}@#U{oNzCEq*+R^%ih-EGibezqE1V-B?vWS*kPKVS&NfOok!w zoIKp_nZhUfBKpuLSc36cZ_!@RzomZh^qHX_Is<+dR=?JUBwr=*HD{S3TSa}~&I65J zs)ItRC3t=adM@VoYti~Dr_O!M9|6n`Xs<=JG1UA0eN&|Noa4B?D;{r5Gl8ac2NZY)~l7Fw>wo~&C?)W65z?#>8TB$NtyY6%u;IeE2H5=do zn7y|xjyq)(Q}`8h*$OknXj z#W||ujk5=fs(Q8kXD4AqwRMbRE=@o1Kt)IA_ucHnM(z(#OFbdU@y8=pRgT=7#JvPU z(^D0R)9;u>8q%!uhV47EK4r_2V))B^1Nhh)dj3zYzj~=J_Wvr>OB!G4uc>1$%89a- ztH*t0X;Ri`J4Jiryy;h~fW=wNZd!Y{|5^7^g_Ts&3Os&ZQH7FyfxzVy~QZYpo8dP4QWaR5Pn9k~!c#MRk=I9-25(~V>0sBRYxTFy*YwbO=5 z@qNT$v+ONq8@ykc$`+cBe%d!|uLoc2hhNRnQ(Xq~N(6nrG$;kvcYHFN@^AF3`N80d z1`j7ZnJLYAzOhcCa1(p?XGNy7HEAcu1`e95k@Nwk#bR(T@ zU7vyinudB38X~T<=k*%7KEgu^=jDz>50d+=hJE9Oa|Hg_P6Fz7bz|e!c1pr@-p1K` zy_O26YtI~?J4~8}U8!xrQ5n=QGWBdLOYtX*P?*?UE+wSLN>pClnt9K$z6LQvwaW;? zdq2-Cv_}$OSFAS75!SV^PF5c=6R_=^KU_(pV5p#$H%}$_IbCZ!F%uISz&-)(6 z^aOK4@$+W}`TioLSH5u^aT_)lHb;1>wbjf^)f`C(fxX#eSrGzXgO$^f-L6!oTtj*F zW;0Ri`1J<+j}W=Wi)DQxwCB}e2af(4;6|ocA{D%vX_yia>G{rjI|b9popN@HQb?d6$yWL9BjO1Y7yJX}*C@$7D5*xt68w8eHVDQD@F zDY0o=c)PNc5vz~2b5nxLsc5{O$CBc$*U|)JqPwZfZCSQg!1Fa92>*P51H1b4CnCqq zak0%*?Z8=|)9wT{Km8NQ(l2yCP<&~f^JZq=Lll{HvfHDHvAKH^%lwAH_Sxj*d-J#L zcEVg;?J*Asb%)w*9Z(Qi%}_%*OL@V=2~z^3ipW?oo2A6M%*q;S5+Uv_#U{^N_U+>P{V z0W^@s9iE4Y+lXn_>YN@P9PGQF%kxC%06lWn3tO#Zx}V^>7)RDY_EWgst|&+4P$1L}Qn_>GiwUNj?d- zX2*!ybAR@^v?#t}?2o5e^nlG2$7*(}$fZGP+g3TER9a9v_64L~ zc5Ip8B=7wsT3!&pzzuxR-d={ilfx4sZ2<*HmAjEtb+t#o*~#htmO7hKv&DTX3TwZ4 z5WE4!(F{J>`9$RkS8Z}X_uM&?l@)L@;UU-qxo=Ua6oZcI5X4th9IBQ>R12+%4R2_k z>E~h%Mrhs+2Hvmdnw!U3wx`+!bYsYxT%ZQM=|TGB-G`i==Fe6)9*{~Lk|7A?RB65O zZ@+9)6!vz)Zch+`cZue_8{;BvQ@;utpHYQ}K*yRBvRIvWVxv1j%V1$4J4I$b6qgl_ zCO-P9m6EZ162TSets`%jiR)uVQP4X_1(N4CL2HRE6xW<$$2_Gg&9PMN6ZaE1f}I17Ag8sOtUM6^0p%FgW`EBs&gKWnRFgn- zRm`?5MUuqS2IVfh1=e$Cxb_1CFBWI`qAl4BiGVpN+8wk(@@7~x}T|(}UqeI~AZ*;`^N5|XJJ;z}frCctCfHk+u&MlU(}hT3hTG7$Z-1(+?m=4;m%8vl;D zM1d%hUIfST%F?fLlftG>3&e_Xv3dc4ydC5KY~}ME(=bhatDPQX0rQQ_zsVGY zQc)}hwGExU6MJl`MOr?)hpe1=v@`)5wO789-2?)2mfTM>?!l?U^U%C;FnqRl$O+i@ zOZ3*9bEqrqz&c1;yA}ER1nMg3OqAoS03Hzi)flrz(T%*b<#uq$=PQ76zTGjq?W@ak z^*MM(Zo}*=VKueQ2Y9g10R$)G&xtF&9#_5F>ZxyD>zQecm>#d)=kuc1$Kd z&{sHKZ+qe8^syX$As`46-00kS6*qC$IhH#f2|4Oc!geU!DThopPag&iw^l6H(})^E z%P>ps*Qt|ZNC9Xe#0)bE;d0>WZElzSy@2yWpxCJ|wjoc_MFNDO_rX_mC0qJ9J;}Ag zFC^O)lwkT=9C6Cs<9*yu<-O`*fQB4Qe*x!V%Hz%Ntl~Zu>d*ZhqLcR~T6u7fIM#w# zq#nC5U&V_lgC9TWgei5AYr9+_q=qcs{XXXF!kOX<{3EfADut|l-8&n`xtg*e<<{Zi zKa0=6e4}HQFZUZC1ip!$o<2S$MW)KQ1K$>BFS){?38CI7X=Fsfq?A!Re!gX8h3dF? zS}JqDHKapwcirXUW}U>ZBl+gNVp*iH=D>)2&&qrRZ^^@jcBPN)bMF;D(u#|BrkRWk z43{tbw6zJtCfwNADbLikwUy@+-`ZJ|MmEA#KjUL-YZwytrQ|A?w!u3Vtq0^3GN^Dh zSC={MQFKhRCdE7W^$Jy&@mO^d_I#>S&uH!4I~4(F$vNlu<#lONt!E5G)~ z@La-Pb9H{_!Ng_kDy#^&#Q;!ZS~2kJYSbw>I~$I^>P+Olr;krel{8QK)-N@ajG$Sn zWlTufa!mXLe1VX;Gp6XtOqNNVo3LIQsg6s;m5_BK%os!^+z6o@M}l#9lp1Df0le7i z9x{4Hu^)qJj0C=XNY3Fh?%q-a4Dnqehmb0=g7=QSREnqio#`m^Tidhu<5LRD+1q2U zk~0X=Q92WG?`3)Q5M|!`YlBxm0nW*7ce=dNeh7VzG9L;NNaUMTaH^%&w>c;X(L)&0 z$1A`_(W9c%;~qr5b&IExcynnvKEJgvR78$cujH6BE3>?8QGh}io2>|SEdY|>r*_m& zx8H6iYtO<~(w~?p;}_h}J5H4hnR&-@U?)|ISyEeLAVh8^=Zfh?*F$9B7MT^U3g+%5 zn4S);X0S?Ft!`{{cs}=-v9lt-R&R2jc-XOnA{g?#bohk~$2=aNf(Q7@7r?F-Eb)=4 zJ1Y!skY3C`L1N~jBD^?EVacd%TG#g~;aCP?&?4%45_!WEgW9uoW|I+QRt|>4z3Uf= z%LQM`&Ntr7Rw=A64Xe_Y#ax+l6FX!-v{YCQARebckLKUBX$&4soI>q{IxM|i4DMjk z*((mM7j)MM=v%dZ#r)9~r#!1@XIGeb#vy{Yh|62#IQ*m;T9vX%!#6%P@ojx{479jj zqs+)x^@G=D9dpz8}(>OnJr%)S$r3A^T^d0avzcKJQaRl7Dg z(mVB`3o|-tb3`mrRLfeQo!F<&e^ne8U@zwe{DO!~3MV%V3`_pr?0TqCLxHn}VCRMMED>!m->R?2%(Ot$UHt*!V(@ zav}FVlMb()1Q$9=NS}F4YB3=7ioa30&Xx3NbJG%88q~q&k32xepP^PtAayF1FRduC z6C*gcE^>Lj#7$QfP1Zta=v$CZ{vK$z+f-Eh-C~ks?;c`>p+ne_*tvNgr@a;}GDr$% zJC<-16Q_tOF)#HhScjSDwEV;@5hxszl>+}P!Q7~pWhuF$JcTf6!-Y+_;3#(y5-w*y z#n|Omy{m~CNpeL52$>R&B27(cX_w=QJ|R#R3r)hv7u~PoKnQGEw{=}YLc({XC56v# zpL9Xu%!s2l0ASauiVEc4t~z2eR#G5o=`93qfC7O>&{Ek%Q!^m?RwyR@n$QAx#g4qm z9lusW$JP?d3dpX1PNgk{7_=U8gkRoD$66NoS{i*P#6YP5JG9<4q2ns{a^r&@dp59k zo7r;n5zVE|KSO{9ViAA@RwlR5pQqswpp9g0CT8OB$ns5*AvmX4>?ag}Oe>G_Qx00W z`qowv1aLGi9gc|-B3+=)AdN~*7>yGt&8@8II_-)`_16;cP?FZl#n+tRK|nLMq_H+? zanOJ+3;D^jg>2N}Ps2H6^ZAt2Qz)|7NveWbWZvu<#o6*We((6 zwMq6Y*KG=3w>A3aFC*jyi}?S*T^hUiKM6X`{}vkko$$-90XMqD^@mVYECP=9X^dp%V&f-!p92O?Z_MNcM4~ zf6cH~`tyG=S2%l;{B&}O^&Tb9XizP8ex%iItVdt_E}3T*<(wnv=vdnjhDfHe}vPweSPQ3f<-$S{88(`{cn#v_(y-S7=3SSOkH1J52S1& z4*R|vAs_AG^|yN92-gx1K2232;V};l{xA6k0%PPxJVA<>JAc2H{|9A9>x=&v zbmW2eClBNA*B;~F(RP2zn^d0foT-o-g8A*C>vGc@i0bwwWQ~dC_ zBr31?`qXsZklyAhACRZCbVSk_8-6+`>*9x7Lw1P`WKBC;I$tDyOyb)+u-mCjt=x`o zNa@QIw_6<%&P;$O)f~f7>cVEY?z5`mIzMGdiKWl5-Hh`ckoZo3F_gF?!r{}h**>^O z#H`_eZzAm^a_6$>rz3^J>A>#nM|Mk{=CvAKg5jMvPOcb zY%9N*#+N}74{#Ez3Ai)uw!zTUb$j3Kr=pZNVKQd(<&?`e9&GvxD?yC{mS4_Y6N zVCOSHecxz>pRK`}E^t|lthC@Dm`^#%tKOyy+hbo_@u!+!)c(R#{pX{#zsVn!8|#cQ z7Z_SaWigij&XAWOdSR>TO#AfJn7GZ87bvFBbmjLY5|UI$d$FXM*jKyn-k6%L)nrdh zJw1Ijv$b{e%$0maiML}cEa8Z_d*KxipX6_7F{8DqC&Q}4Qc$+bhZjJ8#@uoTjU30g zaDzk?m-`FN!MdiiV4sN6bzHlz2(k1m39IHaVxBj6;Ybn4C73{Nx_9>vq~>7+I+D-4 z(BCF6)Zz{uQ1j4bU4)8X6M}j@r-9`3A{ICA-~X(!j?deh6B>fb{DVU0kG% zvgxRWyKcNMyXXq1*=`HpUf%E9z5xN}HzbYJoeRv*oA`D*cff~ZjC3?Auq)bZy77&C zP1N;Bf|}hURhDR!n-d`5JOik5dHxg@rI>G%-YFxp`?@yPq*gm`gTxXqxn5 zIBfL-Bu0bx+5LVKrD?VM3+z6D{F>h~??rQ%=)3`9RZU_^_jZFD_~ zhs}G}oJgpi2i2tIW-tO5?O1NckVnX~LPCgBOvJj8hW&X)8pB2tp5vaWZh>qrY|wcV@?GxCC1k5T zepu&+aPM?C=?dj@K?X;63f*IEHsA+B4@^Y7^=4`aay#j0aHk;wGAXAMRdcIS2Kx zw?rSTt6bfGmNtv^k7=G@jTQaWbmX=q^Xbxxw8Pz3hyD^6VnFLz^kU4dV*Bk%T;6>h zum5b;Ymr=QJ0tMEEJWIzW?hzFGzzKDJ!#=)8~LlS04nOIHAZh!!c)~Dw7%Q5+Qxgr z-u1quY$dm(r>oD~kn<72CdpC z7Oywl(oSHvtcW^eGZ>urbJLoHbp4}OYO8t?$r$w2F!Ak5d5e8;uinGHAt7dGC`(H$ zV^z&6sX)#-lZ{!Eh`iEOqN#IpR+AgcxcCL9Cz31={ap0$Q!Mm8+L}f|`*~Nv*w;n9PO->pIzhtd}`SlL8`iDkMUn+z_sp}IHQy`Br23xxfdu%&z~tj z^zc*{@qX0hT_g&4XEsm{iQ`AVDHU0eahhkdXAKGaQGK4o;84N$S%{yE zsJ8ia^cqq-Yso*m%LKBH|J%PP=nZU#PGM2ppq4I9!6s(o0JKx27`Z}yrlcirOC*-^+V2iBS~lzaBUZ~Q0(qcUIkAqet57t zN4?7)ZXm*9@b6J7I`Yd5hu$RCTTrfQ!5=H6g_BtZN!XGI7{sSkoP0}C^2RMyGKX`{>C z-Teb9f&uH#b!LL7-d?T9ymj3S_8%Iuf$wYQF#UVLzrBU6KQq+rn}a~s>>n3GIC=fl zC;E}=U*jPE{?9yV{evq0$9(z!YstSo5Y)cc%1TpO)c>~xEF=Mh-;20J4o*Q-HhYsl zh{L)OY>cqeIKYxs-qH2li!YL+l#255zsze^Jwyls{^Qvs5dNDJO$7K_`MsiIB+&c` zf>{Hx=?^pW7~FyQ?&Kt=rV98w++OTCEYwFTBr)=s_n}ez3k?0IpE`88S~e52L@u!S zlqM$QbnETJ5z63}Q?rt+!B`rTi7w=^c<({MS~{rQNz$f6apoUXn zQd&ktg;~=EKbz0hcbVoeOvdGv8fdLqFUoP(V-QB~YDsafIVhGQX8gm44>cZp8tjDV zsuJ+m2rcfy;$m+RLTK0Ho6m2*fh~|wFus+Sf4znP@(_yYZtm`$ZhyJ3dqFQ;0-f6Y z$hzyF)h?wn3QuvS2DPWpEIunFuv~LebpvZqxh^_?3s^(C-{_@}CCmNX5v}p78LCM6 zu$ZMAC!R{aL$jX}dv|lT)^%ERsT(`$N*UVelJxt^SL{NA1Ri$%%ki`B%v?b2D%-5U z9`?M(F})xcNt>&wa7jc&y(-hKvDBgA39UPkbHU_JLB0$BIc0Ok!Q&+kFrgQU-p`5< zsZoxrZLQpE_3+ZT!}{S}>+}i1M@tuOrb^Rc{WMNoD30QLm>-AsSh1?uuLDtB1#i99 zZ@IDREjPwaejfbFWh#7x-}0yBnvsUv!@M|Gfi37@1U-fxIJfI1AeqjsLD!!(F#KwJ zRe;J|D+tDm?oc4aI`cAg{^rm~tiwgrOjW?Q1ZTG0hY1kyk!P!>F%jAX167RIjLn7w z39EPd9gZ(uoAFF6W4;}K+g}I(M&}*+mW$_4Fvm$e2z~kT1)=iceu!YF%bUX|AUIue zA6M7a9oUGIPj#}q@ zZhasXm#p`?^ z#ChnFfsi;S?UpFZ znSsLSFvE;3xHz$VsUi9-KBvB2Y%+7{0T&x~DwjjwQlN!@Oe@~Sq zxoj~6l<>CdRCCZ>plh9lvfOg6(oOQ}_1W2ECPdFd_B0J&!w|1~`zkRvCl*vxmV{t* zdc~WKpM8d>^02Q$nFqj_Qy%Z_+JxK}yF5=DA&n~TEL~O=KXNEPk5XhUi4j&99(62N z9sNkb|C!mkFxDdUZVyg$ z*#E(KnXK*L?xP(%GEJcJw0X&+&U06UCdbxoJ8dx|<$vD=NZR(1@==3?Z_E_Pz(`n@ z-jNlm(R_ROa7nCs>%1hNPFg5k$5YsK?l@t6S|V7F*63$ zyV}ZKd>y-LGd+eoma`Bui1B_h$X^*Z`MU;DUuu$!wPxSAl1Y7{u;EzN{fE3{(I?yAMH;J2>v_DV?bipVze;@a9R3Cg z$9&w=S9f#kJ4>&WAM@Vb)@)R2fgQW;mO3?Mct^yuQ|nsv|BNKLkZrB2IsaY|Nd`}% z&)sB>B-Ry9^%=io*6P-2Vk$hB60mrinV%X|UPZTY0!(Ia=nnGxmJe3SYB?uRRd=7B z-8MbuW;9~$j7#n7P!CgV++eYOaD*EIb{bmohG}_UQ|@(Lz)Qqx>iX>HdH!_zZo6!( z%_}&%*tF89+hNP<1`rCER;Nw^2Xl-9J4?yL_zM zm7csHaq)e8ua-2!Ywd&V#QC`WTbi5-8~Y(~30cU*hm7A=w5kt?F;BZ9>XThr8hOMJ z8=@~`nr05_E9HxM1*mS|Xj9DQQky3SsTIFt2Z6{Gh471zmfZJ2^E>+VjvDJR27 zH;m`97ILN;GU;(@c9+UEZQ3;m5i%s@a4%U(HK02FRcKjlr==od^UA$NJRe z^7c*%-vXP2Ao#%-K1@J2jAsbniql*$I?-UW-L`t|&u`mC$$H*=;=yR}`Y=J0RhYYL z6d;O-C)%Jd*y+$l|F3(xW<%*EsLm8%((McX`W5`Db(1{yzackN$c7lF4BF>E;dDb3 z=XWGwyVtu;39zIMzCykKw|fN9$|X34Yx!NI{ZA>+>x=PLXvV(W(bvMR^bXBc(Qc z2V~P`TXOYL5X_0B;8<5Xu)0E3y{kjodjG*W|CW}gGajAGE7fh6sqn_u0PeCCz1{9y zs9h&@$TyPh!%d;yY?QN^o@-!SLAKKDy`cMvP=OQE=ZDFOerD?#huVuXr#v-NdqtQW zZ5IL=95-b`)nj18v~1x|K3~m`qmxebPmh>9vx_=DTbMSPeUw%69H&h@*O{d9Z!C8b zSD=%W*T`3G1P`~F8PhuDat~Zx5Ieoq*TAbsy@wSXGR_kp1@aJzbq}z}dxh4dE?LHI zv;NB}w=69(uh=~6w1MjWU}^h(enszRWa~365WMSS`C)mBF=Em45rd>FAw!P(b;+wd ziSx?~pYT-2Q@s?`js8%G#`RN$;N#Yh)lU}q(YZnGb$0K%z}w}IZ6<7CNR;ZIz>F{z zrwqTkjrZQ3SBlmiU}M4Us*Sjutc69#rJ^iu+Z*A4s7vQZEZi99B~QwnVIr6dNv^ zF8n@=wb`3tLV-;Bjx{O_;dmMOMA>Dlw!u*G7#M^_ub$&gSj@eGRKK(r zdgk6X@BSPef&8QXf`l965z!}uE8)>xNSe*CM=Y>cH9KIBlO+UrcSqT-Di8%)eTMnr^1wTNi#FWsdX%<8U_Cf_CV%yE!r@<;6U00=jUf-?xZ#)6wYl47+C%SD{-@*#XZnx2uJH zHyr0l0uJSh8zk&O9q=UN zlNJ}Sc2oD*q6Jo?syjVjRXrmC4z9$sOPkP?)vWi=W5!K4&P{&XVAegK z(x%u5#e<+`Z~2^Yphx@7yLwp8HVrb6-t7iUJvE8tVc9!*BO|Wt>v8dP+n~{6w4dyE zxnmDKOD95A$6x+tLnOsw0{4yho%iRPm@=m+ISi!;Bg9U7#u*6~HU}gPGZv#?+_~(hAWZTrLNnh|6iaL>M@6vkvbf?wd0>Gr1CQ= zCW&LPy*PQI-Fnf%DaG0&S!cE9%EvW&G3S_ehIJ@}UsBIngCk(e`u z(KXSsFp3Z#KkJ~tKtq2>b4}w^XDM^VpscK!aoPdhZnnt8GnqTz^>X}(O$9x6%)24~ zibGTUTWIvamYj!_)SYGtO9|z=-wfW{AVMhU{2m7*#E$pKg@zbo`yN7+jTzFXqj{An zPb=hcXL+aY=EgTaKd-E&=CG*aV)pJI)wF!An%^8JuixrEhgLCi(CO{$ACTP)kk|;r zMb68`6@)tJS^uf#_)LZS(L}kXr8>!#G0eK&ksv$qZm+)N*(^hO?5Ni$XbqveV%Kr- z9mE@w;E_=A(`^E7QkbPp*oH?CP0(BLFoLK4IdNsU!^)UZWAAt@62%Q2&~_;FK;_oHo;6d~vXD8N2z2!|dMZLEu)p0_j{Q@OB8;Mo zVUd29a!33bKqCZN2rOLr6~pUiFH$qZ>gq75ndalDaDt@HNn?Mwi?yBsWw@UNN@Tjg z(Pmv!PU0s9iI2gW5X0ogifwl)Sx=uLIDPn&s1<~Io{XxD+(l=dPFG5c@)DSzM67*) zfa(#-gVdwJFjS%+V(fLNazq%|Y093sWr$ns%kIeovoR=23T6iA8*3T{NPR=MTOtY- zMdz5bQ+*9;1Iv;ta5gel(T&HqBv_0>G`gd^u{^2JqmFT)N{CB$SjKf8Cw}7Y$GoWh zG_v52Do)&S=`cI+&ziZSnXF4xKT+hC-{KyLFKG6op+&$K0>xzWlv%uzx;T~ z`AUB>gKq*U6jo<@v%uOAEa^zCrhu&RETJ}_k;|GB-tl4;@}E|ivrCqHxE}OzkzeI+ zBn@@MNy_iZm^zoxb=!9GpN`dDm<_8ju8J(NB!{{{#=s$RCSL%`tMazMkA&tzrcua@ z#SI?c9JH3D0<^{s??6SCNM&#M6)!$bS$7maIU)M-q9fF^KT!+I0^VUeFMj$#M%}>vE2WlA zRZF_zkbJ_b$8h4~NYYRO8Pxxho_YT5G;WhN)TSww;l;LIWYIv(pybh% z+0(CsPu}>~bw-z6EyrQ|2b>qlk@BkOe?1|hHQJKYvY!&h>#Fwir$^8jGqXN57akqLCekpi zXN0giE8n~;GI+{Z(*_)5h&hZ2IlBwwf}MfCOFsjy!w*@W#cHu z=u4tFr-0MK>(BdHKV0}xHl37%WSwI&2A`?HxtW+j1DVmZS6m-F_<>;$G8d_&!BpzU z4)cL*$E9K(NzgC|z1ct8NK5Evk-EC3>etA8ZX}|ue#1Gv8&9}@3$;RiD$Ac}WO9Q^ zE?|8lX1kAjkTkbzmslQ?r7Sb@?Kbd5hfQ%b{3YQ+CsbGhaU1`n!Eg+JV8_3r{cf3K zlmcC)fgsm&%!Fa3_!F}{YnXCvhv3}S$Lg@C$R98^>my+mGoumUYjT~j1ND!OsvU_F z1)^KN269woAMs+Sy^9|QVQo!9h9b>{&PS?jldK6u9F7_SdH1Xo7Moc)T3>Pd_pyi?6ud z$0nEXU2?GSZogtl)gFn6X$MT2xKuW-bN_0Xn3n9oU@vX5F8qX#j8-0|@qWj>x?e7i zxk98#fy$BqjV!Y#$wgS-$ci|06XH&K?Xt^mqHb>L!6ik<8y;DT{vOfAhCSG3;QHx# zv+B^NXFzr$o2@CtEpy$;<6rACak;B^T&mZ6EKR@11yufn3 zLzvB(d{O)uYnS${$UmKBM**a>7tV(@vX|kL66T5z7WxfZVPNUvN(ILf^-J9Ad#YCE zJFFFsXk){e)Aq|pj!~kxA=m1-ndK$#d%A^aVPma9Tgf8pol``uV~2)ch+`m)FZ1x@ zE|z2XlLwK^?bkh$M@m1)^Z@CA%64`%nFj8iQrG~E2fWrXkMzKmi~3ykw5u8{PNBRf zP86LFrXZYE&sDC}lF8{3zNb~~8^qKz5mkZDd!#)j_qyd^dZU!bG@5%S=yDN?Ze5-ozp)UALG+>fx=7&$m=|g_GKqK zyq=9`G&rjV3e3bA8r&oybgL-*X+#S` zW{J-7Q9u7UYu_U=yxBwMfnsh8v@F)7DS-FSh0R_z{>ZePmx`8q+>-C{O>XcM-3=Q1 z3D2@_wppBSZ1OzXt))I!pI2E;jUwt>%^xq`e(P^K(Kz!o#f!c{6RdeF9hEcQ{`BkP z!jZ!W?ww}*u>5+x3||!({>AN-LUDF00n#4Xb+IoyQrpn!0Fm2^F&5kN@N6uI-t5C> zABQ6XK?ARN6GR?qg{^9zW9y)!)CifMBaa$TUAvfKlnQSKt(Hd8-RVIfH&z#22)nK+ zGuOy=%R%^>RjGSUFRR8r;RL{*gk*UrmD7|1R)qX*T_v&TjH0r(f0mO&hl4qOW_X;n zM8Z_;cgK<)=6-x7iPQUPZqBf%=Oc7@c=+GP=~rAHGvL_*w$98@#>kEYbSvptn2M1; z7-)oz4hM2&;%tPffeT~CvLKB zV9Um}Yqd(P-x3ToZbn0K$4l!Eyi3<9&WCRAMJ^O7brPgC+ljMX1o2)x-)c0jwHys( zbexjDxUapcRqPoj8e7svURh}YksPBo#oC>`<^Vw=nVtFwl77LlGjzGe35b-ujzF*w zlx4~xQ(|pP7)f0~nEWR3CEqKOS|*8j2BJO@njId_kETFa66Udx6OlB&-`G{YdDHb2 zm!tec!<3w_qTtq3uJ`3_=}~v$4z*cT!wH7velM7@w75?qjt8Zw;xOU8fw`CPlL2Fx zS&8e3=3mq&TKn=l*9R2?VtO+w0ZagD+A@gyz_o)Eb8+kX0YwYvo6N1gjp}aGi#93| z`Bv4R+{y0vB^6a2a05YRwUS9UcMcq)zhOulcYrosOB=>Y8g&+W{RGd}d={&VH~XjAj0VN+1b+ zKDB@V+pTfNpQ=}SOX0KwGPxZAVd`35qrL>F-&KA@P}6^?DvLOC;-UmIG8A(P<`>Y^ zDlnK2zEM{BZt;y`{@9#v|G2dC!WDgt^nsC#%nQAXxXHsyFJ8SGNzci*m^n7#JtoFj z&&b~uHf|K}5bZl77h0LUlc&y)10G$uAz>)+Yh(q~IA91KYSe?LagoDHQYRLne|?(7 zG%`kh5{q)~Hm?0$Dr-BcxHO=B#rlE+bA!xDmSb&OxsD;Z*^YhaO>r@dH(~%<&#fS zw`oaaca9m99+bF#@lc<6-xdNPE zvha9B^VO?)e)Ea4X^brcO^(KY3)+f|JRn0=0-gKkGYX`uSt!%ZQB|gOlOt} zHwtAe2P0%~S3!)=Z1_~<Ec{UFtWk50t>2?NgJMd_c*_~(W1pq@DSFQ8juYV|hcZ=F!^Yk*%^ z$CT}+89v_`OatMaCsM7gWr>;oYP$7F(>?0jL@?mtS4B3jFLNe4Es1#a^F@r@YFAJU zo@H*U_s|HbkY5eZJi6g)vn6x3O|8RRacBOoE2MuGjxx>w|1S}4n7r6@ewz*k8uM}@ zl)G<{Jy|*VRJI&yN6TCCX;eNxB3458-Gg=c(q%$giq$XPb-AsNmTR$?h>d35r*JVo z4BY~h90seJ4b1tGjfk1spDE9LmPT!&PsibG6LJw*9iY*(;Qi_aWZ&%^&C=3RltiZe z0F{=Tl+_XVjScs+&NFi1GS2EHZC6eQ0uDp8*)9jB4jjzh#KRgkZ#}NW9DCtsS7xE> z7$e!nD4Q-+s%V=Digi$G-(37-yyq0lXiV*MqDS-Pyv~<2A?v)MNIm;&4Yztvd^vw2 z(EiI%e2aJUe*o`jMHEc9fYQ=DO%+*fx1N|&5M{#10 zp5X_k)N4LtdL>?C{Z~jEr=aY)ZqFo3bT(n?96Mk3YA?Pr3miVD-^l@7!FwkT42zS& zy3qj(2|XTjVcNFuU#liv_LPF*JykRGne%0N(`6)Szbn;;1=)xUq04YPoSp;rQt~TF z(i&WmIkunt-hqR+VivJQETuIw(i%|R4(onIrrNW?JT!ks@@1BJ1iisy-toiZo`nh3 zW~5mRB_;+BI{goZkCAcq57uuP1mu7UapQZnob+pJ5-FftJqNa=qXmzreFg;M0Xc%% z7@kRl)iq_oDZ;$)q1DG_6M^l01gQ;0DEgA6z#2E&pbt*{I%YSdOA)Jq9g=X{qSDT) zVv-mHl8DEPmPLYRIg1;eJ3OoOL?!eE)f|ywh&JJ6^8$Q*orc^t%sJy^Lz$_7Kb@&m zn)hBhOy397Y#M)<cz3X3#+*+v#YY?yqZQ&%~ZT7uMvi`x{r);@49-OPWb*Ai& zc_I2Q5?GqK0#sBE64|4wQ`39gZ@wq^7==6v{DGAEV1~b|rQT5z?rKjej%>m+ zSbw@rRMeQCGNT{3Rmv7vx>RFDi$#Rbjmg)tZc-CIpIGgEDlaYW%;A1(tZyxbd_U5i zxe{aKK;G`g%;Fp;WXnbg;nR#XIvl($XN`!RDHCboC;y+IS|9PxUc=~av|3r}^b&x9 z@$cWi*KcxJ6RWoa5$<_@m%G{_v(+|dL~yz6N&Gf+84*kWsdF@|=U|gmSML&C zB3AgO7Ge6Ws<)2#*7Vo-^QDfcs^;xhQw_6kG^~J#iq_v&i3Az;yT;nKvNKr#RI9z3 zbW%!~{h?j^9XI2}@AubA@g6kLW?0g>z&p`~E2}iK)B|4tHA@brF z`l)s=f{#Zk0D=By+(EIW0N-dw*7^yEZ?E}4Cv)^pp1@>xk~K-mRUW?MR6jWUVIvmV z?PlyF0V1%O!KJ#7BT@!>ACfWkGkc4RDD}E(D5Y-wW1AW`iXS$&+TB+8iYfd0$|U@W zD_6u>Ya&EdOKM_*W@69u*qMw^$*0!_KqfZJhPc=2PhGyXEK{PyH_sM2{&VAXpcVkteI zqi4^Y?hK~qy~XzSn1qYtuU0s19ph0Q$^H5=;FXOua+WAs?#fc~%>21lp8sF4D1{)V z?q$A7)5p(%?IQ9p3R=G27?4{4b4ax#MoB%K&}}uEHl0gMSm>HC97sH(_UN}I&gy?Y z8;X|5-ju!i?RGO|l0Cnl5MNE(e1C)DS^qo#Nm~(ezh;q+q#8n^X8zU;0kSEtVBrKx zTYeV0YwAeo>=1ZQ3v2$K=l!)cGV`Ipt;lP|6&yiPM;|~qLiWXD)`T&hDF2pvz3>}! zZMf}YwZB+I1RHoN)}9FIA0w01z8pS06SQxk-*rbyoCcQc;Wv z4ma(lHObUnbYPUH`Ju}xndjp!F{$?vzvdv=0M2AUb^UqKqW$(XRnWzF#&5lmy6sJy z6B=eFL3DvRUbfH+MLbAPd|yBS>j!AEe$uiNd~RB9=1s5-oeB8jV|%VKhzflQY{G5Y z%BjPAo3aSbwWQ_ed*wZ15QCGpqVv=HnHy)3+OE%NaZ02Iv#%p2Tlay-MqXDG!oC(- z3%9PA^lXEzgvxKbKbt&L5r%%DnAQ-L8~h2iFMAHvW)I|JC2x5vk>k0YEckR&5t^8m?1kgA{m zk!x;T3^sv1n8SG@EIaxLqs|-+Q-yGtjj2)Q+YmL2Xsl z**@5sd5yb8$3Ro+BqLiDl98QU_voW^z|f3ELY%0Rg9i!?ek6LWO+Fg%w%hLe7yhE83uDrYz;(&#l+AG2|X{JV}4ix zn@bA6=v3ypl;7I&U~zkLCKE#&SJxO@RRN>EJM#6nT0JuryJ+Dk1(pzV=Ox7!I_hp7 z+G?zKGLkZEYl-i1lYSg>qexkYd#Q4_G0G{Pa!~?eJ6H{WrB59h5xn%%KzKIF(Ozw7 zPQArZlVA^`##k*BnZU6cA6}J7ObrB8g`ge|Z`?ul=`p1KKw;t!olP01Dwzkw%3XPU z&Mbz`qMriJ52UwV43~3P> z{#uXTEv-ECa)Sb4mGNfTIKurFg7(8Zkb@*KzFdN+L>j-l#mo=i7i%H>+T$zRIr7@* zKZ%UIaqzrYQF`SqGxVwV^@*q`*Ni7fX_RqTr_rA~S#Nydux=RNjy||y53@y%Lv!{8 zKzZjA!kzkjVRVww^gEJ~)yfu_t65m%^mw12>BI5@>(*x$53>8soM`WfT-q$OL$F9B z^|obV%oYm=ozeMp#gD#y`693I7A{@>&Qi1QF$29F)F^UUg(>n(+2!DATLmef$t}Jc`T=P0U;d`%)9?Ry_mr31s<#Z5cmjl~qXKQWW6cj`-;PqKOlE!z6!li;StR$8U z3>~vNx-Njd(z(c(f4qL3Mn!g0O`4k-^wttHcziP5zhaVV3&iai6eSBlWCC9xtiRad zCEme_JymQl3`uZcD4ZJ6)LZw~tfpqTjk%pi0Uo@+ez@!Y_^Nz^$w52~rwOHV*hE>W z*HeKW*FRm-@cxXvYZX=W){S#4pTmcz;Kbk&6>u59`?)o5%8#cq^et-$`gkje^~V&r zGQTEs*0#})HVayU&E4+b*FOB%jWVz)z!R%zj;N*o=wFB9&s*p+B#YM)(X}=2f>%>9 zBl$g4L{&SXH7BUAuV-GFIq7DpZ@hW6``CjwYsND?^p8frXiRkD_qber6J2_1UMe_G zFb7G;gTPYTB1&vc;6v$(w5wsWwctO`+^sr`9z!u4oL`qkqL$CjG;L~?G?g+#lxIf1 zRe09o5>0YLN9TaS61`c2IhEUW)=%tNH!>l$u(0*ZW5TxF8z#{#2&;R(!?}w1XzI*G zd1d?bJf87Pv4DS*P0P`?sZAKKhcoZsw!H}*`*Z)tyFRQQp7f3-yGK#WL-B6hbaJ@^ zTy$%4@CR-Dwhrw4Vj>-&<#1LFpMQRi7|<3PB{H#7#Kor!rk(19!YKO$s$G1SJ9CEU z1E^H3Mfu&evN^qDwS=29QY`}Y+FkM(a`b*C~@o_#9Tx17c^w0a-J+fvnf`GTd2 z<;^AlN<7w`aMWF3v<+FkyU{JCocqRhQ$B-edukH2N9sSdwa3x@>U%u=6$tf{;8VKCuhwuKh(AzI^GY zwU~UBc6%6R(D2*Q8MAh8yy^qodYd;+8R+5N>~VqXSKOCPgM5q=(1DRjWOIUB3=H|o zM#6rNqjUb8R&VXMcv{Frn|!f10(YX(=9h>As;JRvv#9JoI`g70t8|jD^uGq_5knQ;BD9$X@o{C$^s7Udn7VIBa;BAS2&%qT6WQrk*dp{^0Sfh`;q(<-OnI^bSuzBE;s@|Q)SV<2J+wattHpbejTHh+ zP3NnaN5w}T&r|CPB9CaA{lCR@4jyf=XxmOdIMzbPeX<`TtyGF6Q7sqB2~4xSxM9PZ zuz^IFDdWL<2gL5+*+Q}1oCbu4G;5;{=|iIL7&uPlZ%dh44>-Uz<2%{cQZJLwSGF`b zd~7IZi7xn>ULD|G)VkCmjHh{%>vC1qp(=E;mJzl6MLEp^)51lx?7B4$yS)oWQROyX znC^V*thga__dTHnxyc9ZvWE*WU;SV(B;i&;E`auGJ1(p+a^|<|jAHscI63Xz=%%E| zU6SSQPyG~P{MjL=rNDfQkD9a#OKr_zwo=qgFcbFSnn2d{Mh zI4gBhaNe^ak9d!CyG-_kxC(Ku&g;P|AYWYUt|r`YQc_Eq$4!+&3$kRkC8evfAk(@c z=cj%GcmDYG`dvCc8e-ehewh@HN8{Pt$gr@ zqNb5RS(ga>=H}}!fjHP?Up3CGN9|pB9-Fbu==+@xyMq-vEvLLyq0gB@8OYvljfh|z z{0|!2WWl@5#0s#Fty_5%4x;3B0Dl$)dH05IiF-fR2hKWAJ!B-teo2Q!woxUra%`WdLHeCRQyG`T0R=Wh=tOed4h#rxX*gmHf z#+(1VI=w$0S?x&n_u74O=k+jDc$v!$G_#R2HPii|E4%t3$Wn_v+s2!|6f3`CIen~= zSxa5m2e&FRd)&~%qmm>^49>TMeqVPg!wcj&JjD36_(l~_(&jQm*qL54iI@M$U(5Cf z)V5am`8VqV?$)Os$K=}6eQHZOA*%6XJn^ADr1Y+Iz-Xq&Fi7c3iH8qY&=A%D%U;E5 z!0c<65$?_hkflA*i|wrMu?0C(4a$N)*SMbEXFCnV-485!Y)iPaSuZ2O3aHDyf@l64R{^l+?F^6}VpJxda`J zqG>58a>@UAp`Cm~z@L6GSkLSXNJ4hmxJs&ij8ArT&}Em4GeoK38wP4g2lw5m7`bYL zU$VX+-Ti@kMX~MWfJf-v19oGuOWjy+3(DBylJ(pXJxNI^41?uUyWb>u+us%cZlBYq zZe4kx^0_4`3tyRLH>E+f^1_eDhU0}7kW<`#vr6{F{%Ttam6fJ!DQcynk;Vyh{AzYG zr|6ci6U33hx#exJu<&}4h@=gQ&?7T)q~Llu;r5>A8wK~!nit}Kxd8pal%}i&1ku50 zxTwv*HtLWqE*!TVQGpbi!ovb{8@_K682pY0J*6sT@?nHR!VWK_-#g8?K|7Cjd#5^> zX+AMzgdy_8eF5j20@1OK;eU{g{iCmg!rbq$5kKOC`2IwPOoZiA2 zkRY+QTdN2f&2fhZWx6<~6f*lE=i8UU@%} z#dvG&$Y?yArI){^KwcYhpv1mJcuL3InjE`!eLOX7*|h3T>gV%Ht2OgG+xjOvE)u93 z>YIFs2%Y>DRhHYEOqw|zUe1TgYjn}wcSiJ%Ky)|Dh)9QyN;ul2!=v^kujF=}_IN1! zO;`*iUEzq0{om9W(HGMsaOy6OJW!Y;2vH70If~H(_ncXJW8o4rmh`7DV?+$8ds1zH z3m3+N#4_6vT7vqMKT0&o@Y;6eM_?sGa$a4a%Z7g=+2!HZDgLo4HrIw;KV&&NxpXEV zc>9K*&S?qdlBZgIZefS*DQ&t*;mx*5CCp;`9GK_~uj76C;b_!k!6QPd*+~$y0NG%J z;y5qFwXu9Mokq2kp_2UVcYQ6J~09SVO+1yj4PVw zmS(GAgI8y|cTA}x3Lj$82xii%^CWkzKDFJDuXo(A-KSJLO1>Pk2k)KdED=e`&c1oY zY1mP;9cvGZXn z4HBbi-Hk0aICboH*=zsSIeDWR345L@V?+F{F?hgsVYq90`wIK&K4BXjjh2R?c(NA4 zbvhaaJsOR2A}-rbbh+Hy5ISMuMv0E5VVHU)?y)#ZS-dUR4q3no*8v@);(OQJ5P8u) zOD<+63l(zm2rp-0dE8Y43@B^OaC(n;YbcXPBu95Kug`YBdeES5M8Y~#yPc3>#+!H8 zL~?=IJ?K6QR{yw??l?AiJV>{*@aWidkVZUrvtmSVVVkUai%6_Ezl&WUhMV2)(b7BHD0=g+%kPtLhD7Eg5oKn-dZyy+o}Mrov&yKUD%VG9f(s!!p*m&@Ff^SS*d zQ^i9-1oKC@h_!`3+pzJ>xq*8#dv^f5=l7ugJA*HPLqXVkwB`6!Xx&R~jlPp?-zwI= zcz83|&X!=oNar5Yz*~mdq|Ckvp}ZRS!m>brMIXc5C!(n~d3hqqcg)C6MK_0Psg{Kt zM~^hbu5;Jl!Pl7OT~vwD2H#r^xMhS0o~RdKhIU+hCz+vO-Tik$rzGo38#xmbrYS%Pcjo$bQ{SyAJ*+?<6~n{16W)$BgC!IjLItpm zlh!pVH4A+`Dbey93&O8Um%navW(dz z-b95_-td?+Hg3?x`8(PCGrt#$P`k(Uu~TcGutyILdckJ6Tp0hb?WqUn3K=H@3SWO^ zLwnWR7kauB-KeJHJZ}6ZGMvgv->1=&vu>ePFUG89ap8mQCA` zmJ_hIbyWSN4}pX|NEe+y3xpnW44Qo6UI;v&?R zTb`~o+un2ii=*Xd}klsoXldv)?H zLx3vCPGN0m@Q8@?6sENZ(=KI>hWSM7T|(D~5WcaipN=^4Q(_Zs41T2ZdhLRq+0Tdx zjVig6yDVEB6Xwi}#e4~>dzycB{1kZ+Q@E`${S`PI(|o5Bs^s+VsPHg-N8 z3Ntj9o$UvK^cocLX2m6@g&CM~z62rLj?WgQSu=#crN4i~A;gmQy}da`-?!y0E-$BI zWBY!3R-D+7c>nUkFleP<>$F^z!%Mre?v~Qjdv0)&O+gP*^W&ljpArw*R@PE#vjC&N zRgl1fFfav52I1Hy5M?!$hISYu8T{A;YaO+&seD&fk6si>2%Um^36-m^uYd15H8mx9 zZj(l{xw)yVth{mS4qseaNtVahkVnV*h6V=%73B;%D#sJQq*YQdT5&rWL>a{ysxcz7b zmf;|SG}Dh*?0)7J_U+c+)dMKPN=)-=UVnLqW1GLC^DdU%-0!R6?x$*qMTXYD-_7@- zb6fT4WlUYY|H%$o>7e7;B>ywASs5nZ`sHQnJsj?X5T~5>?k;{w@>O@DPG||cd1d18 zq|cUT*ObwDEDHr~;;hvM_2&=d|2z>Xin?7^M?qc$&y>A~kb?lH%DSbS_?FPnr^~}x z*`53G3(A~*M5?)#8R?&G4hLnLuq*ucDB;iUUmX!i2siQP0<^~ z|1)3+d|* z?QuKWsBnJz78$~9w|YK>-H2>yp=GUsuDW$lo5Ay64@nG)bqlPcnL42-Uu$(jG|sbo zyJa9)Hpr_%<=LE>z_F&{_mEQ?apRk|F?#)XYQIr~Z4je3CGOO&B;JNU9KUMAchSw}|Yi`XUCyOAfh7wf3(jJX{cLoetF{GrT zc-58{YUuJVwnzS|(b_1cgYPtc#ddo5)2o0|qCZ7ji&m>UR%>E@1ag`Yuf@u_Na5)x z*2f#YR1E=Ac_j^zxutLvz0dQM*UBH3;x_LE>wR)Eg4((aXY0oz_P19>+4a+`qUSfG49eHoKsEgtHOHXYC=}kmQNcQ&}Pp1S1<% ziox`Ps?LcNLi>i_`~(B_~X=YN$b_~b0t+fywn zTY_OLtf-^}tTsSk?Rw%655X`7*1{~6+5LxyrBo?EZ&i8`w zboF6E3upu!{Y~B%8$FIkb73%87aI?6NE}nBzuKTLI_+MLXRUv=#o?QrobgJd)t9ed zIjxpI<>ux(PD^~*Y3BEYTVgVuIELy!MRvST2e6xXyf^C`y6msEUFf`qYl6B^Uh2$T zSZnsI%Nx16t=eiL66hz9!0z#n6kR;)rik#jcr<=s%_swXIFR{EJXHh)Y( z^qZxcaGi>?Js(zG@d!ACb_pi$OVyVDiVhI|!$5zTf^QvJRW|ev*@nB9usG(fO-qQmxJe zdti)?j>4W4+CI;>Xk@|}v{|mNdI;3Pzg%y&YTJiyx!N52=g&tt8ilNJnED1xeNNkHUPU%butgFM zU;lDzfJv`&6|cQQVclpbnwp&*tN3iwb6!R5^646Iy<`+~*b5uvv2y~$Rbz=QvR7T? z-y5DeM{S>WHPONqYu-~}c53%GoO=xvtNML!j7zTShz(gk9YyA8>TdJi!dirsOzzT^ z%emW6AR^s^+}YCsB*VZ=ftky3Qb#M`YY~K3%j<*9>3HmhXHo4hS1rm4r&>aD5e~D8 zhM<>(s%16gIl&eI^WF2+=8UC#(01Q~==b*DUs*hU!@OL^afHN*wV(NoM8bA@053z- z-<;bAM6Op=nl?fgo%q)HuGQ**z>G32QsVM8kV)RkET21B88@z2TXSF2X(;!Nl-=dP zvgd(8t$SVko>~)CzH@N>Iq^iN3K9KHJ>`1oBi_H^KX$h7?sP??)sa5i`;i`3#>ob) zY+l;cl{cN+%CIjOeLRh8tm#?kepTGvogWAUCL|}<*=fCS5RVy?HVAIMd-PzD5Q}^2=2~kma zc6Rp8?Px--Qc1wt<4)%9-`yv`I*lf45^8E{*ffZ0xq40n3kAiH4ua{8Q=HH_@||OA zVua?&c`Ct7^jM{JUmF>7_xaw>Mp6T>vjg1xUo5J8gcfM~LXQMwI&1;wdn|kVF@u+b z4k}-=?_FpFol#1@;$tnYpGgNB&tXiFjCakdJe3%KzvVVKys_Rin29!wB=!CY{ghp6 zeQ&30=p^0{=(05v5&z&=!!l+DQ1J_Z^FJm8tXJa@!%a#r#$K~My}3d#O(eQd-1PO; z_aHf)@7B#EXPH1?`cKMJ6bl2EEV+s7>>BiH0b^r*Fcq6O{WMfmaKF>jWsHrf$;rtB z0|UVeLqlW-z#15G3ez;%9*U`owYfiA^SZv2&k{^cNx`R)P1(>o-`^jCoOb~-UDgj} zEMUKaD8Zxnd*fssNoQwnSdgSS@NAoopg%M@#R!G!;y7U@ECLa0Q#ZeHHyM8J>!QkSiN|Dw zwf!D{6)OD(p)92TS4vwQK93xxnGwrdm$QKxs;uu^!vD!V_@eUj^EaH^Mn*>|`1o1| zTl4d&VDTNsA?xfuizX59JZ4~Epkrh-0(E+IuD8IlEv~CO_m1|L$K%fK%O04X5Six% zJnS)>S6n=tyxwG^2MY$;lyH{#k`?x3^yjB5P1mPQpt$U8g2s27rhWKJEg2xfS>bC)p<^&K$XGzPka4gB2N+axu^ zq@rOKn0N)9cgH^gN!l5$Z_I=2)(+!S##}&Fd9{Ot@ws}PKmGo{>b?Ugs%~4e5d{SV z!>?q}9}tl!SyGFMBtbxsAfgBeNEVRPjR}+}D2hZAAQGA&l7paYaOQZq=Kqdh_bNQ-!q9eb{I16~1rnwby<}O)Xv#`t*TXb70fD!!^3Crr=#B9DO9- z2vVQN?No)Eb#Je&yWD%gNG-m*wQcgZqPVcBX=x=n4wUwS@6$IhAm2io37eU5rKF_X znQVFFJpBE7^f9imfGRHU;QkWtgWTNO#>Q-M@*b-VOw)JdJjY&H+m7^=VX@zXSVO_b;5+@@RiPV;@+LMX*KeDu7;#(cJ*sQ=40^Ft zQ{~!eI`LNSE8#}dB97>;vYU10EtR0M=HFtjG7);toA=8drg>w%_oU-XD;~~C2&~C= z72Ti{^(|p?Gh^OtVR4=_KXFX4+*RW99JU6|&g~BKoF;3tNMOe!bnF^>5=6rTGn`5+D%n(X@rR*+%+v+TI6Lc(Ipwa0Q z^r(2a$7f?Q`F&zybGD^Mqry@>o2NDyWNoc_#It8M1Eq@2&d$h$0m?(75Fm!#yLW%c z(!PCLXgt=H@fp9i(v5P3-oEt0 z0Lyc0F)WemV(&<$k78DZOjf@y5Fe-(K2MGp84TwaO`d};$s49s6L!Wq?vFTAy>7&h zrAbbbuot~HE^}e0TsF3O9_}WK2c9@E;n5>ljJZmChS8R1R*~DK(v#ajwDXnnx z%zj2YG0hwA_GBeIG`RU9b0Xp8ylQ8V59XT5rdyX5(cQ3#{m3_Bk$^kxzIMszeLY#9 zH4j=lD-{Lx?K~&NC-*hUdrZJ~raPCCZ7^6{&-j&Y0N>7bZTIiO(EW1l)H;pI-BzoI++_?4^p5H|PM6dFiP&=&KQEf-F(wk>A<@-}p^K zPWjnOYwi&$jk(UK7pcP19Ur65tZ=K)3r{+2Zdgo2nYy7KqejWw_o6zCY!G15MKblpF| zBI*6$O!pzjrue%wj9+EHbGL2!@2!-!>$um{C_h`i)uvbY;m;tj`vUzaV&TxX>oE6S zxjgU|f8z^r%?vAl4#L2Z|eyn*duq(0+zxKOR!gp+lxRhYW+r{m$xB30x&c-@n|qIQrp3sRUX)0)XL!%q>zl=Qq&o+*tF$L+%33#6D7p*v(~CYl zEG+i--(u75!4tRYGp;W5y0eE8mr}fDq>As|lj2@2G27f;mARN#^u^LCg!KX5c174k z=63nUHmUFjGO;c#d$|;%n$S@GI^tWy_i`Sp<~qDd&?OFt37Zc`UQYvX`YPeP-ij6c zwI=NL5_e!=pzUqFOP9Wc$n>j%tCA&eE-}S)TnP~_g6!Hhm<;8{!5715dnB6LRF_PB zPDZ2fq1miYdj9_}w@X4lm&>!oU*u&1%H7a=?G z3g(xUl{L*IuQ9LB#IXcsLy!m|{4SPU7v+{HWnfVY5E{$y+fX@p2+Y^a`?B6$h$fB2 zu*Zfi1#r(ZvfjVW5^^G7?LPgysh7>nqExoWLqbxF?O2XIdk3zpV;4de!Vii7$Uo&e zmg&$ZR~+EE$9b;5WOIEu?534fhjE_gl9g3cd_&+NL8k&!sf409Eevs#8OVT~j zbuSj?E16u!<2)9je_TtBwf2QzmU}kQ(|tuiC5VqY(oHP#da`$tFOqmQrc_IPW zZLdS}iDFR}7TBMU*y`eg8R~PIlmsjnOns$Ro0L++t&FnXUh;gkMH;qgrz0e3(w3es zUjMuCtQQT1x^ig0Qwg(zRtFGHvfKy;Z{NLpb<%?7(xpqK_DR|ajp*$KCWvNNKHp{y zQ&`-+*5|6uCT_%Sd=FS(`E zmn2u`0*Gx9_>+WrIqG#`fD>Q@kjF^Dc)Ug33*qARp`hZme(z6?1Mvtz0nX*m$Qjsf z%O@un4NaaF%g9?{^dk9wi;FJ(p5vTA5KiB^^i`{HLM2MR!sn ztwu(r$n>fgh- znab1i`fER2dUpjz@<3&XRmOos!m1u&o7Qa~E}^25YT%doi?xED%griO>x*@wtWvgr zL4L-fuh0$l!4<-+HQsv9_NNv=unctN;NipHK|Swo6UUtkOo3n`q^f6Z@YCf~184Hq z8s0NQMNs9cCG-Apy#Rmcx(L@PnpL^6zC}~_E;Ye0PaWLugvG@RpR^Sqm@(=$}Z)f9?zR4JPpzc9+h>&UNGqvHHuG z52YI7lCrZ8_|4DH%dIgnF~JhWTeB*;mIAJH4)AfddQ6m@efS0OK8G}JUwxj2)&dDh zN6aE!E;)qE7AjJ(3yUa_@=DZBP%8DCe*+$=4uCV2lU!VB!2@h0|bf)5rpxC?L%i2@IeQ1=&PHCl~gxDry8#dlJ&~?t<&}q3S#zbaVgDl+nZnETb0MCjFj;`8{fnP*or@00W9sx0H(<5)!VmD*IXM;juK|t z>2c{}gUTJO5^X5Na7OYqw6w+$XYai>d-LW^r=O3QT_8W#-aR`MBsw;o)06}uz|^%t zs(5p;4moWnE>5#4UeN~XBmrq#R6jjhyxgJz5Zj!EX0CXNk)BzES41QVn6WjzESXC&Gs9@uWOYYm zK>^G4>$VJt^BvN=az#~3ixEx@-MMpT+xj*;JG+Lux_Zf?!13d+A&N>g%2KDc8;?sf z20Q@k2nRuQDmNwmTJnKS#=u8PT{whfWSA?(Y#aDYnE?TT1w07~TH32|mD|$N5}Z*G z$h3o4G9anxKHYh*b&^*~>JS=TMuYe8ZCtrEx(__&Su3k!L?RLR&n?DZ&gXlk&^0r` znJeSn>7uQKM=iR+u^ed{FK=v3@Z3gk>e$Iwm2JD3-Y-M-GjiJQ^b;l#$`xwPnjs;$ zIz`~vG5@HjC?1F5xjAi!TDIs^6Cp{*{>{gv?^RX!A|dIR5HJ$ybq<&rRoGoH?NuqJ zs;Q~?d5&*I7XL2tECe;h->66OOdQo~P7%+hGG5$0GM! zf_Yc=Go|q?3fzZ(+TQ_L-i5vy2z}I*W)$c4TJ0vH z%*chg_6N)RONdL@CBAy{gg@^ha0hRa{cUdFhm-Ey_+o-wUf~qQTOl9O68XI}$@ZnQ zAjcrO%g^(xR$FC>+obNMV@af+Lm#wp9Db4a>ZuM+j#2^vo+A92#@Sz6wag>3qx!@S7hw}9*lK$^4UIRm7r8*N+WUn zgPGeus2KlCQPi|c0j$mI1IdC-8&u}eNhi*>&5k^0W?}iDzVB4KzJA+E)piU=cV^cS z>BADzhqcEW?>ZFh!uJ-e_uV&$LQn7c`%xfhlTIAwOPpD;-oTX+;j2IGHZ3s zI6cZF-QfPz#wC@Joz8M`sC6PSMf}{1mX_z?AginUPL0ZPL?C0UItYe4kn$uK>tXU4tVe=~`Lgq2*u z5vtDZ&y@$(TC%i;<3zd19X&Gm{!q>1CtntR2JBp(xc7~qIR69fE!}uX@U`pscWX1l zOv88o=oPRz`$0Ye(FRqEowRr@lH$dbi12&XUmqLStP1Fb3J(-Erf2-qgsA^oBoDtJ zR#{=2$ZBa>7L@Jjzc+Pju*~V_$x)lOlLL-d|5@TYeyvf5m`mFk2sTtVY+Zfc(37Y! zlWl3mr5AreORMDHD#=AP(8lTR71D8&J9lQjzI|&^+gjb2VaSP$6}hTweiJHHp1UTW zK18~wmD~=C`S`Kh=FOX`=ZWEwm;XhN{tWwrU6f^AcP@;Ywa5dnE@5#abS9`WS}K?D z+RjkwPy6xk0oIt06y1IQbBY0lGutXU9Kx^yqg*`ndo>deWC zine`-U5(_kE8GfA$}jO@PMX$H_D{fL5TjaIoH|D zl`BR`nw8QX4l~(|T)pcG<4sjV?)dt-&87BVf$pJE@!gZKe0)q?Ji>En%oz!Ez&!!X z)gvTx{%57<&=Y=C{&1*#{=#>5qkN~McKD1@$ekf5Z0D|BR64r4Z|R^9UTfgkuQCOj z_l5UgcW`5G>ziR-n$g9`aO-&nCu%Gd{q#4UoIQH>_4%L+<0kl1o+A0D_fn=zD+)4@ zp|F68f;G>xq}3UO)0pHrSOVDV^LwVx{(=YmBSWmruBu9I&nV&*l;_xX0$j?+;W zGQjP$2LI985eVjv7cYiL66#-t)YeH`&`?>&KiOLCIr&1w{zs|RgXdPm-IElL%@x z;z8rC55|g7wY0EdBVuGMuI40Nh#=Jpo=h{4LQ%NDb=W>>E6jiFSOiqC^voQSk-_IV z07gfFf>DV9jVs-l5_F&IZy10S1hVjHW0P{?GB|nmKkSU9Zu(iwbWWXqY!y3c>*Y6#$WiX2J|+@Bt8r?;mRWpgnoWXFNj`%yt-X1jz$ zQv}{}KkYm%^o?Z&+M{`M$qTfg`jmLT}iQBZiZ?nyXHQ`f&25G7h3Xr-v1z)Y*-O-ocT}Vt#70l~( z(dh2(en?l|B( z!kxB_C9f@Cby3?8DLkGyHg=ZFaPl6lE@tS7GHylKc;q29N^GQmt#oY^AY-FMlftuw z;VSEq>hP5{IXSs(+xCye^A+?0k?IfPnK!rB%FsXv8)1FsrFvon5dP69i_rbYQI3Li z<|vfxxh>c6By8>T=Van^7Ozd=)~bI0IjUGaZOwtavba)5tUR?zUeabVI`L&ooQ;k+%l0982i-+EM)%B5pS*Z$1!0I_%}`-P+S5 zxZhuMG{G=(y0<`&CCcM3GYyTPeS!&0!I|dvlGW$xCQGVuNF7V5MW} zShQrD?aE4Nov5~!e1j+KU_i;LOEMbU+$P<&+mF)UG!u8sz2RV`oT}j5C+5e>3UF!1~N9aZ7dR z^5K3ZG#LyBXs?n`564ueSvn3U3g%Uv_|hy|L!^KgF{#gv1KZI}ZXO=iKPw)cT4~c; zg2PcZr3jUAOsKOIC4w>Sw-~E`^-An|g-L&DSs6MmE^cye4lPtAVci(JIb~QT_v`*P z;A2n0dfH;ioUiE2%#7!p_dpEvN#k!#)^38hP3!9pG<8 zzbVf&sG8;Uv!ZyIbM6BUzy_bay?u&7D)ND(i?1S9S67vLZo^_8WK|kRYMx2l`1%+> zodW~1>qt{e)U63-m1ybcaMvMWq0mS#-5>{W1r!wtfR(VyyWfs@pOYg2hp^OlW?8g0 zH;4QC`%^nCO=Vp^fxsT=L|p+Gr?#G6t8y5G6I?xraPei?CLgTi-i{bay|!g5l0SIg zXL~833DTVLx+%|Jnt2HzgZX6B+S1nc9Ekm1W9;Yv68v&(T9b;G;^yjMP*ZaymoOxD zK@?dIQC7G@SzO2JYbqYmLng9)IG4VLO{g-ylxc!!ZB#*+SG(u&G8vJm>@g2jh%nMeG~9P z0c1dOZhQ-j#cWI#0BXrL|8iepzMLAe(YEnkQz^(t1r0OmAp554FM2Jh3m z^g351g0=wRZ-APTXRUC2i(geP^pJ&G9fiC;caxG$%?OYHyF>m_PEJnG`7gAtvjyX0 z0K%GJUSIM;dB{}=t&wHhE4Y;vQOrUR5ri4r)ln&xZ%IT}ErS z#`4OtcFg16{ZZ*vNS%*lRdLn9R}9jZ%qY`bS)^z>o3{p0-_(r469dFX4{R_$cySy@IRgZEB|6f_(Q6wIiG-w;S8 zvxNk4=b^8>YUu`b)@V`}B6Yxjm`Z!I6ws?{>lMr{5F*EtVjR>XAh~Gy3XR1;iAlwrg)|3*QXQL*?Y0{m8!kQed33Y+tl#0eF2bbG3y^~zMcjiX}|6de!@zsx$49dE+AIB{zZ zn*i$#Qt((>*REaT@?CC*V}Idvg2gpB|IYBL+vTlXNAOZeh89s;YA!=*&37TMYLT1Hxe{44@k)|QyQ_qq^>f_{PfMV1_9$dm} zdE!%U?&vq>YYGz!NZ_@(eVb#sxOdONW4vmGg@p)E*y6&Mo^*G2??4x6=NdNvT_KR< zSq}1R)gzh*fQq7paQ1>rU+7PYQmu@K#f)hbF6 zIP4YyZlxW8RbXBRhi$PzA~8)l26Lm8u%w=WDZ^rEY3U?`)b^k;Xy`Tq3HgCJX`Hm% zR9h?zv|zQ{P68}vdwbgll(B&pz5d1PsLv6ZzB_u5ta$-VE%Ef70o)kbfsKy5>|4!m zADoC-o1C7mKd7w`&THe~(D=$a{*`h13-HO*V;--wc8G2Mj!PVo@UWPT)`T(eotBW? zdoG}tGy+Yj*_L0yvj{3GD#9{>DPSvcm~5Y6_5s<6ibbGvjazF23Hy02-0Vm*Li9M& z(Cigdd0GJrB98E*Uj>O2-YV-U?spai7X(FzI^RRsU&44!vP<8t=Je=w{$W9`w^n)v za+ZLuj+&w9?R7*R+@#K`#Y9nG0hs}xrI^|U;y9eKZk-SZ;LQ?}`NXzlrATh_dX#4f!09p$MD2~}& z4`!2^azp399gsi;RhC27iCm>_gbpZw5>AeFQLi0cH0jqiG&BUM!UM0p_{`11QVp;4 zQuJLQ&LkHU5QS$zc}L-yG!u2zyuH1*Huqk}pg7DRPJ>2k6c!aJQd8iA-#ZgMJv}W@ z;Vlf9rZ9N!fEh=q-;#zjG_*vBz0;x=@X0qtzqST!yt=CS$B(BldkiKR6a#0T9|dio zP{()wHYL<)<>S9>ABCbjgWx>m(%JVr$N_-4)tjf2ZqVA=$^&pK*H|+G%xX9FQfLJ` zoJhNm@^%)Nl^sA~!9`#Gn;`~3HKJaJX~sAo;eQM!vBP^Z=ki!l<`Zr7gGoupY{b$4 zz&+!Im|js{{0kn*GMI+$q}=RZ{`mhLdisBQp8xt=Hs?FO$;*=|DJeN{y;J{0ByUY) zoIFJZb3c9BO>w+_NAa?^609x7`mgsRKP?WCl#!vQLit}Qp#mRzF-1ROccs-p zWK^JRy?j4o?P&HN@yGwWiTkgA(BEM8KXW<|*%_xNB`2$ZXl!$%d0AOl_92=j184Oe zr6`Qp$kZ-a2iLN*OFhRT9jVTz*3#Q6#859!hkNry6Ic(*e85oxRsJJ|xm;6Iv&H<% z%IfMdHDhDrhxa^bDYtN9$>-QZdG+tW`G4l~{C^P9e{jpU&I4y09UZ~q_$o3XW~oKM z0wEn@z;-q^`zeG4bvDEKhq}c(5Ffa;;!285-epIOcn69h%Zs|DvolIJg?GPyL#g1& zL(Wki#hlOUEdPjK;g@Inx5VauzU;u|X={gpXxeS1)Bvj_nEi_q zCR$n+{pV)7a#T*kNB^qWE*)N7UVfjNs-cP!+X+B)sxAbP{Zjx!sx&D7ALZrcgwj%o zcyPSIS;}X+q1Ywc4lkmND&J=Z6>GXEzw5f`26`ed2?Pl7XTYJpp7$Z|^82}jB|VMG Vc->qF!$YCe&TE~^IAebQe*vpTAZ`Ev literal 0 HcmV?d00001 diff --git a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md index 5174fca383..3a87bfa491 100644 --- a/docs/pages/pmd/userdocs/extending/writing_rules_intro.md +++ b/docs/pages/pmd/userdocs/extending/writing_rules_intro.md @@ -10,16 +10,37 @@ author: Clément Fournier ## Why write custom rules? +TODO + ## How rules work: the AST -Before running rules, PMD parses the source file into a data structure called an *abstract syntax tree* (AST). This tree represents the syntactic structure of the code, and encodes syntactic relations between source code elements. For instance, in Java, method declarations belong to a class: in the AST, the nodes representing method declarations will be descendants of a node representing the declaration of their enclosing class. This representation is thus much richer than the original source code (which, for a program, is just a chain of characters), or the token chain produced by a lexer. +Before running rules, PMD parses the source file into a data structure called an +*abstract syntax tree* (AST). This tree represents the syntactic structure of the +code, and encodes syntactic relations between source code elements. For instance, +in Java, method declarations belong to a class: in the AST, the nodes representing +method declarations will be descendants of a node representing the declaration of +their enclosing class. This representation is thus much richer than the original +source code (which, for a program, is just a chain of characters), or the token +chain produced by a lexer (which is e.g. what Checkstyle works on). -Conceptually, PMD rules work by *matching a "pattern" against the AST* of a file. Rules explore the AST and find nodes that satisfy some conditions that are characteristic of the specific thing the rule is trying to flag. Rules then report a violation on these nodes. +Conceptually, PMD rules work by *matching a "pattern" against the AST* of a file. +Rules explore the AST and find nodes that satisfy some conditions that are characteristic +of the specific thing the rule is trying to flag. Rules then report a violation on these nodes. ## Defining rules -PMD supports two ways to define rules: using an **XPath query**, or using a **Java visitor**. XPath rules are much easier to set up, since they're defined directly in your ruleset XML, and are expressive enough for most tasks. +PMD supports two ways to define rules: using an **XPath query**, or using a +**Java visitor**. XPath rules are much easier to set up, since they're defined +directly in your ruleset XML, and are expressive enough for most tasks. -On the other hand, some parts of PMD's API are only accessible from Java, e.g. accessing the usages of a declaration. And Java rules allow you to do some complicated processing, to which an XPath rule couldn't scale. +On the other hand, some parts of PMD's API are only accessible from Java, e.g. +accessing the usages of a declaration. And Java rules allow you to do some +complicated processing, to which an XPath rule couldn't scale. -In the end, choosing one strategy or the other depends on the difficulty of what your rule does. I'd advise to keep to XPath unless you have no other choice. +In the end, choosing one strategy or the other depends on the difficulty of what +your rule does. I'd advise to keep to XPath unless you have no other choice. + + +## Testing rules + +TODO link to the page \ No newline at end of file diff --git a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md index 32b293ec6c..a597e34d6b 100644 --- a/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md +++ b/docs/pages/pmd/userdocs/extending/writing_xpath_rules.md @@ -7,10 +7,15 @@ permalink: pmd_userdocs_extending_writing_xpath_rules.html author: Miguel Griffa --- +TODO create more technical reference page for XPath rules + {% include note.html content="For a translation to Georgian, see [webhostinggeeks.com/science/xpath-sourceforge-ka](http://webhostinggeeks.com/science/xpath-sourceforge-ka)" %} -Since the AST is a tree, conceptually similar to a DOM, it can be queried with an *XPath expression* that matches the nodes your rule is looking for. XPath rules are defined using a single XPath expression, specified directly in the ruleset XML. The next section walks you through the development of an XPath rule. +Since the AST is a tree, conceptually similar to a DOM, it can be queried with an + *XPath expression* that matches the nodes your rule is looking for. XPath rules + are defined using a single XPath expression, specified directly in the ruleset + XML. The next section walks you through the development of an XPath rule. {% include note.html content="This page assumes you already know what XPath is and how to read basic XPath queries. W3C has a good tutorial [here](https://www.w3schools.com/xml/xpath_syntax.asp) if you don't." %} @@ -21,20 +26,29 @@ Since the AST is a tree, conceptually similar to a DOM, it can be queried with a > See [Designer Reference](pmd_userdocs_extending_designer_reference.html) for a more detailed explanation on how to use the designer. -The rule designer is a tool that packs a lot of features to help you develop XPath rules quickly and painlessly. Basically, it allows you to examine the AST of a code snippet and evaluate an XPath expression against it. -As for PMD and CPD, you can launch it using `run.sh designer` on Linux/Unix and `designer.bat` on Windows. The interface looks like the following: +The rule designer is a tool that packs a lot of features to help you develop XPath +rules quickly and painlessly. Basically, it allows you to examine the AST of a code +snippet and evaluate an XPath expression against it. -{% include image.html file="userdocs/designer-overview-with-numbers.png" alt="Designer overview" %} +As for PMD and CPD, you can launch it using `run.sh designer` on Linux/Unix and +`designer.bat` on Windows. The interface looks like the following: -The zone (1) is the **main editor**. If you write a code snippet in it, you'll see that the zone (2) will be updated automatically: it's the AST of the code. Note that the code snippet must be a syntactically valid compilation unit for the language you've chosen, e.g. for Java, a compilation unit necessarily has a top-level type declaration. +{% include image.html file="userdocs/designer-overview-with-nums.png" alt="Designer overview" %} -If you select a node in the AST, its specific properties will also be displayed on the left (panel (3)): they're the XPath attributes of the node. +The zone (2) is the **main editor**. When you write a code snippet in the + code area to the left, you'll see that the tree to the right will be updated + automatically: it's the AST of the code. + Note that the code snippet must be a syntactically valid compilation unit for the + language you've chosen, e.g. for Java, a compilation unit necessarily has a top-level + type declaration. -The zone (4) is the **XPath editor**. If you enter an XPath query in that area, it will be evaluated on the current AST and the results will be added to the list in zone (5). - -In the center of the window, a toolbar lets you *select the language version* and *XPath version* you want to use. +If you select a node in the AST, its specific properties will also be displayed +on the left (panel (1)): they're the XPath attributes of the node. +The zone (3) is the **XPath editor**. If you enter an XPath query in that area, +it will be evaluated on the current AST and the results will be added to the +list to the bottom right. ### Rule development process @@ -44,14 +58,17 @@ The basic development process is straightforward: 1. Write a code snippet in the main editor that features the offending code you're looking for 2. Examine the AST and determine what node the violation should be reported on 3. Write an XPath expression matching that node in the XPath editor -4. Refine the XPath expression iteratively using different code snippets, so that it matches violation cases, but no other node +4. Refine the XPath expression iteratively using different code snippets, so that + it matches violation cases, but no other node 5. Export your XPath expression to an XML rule element, and place it in your ruleset In the following sections, we walk through several examples to refine your rule. ## A simple rule -Let's say you want to prevent your coding team from naming variables of type `short` after your boss, whose name is Bill. You try the designer on the following offending code snippet: +Let's say you want to prevent your coding team from naming variables of type +`short` after your boss, whose name is Bill. You try the designer on the following + offending code snippet: ```java @@ -65,7 +82,9 @@ public class KeepingItSerious { ``` -Examining the AST, you find out that the LocalVariableDeclaration has a VariableDeclaratorId descendant, whose `Image` XPath attribute is exactly `bill`. You thus write your first attempt in the XPath editor: +Examining the AST, you find out that the LocalVariableDeclaration has a VariableDeclaratorId +descendant, whose `Image` XPath attribute is exactly `bill`. You thus write your first attempt +in the XPath editor: ```xpath //VariableDeclaratorId[@Image = "bill"] ``` @@ -105,7 +124,7 @@ copy-paste into your ruleset XML. The resulting element looks like so: ```xml TODO @@ -123,13 +142,21 @@ TODO ``` -You can notice that your XPath expression ends up inside a [property](pmd_userdocs_configuring_rules.html#rule-properties) of a rule of type XPathRule, which is how XPath rules are implemented. +You can notice that your XPath expression ends up inside a [property](pmd_userdocs_configuring_rules.html#rule-properties) +of a rule of type XPathRule, which is how XPath rules are implemented. ### Defining rule properties -Some time later, your boss' boss decides he doesn't want to be called short in Java too, and would like you to add him to the rule. There are several ways to do that, but you decide to use a rule property to make your rule extensible. Doing that directly in the XML is [explained on that page](pmd_userdocs_extending_defining_properties.html#for-xpath-rules), and we'll explain here how to do that in the designer. +Some time later, your boss' boss decides he doesn't want to be called short in Java +too, and would like you to add him to the rule. There are several ways to do that, +but you decide to use a rule property to make your rule extensible. Doing that +directly in the XML is [explained on that page](pmd_userdocs_extending_defining_properties.html#for-xpath-rules), + and we'll explain here how to do that in the designer. -The zone (6) in the screenshot above is a list of properties defined for your rule. Right-clicking the table and selecting "Add property..", you may add a property of type `List[String]` to represent your boss names. You can then use it in your XPath query with a dollar prefix, i.e. +The zone (6) in the screenshot above is a list of properties defined for your rule. +Right-clicking the table and selecting "Add property..", you may add a property of +type `List[String]` to represent your boss names. You can then use it in your XPath +query with a dollar prefix, i.e. ```xpath //VariableDeclaratorId[@Image = $bossNames and ../../Type[@TypeImage = "short"]] From 787a6a4a4d35a6d0fb70df5fc1934b1c1e6f4383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 6 Mar 2019 01:29:53 +0100 Subject: [PATCH 030/235] Document XPath funs --- docs/_data/sidebars/pmd_sidebar.yml | 6 + docs/_data/xpath_funs.yml | 29 ++++ docs/_includes/custom/xpath_fun_doc.html | 56 +++++++ docs/_plugins/javadoc_tag.rb | 2 +- docs/_plugins/render_block.rb | 19 +++ .../pmd/userdocs/extending/designer_intro.md | 157 ++++++++++++++++++ .../userdocs/extending/writing_rules_intro.md | 4 +- .../userdocs/extending/writing_xpath_rules.md | 60 +++++-- 8 files changed, 320 insertions(+), 13 deletions(-) create mode 100644 docs/_data/xpath_funs.yml create mode 100644 docs/_includes/custom/xpath_fun_doc.html create mode 100644 docs/_plugins/render_block.rb create mode 100644 docs/pages/pmd/userdocs/extending/designer_intro.md diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index 1725effaac..a3cc8c24a4 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -64,6 +64,12 @@ entries: - title: Writing a rule url: /pmd_userdocs_extending_writing_pmd_rules.html output: web, pdf + - title: Introduction to writing rules + url: /pmd_userdocs_extending_writing_rules_intro.html + output: web, pdf + - title: Using the Rule Designer + url: /pmd_userdocs_extending_designer_intro.html + output: web, pdf - title: Writing XPath rules url: /pmd_userdocs_extending_writing_xpath_rules.html output: web, pdf diff --git a/docs/_data/xpath_funs.yml b/docs/_data/xpath_funs.yml new file mode 100644 index 0000000000..ac403fb965 --- /dev/null +++ b/docs/_data/xpath_funs.yml @@ -0,0 +1,29 @@ +langs: + - name: "Java" + ns: "pmd-java" + funs: + - name: typeIs + returnType: "xs:boolean" + description: "Returns true if the context node's static type is a subtype of the given type" + notes: "The context node must be a {% jdoc jast::TypeNode %}" + parameters: + - name: javaQualifiedName + type: "xs:string" + description: "the qualified name of a class, possibly with pairs of brackets to indicate an array type. + Can also be a primitive type name." + + - name: typeIsExactly + returnType: "xs:boolean" + description: "Returns true if the context node's static type is exactly the given type. + In particular, returns false if the context node's type is + a subtype of the given type." + notes_are_same_as: typeIs + params_are_same_as: typeIs + + - name: metric + returnType: "xs:decimal?" + description: "Returns the value of the metric as evaluated on the context node" + notes: "The context node must be a {% jdoc jast::ASTAnyTypeDeclaration %} or a {% jdoc jast::MethodLikeNode %}" + parameters: + - name: "metricKey" + type: "xs:string" \ No newline at end of file diff --git a/docs/_includes/custom/xpath_fun_doc.html b/docs/_includes/custom/xpath_fun_doc.html new file mode 100644 index 0000000000..b81ee2e1c0 --- /dev/null +++ b/docs/_includes/custom/xpath_fun_doc.html @@ -0,0 +1,56 @@ +{% for lang in site.data.xpath_funs.langs %} + +### {{ lang.name }} + +{{ lang.name }} functions are in the namespace `{{ lang.ns }}`. + +{% for fun in lang.funs %} + + + +