diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/PmdCli.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/PmdCli.java
index 1de2edc64a..4fb3877359 100644
--- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/PmdCli.java
+++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/PmdCli.java
@@ -13,9 +13,9 @@ public final class PmdCli {
private PmdCli() { }
public static void main(String[] args) {
- final int exitCode = new CommandLine(new PmdRootCommand())
- .setCaseInsensitiveEnumValuesAllowed(true)
- .execute(args);
- System.exit(exitCode);
+ final CommandLine cli = new CommandLine(new PmdRootCommand())
+ .setCaseInsensitiveEnumValuesAllowed(true);
+
+ System.exit(cli.execute(args));
}
}
diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/PmdRootCommand.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/PmdRootCommand.java
index ef15d504fd..169690f98a 100644
--- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/PmdRootCommand.java
+++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/PmdRootCommand.java
@@ -6,6 +6,7 @@ package net.sourceforge.pmd.cli.commands.internal;
import net.sourceforge.pmd.PMDVersion;
+import picocli.AutoComplete.GenerateCompletion;
import picocli.CommandLine.Command;
import picocli.CommandLine.IVersionProvider;
@@ -14,7 +15,8 @@ import picocli.CommandLine.IVersionProvider;
exitCodeListHeading = "Exit Codes:%n",
exitCodeList = { "0:Successful analysis, no violations found", "1:An unexpected error occurred during execution",
"2:Usage error, please refer to the command help", "4:Successful analysis, at least 1 violation found" },
- subcommands = { PmdCommand.class, CpdCommand.class, DesignerCommand.class, CpdGuiCommand.class, TreeExportCommand.class })
+ subcommands = { PmdCommand.class, CpdCommand.class, DesignerCommand.class,
+ CpdGuiCommand.class, TreeExportCommand.class, GenerateCompletion.class })
public class PmdRootCommand {
}
diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/CpdLanguageTypeSupport.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/CpdLanguageTypeSupport.java
index 82b0125f52..74bdcd594d 100644
--- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/CpdLanguageTypeSupport.java
+++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/CpdLanguageTypeSupport.java
@@ -8,9 +8,6 @@ import net.sourceforge.pmd.lang.LanguageRegistry;
/**
* Provider of candidates / conversion support for supported CPD languages.
- *
- * Beware, the help will report this on runtime, and be accurate to available
- * modules in the classpath, but autocomplete will include all available at build time.
*/
public class CpdLanguageTypeSupport extends LanguageTypeSupport {
diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/LanguageTypeSupport.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/LanguageTypeSupport.java
index e1cf8978c3..0630b125f6 100644
--- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/LanguageTypeSupport.java
+++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/LanguageTypeSupport.java
@@ -14,9 +14,6 @@ import picocli.CommandLine.TypeConversionException;
/**
* Provider of candidates / conversion support for supported PMD/CPD languages.
- *
- *
Beware, the help will report this on runtime, and be accurate to available
- * modules in the classpath, but autocomplete will include all available at build time.
*/
public class LanguageTypeSupport implements ITypeConverter, Iterable {
diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/PmdLanguageTypeSupport.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/PmdLanguageTypeSupport.java
index 6b6332b343..41023a59b0 100644
--- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/PmdLanguageTypeSupport.java
+++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/PmdLanguageTypeSupport.java
@@ -8,9 +8,6 @@ import net.sourceforge.pmd.lang.LanguageRegistry;
/**
* Provider of candidates / conversion support for supported PMD languages.
- *
- * Beware, the help will report this on runtime, and be accurate to available
- * modules in the classpath, but autocomplete will include all available at build time.
*/
public class PmdLanguageTypeSupport extends LanguageTypeSupport {
diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/PmdLanguageVersionTypeSupport.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/PmdLanguageVersionTypeSupport.java
index 114bcf64d0..fdc5f51efa 100644
--- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/PmdLanguageVersionTypeSupport.java
+++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/typesupport/internal/PmdLanguageVersionTypeSupport.java
@@ -17,9 +17,6 @@ import picocli.CommandLine.TypeConversionException;
/**
* Provider of candidates for valid language-version combinations.
- *
- * Beware, the help will report this on runtime, and be accurate to available
- * modules in the classpath, but autocomplete will include all available at build time.
*/
public class PmdLanguageVersionTypeSupport implements ITypeConverter, Iterable {
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/impl/MultiThreadProcessor.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/impl/MultiThreadProcessor.java
index 035accf05f..cd0e26dc37 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/impl/MultiThreadProcessor.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/impl/MultiThreadProcessor.java
@@ -4,8 +4,12 @@
package net.sourceforge.pmd.lang.impl;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import net.sourceforge.pmd.RuleSets;
@@ -18,13 +22,15 @@ import net.sourceforge.pmd.util.log.MessageReporter;
* @author Romain Pelisse <belaran@gmail.com>
*/
final class MultiThreadProcessor extends AbstractPMDProcessor {
-
private final ExecutorService executor;
+ private final List> futureList;
+
MultiThreadProcessor(final AnalysisTask task) {
super(task);
executor = Executors.newFixedThreadPool(task.getThreadCount(), new PmdThreadFactory());
+ futureList = new LinkedList<>();
}
@Override
@@ -42,18 +48,30 @@ final class MultiThreadProcessor extends AbstractPMDProcessor {
});
for (final TextFile textFile : task.getFiles()) {
- executor.submit(new PmdRunnable(textFile, task) {
+ futureList.add(executor.submit(new PmdRunnable(textFile, task) {
@Override
protected RuleSets getRulesets() {
return ruleSetCopy.get();
}
- });
+ }));
}
}
@Override
public void close() {
try {
+ try {
+ for (Future> task : futureList) {
+ task.get();
+ }
+ } catch (ExecutionException e) {
+ task.getMessageReporter().error("Unknown error occurred while executing a PmdRunnable: {0}",
+ e.getCause().toString(), e.getCause());
+ if (e.getCause() instanceof Error) {
+ throw (Error) e.getCause();
+ }
+ }
+
executor.shutdown();
while (!executor.awaitTermination(10, TimeUnit.HOURS)) {
// still waiting
diff --git a/pmd-core/src/main/resources/rulesets/releases/700.xml b/pmd-core/src/main/resources/rulesets/releases/700.xml
index 6b3eaf09c5..edd237b438 100644
--- a/pmd-core/src/main/resources/rulesets/releases/700.xml
+++ b/pmd-core/src/main/resources/rulesets/releases/700.xml
@@ -9,6 +9,7 @@ This ruleset contains links to rules that are new in PMD v7.0.0
+
@@ -23,4 +24,3 @@ This ruleset contains links to rules that are new in PMD v7.0.0
-
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/AbstractPMDProcessorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/AbstractPMDProcessorTest.java
index a95f36e3da..ca52a03e65 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/AbstractPMDProcessorTest.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/AbstractPMDProcessorTest.java
@@ -4,24 +4,136 @@
package net.sourceforge.pmd.lang.impl;
+import static net.sourceforge.pmd.util.CollectionUtil.listOf;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
+import java.util.concurrent.atomic.AtomicInteger;
+
import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import net.sourceforge.pmd.PMDConfiguration;
+import net.sourceforge.pmd.PmdAnalysis;
+import net.sourceforge.pmd.Report;
+import net.sourceforge.pmd.RuleContext;
+import net.sourceforge.pmd.RuleSet;
+import net.sourceforge.pmd.RuleViolation;
+import net.sourceforge.pmd.lang.DummyLanguageModule;
import net.sourceforge.pmd.lang.LanguageProcessor;
+import net.sourceforge.pmd.lang.LanguageVersion;
+import net.sourceforge.pmd.lang.ast.Node;
+import net.sourceforge.pmd.lang.document.FileId;
+import net.sourceforge.pmd.lang.document.TextFile;
+import net.sourceforge.pmd.lang.rule.AbstractRule;
+import net.sourceforge.pmd.reporting.FileAnalysisListener;
+import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
+import net.sourceforge.pmd.util.log.MessageReporter;
+
+abstract class AbstractPMDProcessorTest {
+ protected SimpleReportListener reportListener;
+
+ protected MessageReporter reporter;
+
+ protected abstract int getThreads();
+
+ protected abstract Class extends AbstractPMDProcessor> getExpectedImplementation();
-class AbstractPMDProcessorTest {
@Test
- void shouldUseMonoThreadProcessorForZeroOnly() {
- AbstractPMDProcessor processor = AbstractPMDProcessor.newFileProcessor(createTask(0));
- assertSame(MonoThreadProcessor.class, processor.getClass());
-
- processor = AbstractPMDProcessor.newFileProcessor(createTask(1));
- assertSame(MultiThreadProcessor.class, processor.getClass());
+ void shouldUseCorrectProcessorImpl() {
+ try (AbstractPMDProcessor processor = AbstractPMDProcessor.newFileProcessor(createTask(getThreads()))) {
+ assertSame(getExpectedImplementation(), processor.getClass());
+ }
}
private LanguageProcessor.AnalysisTask createTask(int threads) {
- LanguageProcessor.AnalysisTask task = new LanguageProcessor.AnalysisTask(null, null, null, threads, null, null, null);
- return task;
+ return new LanguageProcessor.AnalysisTask(null, null, null, threads, null, null, null);
+ }
+
+ @Test
+ void exceptionsShouldBeLogged() {
+ try (PmdAnalysis pmd = createPmdAnalysis()) {
+ pmd.addRuleSet(RuleSet.forSingleRule(new RuleThatThrowsException()));
+ pmd.performAnalysis();
+ }
+
+ assertEquals(2, reportListener.files.get());
+ assertEquals(2, reportListener.errors.get());
+ // exceptions are reported as processing errors
+ Mockito.verifyNoInteractions(reporter);
+ }
+
+ protected PmdAnalysis createPmdAnalysis() {
+ PMDConfiguration configuration = new PMDConfiguration();
+ configuration.setThreads(getThreads());
+ configuration.setIgnoreIncrementalAnalysis(true);
+ reporter = Mockito.spy(configuration.getReporter());
+ configuration.setReporter(reporter);
+
+ PmdAnalysis pmd = PmdAnalysis.create(configuration);
+ LanguageVersion lv = DummyLanguageModule.getInstance().getDefaultVersion();
+ pmd.files().addFile(TextFile.forCharSeq("abc", FileId.fromPathLikeString("file1-violation.dummy"), lv));
+ pmd.files().addFile(TextFile.forCharSeq("DEF", FileId.fromPathLikeString("file2-foo.dummy"), lv));
+
+ reportListener = new SimpleReportListener();
+ GlobalAnalysisListener listener = GlobalAnalysisListener.tee(listOf(
+ new Report.GlobalReportBuilderListener(),
+ reportListener
+ ));
+
+
+ pmd.addListener(listener);
+ return pmd;
+ }
+
+ protected static class RuleThatThrowsException extends AbstractRule {
+ RuleThatThrowsException() {
+ setLanguage(DummyLanguageModule.getInstance().getDefaultVersion().getLanguage());
+ }
+
+ @Override
+ public void apply(Node target, RuleContext ctx) {
+ throw new RuntimeException("test exception");
+ }
+ }
+
+ protected static class RuleThatThrowsError extends AbstractRule {
+ RuleThatThrowsError() {
+ setLanguage(DummyLanguageModule.getInstance().getDefaultVersion().getLanguage());
+ }
+
+ @Override
+ public void apply(Node target, RuleContext ctx) {
+ throw new Error("test error");
+ }
+ }
+
+ protected static class SimpleReportListener implements GlobalAnalysisListener {
+
+ public AtomicInteger violations = new AtomicInteger(0);
+ public AtomicInteger files = new AtomicInteger(0);
+ public AtomicInteger errors = new AtomicInteger(0);
+
+ @Override
+ public FileAnalysisListener startFileAnalysis(TextFile file) {
+ files.incrementAndGet();
+
+ return new FileAnalysisListener() {
+ @Override
+ public void onRuleViolation(RuleViolation violation) {
+ violations.incrementAndGet();
+ }
+
+ @Override
+ public void onError(Report.ProcessingError error) {
+ errors.incrementAndGet();
+ }
+ };
+ }
+
+ @Override
+ public void close() throws Exception {
+
+ }
}
}
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/MonoThreadProcessorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/MonoThreadProcessorTest.java
new file mode 100644
index 0000000000..755003142b
--- /dev/null
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/MonoThreadProcessorTest.java
@@ -0,0 +1,43 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.impl;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import net.sourceforge.pmd.PmdAnalysis;
+import net.sourceforge.pmd.RuleSet;
+
+class MonoThreadProcessorTest extends AbstractPMDProcessorTest {
+
+ @Override
+ protected int getThreads() {
+ return 0;
+ }
+
+ @Override
+ protected Class extends AbstractPMDProcessor> getExpectedImplementation() {
+ return MonoThreadProcessor.class;
+ }
+
+ @Test
+ void errorsShouldBeThrown() {
+ try (PmdAnalysis pmd = createPmdAnalysis()) {
+ pmd.addRuleSet(RuleSet.forSingleRule(new RuleThatThrowsError()));
+ Error exception = assertThrows(Error.class, pmd::performAnalysis);
+ assertEquals("test error", exception.getMessage());
+ }
+
+ // in mono thread, files are processed one after another.
+ // in case of error, we abort at the first error, so in this test case
+ // we abort at the first file, so only 1 file is processed.
+ assertEquals(1, reportListener.files.get());
+ // in mono thread, the error just falls through, we don't additionally catch and log it.
+ Mockito.verifyNoInteractions(reporter);
+ }
+}
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/MultiThreadProcessorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/MultiThreadProcessorTest.java
index f32b330b0a..12e381fac1 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/MultiThreadProcessorTest.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/impl/MultiThreadProcessorTest.java
@@ -4,51 +4,61 @@
package net.sourceforge.pmd.lang.impl;
-import static net.sourceforge.pmd.util.CollectionUtil.listOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
-import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.PmdAnalysis;
-import net.sourceforge.pmd.Report.GlobalReportBuilderListener;
import net.sourceforge.pmd.RuleContext;
-import net.sourceforge.pmd.RuleViolation;
-import net.sourceforge.pmd.lang.DummyLanguageModule;
-import net.sourceforge.pmd.lang.LanguageVersion;
+import net.sourceforge.pmd.RuleSet;
import net.sourceforge.pmd.lang.ast.Node;
-import net.sourceforge.pmd.lang.document.FileId;
-import net.sourceforge.pmd.lang.document.TextFile;
import net.sourceforge.pmd.lang.rule.AbstractRule;
-import net.sourceforge.pmd.reporting.FileAnalysisListener;
-import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
-class MultiThreadProcessorTest {
+class MultiThreadProcessorTest extends AbstractPMDProcessorTest {
- private SimpleReportListener reportListener;
+ @Override
+ protected int getThreads() {
+ return 2;
+ }
- PmdAnalysis setupForTest(final String ruleset) {
- PMDConfiguration configuration = new PMDConfiguration();
- configuration.setThreads(2);
- configuration.setIgnoreIncrementalAnalysis(true);
- PmdAnalysis pmd = PmdAnalysis.create(configuration);
- LanguageVersion lv = DummyLanguageModule.getInstance().getDefaultVersion();
- pmd.files().addFile(TextFile.forCharSeq("abc", FileId.fromPathLikeString("file1-violation.dummy"), lv));
- pmd.files().addFile(TextFile.forCharSeq("DEF", FileId.fromPathLikeString("file2-foo.dummy"), lv));
+ @Override
+ protected Class extends AbstractPMDProcessor> getExpectedImplementation() {
+ return MultiThreadProcessor.class;
+ }
- reportListener = new SimpleReportListener();
- GlobalAnalysisListener listener = GlobalAnalysisListener.tee(listOf(
- new GlobalReportBuilderListener(),
- reportListener
- ));
-
- pmd.addListener(listener);
+ private PmdAnalysis createPmdAnalysis(final String ruleset) {
+ PmdAnalysis pmd = createPmdAnalysis();
pmd.addRuleSet(pmd.newRuleSetLoader().loadFromResource(ruleset));
return pmd;
}
+ @Test
+ void errorsShouldBeThrown() {
+ // in multithreading mode, the errors are detected when closing PmdAnalysis
+ Error error = assertThrows(Error.class, () -> {
+ try (PmdAnalysis pmd = createPmdAnalysis()) {
+ pmd.addRuleSet(RuleSet.forSingleRule(new RuleThatThrowsError()));
+ pmd.performAnalysis();
+ }
+ });
+ assertEquals("test error", error.getMessage());
+
+ // in multithreading mode, all files are started but eventually fail
+ // depending on how many tasks have been started before getting the first results
+ // we might have started only one file analysis or more. But we rethrow
+ // the error on the first.
+ assertTrue(reportListener.files.get() >= 1);
+ // we report the first error
+ Mockito.verify(reporter).error(Mockito.eq("Unknown error occurred while executing a PmdRunnable: {0}"),
+ Mockito.eq("java.lang.Error: test error"),
+ Mockito.any(Error.class));
+ }
+
// TODO: Dysfunctional rules are pruned upstream of the processor.
//
// @Test
@@ -71,7 +81,7 @@ class MultiThreadProcessorTest {
@Test
void testRulesThreadSafety() throws Exception {
- try (PmdAnalysis pmd = setupForTest("rulesets/MultiThreadProcessorTest/basic.xml")) {
+ try (PmdAnalysis pmd = createPmdAnalysis("rulesets/MultiThreadProcessorTest/basic.xml")) {
pmd.performAnalysis();
}
@@ -130,23 +140,4 @@ class MultiThreadProcessorTest {
}
}
- private static class SimpleReportListener implements GlobalAnalysisListener {
-
- public AtomicInteger violations = new AtomicInteger(0);
-
- @Override
- public FileAnalysisListener startFileAnalysis(TextFile file) {
- return new FileAnalysisListener() {
- @Override
- public void onRuleViolation(RuleViolation violation) {
- violations.incrementAndGet();
- }
- };
- }
-
- @Override
- public void close() throws Exception {
-
- }
- }
}
diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml
index 4a657699bf..facb2c6dc0 100644
--- a/pmd-dist/pom.xml
+++ b/pmd-dist/pom.xml
@@ -132,14 +132,6 @@
pmd-cli
${project.version}
-
-
- net.sourceforge.pmd
- pmd-cli
- ${project.version}
- sh
- completion
-
net.sourceforge.pmd
pmd-ant
diff --git a/pmd-dist/src/main/resources/assemblies/pmd-bin.xml b/pmd-dist/src/main/resources/assemblies/pmd-bin.xml
index a69cde3c66..f33bf93348 100644
--- a/pmd-dist/src/main/resources/assemblies/pmd-bin.xml
+++ b/pmd-dist/src/main/resources/assemblies/pmd-bin.xml
@@ -67,19 +67,6 @@
-
-
- runtime
-
- net.sourceforge.pmd:pmd-cli:sh:completion:*
-
- pmd-completion.sh
- shell
- 0755
- 0644
- false
-
-
runtime
diff --git a/pmd-dist/src/main/resources/scripts/pmd b/pmd-dist/src/main/resources/scripts/pmd
index 926238f9da..73476fdab9 100755
--- a/pmd-dist/src/main/resources/scripts/pmd
+++ b/pmd-dist/src/main/resources/scripts/pmd
@@ -52,7 +52,7 @@ set_lib_dir() {
if [ -L "$0" ]; then
local script_real_loc=$(readlink "$0")
else
- local script_real_loc=$0
+ local script_real_loc=${BASH_SOURCE[0]:-${(%):-%x}}
fi
local script_dir=$(dirname "${script_real_loc}")
@@ -74,7 +74,7 @@ set_conf_dir() {
if [ -L $0 ]; then
local script_real_loc=$(readlink "$0")
else
- local script_real_loc=$0
+ local script_real_loc=${BASH_SOURCE[0]:-${(%):-%x}}
fi
local script_dir=$(dirname "${script_real_loc}")
diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java
index 86aec7be9b..86bb126f76 100644
--- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java
+++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java
@@ -88,7 +88,6 @@ class BinaryDistributionIT extends AbstractBinaryDistributionTest {
result.add(basedir + "bin/pmd");
result.add(basedir + "bin/pmd.bat");
result.add(basedir + "conf/simplelogger.properties");
- result.add(basedir + "shell/pmd-completion.sh");
result.add(basedir + "lib/pmd-core-" + PMDVersion.VERSION + ".jar");
result.add(basedir + "lib/pmd-java-" + PMDVersion.VERSION + ".jar");
result.add(basedir + "sbom/pmd-" + PMDVersion.VERSION + "-cyclonedx.xml");
diff --git a/pmd-doc/src/test/resources/expected/pmd_sidebar.yml b/pmd-doc/src/test/resources/expected/pmd_sidebar.yml
index 685cfc5851..756c9ece74 100644
--- a/pmd-doc/src/test/resources/expected/pmd_sidebar.yml
+++ b/pmd-doc/src/test/resources/expected/pmd_sidebar.yml
@@ -93,7 +93,7 @@ entries:
- title: null
output: web, pdf
subfolders:
- - title: Salesforce VisualForce Rules
+ - title: Salesforce Visualforce Rules
output: web, pdf
subfolderitems:
- title: Index
@@ -120,7 +120,7 @@ entries:
- title: null
output: web, pdf
subfolders:
- - title: VM Rules
+ - title: Velocity Template Language (VTL) Rules
output: web, pdf
subfolderitems:
- title: Index
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java
index 5d5892bc43..23506062fe 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java
@@ -52,16 +52,16 @@ public class CommentDefaultAccessModifierRule extends AbstractJavaRulechainRule
"com.google.common.annotations.VisibleForTesting",
"android.support.annotation.VisibleForTesting",
"co.elastic.clients.util.VisibleForTesting",
- "org.junit.jupiter.api.Test",
- "org.junit.jupiter.api.extension.RegisterExtension",
- "org.junit.jupiter.api.ParameterizedTest",
+ "org.junit.jupiter.api.AfterAll",
+ "org.junit.jupiter.api.AfterEach",
+ "org.junit.jupiter.api.BeforeAll",
+ "org.junit.jupiter.api.BeforeEach",
"org.junit.jupiter.api.RepeatedTest",
+ "org.junit.jupiter.api.Test",
"org.junit.jupiter.api.TestFactory",
"org.junit.jupiter.api.TestTemplate",
- "org.junit.jupiter.api.BeforeEach",
- "org.junit.jupiter.api.BeforeAll",
- "org.junit.jupiter.api.AfterEach",
- "org.junit.jupiter.api.AfterAll",
+ "org.junit.jupiter.api.extension.RegisterExtension",
+ "org.junit.jupiter.params.ParameterizedTest",
"org.testng.annotations.Test",
"org.testng.annotations.AfterClass",
"org.testng.annotations.AfterGroups",
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml
index 8ce22f0ebe..6375c33a89 100755
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml
@@ -454,16 +454,16 @@ public enum MyEnum {
- #3859 #4273 [java] CommentDefaultAccessModifier is triggered in JUnit5 method and it was conflicting with rule JUnit5TestShouldBePackagePrivate
+ #3859 #4273 #4645 [java] CommentDefaultAccessModifier is triggered in JUnit5 method and it was conflicting with rule JUnit5TestShouldBePackagePrivate
0
>=" > : DEFAULT
| < RUNSIGNEDSHIFTASSIGN: ">>>=" > : DEFAULT
}
+
+/*
+ * Decorators
+ * See https://github.com/tc39/proposal-decorators
+ */
+
+TOKEN :
+{
+ < AT: "@" > : DEFAULT
+}
diff --git a/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/ecmascript/cpd/EcmascriptTokenizerTest.java b/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/ecmascript/cpd/EcmascriptTokenizerTest.java
index 9e0163405d..32c5c769c0 100644
--- a/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/ecmascript/cpd/EcmascriptTokenizerTest.java
+++ b/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/ecmascript/cpd/EcmascriptTokenizerTest.java
@@ -9,6 +9,8 @@ import org.junit.jupiter.api.Test;
import net.sourceforge.pmd.cpd.test.CpdTextComparisonTest;
import net.sourceforge.pmd.lang.ecmascript.EcmascriptLanguageModule;
+
+
class EcmascriptTokenizerTest extends CpdTextComparisonTest {
EcmascriptTokenizerTest() {
@@ -57,4 +59,9 @@ class EcmascriptTokenizerTest extends CpdTextComparisonTest {
void testTabWidth() {
doTest("tabWidth");
}
+
+ @Test
+ void testDecorators() {
+ doTest("decorator");
+ }
}
diff --git a/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/ecmascript/cpd/testdata/decorator.js b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/ecmascript/cpd/testdata/decorator.js
new file mode 100644
index 0000000000..53de860398
--- /dev/null
+++ b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/ecmascript/cpd/testdata/decorator.js
@@ -0,0 +1,8 @@
+// A simple decorator\n"
+@annotation
+class MyClass { }
+
+function annotation(target) {
+ // Add a property on target
+ target.annotated = true;
+}
\ No newline at end of file
diff --git a/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/ecmascript/cpd/testdata/decorator.txt b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/ecmascript/cpd/testdata/decorator.txt
new file mode 100644
index 0000000000..0469118758
--- /dev/null
+++ b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/ecmascript/cpd/testdata/decorator.txt
@@ -0,0 +1,26 @@
+ [Image] or [Truncated image[ Bcol Ecol
+L2
+ [@] 1 2
+ [annotation] 2 12
+L3
+ [class] 1 6
+ [MyClass] 7 14
+ [{] 15 16
+ [}] 17 18
+L5
+ [function] 1 9
+ [annotation] 10 20
+ [(] 20 21
+ [target] 21 27
+ [)] 27 28
+ [{] 29 30
+L7
+ [target] 4 10
+ [.] 10 11
+ [annotated] 11 20
+ [=] 21 22
+ [true] 23 27
+ [;] 27 28
+L8
+ [}] 1 2
+EOF
diff --git a/pmd-tsql/src/main/java/net/sourceforge/pmd/lang/tsql/TSqlLanguageModule.java b/pmd-tsql/src/main/java/net/sourceforge/pmd/lang/tsql/TSqlLanguageModule.java
index 293421b00e..5dbd3e88ef 100644
--- a/pmd-tsql/src/main/java/net/sourceforge/pmd/lang/tsql/TSqlLanguageModule.java
+++ b/pmd-tsql/src/main/java/net/sourceforge/pmd/lang/tsql/TSqlLanguageModule.java
@@ -17,7 +17,7 @@ public class TSqlLanguageModule extends CpdOnlyLanguageModuleBase {
private static final String ID = "tsql";
public TSqlLanguageModule() {
- super(LanguageMetadata.withId(ID).name("TSql").extensions("sql"));
+ super(LanguageMetadata.withId(ID).name("T-SQL").extensions("sql"));
}
public static TSqlLanguageModule getInstance() {
diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageModule.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageModule.java
index b6d6bd25d6..f596902c2b 100644
--- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageModule.java
+++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageModule.java
@@ -17,7 +17,7 @@ import net.sourceforge.pmd.lang.vf.cpd.VfTokenizer;
*/
public class VfLanguageModule extends SimpleLanguageModuleBase implements CpdCapableLanguage {
static final String ID = "vf";
- static final String NAME = "Salesforce VisualForce";
+ static final String NAME = "Salesforce Visualforce";
public VfLanguageModule() {
super(LanguageMetadata.withId(ID).name(NAME)
diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageProperties.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageProperties.java
index 3ec4d2d21b..445e6d3f1f 100644
--- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageProperties.java
+++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/VfLanguageProperties.java
@@ -19,7 +19,7 @@ public class VfLanguageProperties extends LanguagePropertyBundle {
/**
* Directory that contains Apex classes that may be referenced from a Visualforce page.
*
- * Env variable is {@code PMD_VF_APEXDIRECTORIES}.
+ *
Env variable is {@code PMD_VF_APEX_DIRECTORIES}.
*/
public static final PropertyDescriptor> APEX_DIRECTORIES_DESCRIPTOR =
PropertyFactory.stringListProperty("apexDirectories")
@@ -30,7 +30,7 @@ public class VfLanguageProperties extends LanguagePropertyBundle {
/**
* Directory that contains Object definitions that may be referenced from a Visualforce page.
*
- * Env variable is {@code PMD_VF_OBJECTSDIRECTORIES}.
+ *
Env variable is {@code PMD_VF_OBJECTS_DIRECTORIES}.
*/
public static final PropertyDescriptor> OBJECTS_DIRECTORIES_DESCRIPTOR =
PropertyFactory.stringListProperty("objectsDirectories")
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 ce35a109ec..b441d472ae 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
@@ -15,7 +15,7 @@ import net.sourceforge.pmd.lang.vm.cpd.VmTokenizer;
*/
public class VmLanguageModule extends SimpleLanguageModuleBase {
static final String ID = "vm";
- static final String NAME = "VM";
+ static final String NAME = "Velocity Template Language (VTL)";
public VmLanguageModule() {
super(LanguageMetadata.withId(ID).name(NAME)